0

First time asking a question so if I miss any important details, apologises in advance. I'm still new to R, but as I learn more I'll attempt to contribute myself. In the meantime hopefully, someone can help.

I have a for loop that generates multiple plots from my data. The plots themselves are perfect however, I'm struggling to add say plot 1 to 4 to a single image.

If I was using plot() I could use par(mfrow - c(1,2,3,4) but as I'm adding multiple data frames to each plot i.e. multiple geom_point() in ggplot I don't think I can do that.

My data looks like this but is much longer, multiple data points for line N01, N02 etc. for which I am generating a new plot with the data from N01, N02 etc. with the WT1 and WT2 points overlayed.

I think I may need to save each iteration of the loop into new variables then use multiplot() to get my desired result.

If I come up with the answer I'll post but if someone beats me to it, thank you in advance.

N01 N01.01  0.0 7693
2   N01 N01.02  2.0 3404
3   N01 N01.03  2.0 3404
4   N01 N01.04  1.0 6395
5   N01 N01.05  1.0 5171
6   N01 N01.06  2.0 6001
7   N01 N01.07  1.0 6671
8   N01 N01.08  1.5 6700
9   N01 N01.09  1.0 9060
10  N04 N04.01  2.0 6857
11  N04 N04.02  4.0 10378

setwd ("C:/Users/HP/Desktop/Studio R/Patty")
df <- read.csv("Data/Raw V2.csv")

#need to create a new data frame with a new coluum taking information from another column
df2 <- split(df, df$ï..ID)
x1 <- df2$WT1[,3:4] #new var for the wild type that wants plotting on all the charts
x2 <- df2$WT6[,3:4]

plot_list <- list() #creates an empty list to save the plots in


for (i in 1:length(df2)){
  z1 <- df2[[i]][,3:4]#new var from the data fram i amount of times using data from column 3 to 4
  title <- (df2[[i]][,1][1]) #used later on to add the title variable in the legend
  par(mar=c(4,4,1,1), mfrow=c(2,2))
  f <- 
    ggplot(data=z1, aes(x=copies, y=leaf_area)) + 
    geom_point(aes(col="black"))+ #creates the plots of i
    geom_point(data=x1, aes(col="blue"))+  #adds the wt to all plots, aes neeeded to create legend
    geom_point(data=x2, aes(col="red"))+
    theme(panel.background = element_blank(), axis.line = element_line(colour = "black"),
          panel.grid.minor = element_line())+
    scale_color_identity(name = "", breaks = c("black", "blue", "red"), labels = c(paste0("(",title,")"),("(WT1)"),("(WT6)")), guide = "legend")+
    theme(legend.position = c(0.95, 0.95), legend.justification = c("right", "top"), legend.direction = "horizontal")+
    scale_x_continuous(limits = c(0, 4)) + #standarsises the axis
    scale_y_continuous(limits = c(0, 12000)) +
    xlab(bquote("Number of Inserts"))+
    ylab(bquote("Leaf Area (mm'^2')"))+
    ggtitle(df2[[i]][,1][1])
    plot_list[[i]] <- f
    list2env(plot_list[[i]], envir = globalenv()) #send the list to the global environment
}

In an ideal world this would have worked:

for (i in plot_list){
  par(mfrow = c(2,2))
  plot(i)
}
Jimmy_BOB
  • 38
  • 1
  • 3
  • 1
    Take a look at the [`patchwork`](https://github.com/thomasp85/patchwork) package. Besides, can you make your problem reproducible and use, e.g. `iris` data? – markus Feb 08 '20 at 11:48
  • [See here](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610#5963610) for tips on how to ask reproducible questions! You can help others to help you! – dario Feb 08 '20 at 11:59
  • 1
    consider whether you can use facet_wrap would be better than making multiple plots (it usually is) – Richard Telford Feb 08 '20 at 12:51

2 Answers2

4

You were trying to use par(mfrow=...), and this works only with base R plots. For ggplot, if you like something similar, maybe use gridExtra since you already have a list of plot. You can see an example below with iris

Also as a comment, most likely you don't need to use list2env since you have already assigned it

library(ggplot2)
library(gridExtra)

plot_list <- list() 
df <- split(iris,iris$Species)

for(i in seq_along(df)){
plot_list[[i]] <- ggplot(df[[i]],aes(x=Sepal.Length,y=Sepal.Width))+
geom_point()+
ggtitle(names(df)[i])
}

grid.arrange(grobs=plot_list,ncol=2)

enter image description here

I see there's like a reference you always want to compare against. I will simulate something that looks like your data:

set.seed(100)
WT1 <- data.frame(Sepal.Length=seq(4,6.5,length.out=50),
Sepal.Width=seq(1.5,3,length.out=50)+rnorm(50,0.5,0.2),Species="WT1")
WT2 <- data.frame(Sepal.Length=seq(6,8,length.out=50),
Sepal.Width=seq(2,4.5,length.out=50)+rnorm(50,0.5,0.2),Species="WT2")

df <- rbind(iris[,c("Sepal.Length","Sepal.Width","Species")],WT1,WT2)
colnames(df)[3] <- "ID"

Now we plot:

# separate the two datasets you want:
obs <- droplevels(subset(df,!ID %in% c("WT1","WT2")))
ref <- droplevels(subset(df,ID %in% c("WT1","WT2")))

plot_list <- list() 
for(i in unique(obs$ID)){

thisDF <- rbind(subset(obs,ID==i),ref)
g <- ggplot(thisDF,aes(x=Sepal.Length,y=Sepal.Width,col=ID))+
geom_point() + theme(legend.position = c(0.9,0.9), 
legend.justification = c("right", "top"), 
legend.direction = "horizontal")+ggtitle(i)
plot_list[[i]] <- g
}
grid.arrange(grobs=plot_list,ncol=2)

enter image description here

StupidWolf
  • 45,075
  • 17
  • 40
  • 72
1

Thanks @StupidWolf, that's a huge help and a more elegant way of doing things, much appreciated.

I did find a workaround although a rather clunky one, that may be useful for someone.

First I removed:

plot_list[[i]] <- f

list2env(plot_list[[i]], envir = globalenv())

from inside the loop then I added the following into the loop:

nam <- paste("A", i, sep ="")

output A1, A2, A3 for each iteration of the loop

assign(nam, f)

creates a new variable for each iteration (f being the ggplot output from the loop)

And outside the loop I added:

figure1 <- ggarrange(A1, A2, A3, A4, ncol = 2, nrow = 2)

figure2 <- ggarrange(A5, A6, A7, A8, ncol = 2, nrow = 2)

ggarrange allows you to assign multiple plots to a single-window

This can probably do in another for loop if you have 20+ outputs.

Once again, shout out to @StupiudWolf for much better code.

Jimmy_BOB
  • 38
  • 1
  • 3