drawing multiple plots, 2 per page using ggplot - r

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)
})

Related

Putting together a patchwork of plots by creating single plots by iterating over a for loop

I want to write a for loop that produces a grid of plots (like when using patchwork). I want to run the loop for each item in the color_list dataframe and use it as an aesthetic.
I managed to write the loop but am unsure how to retain all the plots and put them together at the end.
color_list <- data.frame(color = c("red", "blue", "green", "yellow"))
for(row in 1:nrow(color_list)) {
data %>%
ggplot(aes(x=x,y=y, color = color_list[row,]$color)) +
geom_line()
}
You can create list of plots and pass it to any of the plotting library that you are using. For example, with patchwork::wrap_plots you can do :
do.call(patchwork::wrap_plots, lapply(color_list$color, function(x) {
ggplot(data, aes(x=x,y=y)) +geom_line(color = x)
})) -> plot
plot
data
color_list <- data.frame(color = c("red", "blue", "green", "yellow"))
data <- data.frame(x = rnorm(5), y = rnorm(5))
Are you looking for this, Please let me know if I misinterpreted your question:
library(tidyverse)
library(patchwork)
reduce( map(color_list$color, ~ggplot(mtcars, aes(x=mpg,y=drat)) +
geom_line(color=.x)), `+`)
Explanation:
patchwork library uses plus operator to add plots together, knowing this we can use reduce to gather all the plots and adding them together similar to g1 + g2 + g3...., Note , I am saying similar not same, reduce essentially does reduces to one object by taking inputs at a time, then the result is again taken and to be applied with next object and so on.where g1 , g2 and g3 are ggplot objects. Here I have used mtcars data for doing the same. Here these g1, g2 , g3 and so on are created by map function by iterating over colors.
Output:

Add title to multiple graph in R

I am trying to add title for all my plot in a loop, here is what I have done:
first I split the data with the split() fuction:
sep_team_season_stage <- split(data[cols],
list(data$Season,data$Stage,data$Team),drop = TRUE)
then I want to plot a bunch of radar graph: so I use a loop:
for (i in sep_team_season_stage){
print(ggRadar(i, aes(group = "Team")))
}
And then I want to add tilte for the graph: I saw "titles" produces by the split function is good so I want to recall them:
plotnames = names(sep_team_season_stage)
and added into the for loop:
for (i in sep_team_season_stage){
a=1,
print(ggRadar(i, aes(group = "Team"))+ ggtitle(plotnames[a])),
a= a+1
}
It doesnt work however, how can I fix it?
No data to test this but in such situations when you want to access the names of the list you can use imap from purrr :
plot_list <- purrr::imap(sep_team_season_stage,
~ggRadar(.x, aes(group = "Team"))+ ggtitle(.y))
use Map and pass both name and data.
plot_list <- Map(function(x, y) ggRadar(x, aes(group = "Team")) + ggtitle(y),
sep_team_season_stage, names(sep_team_season_stage))

Changing title of plots in a loop with colnames() in R

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)

How to create a matrix of plots with R and ggplot2

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.

Plotting Several Grouped Bar Plots in Loop [R]

my challenge is to plot several bar plots at once, a plot for each of variables of different subsets. My goal is to compare regional differences for each variable. I would like to print all the resulting plots to a html file via R Markdown.
My main difficulty in making automatic grouped bar charts is that you need to tabulate the groups using table(data$Var[i], data$Region)but I don't know how to do this automatically. I would highly appreciate a hint on this.
Here is a an example of what one of my subset looks like:
# To Create this example of data:
b <- rep(matrix(c(1,2,3,2,1,3,1,1,1,1)), times=10)
data <- matrix(b, ncol=10)
colnames(data) <- paste("Var", 1:10, sep = "")
data <- as.data.frame(data)
reg_name <- c("North", "South")
Region <- rep(reg_name, 5)
data <- cbind(data,Region)
Using beside = TRUE, I was able to create one grouped bar plot (grouped by Region for Var1 from data):
tb <- table(data$Var1,data$Region)
barplot(tb, main="Var1", xlab="Values", legend=rownames(tb), beside=TRUE,
col=c("green", "darkblue", "red"))
I would like to loop this process to generate for example 10 plots for Var1 to Var10:
for(i in 1:10){
tb <- table(data[i], data$Region)
barplot(tb, main = i, xlab = "Values", legend = rownames(tb), beside = TRUE,
col=c("green", "darkblue", "red"))
}
R prefer the apply family of functions, therefore I tried to create a function to be applied:
fct <- function(i) {
tb <- table(data[i], data$Region)
barplot(tb, main=i, xlab="Values", legend = rownames(tb), beside = TRUE,
col=c("green", "darkblue", "red"))
}
sapply(data, fct)
I have tried other ways, but I was never successful. Maybe lattice or ggplot2 would offer easier way to do this. I am just starting in R, I will gladly accept any tips and suggestions. Thank you!
(I run on Windows, with the most recent Rv3.1.2 "Pumpking Helmet")
Given that you say "My goal is to compare regional differences for each variable", I'm not sure you've chosen the optimal plotting strategy. But yes, it is possible to do what you are asking.
Here's the default plot you get with your code above, for reference:
If you want a list with 10 plots for each variable, you can do the following (with ggplot)
many_plots <-
# for each column name in dat (except the last one)...
lapply(names(dat)[-ncol(dat)], function(x) {
this_dat <- dat[, c(x, 'Region')]
names(this_dat)[1] <- 'Var'
ggplot(this_dat, aes(x=Var, fill=factor(Var))) +
geom_bar(binwidth=1) + facet_grid(~Region) +
theme_classic()
})
Sample output, for many_plots[[1]]:
If you wanted all the plots in one image, you can do this (using reshape and data.table)
library(data.table)
library(reshape2)
dat2 <-
data.table(melt(dat, id.var='Region'))[, .N, by=list(value, variable, Region)]
ggplot(dat2, aes(y=N, x=value, fill=factor(value))) +
geom_bar(stat='identity') + facet_grid(variable~Region) +
theme_classic()
...but that's not a great plot.

Resources