I am saving multiple ggplots to a list to be used in a subsequent multiplot. The plots are generated in a loop and appended to the list, however, after the loop all plot objects in the list are the same as the last plot of the loop. I have done the type of operation before, without any issues. Has anyone experienced the same, and solved the problem?
figList <- list()
aoinum <- 1
for (aoi in AOI_list){
...
# prepare dataframe for plotting
dat <- data.frame(...)
fig <- ggplot(data=dat, aes(x=x, y=y, fill=z, alpha=q)) +
geom_bar(...)+
...
figList[[aoi]] <- fig
aoinum = aoinum + 1
}
This is how I managed to make a list of plots in a for loop
#Define list
ggcluster<-list()
for (cluster in 1:nclusters){
# Simple plot )geom_polygon in my case)
ggcluster[[cluster]]<-ggplot() +
geom_polygon(data = datoshp.df, aes(long, lat, group = group))
}
# Build multiplot panel (two columns)
pngname<-paste(output_path,"plot-name",".png",sep="")
png(pngname,width = 1000, height = 1000)
do.call(grid.arrange, c(ggcluster,list(ncol=2)))
dev.off()
Related
I have a list of dataframes and I would like to print them all in a .RMarkdown document with 2 per page. However, I have not been able to find a source for doing this. Is it possible to do this via a for loop?
What I would like to achieve is something with the following idea:
listOfDataframes <- list(df1, df2, df3, ..., dfn)
for(i in 1:){
plot <- ggplot(listOfDataframes[i], aes(x = aData, y = bData)) + geom_point(color = "steelblue", shape = 19)
#if two plots have been ploted break to a new page.
}
Is this possible to achieve with ggplot in rmarkdown? I need to print out a PDF document.
If you just need to output plots with two per page, then I would use gridExtra as was suggested above. You could do something like this if you were to put your ggplot objects into a list.
library(ggplot2)
library(shinipsum) # Just used to create random ggplot objects.
library(purrr)
library(gridExtra)
# Create some random ggplot objects.
ggplot_objects <- list(random_ggplot("line"), random_ggplot("line"))
# Create a list of names for the plots.
ggplot_objects_names <- c("This is Graph 1", "This is Graph 2")
# Use map2 to pass the ggplot objects and the list of names to the the plot titles, so that you can change them.
ggplot_objects_new <-
purrr::map2(
.x = ggplot_objects,
.y = ggplot_objects_names,
.f = function(x, y) {
x + ggtitle(y)
}
)
# Arrange each ggplot object to be 2 per page. Use marrangeGrob so that you can save two ggplot objects per page.
ggplot_arranged <-
gridExtra::marrangeGrob(ggplot_objects_new, nrow = 2, ncol = 1)
# Save as one pdf. Use scale here in order for the multi-plots to fit on each page.
ggsave("ggplot_arranged.pdf",
ggplot_arranged, scale = 1.5)
If you have a list of dataframes that you are wanting to create ggplots for, then you can use purrr::map to do that. You could do something like this:
purrr::map(df_list, function(x) {
ggplot(data = x, aes(x = aData, y = bData)) +
geom_point(color = "steelblue", shape = 19)
})
I am creating a for loop which creates a ggplot2 plot for each of the first six columns in a dataframe. Everything works except for the looping of the title names. I have been trying to use title = colnames(df[,i]) and title = paste0(colnames(df[,i]) to create the proper title but it simply ends up repeating the 2nd column name. The plots themselves produce the data correctly for each column, but the title is for some reason not looping. For the first plot it produces the correct title, but then for the second plot and beyond it just keeps on repeating the third column name, completely skipping over the second column name. I even tried creating a variable within the loop to store the respective title name to then use within the ggplot2 title labels: changetitle <- colnames(df[,i]) and then using title = changetitle but that also loops incorrectly.
Here is an example of what I have so far:
plot_6 <- list()
for(i in df[1:6]){
plot_6[i] <- print(ggplot(df, aes(x = i, ...) ...) +
... +
labs(title = colnames(df[,i]),
x = ...) +
...)
}
Thank you very much.
df[1:6] is a data frame with six columns. When used as a loop variable, this results in i being a vector of values each time through the loop. This might "work" in the sense that ggplot will prroduce a plot, but it breaks the link between the data frame provided to ggplot (df in this case) and the mapping of df's columns to ggplot's aesthetics.
Here are a few options, using the built-in mtcars data frame:
library(tidyverse)
library(patchwork)
plot_6 <- list()
for(i in 1:6) {
var = names(mtcars)[i]
plot_6[[i]] <- ggplot(mtcars, aes(x = !!sym(var))) +
geom_density() +
labs(title = var)
}
# Use column names directly as loop variable
for(i in names(mtcars)[1:6]) {
plot_6[[i]] <- ggplot(mtcars, aes(x = !!sym(i))) +
geom_density() +
labs(title = var)
}
# Use map, which directly generates a list of plots
plot_6 = map(names(mtcars)[1:6],
~ggplot(mtcars, aes(x = !!sym(.x))) +
geom_density() +
labs(title = .x)
)
Any of these produces the same list of plots:
wrap_plots(plot_6)
I am trying to arrange n consecutive plots into one single matrix of plots. I get the plots in first place by running a for-loop, but I can't figure out how to arrange those into a 'plot of plots'. I have used par(mfrow=c(num.row,num.col)) but it does not work. Also multiplot(plotlist = p, cols = 4) and plot_grid(plotlist = p)
#import dataset
Survey<-read_excel('datasets/Survey_Key_and_Complete_Responses_excel.xlsx',
sheet = 2)
#Investigate how the dataset looks like
glimpse(Survey)#library dplyr
#change data types
Survey$brand <- as.factor(Survey$brand)
Survey$zipcode <- as.factor(Survey$zipcode)
Survey$elevel <- as.factor(Survey$elevel)
Survey$car <- as.numeric(Survey$car)
#Relation brand-variables
p = list()
for(i in 1:ncol(Survey)) {
if ((names(Survey[i])) == "brand"){
p[[i]]<-ggplot(Survey, aes(x = brand)) + geom_bar() +
labs(x="Brand")
} else if (is.numeric(Survey[[i]]) == "TRUE"){
p[[i]]<-ggplot(Survey, aes(x = Survey[[i]], fill=brand)) + geom_histogram() +
labs(x=colnames(Survey[i]))
} else {
p[[i]]<-ggplot(Survey, aes(x = Survey[[i]], fill = brand)) + geom_bar() +
labs(x=colnames(Survey[i]))
}
}
I think plots are appended correctly to the list but I can not plot them in a matrix form.
The problem does not appear to be with your multiple plots, but how you are calling the variable into your plot.
You've already put "Survey" into ggplot as the first argument (the data slot). In the mapping argument (the second slot), you put in aes(...) and inside that you should be specifying variable names, not data itself. So try this:
Where you have aes(x = Survey[[i]], fill=brand)) in two places,
put aes(x = names(Survey[[i]], fill=brand)) instead.
Regarding plotting multiple plots, par(mfrow... is for base R plots and cannot be used for ggplots. grid.arrange, multiplot, and plot_grid should all work once you fix the error in your plot.
Context: I have a dataset of 50+ features, and I would like to produce a boxplot, histogram, and summary statistic for each of them, for presentation purposes. That makes 150+ plots. The code I have used to do the above mentioned is as such:
library(ggplot2)
library(dplyr)
library(ggpubr)
library(ggthemes)
library(Rmisc)
library(gridExtra)
myplots <- list() # new empty list
for (i in seq(2,5,3)){
local({
i <- i
p1 <- ggplot(data=dataset,aes(x=dataset[ ,i], colour=label))+
geom_histogram(alpha=.01, position="identity",bins = 33, fill = "white") +
xlab(colnames(dataset)[ i]) + scale_y_log10() + theme_few()
p2<- ggplot(data=dataset, aes( x=label, y=dataset[ ,i], colour=label)) +
geom_boxplot()+ylab(colnames(dataset)[ i]) +theme_few()
p3<- summary(dataset[ ,i])
print(i)
print(p1)
print(p2)
print(p3)
myplots[[i]] <<- p1 # histogram
myplots[[i+1]] <<- p2 # boxplot
myplots[[i+2]] <<- p3 # summary
})
}
myplots[[2]]
length(myplots)
n <- length(myplots)
nCol <- floor(sqrt(n))
do.call("grid.arrange", c(myplots, ncol=nCol)) # PROBLEM: cant print summary as grob
I have created a list of plots, every 3 elements represent the results of a histogram, boxplot, and summary for each feature. I iterate through each of the 50+ features, appending each of the results to my list (not the best way to go about doing this I know). I then run into the following issue when I attempt to print the list through grid arrange:
Error in gList(list(grobs = list(list(x = 0.5, y = 0.5, width = 1, height = 1, :
only 'grobs' allowed in "gList"
Understandably so, as the summary function does not produce a graphical object. Any ideas as to how I can overcome this setback apart from not including summary statistics at all?
Hi after combining several of the suggestions here i managed to figure out how to go about plotting the summary statistics per feature as a grob object, after looping through the different features of my dataset.
library(skimr)
library(GridExtra)
library(ggplot2)
library(dplyr)
mysumplots <- list() # new empty list
for (i in seq(2,ncol(dataset))){
local({
i <-
sampletable <- data.frame(skim((dataset[ ,i]))) #creates a skim data frame
summarystats<-select(sampletable, stat, formatted) #select relevant df columns
summarystats<-slice(summarystats , 4:10) #select relevant stats
p3<-tableGrob(summarystats, rows=NULL) #converts df into a tableGrob
mysumplots[[i]] <<- p3 # summary #appends the grob of to a list of summary table grobs
})
}
do.call("grid.arrange", c(mysumplots, ncol=3)) # use grid arrange to plot all my grobs
What this does is create a skim dataframe of each column (feature), then i selected the relevant statistics, and assigned that grob to the variable p3, which is then iteratively appended to a list of tablegrobs for each feature. I then used gridarrange to print all of the tableGrobs out!
I'd like to save multiple ggplots as jpegs through a for loop. But when I've tried to adapt code I've written for a basic plot command, I get no output (nothing is saved to my working directory).
For Example, this works great:
library(cowplot)
library(ggplot)
X<-c(1,2,3,4,5,6,7,8,9)
Y1<-c(2,3,4,4,3,2,4,5,6)
Y2<-c(3,4,5,3,2,1,1,2,3)
Y3<-c(4,5,6,7,8,9,8,7,6)
DF<-data.frame(X,Y1,Y2,Y3)
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
plot(DF[,1],DF[,i+1])
dev.off()
}
I end up getting three jpeg files saved to my working directory.
I'm not sure how to properly index the ggplot call here for i, but even this should return 3 instances of the same plot:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
dev.off()
}
In the end, I was hoping to combine multiple plots onto one jpeg, and then save multiple jpegs like this:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
A<-ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
B<-ggplot(data=DF,aes(x=X,y=Y2))+geom_line()
C<-ggplot(data=DF,aes(x=X,y=Y3))+geom_line()
plot_grid(A,B,C)
dev.off()
}
So this plot should also return 3 instances of the same plot, all with different indexed file names. But again, I get nothing.
So my question is why is there a difference between generic plotting and ggploting in this for loop. And how can one save mutliple jpegs from ggplots like above?
How about
library(gridExtra) # gridExtra::arrangeGrob
for(i in 1:3) {
jpeg(paste0(i, ".jpg"))
A <- ggplot(data = DF, aes(x = X, y = Y1)) + geom_line()
B <- ggplot(data = DF, aes(x = X, y = Y2)) + geom_line()
C <- ggplot(data = DF, aes(x = X, y = Y3)) + geom_line()
grid.arrange(arrangeGrob(A, B, C, ncol = 3))
dev.off()
}
Note: this solution does not produce the side annotations of cowplot ("A", "B", "C").
using your code:
for(i in 1:3){
jpeg(paste(i,".jpeg",sep=""))
A<-ggplot(data=DF,aes(x=X,y=Y1))+geom_line()
B<-ggplot(data=DF,aes(x=X,y=Y2))+geom_line()
C<-ggplot(data=DF,aes(x=X,y=Y3))+geom_line()
k<-plot_grid(A,B,C)
ggsave(k, filname = "path/finalplot.jpeg")
}
look at ?ggsave to look at other arguments to specify like height and width