How do I add shading and color to the confidence intervals in ggplot 2 generated Kaplan-Meier plot?

FTF picture FTF · Nov 23, 2015 · Viewed 7.1k times · Source

I would like to have the shading of the confidence intervals for the survival estimates. Now I have black lines.

library(survival)
library(ggplot2)
library(GGally)
data(lung) 
sf.sex <- survfit(Surv(time, status) ~ sex, data = lung) 
pl.sex <- ggsurv(sf.sex, CI = TRUE) 
pl.sex

enter image description here

Answer

Sam Dickson picture Sam Dickson · Nov 23, 2015

Here is an easy, almost-right solution:

pl.sex <- ggsurv(sf.sex, CI = FALSE) +
  geom_ribbon(aes(ymin=low,ymax=up,fill=group),alpha=0.3)

Set CI = FALSE to get rid of the dashed-line CI bands then add geom_ribbon() to get the confidence bands you want.

enter image description here

This is only mostly right, though, since we want the confidence bands to use the step function as well. To get exactly what we want, we can use some code from this link to create a new stat for geom_ribbon called "stepribbon" as follows:

library(proto)

stairstepn <- function( data, direction="hv", yvars="y" ) {
  direction <- match.arg( direction, c( "hv", "vh" ) )
  data <- as.data.frame( data )[ order( data$x ), ]
  n <- nrow( data )

  if ( direction == "vh" ) {
    xs <- rep( 1:n, each = 2 )[ -2 * n ]
    ys <- c( 1, rep( 2:n, each = 2 ) )
  } else {
    ys <- rep( 1:n, each = 2 )[ -2 * n ]
    xs <- c( 1, rep( 2:n, each = 2))
  }

  data.frame(
    x = data$x[ xs ]
    , data[ ys, yvars, drop=FALSE ]
    , data[ xs, setdiff( names( data ), c( "x", yvars ) ), drop=FALSE ]
  )
}

stat_stepribbon <- function( mapping=NULL, data=NULL, geom="ribbon", position="identity" ) {
  StatStepribbon$new( mapping=mapping, data=data, geom=geom, position=position )
}

StatStepribbon <- proto(ggplot2:::Stat, {
  objname <- "stepribbon"
  desc <- "Stepwise area plot"
  desc_outputs <- list(
    x = "stepped independent variable",
    ymin = "stepped minimum dependent variable",
    ymax = "stepped maximum dependent variable"
  )
  required_aes <- c( "x", "ymin", "ymax" )

  default_geom <- function(.) GeomRibbon
  default_aes <- function(.) aes( x=..x.., ymin = ..y.., ymax=Inf )

  calculate <- function( ., data, scales, direction = "hv", yvars = c( "ymin", "ymax" ), ...) {
    stairstepn( data = data, direction = direction, yvars = yvars )
  }

  examples <- function(.) {
    DF <- data.frame( x = 1:3, ymin = runif( 3 ), ymax=rep( Inf, 3 ) )
    ggplot( DF, aes( x=x, ymin=ymin, ymax=ymax ) ) + stat_stepribbon()
  }

})

With that new stat you can get the solution I think you were really looking for:

pl.sex <- ggsurv(sf.sex, CI = FALSE) +
  geom_ribbon(aes(ymin=low,ymax=up,fill=group),stat="stepribbon",alpha=0.3) +
  guides(fill=guide_legend("sex"))

enter image description here