{"id":513,"date":"2015-08-01T11:31:15","date_gmt":"2015-08-01T10:31:15","guid":{"rendered":"http:\/\/pcool.dyndns.org:8080\/statsbook\/?page_id=513"},"modified":"2025-07-01T19:12:03","modified_gmt":"2025-07-01T18:12:03","slug":"survival-plot","status":"publish","type":"page","link":"https:\/\/pcool.dyndns.org\/index.php\/survival-plot\/","title":{"rendered":"Survival Plot"},"content":{"rendered":"\n<p>For a more detailed discussion about survival analysis, please refer to the <a href=\"https:\/\/pcool.dyndns.org\/index.php\/survival-analysis\/\" data-type=\"page\" data-id=\"516\">relevant section<\/a>. <\/p>\n\n\n\n<p>When the failure time is know accurately,&nbsp; Kaplan-Meier analysis is the preferred method of analysis and Life Table analysis is mostly obsolete. Here, several methods on how to create a survival plot in R are discussed.<\/p>\n\n\n\n<p>Download the <a href=\"https:\/\/pcool.dyndns.org:\/wp-content\/data_files\/plotsurvival.rda\" target=\"_blank\" rel=\"noreferrer noopener\">plotsurvival.rda<\/a> dataset for this example. The data frame is called plotsurvival and the variables are: number (patient number), fu (continuous; follow up time), group (categorical data; Hip 1 or Hip 2) and censor (binary outcome variable). To show the data:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#f20737\" class=\"has-inline-color\">plotsurvival<\/mark><mark style=\"background-color:rgba(0, 0, 0, 0);color:#070af2\" class=\"has-inline-color\">\n   number   fu group censor\n1       1  5.2 Hip 1      0\n2       2  6.3 Hip 1      0\n3       3  7.0 Hip 1      0\n4       4  8.5 Hip 1      0\n5       5  9.4 Hip 1      0\n6       6 10.1 Hip 1      0\n7       7 11.2 Hip 1      0\n8       8 12.0 Hip 1      0\n9       9 12.5 Hip 1      1\n10     10 12.7 Hip 1      0\n11     11  4.5 Hip 2      1\n12     12  5.8 Hip 2      0\n13     13  6.9 Hip 2      0\n14     14  7.8 Hip 2      1\n15     15  8.2 Hip 2      1\n16     16  8.9 Hip 2      1\n17     17  9.5 Hip 2      1\n18     18 10.2 Hip 2      0\n19     19 11.5 Hip 2      0\n20     20 12.9 Hip 2      0<\/mark><\/em><\/code><\/pre>\n\n\n\n<p>To perform survival analysis, the&nbsp;survival package<sup class='sup-ref-note' id='note-zotero-ref-p513-r1-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r1'>1<\/a><\/sup> should be <a href=\"https:\/\/pcool.dyndns.org\/index.php\/packages\/\" data-type=\"page\" data-id=\"22\">installed<\/a>.<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">library(survival)<\/span><\/em><\/code><\/pre>\n\n\n\n<p><strong>Method 1<\/strong>, in R console:<\/p>\n\n\n\n<p><em>First load the survival library and create a survival object called &#8216;hipsurvival&#8217;:<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>library(survival)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>hipsurvival &lt;- Surv(<span style=\"color: #ff0000;\"><em>plotsurvival<\/em><\/span><\/em><\/span><em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#f60606\" class=\"has-inline-color\">$<\/mark><\/em><span style=\"color: #ff0000;\"><em>fu, <span style=\"color: #ff0000;\"><em>plotsurvival<\/em><\/span><\/em><\/span><em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#f40606\" class=\"has-inline-color\">$<\/mark><\/em><span style=\"color: #ff0000;\"><em>censor)<\/em><\/span>\n<em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#f40606\" class=\"has-inline-color\">hipsurvival<\/mark>\n<mark style=\"background-color:rgba(0, 0, 0, 0);color:#091cf2\" class=\"has-inline-color\"> &#091;1]  5.2+  6.3+  7.0+  8.5+  9.4+ 10.1+ 11.2+ 12.0+ 12.5  12.7+  4.5   5.8+  6.9+  7.8   8.2   8.9   9.5  10.2+ 11.5+ 12.9+<\/mark><\/em><\/code><\/pre>\n\n\n\n<p>A summary can be requested:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#eb0c1b\" class=\"has-inline-color\">summary(hipsurvival)<\/mark><mark style=\"background-color:rgba(0, 0, 0, 0);color:#110cea\" class=\"has-inline-color\">\n      time            status   \n Min.   : 4.500   Min.   :0.0  \n 1st Qu.: 6.975   1st Qu.:0.0  \n Median : 9.150   Median :0.0  \n Mean   : 9.055   Mean   :0.3  \n 3rd Qu.:11.275   3rd Qu.:1.0  \n Max.   :12.900   Max.   :1.0  <\/mark><\/em><\/code><\/pre>\n\n\n\n<p>Next, create a survival curve with 95% confidence intervals from the survival object and call this &#8216;hipsurvivalcurve&#8217; :<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>hipsurvivalcurve&lt;-survfit(hipsurvival~1,conf.int=0.95)<\/em><\/span><\/code><\/pre>\n\n\n\n<p class=\"is-style-text-annotation is-style-text-annotation--1\">The ~1 (tilde one) is required for the function; and means no grouping; otherwise, the grouping variable comes after the tilde (see later).<\/p>\n\n\n\n<p>To plot the curve:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>plot(hipsurvivalcurve)<\/em><\/span><\/code><\/pre>\n\n\n\n<p>and add a title and axis labels:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>title(main='Hip Survival Curve',xlab='Follow Up &#091;years]',ylab='probability'<\/em>)<\/span><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot3-1024x768.png\" alt=\"\" class=\"wp-image-3771\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot3-1024x768.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot3-300x225.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot3-768x576.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot3.png 1355w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>To create a plot grouped by type of hip replacement is very straight forward. Instead of using the ~1 in the survival curve object, use:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">hipsurvivalcurve2 &lt;- survfit(hipsurvival<strong>~plotsurvival$group<\/strong>,conf.int=0.95)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>A new plot can be created by plotting the object, with the first curve in red and the second in green :<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">plot(hipsurvivalcurve2,col=c('red','green'))<\/span><\/em>\n<em><span style=\"color: #ff0000;\">title(main='Hip Survival Curve',xlab='Follow Up &#091;years]',ylab='probability')<\/span><\/em><\/code><\/pre>\n\n\n\n<p class=\"is-style-text-annotation is-style-text-annotation--2\">(if there are more groups, more colours can be added)<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot4-1024x768.png\" alt=\"\" class=\"wp-image-3772\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot4-1024x768.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot4-300x225.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot4-768x576.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot4.png 1355w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Method 2<\/strong>, curves with numbers at risk<\/p>\n\n\n\n<p>It is preferable to have the number of patients at risk indicated in the plot. The&nbsp;<a href=\"https:\/\/pcool.dyndns.org:\/wp-content\/R_functions\/kmatrisk.txt\" target=\"_blank\" rel=\"noreferrer noopener\">KMatRisk<\/a>&nbsp;function can be used for this. Copy the function to the clipboard, paste it into the console and hit return. The function should now be available in R (the library survival should also be loaded).<\/p>\n\n\n\n<p>Create the survival curve object&nbsp;directly (in one step) from the data and call this hipfit:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">hipfit &lt;- survfit(Surv(fu,censor)~group,data=plotsurvival)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>Next call the loaded function to create the survival curve with numbers at risk:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">ggkm(hipfit,timeby=1, ystratalabs=c(\"Hip 1\",\"Hip 2\"), main=\"KM plot, Hip&nbsp;by type\",xlabs=\"FU &#091;Years]\")<\/span><\/em><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot5-1024x768.png\" alt=\"\" class=\"wp-image-3773\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot5-1024x768.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot5-300x225.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot5-768x576.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot5.png 1355w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><strong>Method 3, <\/strong>curves using the product limit package<sup class='sup-ref-note' id='note-zotero-ref-p513-r2-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r2'>2<\/a><\/sup>:<\/p>\n\n\n\n<p>The prodlim package creates nice survival curves. First install the package:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">library(prodlim)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>Create a Kaplan-Meier object using the product limit method:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">kmhipfit &lt;- prodlim(Hist(fu, censor) ~ 1, data = plotsurvival)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>To create a plot that shows numbers at risk at yearly intervals with a shadowed 95% confidence interval:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">plot(kmhipfit, percent=FALSE, axes=TRUE, axis1.at=seq(0,kmhipfit$maxtime+1,1), axis1.lab=seq(0,kmhipfit$maxtime+1,1), marktime=TRUE, xlab=\"Years\", atrisk=TRUE, atrisk.labels=\"At Risk:\", confint=TRUE, confint.citype=\"shadow\", col=4)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>And add a title:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">title(main= \"Kaplan Meier Survival Analysis - All Hips\")<\/span><\/em><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot6-1024x768.png\" alt=\"\" class=\"wp-image-3774\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot6-1024x768.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot6-300x225.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot6-768x576.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot6.png 1355w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Similarly, create a plot grouped by type of hip replacement (instead of ~1, use ~group):<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>kmhipfit2 &lt;- prodlim(Hist(fu, censor) ~ group, data = plotsurvival)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>plot(kmhipfit2, percent=FALSE, axes=TRUE, axis1.at=seq(0,kmhipfit2$maxtime+1,1), axis1.lab=seq(0,kmhipfit2$maxtime+1,1), marktime=TRUE, xlab=\"Years\", atrisk=TRUE, atrisk.labels=\"At Risk:\", confint=TRUE, confint.citype=\"shadow\", col=c(4,3), legend=TRUE, legend.x=0, legend.y=0.4, legend.cex=1)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>title(main= \"Kaplan Meier Survival Analysis - By Hip Type\")<\/em><\/span><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"768\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot7-1024x768.png\" alt=\"\" class=\"wp-image-3775\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot7-1024x768.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot7-300x225.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot7-768x576.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survivalplot7.png 1355w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>For more information re prodlim options:<\/p>\n\n\n\n<p><em><span style=\"color: #ff0000;\">??prodlim<\/span><\/em><\/p>\n\n\n\n<p>Please note the syntax to place the legend position.<\/p>\n\n\n\n<p><strong>Method 4<\/strong>, using the survminer package<sup class='sup-ref-note' id='note-zotero-ref-p513-r3-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r3'>3<\/a><\/sup> to create survival curves with ggplot2<sup class='sup-ref-note' id='note-zotero-ref-p513-r4-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r4'>4<\/a><\/sup>:<\/p>\n\n\n\n<p>Still using the <a href=\"https:\/\/pcool.dyndns.org:\/wp-content\/data_files\/plotsurvival.rda\" target=\"_blank\" rel=\"noreferrer noopener\">plotsurvival.rda<\/a> dataset in this example, make sure the appropriate packages are available:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">library(survival)<\/span><\/em>\n<em><span style=\"color: #ff0000;\">library(ggplot2)<\/span><\/em>\n<em><span style=\"color: #ff0000;\">library(survminer)<\/span><\/em><\/code><\/pre>\n\n\n\n<p>First create a survival object and examine it:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">fit &lt;- survfit(Surv(fu, censor) ~ group, data = plotsurvival)<\/span><\/em>\n<em><span style=\"color: #ff0000;\">fit<\/span><\/em>\n<em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#280bf5\" class=\"has-inline-color\">Call: survfit(formula = Surv(fu, censor) ~ group, data = plotsurvival)\n\n             n events median 0.95LCL 0.95UCL\ngroup=Hip 1 10      1   12.5    12.5      NA\ngroup=Hip 2 10      5    9.5     8.2      NA<\/mark><\/em>\n\n<span style=\"color: #ff0000;\"><em>summary(fit)<\/em><\/span>\n<em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#0608ee\" class=\"has-inline-color\">Call: survfit(formula = Surv(fu, censor) ~ group, data = plotsurvival)\n\n                group=Hip 1 \n        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI \n      12.500        2.000        1.000        0.500        0.354        0.125        1.000 \n\n                group=Hip 2 \n time n.risk n.event survival std.err lower 95% CI upper 95% CI\n  4.5     10       1    0.900  0.0949        0.732         1.00\n  7.8      7       1    0.771  0.1442        0.535         1.00\n  8.2      6       1    0.643  0.1679        0.385         1.00\n  8.9      5       1    0.514  0.1769        0.262         1.00\n  9.5      4       1    0.386  0.1732        0.160         0.93<\/mark><\/em><\/code><\/pre>\n\n\n\n<p>To create a basic survival plot:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">ggsurvplot(fit)<\/span><\/em><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"480\" height=\"480\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survminerbasic.png\" alt=\"\" class=\"wp-image-3787\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survminerbasic.png 480w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survminerbasic-300x300.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survminerbasic-150x150.png 150w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/figure>\n\n\n\n<p>Or a more advanced plot:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">ggsurvplot(fit, legend = 'bottom', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">legend.title = 'Group', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">legend.labs = c('Hip 1', 'Hip 2'), <\/span><\/em>\n<em><span style=\"color: #ff0000;\">palette = c(\"#E7B800\", \"#2E9FDF\"), <\/span><\/em>\n<em><span style=\"color: #ff0000;\">conf.int = TRUE, <\/span><\/em>\n<em><span style=\"color: #ff0000;\">conf.int.style = 'ribbon', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">pval = TRUE, <\/span><\/em>\n<em><span style=\"color: #ff0000;\">risk.table = TRUE, <\/span><\/em>\n<em><span style=\"color: #ff0000;\">main = 'Survival Curve', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">xlab = 'Follow Up &#091;Months]', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">ylab = 'Cumulative Survival Probability &#091;%]', <\/span><\/em>\n<em><span style=\"color: #ff0000;\">surv.scale = 'percent')<\/span><\/em><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"480\" height=\"480\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survmineradvanced.png\" alt=\"\" class=\"wp-image-3784\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survmineradvanced.png 480w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survmineradvanced-300x300.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survmineradvanced-150x150.png 150w\" sizes=\"auto, (max-width: 480px) 100vw, 480px\" \/><\/figure>\n\n\n\n<p><strong>Method 5<\/strong>, using the&nbsp;ggfortify package<sup class='sup-ref-note' id='note-zotero-ref-p513-r5-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r5'>5<\/a><\/sup> to create survival curves with ggplot2<sup class='sup-ref-note' id='note-zotero-ref-p513-r6-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r6'>6<\/a><\/sup>:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>library(survival)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>library(ggfortify)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>fit &lt;- survfit(Surv(fu, censor) ~ group, data = plotsurvival)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>autoplot(fit)<\/em><\/span><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1024\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-1024x1024.png\" alt=\"\" class=\"wp-image-3733\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-1024x1024.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-300x300.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-150x150.png 150w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-768x768.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1-1536x1536.png 1536w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot1.png 1584w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Or for a more advanced plot, ggplot2<sup class='sup-ref-note' id='note-zotero-ref-p513-r7-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r7'>7<\/a><\/sup> calls can be added:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>autoplot(fit) + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em>xlab(\"Tme &#091;years]\") + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em>ylab(\"Survival Probability &#091;%]\") + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em>ggtitle(\"Kaplan Meier Survival\") +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>theme_bw(base_size=14, base_family=\"Roboto\")<\/em><\/span><\/code><\/pre>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1019\" height=\"1024\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-1019x1024.png\" alt=\"\" class=\"wp-image-3739\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-1019x1024.png 1019w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-298x300.png 298w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-150x150.png 150w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-768x772.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2-1528x1536.png 1528w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/survival_autoplot2.png 1584w\" sizes=\"auto, (max-width: 1019px) 100vw, 1019px\" \/><\/figure>\n\n\n\n<p><strong>Method 6<\/strong>, using the&nbsp;ggfortify package<sup class='sup-ref-note' id='note-zotero-ref-p513-r8-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r8'>8<\/a><\/sup> to create <em>bespoke survival curves<\/em> with ggplot2 <sup class='sup-ref-note' id='note-zotero-ref-p513-r9-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r9'>9<\/a><\/sup> and the RcmdrPlugin.KMggplot2 package<sup class='sup-ref-note' id='note-zotero-ref-p513-r10-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r10'>10<\/a><\/sup>:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>install.packages(\"RcmdrPlugin.KMggplot2\")<\/em><\/span><\/code><\/pre>\n\n\n\n<p class=\"p1\">However, there is no need to load the package with the library command. The survival and ggfortify packages should be loaded:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\">library(survival)<\/span><\/em>\n<em><span style=\"color: #ff0000;\">library(ggfortify)<\/span><\/em>\n\n<span style=\"color: #ff0000;\"><em>fit &lt;- survfit(Surv(fu, censor) ~ group, data = plotsurvival)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>fit<\/em><\/span>\n<em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#0518fc\" class=\"has-inline-color\">Call: survfit(formula = Surv(fu, censor) ~ group, data = plotsurvival)\n\n             n events median 0.95LCL 0.95UCL\ngroup=Hip 1 10      1   12.5    12.5      NA<\/mark><\/em>\n\n<span style=\"color: #ff0000;\"><em>summary(fit)<\/em><\/span>\n<em><mark style=\"background-color:rgba(0, 0, 0, 0);color:#1f09f2\" class=\"has-inline-color\">Call: survfit(formula = Surv(fu, censor) ~ group, data = plotsurvival)\n\n                group=Hip 1 \n        time       n.risk      n.event     survival      std.err lower 95% CI upper 95% CI \n      12.500        2.000        1.000        0.500        0.354        0.125        1.000 \n\n                group=Hip 2 \n time n.risk n.event survival std.err lower 95% CI upper 95% CI\n  4.5     10       1    0.900  0.0949        0.732         1.00\n  7.8      7       1    0.771  0.1442        0.535         1.00\n  8.2      6       1    0.643  0.1679        0.385         1.00\n  8.9      5       1    0.514  0.1769        0.262         1.00\n  9.5      4       1    0.386  0.1732        0.160         0.93<\/mark><\/em><\/code><\/pre>\n\n\n\n<p>Convert the survival object to a data frame with the fortify() function:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>plot_data &lt;- fortify(fit, surv.connect = TRUE)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>plot_data<\/em><\/span>\n<mark style=\"background-color:rgba(0, 0, 0, 0);color:#1e08f3\" class=\"has-inline-color\">   time n.risk n.event n.censor      surv   std.err     upper     lower strata\n1   0.0     10       0        0 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n2   0.0     10       0        0 1.0000000 0.0000000 1.0000000 1.0000000  Hip 2\n3   5.2     10       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n4   6.3      9       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n5   7.0      8       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n6   8.5      7       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n7   9.4      6       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n8  10.1      5       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n9  11.2      4       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n10 12.0      3       0        1 1.0000000 0.0000000 1.0000000 1.0000000  Hip 1\n11 12.5      2       1        0 0.5000000 0.7071068 1.0000000 0.1250488  Hip 1\n12 12.7      1       0        1 0.5000000 0.7071068 1.0000000 0.1250488  Hip 1\n13  4.5     10       1        0 0.9000000 0.1054093 1.0000000 0.7320116  Hip 2\n14  5.8      9       0        1 0.9000000 0.1054093 1.0000000 0.7320116  Hip 2\n15  6.9      8       0        1 0.9000000 0.1054093 1.0000000 0.7320116  Hip 2\n16  7.8      7       1        0 0.7714286 0.1868706 1.0000000 0.5348489  Hip 2\n17  8.2      6       1        0 0.6428571 0.2612546 1.0000000 0.3852425  Hip 2\n18  8.9      5       1        0 0.5142857 0.3438807 1.0000000 0.2621155  Hip 2\n19  9.5      4       1        0 0.3857143 0.4489847 0.9299128 0.1599887  Hip 2\n20 10.2      3       0        1 0.3857143 0.4489847 0.9299128 0.1599887  Hip 2\n21 11.5      2       0        1 0.3857143 0.4489847 0.9299128 0.1599887  Hip 2\n22 12.9      1       0        1 0.3857143 0.4489847 0.9299128 0.1599887  Hip 2<\/mark><\/code><\/pre>\n\n\n\n<p>Plot:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>ggplot(plot_data, aes(x = time, y = surv * 100)) + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em># plot the survival curve(s)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>geom_step(aes(colour = strata), size = 2) + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em># add the censor indicators<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>geom_point(data = subset(plot_data, n.censor &gt; 0), shape = 3, size = 3, stroke = 2, aes(colour = strata)) + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em># add confidence intervals using the stepribbon geom in the RcmdrPlugin.KMggplot2 package<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>RcmdrPlugin.KMggplot2::geom_stepribbon(data = plot_data, aes(x = time, ymin = lower * 100, ymax = upper * 100, fill = strata), alpha = 0.15, colour = \"transparent\", show.legend = FALSE, kmplot = TRUE) + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em># set the colours of the confidence intervals<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>scale_fill_manual(values = c(\"steelblue\", \"darkorange\")) +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># set the colours of the survival curves<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>scale_colour_manual(values = c(\"steelblue\", \"darkorange\"), name = \"Hip\") + <\/em><\/span>\n<span style=\"color: #ff0000;\"><em># apply a theme based on the Roboto font size 16<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>theme_bw(base_size = 16, base_family = \"Roboto\") +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># add a title, x label, y label and footnote<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>labs(title = \"Custom Made Survival Curve\", subtitle = \"with ggfortify and ggplot2\", x = \"Time &#091;years]\", y = \"Survival Probability &#091;%]\", caption = \"countcool.com\") +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># set the caption to a smaller italic font in darkolivergreen colour<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>theme(plot.caption = element_text(colour = \"darkolivegreen\", face = \"italic\", size = 10)) +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># set the y axis limit in steps of 20 %<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>scale_y_continuous(breaks = seq(0, 100, 20)) +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># set the x axis in steps of 2 years<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>scale_x_continuous(breaks = seq(0, max(plot_data$time) + 2, 2)) +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em># add numbers at risk when failed (label creates a border)<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>annotate(geom = \"label\", x = subset(plot_data$time, plot_data$n.censor == 0), y = -15, label = subset(plot_data$n.risk, plot_data$n.censor == 0)) +<\/em><\/span>\n<span style=\"color: #ff0000;\"><em>annotate(geom = \"text\", x = 0.2, y = -8, label = \"At Risk\", fontface = \"italic\")<\/em><\/span><\/code><\/pre>\n\n\n\n<p class=\"p1\">This should produce the plot below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1019\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1024x1019.png\" alt=\"\" class=\"wp-image-2812\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1024x1019.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-300x298.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-150x150.png 150w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-768x764.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1536x1528.png 1536w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival.png 1592w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"p1\"><\/p>\n\n\n\n<p><strong>Method 7<\/strong>, using the&nbsp;ggfortify package<sup class='sup-ref-note' id='note-zotero-ref-p513-r11-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r11'>11<\/a><\/sup> to create a <em>function<\/em> for <em>bespoke survival curves<\/em> with ggplot2<sup class='sup-ref-note' id='note-zotero-ref-p513-r12-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r12'>12<\/a><\/sup> and the&nbsp;RcmdrPlugin.KMggplot2 package<sup class='sup-ref-note' id='note-zotero-ref-p513-r13-o1'><a class='sup-ref-note' href='#zotero-ref-p513-r13'>13<\/a><\/sup>:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><span style=\"color: #ff0000;\"><em>install.packages(\"RcmdrPlugin.KMggplot2\")<\/em><\/span><\/code><\/pre>\n\n\n\n<p class=\"p1\">However, there is no need to load the package with the library command.<\/p>\n\n\n\n<p class=\"p1\">Load the following function:<\/p>\n\n\n\n<p class=\"p1\"><a href=\"https:\/\/pcool.dyndns.org:\/wp-content\/R_functions\/cool_survival.txt\" target=\"_blank\" rel=\"noreferrer noopener\">cool survival function<\/a><\/p>\n\n\n\n<p class=\"p1\">by copying and pasting the contents in the R console.<\/p>\n\n\n\n<p class=\"p1\">Run it with the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code><em><span style=\"color: #ff0000;\"><span class=\"s1\">cool_survival(<\/span>plotsurvival<span class=\"s1\">, <\/span>time <span class=\"s1\">= <\/span>plotsurvival<span class=\"s1\">$<\/span>fu<span class=\"s1\">, <\/span>censor <span class=\"s1\">= <\/span>plotsurvival<span class=\"s1\">$<\/span>censor<span class=\"s1\">, <\/span>group <span class=\"s1\">= <\/span>plotsurvival<span class=\"s1\">$<\/span>group<span class=\"s1\">)<\/span><\/span><\/em><\/code><\/pre>\n\n\n\n<p class=\"p1\">This should produce the same plot as before:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1019\" src=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1024x1019.png\" alt=\"\" class=\"wp-image-2812\" srcset=\"https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1024x1019.png 1024w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-300x298.png 300w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-150x150.png 150w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-768x764.png 768w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival-1536x1528.png 1536w, https:\/\/pcool.dyndns.org\/wp-content\/uploads\/2025\/06\/bespoke_survival.png 1592w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"p1\"><\/p>\n\n\n\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For a more detailed discussion about survival analysis, please refer to the relevant section. When the failure time is know accurately,&nbsp; Kaplan-Meier analysis is the preferred method of analysis and Life Table analysis is mostly obsolete. Here, several methods on how to create a survival plot in R are discussed. Download the plotsurvival.rda dataset for [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"footnotes":""},"class_list":["post-513","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/pages\/513","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/comments?post=513"}],"version-history":[{"count":4,"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/pages\/513\/revisions"}],"predecessor-version":[{"id":4724,"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/pages\/513\/revisions\/4724"}],"wp:attachment":[{"href":"https:\/\/pcool.dyndns.org\/index.php\/wp-json\/wp\/v2\/media?parent=513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}