Trey Batey
2011-Jul-05 22:08 UTC
[R] plotting survival curves (multiple curves on single graph)
Hello. This is a follow-up to a question I posted last week. With some previous suggestions from the R-help community, I have been able to plot survival (, hazard, and density) curves using published data for Siler hazard parameters from a number of ethnographic populations. Can the function below be modified, perhaps with a "for" statement, so that multiple curves (different line types---one for each population) are plotted on a single graph for comparison? Thanks so much. --Trey The function and calls below use the data in this Excel file (feel free to access): https://docs.google.com/leaf?id=0B5zZGW2utJN0ZDk1NjA0ZjUtMWU0ZS00ZGQ3LWIxZTUtOWE0NGVmYWMxODJl&hl=en_US ## - plot Siler survival curve ############################## silsurv<-function(a1,b1,a2,a3,b3) { sil=function(t) { h.t<-a1*exp(-b1*t)+a2+a3*exp(b3*t) S.t<-exp(-a1/b1*(1-exp(-b1*t))-a2*t+a3/b3*(1-exp(b3*t))) d.t<-S.t*h.t #return(d.t) return(S.t) #return(h.t) } t<-seq(0,90,1) plot(t,sil(t),ylim=c(0,1),type='l',cex.lab=0.8,cex.axis=0.75,ylab='S(t)',xlab='Age (years)') } with(hazanth[1,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[1,1],cex.main=0.9) # plot for Hadza with(hazanth[2,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[2,1],cex.main=0.9) # plot for Ache with(hazanth[3,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[3,1],cex.main=0.9) # plot for Hiwi with(hazanth[4,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[4,1],cex.main=0.9) # plot for !Kung with(hazanth[5,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[5,1],cex.main=0.9) # plot for Yanomamo with(hazanth[6,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[6,1],cex.main=0.9) # plot for Tsimane ###############################
Bert Gunter
2011-Jul-05 22:16 UTC
[R] plotting survival curves (multiple curves on single graph)
Yes, it can be done using basic plot commands. But if you really want to get fancy and plot "grouped" graphs, I strongly recommend you look into R's packages -- ggplot or trellis. Both have excellent documentation and companion books and were built for this sort of thing. The (considerable) learning curve will be worth the effort. Cheers, Bert On Tue, Jul 5, 2011 at 3:08 PM, Trey Batey <ekt.batey at gmail.com> wrote:> Hello. > > This is a follow-up to a question I posted last week. ?With some > previous suggestions from the R-help community, I have been able to > plot survival (, hazard, and density) curves using published data for > Siler hazard parameters from a number of ethnographic populations. > Can the function below be modified, perhaps with a "for" statement, so > that multiple curves (different line types---one for each population) > are plotted on a single graph for comparison? ?Thanks so much. > > --Trey > > The function and calls below use the data in this Excel file (feel > free to access): > https://docs.google.com/leaf?id=0B5zZGW2utJN0ZDk1NjA0ZjUtMWU0ZS00ZGQ3LWIxZTUtOWE0NGVmYWMxODJl&hl=en_US > > ## - plot Siler survival curve > ############################## > silsurv<-function(a1,b1,a2,a3,b3) > ?{ > ? ?sil=function(t) > ? ? ?{ > ? ? ? ?h.t<-a1*exp(-b1*t)+a2+a3*exp(b3*t) > ? ? ? ?S.t<-exp(-a1/b1*(1-exp(-b1*t))-a2*t+a3/b3*(1-exp(b3*t))) > ? ? ? ?d.t<-S.t*h.t > > ? ? ? ?#return(d.t) > ? ? ? ?return(S.t) > ? ? ? ?#return(h.t) > ? ? ?} > ? ?t<-seq(0,90,1) > plot(t,sil(t),ylim=c(0,1),type='l',cex.lab=0.8,cex.axis=0.75,ylab='S(t)',xlab='Age > (years)') > ?} > > with(hazanth[1,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[1,1],cex.main=0.9) > ?# plot for Hadza > with(hazanth[2,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[2,1],cex.main=0.9) > ?# plot for Ache > with(hazanth[3,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[3,1],cex.main=0.9) > ?# plot for Hiwi > with(hazanth[4,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[4,1],cex.main=0.9) > ?# plot for !Kung > with(hazanth[5,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[5,1],cex.main=0.9) > ?# plot for Yanomamo > with(hazanth[6,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[6,1],cex.main=0.9) > ?# plot for Tsimane > > ############################### > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >-- "Men by nature long to get on to the ultimate truths, and will often be impatient with elementary studies or fight shy of them. If it were possible to reach the ultimate truths without the elementary studies usually prefixed to them, these would not be preparatory studies but superfluous diversions." -- Maimonides (1135-1204) Bert Gunter Genentech Nonclinical Biostatistics 467-7374 http://pharmadevelopment.roche.com/index/pdb/pdb-functional-groups/pdb-biostatistics/pdb-ncb-home.htm
David Winsemius
2011-Jul-05 22:24 UTC
[R] plotting survival curves (multiple curves on single graph)
On Jul 5, 2011, at 6:08 PM, Trey Batey wrote:> Hello. > > This is a follow-up to a question I posted last week. With some > previous suggestions from the R-help community, I have been able to > plot survival (, hazard, and density) curves using published data for > Siler hazard parameters from a number of ethnographic populations. > Can the function below be modified, perhaps with a "for" statement, so > that multiple curves (different line types---one for each population) > are plotted on a single graph for comparison? Thanks so much. >There are (at least) three methods to plot multiple curves in base plotting: -- plot() then lines() ?lines --plot(); par(add=TRUE); plot() ?par # There is also matplot() ?matplot After extracting the sil function to exist on its own, you could try: matplot(x=t, y=apply(hazanth[ ,3:7], 1, sil) My first choice would be to make a modified version of your silsurv that uses the lines function rather than plot and then you can just use the lines of code you already have. -- David> --Trey > > The function and calls below use the data in this Excel file (feel > free to access): > https://docs.google.com/leaf?id=0B5zZGW2utJN0ZDk1NjA0ZjUtMWU0ZS00ZGQ3LWIxZTUtOWE0NGVmYWMxODJl&hl=en_US > > ## - plot Siler survival curve > ############################## > silsurv<-function(a1,b1,a2,a3,b3) > { > sil=function(t) > { > h.t<-a1*exp(-b1*t)+a2+a3*exp(b3*t) > S.t<-exp(-a1/b1*(1-exp(-b1*t))-a2*t+a3/b3*(1-exp(b3*t))) > d.t<-S.t*h.t > > #return(d.t) > return(S.t) > #return(h.t) > } > t<-seq(0,90,1) > plot > (t > ,sil > (t > ),ylim=c(0,1),type='l',cex.lab=0.8,cex.axis=0.75,ylab='S(t)',xlab='Age > (years)') > } > > with > (hazanth > [1,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[1,1],cex.main=0.9) > # plot for Hadza > with > (hazanth > [2,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[2,1],cex.main=0.9) > # plot for Ache > with > (hazanth > [3,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[3,1],cex.main=0.9) > # plot for Hiwi > with > (hazanth > [4,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[4,1],cex.main=0.9) > # plot for !Kung > with > (hazanth > [5,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[5,1],cex.main=0.9) > # plot for Yanomamo > with > (hazanth > [6,3 > : > 7 > ],silsurv > (a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[6,1],cex.main=0.9) > # plot for Tsimane > > ############################### > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.David Winsemius, MD West Hartford, CT
Dennis Murphy
2011-Jul-06 00:29 UTC
[R] plotting survival curves (multiple curves on single graph)
Hi: Here's one way to put all the plots in one graph using ggplot2 and a couple of tricks using the plyr package. You could take the data frame I generate below and use it as input to lattice graphics if you prefer. For groupwise plots, either as an ensemble or as separate panels, these packages are usually less work than an equivalent base graphic. OTOH, if you want a graphic to be 'just so', it may be better to use base graphics since both ggplot2 and lattice make certain design decisions that are not always trivial to override. I concur with Bert's comments re lattice and ggplot2, though. The first step is to produce a suitable data frame. To generate the Siler curves for each group, one can use the mapply() function in base R or the mdply() function in the plyr package. I chose the latter, but some post-processing is necessary. Once the curves are obtained, the next step is to generate a data frame that contains the curves which will subsequently be used as input to render the curves by group. library(ggplot2) # also loads package plyr time <- 0L:90L # Function to generate a Siler survival curve siler <- function(a1, b1, a2, a3, b3) { exp(-a1/b1 * (1 - exp(-b1 * time))- a2 * time + a3/b3 * (1 - exp(b3 * time))) } # See explanation below silerCurves <- as.vector(t(mdply(hazanth[, 3:7], siler)[, 6:96])) # Generate a data frame with the populations, times and curve values silerdat <- data.frame(pop = rep(hazanth[['pop']], each = length(time)), time = rep(time, nrow(hazanth)), surv = silerCurves) # Basic form of graph: ggplot(silerdat, aes(x = time, y = surv, colour = pop)) + geom_line(size = 1) + xlab('Years') + ylab('S(t)') To get the Siler curves, I used that part of the hazanth data frame containing the parameters that determine a curve. The mdply() function operates rowwise, and substitutes the values of the parameters into the calling function (siler) to generate each curve. (The order of the parameters in the input data frame have to be exactly the same as those in the calling function.) The result is a 6 x 96 data frame, but the first five columns are the input parameters which are no longer needed; moreover, we want to transpose the result (t) and then stack the columns one below the other (i.e., the first set of curve values is on top, the last on the bottom), which is what as.vector() does. The new data frame silerdat then associates a population with each curve and matches the times corresponding to the curve values. This data frame is then input into ggplot(). If ggplot2 is new to you, the basic idea is that a plot is assembled incrementally in 'layers'. The '+' sign indicates that a new layer is being added to the existing plot. 'Geoms' represent different geometric elements of a plot; in this case, geom_smooth() is a reasonable choice to fit a smooth curve through the (time, surv) pairs. Color is an 'aesthetic' that is used here to distinguish among the various populations. A default legend is produced with the plot, which can be optionally repositioned or modified. The on-line help pages for ggplot2 are found at http://had.co.nz/ggplot2/ Scroll down to 'Reference manual'. A freely available chapter of the ggplot2 book is a useful way to get started with the package; see the 'ggplot book' heading on the same page and click on the book website to gain access to it. Similar graphs using the lattice package are obtained as follows, with a couple of choices of legend: # Legend inside the plot region mykey <- list( corner = c(1, 1), title = 'Population', cex.title = 1.1, text = list(levels(silerdat$pop), cex = 0.8), lines = list(col = 1:6, lwd = 2)) xyplot(surv ~ time, data = silerdat, groups = pop, type = 'l', lwd = 2, col.line = 1:6, key = mykey, xlab = 'Years', ylab = 'S(t)') # Legend outside the plot region (similar to the ggplot() above) mykey2 <- list( space = 'right', title = 'Population', cex.title = 1.1, text = list(levels(silerdat$pop), cex = 0.8), lines = list(col = 1:6, lwd = 2)) xyplot(surv ~ time, data = silerdat, groups = pop, type = 'l', lwd = 2, col.line = 1:6, key = mykey2, xlab = 'Years', ylab = 'S(t)') HTH, Dennis On Tue, Jul 5, 2011 at 3:08 PM, Trey Batey <ekt.batey at gmail.com> wrote:> Hello. > > This is a follow-up to a question I posted last week. ?With some > previous suggestions from the R-help community, I have been able to > plot survival (, hazard, and density) curves using published data for > Siler hazard parameters from a number of ethnographic populations. > Can the function below be modified, perhaps with a "for" statement, so > that multiple curves (different line types---one for each population) > are plotted on a single graph for comparison? ?Thanks so much. > > --Trey > > The function and calls below use the data in this Excel file (feel > free to access): > https://docs.google.com/leaf?id=0B5zZGW2utJN0ZDk1NjA0ZjUtMWU0ZS00ZGQ3LWIxZTUtOWE0NGVmYWMxODJl&hl=en_US > > ## - plot Siler survival curve > ############################## > silsurv<-function(a1,b1,a2,a3,b3) > ?{ > ? ?sil=function(t) > ? ? ?{ > ? ? ? ?h.t<-a1*exp(-b1*t)+a2+a3*exp(b3*t) > ? ? ? ?S.t<-exp(-a1/b1*(1-exp(-b1*t))-a2*t+a3/b3*(1-exp(b3*t))) > ? ? ? ?d.t<-S.t*h.t > > ? ? ? ?#return(d.t) > ? ? ? ?return(S.t) > ? ? ? ?#return(h.t) > ? ? ?} > ? ?t<-seq(0,90,1) > plot(t,sil(t),ylim=c(0,1),type='l',cex.lab=0.8,cex.axis=0.75,ylab='S(t)',xlab='Age > (years)') > ?} > > with(hazanth[1,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[1,1],cex.main=0.9) > ?# plot for Hadza > with(hazanth[2,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[2,1],cex.main=0.9) > ?# plot for Ache > with(hazanth[3,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[3,1],cex.main=0.9) > ?# plot for Hiwi > with(hazanth[4,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[4,1],cex.main=0.9) > ?# plot for !Kung > with(hazanth[5,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[5,1],cex.main=0.9) > ?# plot for Yanomamo > with(hazanth[6,3:7],silsurv(a1=a1,b1=b1,a2=a2,a3=a3,b3=b3));title(main=hazanth[6,1],cex.main=0.9) > ?# plot for Tsimane > > ############################### > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >