0

I am trying to run a simple loop consisting of 1) running models and 2) saving plots. I'll end up running tons of these!

The problem I run into is this. In order to save the plot by the method I'm using, I have to "call" the plot as in:

png(file=paste(ImageDirectory,"\\","i0.png",sep=""), width = 1000, height = 500)
i0
dev.off()

This is successful. However, in the loop, the plot is not rendered. Instead, R simply prints the plot name as a character string.

# Attempted and Failed Loop
images <- c("i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", "i9", "i10", "i11")
for (i in images){
  png(file=paste(ImageDirectory,"\\",i,".png",sep=""), width = 1000, height = 500)
  i
  dev.off()
  print(typeof(i))
}
[1] "character"

As a result, the image call results in a blank image. I know why this happens I think. I've stored the names of the images as text. I've tried:

as.data.frame(i)

No joy! Apologies if this has been asked and answered, I couldn't find anything on point. This question gets close, but wasn't successful for me either.

Full code sequence below. Any suggestions would be muy appreciado!

#Run Survival Models
survival_model <- Surv(time = df$LOS, event = df$isTermed)
fit1 <- survfit(survival_model ~ rResult, data = df)
i0<-ggsurvplot(fit1, data = df,title=df$Label,legend.title = "Result",legend.labs = c("Not Recommended", "Recommended", "Not Assessed"),pval = TRUE,conf.int = FALSE,palette = c("#C00000","#92D050", "#FFC000"),linetype="solid",ggtheme = theme_classic(),break.time.by=90,xlab = "Time in Days",ylab = "Probability of Retention") 
pvals<-rbind(pvals, list("pvals"=surv_pvalue(fit1)$pval.txt),stringsAsFactors=FALSE)

survival_model <- Surv(time = df1$LOS, event = df1$isTermed)
fit1 <- survfit(survival_model ~ rResult, data = df1)
i1<-ggsurvplot(fit1, data = df1,title=df1$Label,legend.title = "Result",legend.labs = c("Not Recommended", "Recommended"),pval = TRUE,conf.int = FALSE,palette = c("#C00000","#92D050", "#FFC000"),linetype="solid",ggtheme = theme_classic(),break.time.by=90,xlab = "Time in Days",ylab = "Probability of Retention") 
pvals<-rbind(pvals, list("pvals"=surv_pvalue(fit1)$pval.txt),stringsAsFactors=FALSE)

survival_model <- Surv(time = df2$LOS, event = df2$isTermed)
fit1 <- survfit(survival_model ~ rResult, data = df2)
i2<-ggsurvplot(fit1, data = df2,title=df2$Label,legend.title = "Result",legend.labs = c("Not Recommended", "Recommended", "Not Assessed"),pval = TRUE,conf.int = FALSE,palette = c("#C00000","#92D050", "#FFC000"),linetype="solid",ggtheme = theme_classic(),break.time.by=90,xlab = "Time in Days",ylab = "Probability of Retention") 
pvals<-rbind(pvals, list("pvals"=surv_pvalue(fit1)$pval.txt),stringsAsFactors=FALSE)

#Save their plots
png(file=paste(ImageDirectory,"\\","i0.png",sep=""), width = 1000, height = 500)
i0
dev.off()

png(file=paste(ImageDirectory,"\\","i1.png",sep=""), width = 1000, height = 500)
i1
dev.off()

png(file=paste(ImageDirectory,"\\","i2.png",sep=""), width = 1000, height = 500)
i2
dev.off()
png(file=paste(ImageDirectory,"\\","i3.png",sep=""), width = 1000, height = 500)


# Attempted and Failed Loop
images <- c("i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", "i9", "i10", "i11")
for (i in images){
  png(file=paste(ImageDirectory,"\\",i,".png",sep=""), width = 1000, height = 500)
  i
  dev.off()
}
David Weisser
  • 117
  • 1
  • 10

2 Answers2

1

I have not tried it (because I can't at the moment), but I think it is because

i0 <- ggsurvplot(
    fit1,
    data = df,
    title=df$Label, ...)

does not return the plot. Instead, you get the data typ character. For example, try

typeof("MyName")

Move the plot logic into the for loop. This would require that save your data frames into a list and loop over this instead. For exmpale

my.dfs <- list(
  df.name.one = df.name.one,
  df.name.two = df.name.two,
  ....)

for ( i in length(my.dfs) ){
  png(file=paste(ImageDirectory,"\\", names(my.dfs)[i] ,".png",sep=""), width = 1000, height = 500)

  survival_model <- Surv(time = my.dfs[i]$LOS, event = my.dfs[i]$isTermed)
  fit <- survfit(survival_model ~ rResult, data = df)
  ggsurvplot(fit, ....)

  dev.off()
}

You may further consider using a function from the apply family and move the modelling and plotting logic into functions.

I hope this helps!

MacOS
  • 1,149
  • 1
  • 7
  • 14
1

You mainly need get()

images <- c("i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8", "i9", "i10", "i11")
for (i in images){
  png(file=paste(ImageDirectory,"\\",i,".png",sep=""), width = 1000, height = 500)
  get(i) ## may have to print, too:. print(get(I))
  dev.off()
}

It seems like you would be better off using a list() of some sort.

l <- mget(ls(pattern = "df"))
lapply(seq_along(l),
    function (i) {

     DF <- l[[i]]
      survival_model <- Surv(time = DF$LOS, event = DF$isTermed)
      fit <- survfit(survival_model ~ rResult, data = DF)

      png(file=paste(ImageDirectory,"\\",images[i],".png",sep=""), width = 1000, height = 500)

      ggsurvplot(fit, data = DF,title=DF$Label,legend.title = "Result",legend.labs = c("Not Recommended", "Recommended"),pval = TRUE,conf.int = FALSE,palette = c("#C00000","#92D050", "#FFC000"),linetype="solid",ggtheme = theme_classic(),break.time.by=90,xlab = "Time in Days",ylab = "Probability of Retention") 

      return("pvals"=surv_pvalue(fit)$pval.txt)
    }
 )
Cole
  • 11,130
  • 1
  • 9
  • 24
  • I accepted this answer because I plainly, and now so obviously, needed `get()`. Both @Cole @MacOS are generally correct though in their observation that I would be better off looping over the data frames thereby reducing my code even further. Thank you both!! – David Weisser May 15 '20 at 13:34