--- title: "Creating survival plot" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Creating survival plot} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", echo = TRUE, eval = TRUE, fig.height = 6, fig.width = 9, fig.align='center' ) ``` After inserting the `survfit{survival}` object into `surv.plot{survSAKK}`, we can create simple survival curves, allowing to visualize survival patterns and incorporate various statistics in our plot. To show some benefit of this function, *NCCTG Lung Cancer Data*, available in the survival package is used. # Setup and Loading Data ```{r setup, warning=FALSE} # Load required libraries library(survSAKK) library(survival) # Load lung data lung <- survival::lung # Compute survival time in months and years lung$time.m <- lung$time/365.25*12 lung$time.y <- lung$time/365.25 # Create survival objects fit.lung.d <- survfit(Surv(time, status) ~ 1, data = lung) fit.lung.m <- survfit(Surv(time.m, status) ~ 1, data = lung) fit.lung.arm.m <- survfit(Surv(time.m, status) ~ sex, data = lung) fit.lung.arm.y <- survfit(Surv(time.y, status) ~ sex, data = lung) ``` # Drawing basic survival plot ```{r baseplot1} # Single arm surv.plot(fit.lung.m) # Two arm surv.plot(fit.lung.arm.m) ``` # Customisation of the survival plot ## Colour, title and axis label ```{r baseplot2} surv.plot(fit.lung.arm.m, # Colour col = c("cadetblue2", "cadetblue"), # Title main = "Kaplan-Meier plot", # Axis label xlab = "Time since treatment start (months)", ylab = "Overall survival (probability)" ) ``` ## Legend position, name and title ```{r baseplot3} # Choose legend position and names of the arms surv.plot(fit.lung.arm.m, legend.position = "bottomleft", legend.name = c("Male", "Female") ) # Choose legend position manually and add a legend title surv.plot(fit.lung.arm.m, legend.position = c(18, 0.9), legend.name = c("Male", "Female"), legend.title = "Sex" ) ``` ## Axis limits, xticks and yticks ```{r baseplot4} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), xticks = seq(0, 36, by = 12), yticks = seq(0, 1, by = 0.2) ) # Cut curve at 24 months surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), xticks = seq(0, 24, by = 6) ) ``` ## Font size ### Global adjustment ```{r baseplot6} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), # Global adjustment cex = 1.3, risktable.name.position = -6, risktable.title.position = -6 ) ``` ### Specific adjustment ```{r baseplot7} surv.plot(fit.lung.arm.m, main = "Kaplan-Meier plot", legend.name = c("Male", "Female"), legend.title = "Sex", # Size of x-axis label xlab.cex = 1.2, # Size of y-axis label ylab.cex = 1.2, # Size of axis elements axis.cex = 0.8, # Size of the censoirng marks censoring.cex = 1, # Size of the legend title legend.title.cex = 1.2, # Size of the risktable risktable.cex = 0.7, # Size of the risktable name risktable.name.cex = 0.9 ) ``` ## Label position x and y axis ### Shift x and y axis label ```{r baseplot8} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), xlab.pos = 6, ylab.pos = 5 ) ``` ## Margin area customisation ```{r baseplot9} # Change the margins and shift the y axis label surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), # New margin area margin.bottom = 6, margin.left = 7, margin.top = 1, margin.right = 2, # Define margin of the y-axis label ylab.pos = 4 ) ``` ## Time unit and y-axis unit The parameter `time.unit` can be set as follows: `"day"`, `"week"`, `"month"`,`"year"`. **Note the following:** - The time unit in `time.unit` needs to correspond to the time unit which was used to calculate the survival object `fit`. - If `time.unit = "month"` x ticks are automatically chosen by intervals of 6 months. Whereas for `time.unit = "year"` the x ticks are chosen by intervals of 1. ```{r baseplot10} # Time unit of month surv.plot(fit.lung.arm.m, time.unit = "month", y.unit = "probability", legend.name = c("Male", "Female") ) # Time unit of year surv.plot(fit.lung.arm.y, time.unit = "year", y.unit = "percent", legend.name = c("Male", "Female") ) ``` # Drawing risk table Per default the risk table is provided below the Kaplan-Meier plot. It provides information about the number of patients at risk at different time points. ## Undisplay risk table ```{r risktable1} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), risktable = FALSE ) ``` ## Risktable position ```{r risktable.pos1} # Move risk table names and titles to the left surv.plot(fit.lung.arm.m, legend.name = c("male", "female"), risktable.name.position = -6, risktable.title.position = -6 ) ``` ## Risktable title, colour and label name ```{r risktable.pos2} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), risktable.name = c("M", "F"), risktable.col = TRUE, risktable.title = "Number at risk", risktable.title.font = 4, risktable.title.col = "#E41A1C" ) ``` ## Risktable with censoring indication ```{r risktable_censoring} surv.plot(fit.lung.arm.m, risktable.censoring = TRUE) ``` # Drawing segment This section explains how to highlight a **specific quantile** or **time point** as a segment in the survival curve and how to adjust segment annotation. ## For a specific quantile ```{r median} # Drawing a segment line for the median, which corresponds to 0.5 quantile surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.quantile = 0.5 ) surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.quantile = 0.5, # Specifying time unit time.unit = "month" ) ``` ```{r quantile0_75} # Drawing segment for the 0.75 quantile surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.quantile = 0.75 ) ``` ## For a specific time point ```{r timepoint} # Drawing a segment line at 12 months surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), time.unit = "month", segment.timepoint = 12 ) ``` # Customisation of the segment ## Change position of segment annotation The parameter `segment.annotation` can take the following values: `c(x,y)`,`"bottomleft"`, `"left"`, `"right"`, `"top"`, `"none"` ```{r segment1} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.timepoint = 18, segment.annotation = "top", time.unit = "month" ) ``` ## Segment title, font, size, and colour ```{r segment2} surv.plot(fit.lung.arm.m, col = c("cadetblue2", "cadetblue"), legend.name = c("Male", "Female"), time.unit = "month", segment.quantile = 0.5, segment.font = 10, segment.main.font = 11, segment.main = "Median PFS in months (95% CI)", segment.cex = 0.8, segment.annotation.col = "darkgray" ) ``` ## Segment lines for different time points / quantile Note that `segment.annotation` needs to be set to "none". Otherwise the code does not work. ```{r segment3} # Several quantiles surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.quantile = c(0.5, 0.25), segment.annotation = "none", time.unit = "month" ) # Several time points surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.timepoint = c(6, 18), segment.annotation = "none", time.unit = "month" ) ``` ## Segment line type, line width and text spacing ```{r segment5} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), time.unit = "month", segment.quantile = 0.5, segment.lwd = 2, segment.lty = "dashed", segment.annotation.space = 0.1 ) ``` ## Segment annotation short version Note that the option `segment.confint = FALSE` only works for two arms. ```{r segment7} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), time.unit = "month", segment.quantile = 0.5, segment.confint = FALSE ) surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), time.unit = "month", segment.timepoint = 18, segment.confint = FALSE, segment.annotation = "bottomleft" ) ``` # Modify confidence interval ```{r segment6} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), segment.quantile = 0.5, conf.int = 0.8 ) surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), time.unit = "month", segment.timepoint = 18, y.unit = "percent", conf.int = 0.9 ) ``` # Include statistics There are three options for the parameter `stat` to display statistics: - `logrank`: gives the p value of the log rank test calculated using `survdiff{survival}`. - `coxph`: gives the hazard ratio (HR) and its 95% CI of the conducted Cox proportional hazards regression using `coxph{survival}`.⁠ - `coxph_logrank`: is a combination of `logrank` and `coxph`. ## `logrank test` ```{r stat1} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), stat = "logrank", ) ``` ## `coxph` ```{r stat2} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), stat = "coxph" ) ``` ## `coxph_logrank` ```{r stat3} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), stat = "coxph_logrank" ) ``` # Customisation of the statistics ## Stat position, colour, text size, and text font ```{r stat4} surv.plot(fit.lung.arm.m, legend.name = c("Male", "Female"), stat = "logrank", stat.position = "right", stat.col = "darkgrey", stat.cex = 0.8, stat.font = 3 ) ``` ## Stat with redfined reference arm and confidence level ```{r stat_ref_arm} surv.plot(fit.lung.arm.m, legend.name = c("Female","Male"), stat = "coxph_logrank", reference.arm = 2, stat.conf.int = 0.80 ) ``` ## Stat with stratification In the next example the ECOG performance status is used as stratification factor for the calculation of the statistics. ```{r stat_stratified} # Fit survival object with stratification fit_lung_stratified <- survfit(Surv(time.m, status) ~ sex + strata(ph.ecog), data = lung) surv.plot(fit.lung.arm.m, stat.fit = fit_lung_stratified, legend.name = c("Male", "Female"), stat = "coxph_logrank" ) ``` # Predefined theme options The following themes are implemented: `SAKK`, `Lancet`, `JCO`, `WCLC`, `ESMO` ```{r Design1} surv.plot(fit.lung.arm.m, theme = "ESMO") ``` ```{r Design2} surv.plot(fit.lung.arm.m, theme = "Lancet") ``` # Multiple survival plots We present to ways how to combine plots: via `par(mfrow=c())` and via `split.screen()` ## Multiple plots using `par(mfrow=c())` ```{r default_setting, echo=FALSE, eval=TRUE} # Save old settings users_default_setting <- par(no.readonly = TRUE) ``` ```{r plots1, fig.height = 8, fig.width = 8} # Creating 4 sub-plot par(mfrow=c(2,2)) # Plot 1 surv.plot(fit.lung.d) # Plot 2 surv.plot(fit.lung.arm.m, time.unit = "month") # Plot 3 surv.plot(fit.lung.arm.y, col = c("cadetblue2", "cadetblue"), time.unit = "year", stat = "coxph") # Plot 4 surv.plot(fit.lung.arm.m, # Cusomization of the survival plot main = "Kaplan-Meier plot", legend.name = c("Male", "Female"), legend.title = "Sex", xlab.cex = 1.2, ylab.cex = 1.2, axis.cex = 0.8, censoring.cex = 1, legend.title.cex = 1.2, # Customization of the risktable risktable.name.position = -9, risktable.title.position = -9, risktable.cex = 0.7) ``` ```{r plots2, fig.height = 10, fig.width = 8} par(mfrow=c(2,1)) # Plot 1 surv.plot(fit.lung.arm.m, col = c("cadetblue2", "cadetblue"), time.unit = "month", segment.quantile = 0.5) # Plot 2 surv.plot(fit.lung.arm.m, col = c("cadetblue2", "cadetblue"), time.unit = "month", segment.timepoint = 6) ``` ```{r resetSetting, echo = FALSE, eval = TRUE} # Ensure that old settings are restored when the function exits par(users_default_setting) ``` ## Multiple plots using `split.screen()` ```{r plots3, fig.height = 10, fig.width = 8} split.screen(c(2,1)) screen(1) surv.plot(fit.lung.arm.m, time.unit = "month", segment.quantile = 0.5, segment.confint = FALSE) screen(2) surv.plot(fit.lung.arm.m, time.unit = "month", segment.quantile = 0.75, segment.confint = FALSE) close.screen(all = TRUE) ``` # Export plots as png file ## Figure output for a report The following examples show how a figure can be exported as png file for a report. ```{r export1, eval = FALSE} png(file = file.path("kaplan_meier_plot.png"), width = 20, height = 14, units = "cm", res = 300) surv.plot(fit.lung.arm.m, risktable.name.position=-4, risktable.title.position=-4) dev.off() ``` ## Figure output for a poster If a bigger font size is needed then this can be done efficiently by choosing a different size of the output file. ```{r export2, eval = FALSE} png(file = file.path("kaplan_meier_plot_big_font.png"), width = 20*0.7, height = 14*0.7, units = "cm", res = 300) surv.plot(fit.lung.arm.m, ylab = "Estimated survival \n (probability)", risktable.name.position=-6.5, risktable.title.position=-6.5) dev.off() ```