EskCargo
EskCargo

Reputation: 35

ggplot figure number in for loop in R

I have got the following data:

    Detector=c("A", "A", "A", "A","B", "B", "B", "B","C", "C", "C", "C")
    hours=rep(c(0,4,24,48),3)
    LoD=c(rep(25,4),rep(40,4),rep(34,4))
    Ct=c(24,24.2,24.3,24,43,42,43,41,35,37,35,35.6)
    Sample.Type=c(rep("T",2),rep("P",4),rep("T",5), rep("P",1))
    d4.1=data.frame(Detector,hours, Ct, LoD, Sample.Type)

I want to plot Ct vs hours as a simple scatterplot, as a loop for each Detector, and show each detector's lod value as a horizontal line on the plot. I use the following code which works perfectly well:

    for(i in unique(d4.1$Detector)) {
    print(ggplot(d4.1[d4.1$Detector==i], aes(d4.1$hours[d4.1$Detector==i], 
    d4.1$Ct[d4.1$Detector==i], colour = d4.1$Sample.Type[d4.1$Detector==i]))+
    geom_point()+
    geom_hline(yintercept=mean(d4.1$LoD[d4.1$Detector==i]))+
    ggtitle(paste("Figure", j,i, sep=" "))+
    theme(plot.title = element_text(hjust = 
    0.5),plot.caption=element_text(hjust = 0))+
    labs(x="Hours/Time Points", y="Ct",caption=paste("The solid black line 
    is the LoD(=",mean(d4.1$LoD[d4.1$Detector==i]),") for",i,sep=" "), 
    colour="Sample Types"))}

What I need help with is the ggplot's titles. Each of the plots generated is labeled with A,B and C but i'd like to add the following text to it:

    Figure 1: A
    Figure 2: B
    Figure 3: C

I tried adding a "j" sequence of 1-3 and paste it in title (below) which didnt work. It gave me 9 plots (Figure 1 A,Figure 1 B, Figure 1 C, Figure 2 A...etc)

     for(i in unique(d4.1$Detector)){for (j in seq(1:3)){print(ggplot(d4.1[which(d4.1$Detector==i),], aes(hours,Ct, colour = Sample.Type))+geom_point()+geom_hline(yintercept=mean(LoD))+ggtitle(paste("Figure",j,i,sep=" "))+theme(plot.title = element_text(hjust = 0.5),plot.caption=element_text(hjust = 0))+labs(x="Hours/Time Points", y="Ct",caption=paste("The solid black line is the LoD(=",mean(LoD),") for",i,sep=" "), colour="Sample Types"))}}

How do I add a sequence of numbers (1,2,3...) to ggplot titles in a loop? Thank you very much.

Upvotes: 0

Views: 314

Answers (3)

Maarten Punt
Maarten Punt

Reputation: 256

Your code was not reproducible because the way you programmed your loop. You subset the dataframe first and then within your aes() ask for subsets that no longer exists.

Although I find Kristoffer's and Adam's answers more elegant than mine here is a crude version that uses your original loop. I use the fact that factor level A corresponds to the first level, by converting the factor to a numeric.

for(i in unique(d4.1$Detector)) {


 print(ggplot(d4.1[d4.1$Detector==i,], aes(hours, 
                                           Ct, colour = Sample.Type))+
          geom_point()+
          geom_hline(yintercept=mean(d4.1$LoD[d4.1$Detector==i]))+
          ggtitle(paste("Figure", as.numeric(d4.1$Detector[d4.1$Detector==i]), ":" , i, sep=" "))+
            theme(plot.title = element_text(hjust = 
                                            0.5),plot.caption=element_text(hjust = 0))+
          labs(x="Hours/Time Points", y="Ct",caption=paste("The solid black line 
                                                           is the LoD(=",mean(d4.1$LoD[d4.1$Detector==i]),") for",i,sep=" "), 
               colour="Sample Types"))}

Upvotes: 0

If you store unique Detector in a variable (detectors) and use seq_along you will get indexes 1 to 3 (x in the function). You can then create your three plots like this:

detectors <- unique(d4.1$Detector)
lapply(seq_along(detectors), function (x) {
  selected_detector <- detectors[[x]]
  df_plot <- d4.1[d4.1$Detector == selected_detector, ]
  p <- ggplot(df_plot, aes(x = hours, y = Ct, colour = Sample.Type)) +
      geom_point() + geom_hline(yintercept = mean(df_plot$LoD)) +
      ggtitle(paste("Figure", x, selected_detector, sep = " ")) +
      theme(plot.title = element_text(hjust = 0.5),
        plot.caption = element_text(hjust = 0))+
        labs(x = "Hours/Time Points", y = "Ct",
          caption=paste("The solid black line is the LoD(=",
            mean(df_plot$LoD),") for", selected_detector, sep=" "),
          colour="Sample Types")
  print(p)
})

enter image description here

Upvotes: 1

Adam Quek
Adam Quek

Reputation: 7163

Since your code is not reproducible, I'd decided to give an alternate example using the iris data.

(i) split iris into a list of 3 subset, based on Species. This is similar to d4.1[d4.1$Detector==i,] in the code provided

df <- split(iris, iris$Species)

(ii) write a generic plot function that takes in different subset

plotFn <- function(df){
              ggplot(df, aes(Sepal.Length, Petal.Length)) + 
              geom_point() + 
              geom_hline(yintercept = mean(df[,"Petal.Length"]))
          }

(iii) get the list of ggplot object and then do a lapply to individually add in the Figure x: y format.

p <- lapply(df, plotFn)

lapply(1:length(p), function(x){
          p[[x]] + 
          ggtitle(paste0("Figure ", x, ": ", names(p)[x]))
       })

This will provide three plots:

enter image description here

Upvotes: 0

Related Questions