I am trying to plot adjusted Kaplan-Meier curves. I know publications like to see something graphical. But using R, I don't know how to go about adjusting for something like age, gender, income when graphing a survival curve.

Otherwise my curves will always be just crude and unadjusted, which I'm guessing people will not like. Any ideas?

I have 4 groups to compare.

  • $\begingroup$ The crude KM curve is a kind of prediction at the means. Therefore, you can backtransform a KM curve using a complementary log log, apply the covariate values estimated from the Cox model, and transform back to the survival scale to plot them. $\endgroup$
    – AdamO
    Sep 19, 2023 at 18:56

4 Answers 4


The only way to provide differential survival with true KM curves is to generate new curves for different groups. You could then display a curve for all persons of group 3, for example. The number of units in each group will decrease as the number of strata increase. However, this method is empiric and does not truly adjust the sample to some chosen set of values.

I am most familiar with methods for obtaining adjusted curves derived from Cox or parametric survival models. Generally speaking, the role of an adjusted curve is to graphically display the expected mortality (or mortality transformed to survival) of the sample if a single or combination of values is set to some fixed value or set of values, respectively.

For example, one might find from a Cox model the hazard ratio for blood pressure is 1.1. Thus, for each 1 unit increase in blood pressure, the average hazard at a given time point multiplies by 1.1. Now, if we wanted to display the mortality curve for all units under analysis (sample) adjusted to a blood pressure of 1 standard deviation above the mean, we could display an adjusted curve.

Here is a self-contained example using group for your reference. Note that the final, adjusted curve is for the mean of group which, for most applications, would have no real meaning. Also note that transformation from mortality to survival are required for this method.


days <- rpois(100, 3)
status <- rbinom(100,1,0.34)
group <- sample(c(1,2,3,4), 100, replace=TRUE)
df <- data.frame(days, status)

#overall survival
surv <- survfit(Surv(days, status)~1)

#survival by group
kmsurv <- survfit(Surv(days,status) ~ strata(group), df)

#survival adjusted to group effect
cox <- coxph(Surv(days,status)~group, df)

Essential information on the R code can be found here.

Lastly, it is my opinion that adjusted survival analysis is generally statistical sleight of hand as the adjustment process can 1) be used for unrealistic patterns of covariates, 2) fool the reader into believing that non-significant effects can result in some displayed survival/mortality pattern and 3) be confused with empiric curves, leading readers to believe you have more events or information for each subgroup/pattern than you actually possess. I would carefully consider why adjusted curves are desirable over adjusted hazard ratios before spending too much time.

  • 1
    $\begingroup$ +1. I particularly agree with the cautions about how adjusted survival curves can be misleading. $\endgroup$
    – EdM
    Aug 28, 2016 at 22:23
  • 2
    $\begingroup$ I also strongly suggest plotting the raw KM curves, rather than adjusted Cox PH curves. By plotting the KM curves, a reader can quickly visualize how reasonable the PH assumption is. With the Cox PH adjusted curve, it automatically looks perfect (even if it's horrible). $\endgroup$
    – Cliff AB
    Aug 28, 2016 at 23:00
  • $\begingroup$ Multiple things are wrong here. 1.) In your example, you did not adjust the survival curve for anything, because you did not add any covariates to adjust for to the model. 2.) The method you are using is known to be biased as pointed out by @friendlystatsguy. 3.) Statistical adjustment is not "sleight of hand". If there are known measured confounders it is absolutely necessary to get unbiased estimates. 4.) adjusted hazard ratios do not have a causal interpretation as pointed out by multiple authors (see doi.org/10.1146/annurev-statistics-040320-114441) $\endgroup$
    – Denzo
    May 9, 2023 at 5:57
  • $\begingroup$ Raw KM curves are usually misleading. By not adjusting for anything you are more likely to see apparent non-proportional hazards that can sometimes disappear when accounting for outcome heterogeneity. $\endgroup$ May 9, 2023 at 11:38

