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
# 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
Customisation of the survival plot
Colour, title and axis label
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
# 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
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
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
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
surv.plot(fit.lung.arm.m,
legend.name = c("Male", "Female"),
xlab.pos = 6,
ylab.pos = 5
)
Margin area customisation
# 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.
# 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
surv.plot(fit.lung.arm.m,
legend.name = c("Male", "Female"),
risktable = FALSE
)
Risktable position
# 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
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
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
# 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"
)
# 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
# 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"
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
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.
# 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
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.
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
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
surv.plot(fit.lung.arm.m,
legend.name = c("Male", "Female"),
stat = "logrank",
)
coxph
surv.plot(fit.lung.arm.m,
legend.name = c("Male", "Female"),
stat = "coxph"
)
coxph_logrank
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
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
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.
# 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
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())
# 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)
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)
Multiple plots using split.screen()
Export plots as png file
The following examples show how a figure can be exported as png file
for a report.
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.
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()