Plotting survival curves in R with ggplot2

后端 未结 2 2009
-上瘾入骨i
-上瘾入骨i 2020-12-16 02:31

I\'ve been looking for a solution to plot survival curves using ggplot2. I\'ve found some nice examples, but they do not follow the whole ggplot2 aesthetics (mainly regardin

相关标签:
2条回答
  • 2020-12-16 03:11

    I wanted to do the same thing and also got the error from the cartesian error. In addition I wanted to have numbers of censored in my code and numbers of events. So I wrote this little snippet. Still a bit raw but maybe useful for some.

    ggsurvplot<-function(  
      time, 
      event, 
      event.marker=1, 
      marker,
      tabletitle="tabletitle", 
      xlab="Time(months)", 
      ylab="Disease Specific Survival", 
      ystratalabs=c("High", "Low"),
      pv=TRUE,
      legend=TRUE, 
      n.risk=TRUE,
      n.event=TRUE,
      n.cens=TRUE,
      timeby=24, 
      xmax=120,
      panel="A")
    
    {
      require(ggplot2)
      require(survival)
      require(gridExtra)
    
      s.fit=survfit(Surv(time, event==event.marker)~marker)
      s.diff=survdiff(Surv(time, event=event.marker)~marker)
    
    
      #Build a data frame with all the data
      sdata<-data.frame(time=s.fit$time, 
                        surv=s.fit$surv, 
                        lower=s.fit$lower, 
                        upper=s.fit$upper,
                        n.censor=s.fit$n.censor,
                        n.event=s.fit$n.event,
                        n.risk=s.fit$n.risk)
      sdata$strata<-rep(names(s.fit$strata), s.fit$strata)
      m <- max(nchar(ystratalabs))
      if(xmax<=max(sdata$time)){
        xlims=c(0, round(xmax/timeby, digits=0)*timeby)
      }else{
        xlims=c(0, round((max(sdata$time))/timeby, digits=0)*timeby)
      }
      times <- seq(0, max(xlims), by = timeby)
      subs <- 1:length(summary(s.fit,times=times,extend = TRUE)$strata)
      strata = factor(summary(s.fit,times = times,extend = TRUE)$strata[subs])
      time = summary(s.fit, time = times, extend = TRUE)$time
    
    
      #Buidling the plot basics
      p<-ggplot(data = sdata, aes(colour = strata, group = strata, shape=strata)) + 
                            theme_classic()+
                            geom_step(aes(x = time, y = surv), direction = "hv")+
                            scale_x_continuous(breaks=times)+ 
                            scale_y_continuous(breaks=seq(0,1,by=0.1)) +
                            geom_ribbon(aes(x = time, ymax = upper, ymin = lower, fill = strata), directions = "hv", linetype = 0,alpha = 0.10) + 
                            geom_point(data = subset(sdata, n.censor == 1), aes(x = time, y = surv), shape = 3) + 
                            labs(title=tabletitle)+
                            theme(
                              plot.margin=unit(c(1,0.5,(2.5+length(levels(factor(marker)))*2),2), "lines"),
                              legend.title=element_blank(),
                              legend.background=element_blank(),
                              legend.position=c(0.2,0.2))+
                            scale_colour_discrete(
                              breaks=c(levels(factor(sdata$strata))),
                              labels=ystratalabs) +
                            scale_shape_discrete(
                              breaks=c(levels(factor(sdata$strata))),
                              labels=ystratalabs) +
                            scale_fill_discrete(
                              breaks=c(levels(factor(sdata$strata))),
                              labels=ystratalabs) +
                            xlab(xlab)+
                            ylab(ylab)+
                            coord_cartesian(xlim = xlims, ylim=c(0,1)) 
    
                            #addping the p-value
                            if (pv==TRUE){
                                    pval <- 1 - pchisq(s.diff$chisq, length(s.diff$n) - 1)
                                    pvaltxt<-if(pval>=0.001){
                                                  paste0("P = ", round(pval, digits=3))
                                              }else{
                                                  "P < 0.001"
                                              }
                                              p <- p + annotate("text", x = 0.85 * max(xlims), y = 0.1, label = pvaltxt)
                            }
    
                            #adding information for tables
                            times <- seq(0, max(xlims), by = timeby)
                            subs <- 1:length(summary(s.fit,times=times,extend = TRUE)$strata)
    
                            risk.data<-data.frame(strata = factor(summary(s.fit,times = times,extend = TRUE)$strata[subs]),
                                                  time = summary(s.fit, time = times, extend = TRUE)$time[subs],
                                                  n.risk = summary(s.fit,times = times,extend = TRUE)$n.risk[subs],
                                                  n.cens = summary(s.fit, times=times, extend=TRUE)$n.cens[subs],
                                                  n.event=summary(s.fit, times=times, extend=TRUE)$n.event[subs])
                            #adding the risk table 
                            if(n.risk==TRUE){ 
                                    p<- p + annotate("text", cex=3, x=0.5*max(xlims), y=-0.15, label="Numbers at risk")
                                    for (q in 1:length(levels(factor(marker)))){          
                                        p<- p + annotate("text", cex=3, x=-0.15*max(xlims),y=(-0.15+(-0.05*q)), label=paste0(ystratalabs[q]))
                                        for(i in ((q-1)*length(times)+1):(q*length(times))){
                                              p <- p + annotate("text", cex=3, x=risk.data$time[i], y=(-0.15+(-0.05*q)), label=paste0(risk.data$n.risk[i]))
                                        }
                                    }
                            }
                            #adding the event table 
                            if(n.event==TRUE){ 
                                    p<- p + annotate("text", cex=3, x=0.5*max(xlims), y=(-0.20+(-0.05*length(levels(factor(marker))))), label="Number of events")
                                    for (q in 1:length(levels(factor(marker)))){          
                                        p<- p + annotate("text", cex=3, x=-0.15*max(xlims),y=(-0.20+(-0.05*length(levels(factor(marker))))+(-0.05*q)), label=paste0(ystratalabs[q]))
                                    for(i in ((q-1)*length(times)+1):(q*length(times))){
                                        p <- p + annotate("text", cex=3, x=risk.data$time[i], y=(-0.20+(-0.05*length(levels(factor(marker))))+(-0.05*q)), label=paste0(risk.data$n.event[i]))
                                      }
                                    }
                                  }
                            #adding the cens table 
                            if(n.event==TRUE){ 
                                    p<- p + annotate("text", cex=3, x=0.5*max(xlims), y=(-0.25+(-0.05*length(levels(factor(marker)))*2)), label="Number of censored")
                                    for (q in 1:length(levels(factor(marker)))){          
                                        p<- p + annotate("text", cex=3, x=-0.15*max(xlims),y=(-0.25+(-0.05*length(levels(factor(marker)))*2)+(-0.05*q)), label=paste0(ystratalabs[q]))
                                    for(i in ((q-1)*length(times)+1):(q*length(times))){
                                        p <- p + annotate("text", cex=3, x=risk.data$time[i], y=(-0.25+(-0.05*length(levels(factor(marker)))*2)+(-0.05*q)), label=paste0(risk.data$n.cens[i]))
                                      }
                                    }
                                  }
    
                            #adding panel marker
                                  p <- p + annotate("text", cex=10, x= -0.2*max(xlims), y=1.1, label=panel)
                            #drawing the plot with  the tables outside the margins
                                  gt <- ggplot_gtable(ggplot_build(p))
                                  gt$layout$clip[gt$layout$name=="panel"] <- "off"
                                  grid.draw(gt)
    }
    
    0 讨论(0)
  • 2020-12-16 03:22

    You could try the following for something with shaded areas between CIs:

    (I'm using the development version here as there's a flaw with the parameter alpha in the production version (doesn't shade upper rectangles correctly for non-default values). Otherwise the functions are identical).

    library(devtools)
    dev_mode(TRUE) # in case you don't want a permanent install
    install_github("survMisc", "dardisco")
    library("survMisc", lib.loc="C:/Users/c/R-dev") # or wherever you/devtools has put it
    data(kidney, package="KMsurv")
    p1 <- autoplot(survfit(Surv(time, delta) ~ type, data=kidney),
                   type="fill", survSize=2, palette="Pastel1",
                   fillLineSize=0.1, alpha=0.4)$plot
    p1 + theme_classic()
    dev_mode(FALSE)
    

    giving:

    enter image description here

    And for a classic plot and table:

    autoplot(autoplot(survfit(Surv(time, delta) ~ type, data=kidney),
                      type="CI"))
    

    enter image description here

    See ?survMisc::autoplot.survfit and ?survMisc::autoplot.tableAndPlot for more options.

    0 讨论(0)
提交回复
热议问题