Search code examples
rsurvival-analysis

ggsurvplot : legend number at risk


I produced the following life curves with ggsurvplot :

enter image description here

However, I can not display the same colors for the Number at risk legend as for the curves.Also, do you know if it is possible to display the lines instead of the legend for the number at risk (solid or dotted)?

Thank you very much for your help !

below is the code I used to obtain the result :


subjid <- 1:n

status_os <- sample(c(0,1), n, replace = TRUE)
time_os <- ifelse(status_os==0, rnorm(n,mean=365, sd=30), rnorm(n, mean=180, sd=30))

groupe <- sample(c(1,2), n, replace=TRUE)
mutation <- sample(c(1, 0), n, replace=TRUE)

data <- data.frame(Identifiant=subjid, status_os=status_os, time_os=time_os, groupe=groupe, mutation=mutation)

fit <- survfit(Surv(time_os, status_os)~groupe+mutation, data=data)

p <- ggsurvplot(fit, data = data, break.time.by = 12, risk.table = "nrisk_cumevents",
                legend.title = "", legend = c(0.2, 0.2), linetype = c("strata"),
                risk.table.y.text=TRUE, break.x.by = 50)

colors <-  rep(c("red", "red","blue","blue"))
lines <-  rep(c("solid","dashed","solid", "dashed"))

p$plot <- p$plot + scale_linetype_manual(values = lines) +
  scale_colour_manual(values = colors)

p$plot <- p$plot / p$table + plot_layout(ncol = 1, heights = c(2, 1))

Solution

  • What you call "legend" is the axis text of the table plot. And as the style of the axis set is set via the theme() one option to set your colors would be via the color= argument for the axis.text.y which uses ggtext::element_markdown instead of element_text.

    Note: I added the missing pieces to make your example and data reproducible.

    library(survival)
    library(survminer)
    
    p <- ggsurvplot(fit,
      data = data, break.time.by = 12, 
      risk.table = "nrisk_cumevents",
      legend = c(0.2, 0.2), 
      linetype = c("strata"),
      risk.table.y.text = TRUE, 
      break.x.by = 50,
      tables.height = 1/3
    )
    
    colors <- rep(c("red", "red", "blue", "blue"))
    lines <- rep(c("solid", "dashed", "solid", "dashed"))
    
    p$plot <- p$plot + 
      theme(
        legend.position = c(0.05, 0.05),
        legend.justification = c(0.05, 0.05)
      ) +
      scale_linetype_manual(values = lines) +
      scale_colour_manual(values = colors) +
      labs(color = NULL, linetype = NULL)
    
    p$table <- p$table + 
      theme(
        axis.text.y = ggtext::element_markdown(
          color = rev(colors)
        )
      )
    
    p
    

    EDIT A quick and easy approach to have lines in the table plot would be to use unicode characters for the y axis labels to fake a line, e.g. U+2501.

    p$table <- p$table +
      theme(
        axis.text.y = ggtext::element_markdown(
          color = rev(colors),
          hjust = 0,
          vjust = .6
        )
      ) +
      scale_y_discrete(
        labels = ~ rep(
          c("\u2501", "\u2501\u2501"), 2
        ),
        limits = rev
      )
    
    p
    

    enter image description here

    DATA

    set.seed(123)
    
    n <- 100
    subjid <- seq(n)
    
    status_os <- sample(c(0, 1), n, replace = TRUE)
    time_os <- ifelse(
      status_os == 1,
      rnorm(n, mean = 365, sd = 30),
      rnorm(n, mean = 180, sd = 30)
    )
    
    groupe <- sample(c(1, 2), n, replace = TRUE)
    mutation <- sample(c(1, 0), n, replace = TRUE)
    
    data <- data.frame(
      Identifiant = subjid,
      status_os = status_os,
      time_os = time_os,
      groupe = groupe,
      mutation = mutation
    )
    
    fit <- survfit(Surv(time_os, status_os) ~ groupe + mutation, data = data)