There is a lot of literature on the subject and there is also some R Code available.

The method Todd D described is known as average method and it is conceptually and empirically biased (See for example Nieto (1996). It is generally recommended to use direct adjustment or conditional adjustment instead.

The survminer package contains a function called ggadjustedcurves which implements direct adjustment (given a cox model) in the method marginal. A non-parametric method to adjust survival curves, which is based on a weighted kaplan-meier estimator, can be found in Xie (2000). This method and a corresponding weighted log-rank test are implemented in the R-Package RISCA.


Unadjusted Kaplan-Meier curves are not a problem in general. The question is: what do you want to show? Usually you would want the plot to be a visualization of the causal average treatment effect of a grouping variable on the survival probability. If your groups were randomized in a large study, you can go usually go ahead and use the standard Kaplan-Meier curves, since randomization should take care of confounding already.

However, if you are analyzing the effect of a non-randomized group (which is always the case in observational studies), it may be very important to adjust for confounders to obtain an unbiased estimate of the treatment-specific survival curves.

The literature on causal inference deals with this problem in great detail. Many methods have been proposed to obtain confounder-adjusted survival curves. Which method you want to use depends on your specific situation. In a recent article me and my colleagues give a detailed overview and comparison of those methods which may provide some guidance (https://doi.org/10.1002/sim.9681).

I also developed the adjustedCurves R package which implements most of the available methods. Here is a very small example on how this package may be used to obtain adjusted survival curves using g-computation:

# install the package if needed

# load packages

# just used to make the example reproducible

# simulate some example data
sim_dat <- sim_confounded_surv(n=50, max_t=1.2)
sim_dat$group <- as.factor(sim_dat$group)

# outcome model
cox_mod <- coxph(Surv(time, event) ~ x1 + x2 + x4 + x5 + group,
                 data=sim_dat, x=TRUE)

# using g-computation with confidence intervals
adjsurv <- adjustedsurv(data=sim_dat,
plot(adjsurv, conf_int=TRUE)


More information can be found in the extensive documentation of the package and the article I cited.

  • $\begingroup$ Why is $g$-computation needed for this? $\endgroup$ May 9, 2023 at 11:38
  • $\begingroup$ Because without g-computation you can only obtain conditional survival probabilities from the cox-model, namely the survival probability at t for specific covariate values (for example someone with group = 1 & x1 = 0 & x2 = 1 & x4 = 1.2 & x5 = 2.3). If you are interested in the survival probability that would have been observed if all people in the dataset had been set to group = 0 or group = 1, this is insufficient. $\endgroup$
    – Denzo
    May 9, 2023 at 12:38
  • $\begingroup$ The "if all people" estimand is not relevant. It merely hides differences among people. And it does not transport outside the sample unless you have a true probability sample from the population. Covariate-specific estimands transport, not depending on covariate mix in the sample. $\endgroup$ May 9, 2023 at 13:59
  • $\begingroup$ I disagree. The estimand I described is a type of average treatment effect, which is the standard estimand in almost all randomized studies. Even if we accepted your opinion as truth, how would you visualize the effect of the group variable using survival curves if you have many, possible continuos variables in the cox model? $\endgroup$
    – Denzo
    May 9, 2023 at 14:31
  • 2
    $\begingroup$ Glad to call out CI on this. The causal inference literature has largely failed to correct this error, insisting on marginal estimates that do not necessarily apply to anyone even going so far as to sometimes label sample averaged effects as population average effects. Elaborated here. This causal approach applies only when doing simple random samples or probability samples from a population. That is far from the case in randomized trials. $\endgroup$ May 10, 2023 at 22:26

There is also recently published paper which can create adjusted survival and cumulative incidence curve for survival and competing risks outcome respectively. https://www.tandfonline.com/doi/full/10.1080/03610918.2023.2245583.

Furthermore, there is also an R package adjSURVCI. https://cran.r-project.org/web/packages/adjSURVCI/index.html.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.