Cox-Proportional Hazards Survival Curve has too many lines - can binning the continuous variable help? [duplicate]

I am doing survival analysis on some continuous variables and am finding that some of my plots are difficult to interpret because there are too many lines. Here is an example:

I am interested in making complex curves like these more interpretable. I guess it might be possible to improve things with some graphical tweaks and I welcome any suggestions for how to do so in R (I am using packages ggplot2, GGally and survival). But I think what I really need to do to improve interpretability is reduce the number of lines shown on the plot by binning the continuous variable. I am asking the community for guidance about how and at what point should such binning occur?

Without knowing any better approach, my binning method would simply be to divide the variable into three categories:

• 0
• less-than-median
• greater-than-median

with the median being computed after removing the 0 values. This method makes intuitive sense to me but I don't have any mathematical justification for it nor have I been able to find any examples of people doing something similar in survival analysis. If there's something problematic about it or if there's a better way, please let me know, but I am ultimately much less comfortable with the question of when to bin.

As for when the binning should occur, I am reluctant to bin the continuous variable before computing the Cox PH values because I think this could have a major impact the p-value and because my only rationale for binning this way is that I expect it will make my graphs easier to interpret. But if I bin the continuous variable after computing the Cox PH, I worry that that I'll be misrepresenting the data since the p-value will have been based on values which are masked by the binning.

Apologies if this is a common/simple/already-answered question. I am pretty new to data science and have not had much formal training (and none at all relating to survival analysis),

You need to think differently about the Cox PH analysis itself and the way that you display the data.

Keeping the variable as continuous in the Cox PH analysis itself is important, as you recognize. That forms the basis of statistical significance, hazard ratios and their confidence intervals, and so forth.

That, however, is no reason to avoid showing survival plots for binned values of the continuous variable. Your claim of statistical significance is not based on the plots, it's based on the Cox PH analysis. The survival curves are just a convenient way to show the audience how much survival may vary over the range of the variable. The choice of number of bins to use is pretty much up to you; you don't want so many lines as to confuse the reader. You should include similar numbers of cases in each bin.

This also can be a useful tool for checking your model. I once found a "significant" relation for a continuous variable, but when I looked at plots over binned ranges it was clear that the influence of the variable on outcome hit a maximum well below the top of its range.

If you want to visualize the effect of a continuous variable on the survival probability you might be interested in the contsurvplot R-package (written by me), available on github: https://github.com/RobinDenz1/contsurvplot

It includes multiple plots that display the survival probability as a function of both time and the continuous variable simultaneously. All you need is a suitable model, such as a Cox model and you are good to go.

Here is a simple example using the nafld1 dataset from the survival package. First you need to install the contsurvplot package, which can be done using:

devtools::install_github("RobinDenz1/contsurvplot")


Lets suppose we are interested in the effect of age on the survival time. First we will fit a Cox model:

library(contsurvplot)
library(riskRegression)
library(survival)
library(ggplot2)
library(pammtools)

# using data from the survival package
data(nafld, package="survival")

# taking a random sample to keep the example fast
set.seed(43)
nafld1 <- nafld1[sample(nrow(nafld1), 400), ]

# fit cox-model with age
model <- coxph(Surv(futime, status) ~ age, data=nafld1, x=TRUE)


Now, all we need to do is plug it into one of the plot functions. For example, this is a survival area plot for 40-70 year olds:

plot_surv_area(time="futime",
status="status",
variable="age",
data=nafld1,
model=model,
horizon=seq(40, 70, 0.5))


And this is a survival contour plot for the same age range:

plot_surv_contour(time="futime",
status="status",
variable="age",
data=nafld1,
model=model,
horizon=seq(40, 70, 0.5))


The package includes many other plot functions. The methodology behind it is explained in the associated preprint: https://arxiv.org/abs/2208.04644 (also written by me)

• Rather than repeating a (very nice!) answer, it's best to flag a question as a duplicate if the threads are very similar and the same answer addresses both. Also, I suggest mentioning that you're linking to a tool & paper of your creation (I'm guessing) - it's standard practice here.
– mkt
Commented Aug 11, 2022 at 19:31
• I am sorry, I did not know that. Yes it is both authored (at least partially) by me. I will link my answers accordingly next time. Commented Aug 11, 2022 at 19:33
• No problem! It's nice work and we're happy to have your expertise here. Just FYI, this particular answer will likely be deleted because of the duplication with the earlier one. Or at least, one of the questions will be closed because they are so similar.
– mkt
Commented Aug 11, 2022 at 20:31