How to add a loop to another loop? - r

I have the script below that is functioning.
But, I would like to have a loop for taking as y, different variables that are in columns; in this example : Petal.length and Petal.width.
Since, there is already a loop in this script, I don't know how to add one.
data <-iris
uniq_species = unique(data$Species)
plot_list = list()
for (i in uniq_species) {
temp_plot = ggplot(data= subset(data, Species == i),aes(x=Sepal.Length, y=Sepal.Width, colour=Species)) +
geom_boxplot()+ ggtitle(i)
plot_list[[i]] =temp_plot}
pdf("y=Sepal Width per species.pdf")
for (i in uniq_species) {
print(plot_list[[i]])}
dev.off()

One possibility should be to set the pdf file before and then have both contents in the same for loop:
plot_list = list()
pdf("y=Sepal Width per species.pdf")
for (i in uniq_species) {
temp_plot <- ggplot(data = subset(data, Species == i), aes(x = Sepal.Length, y = Sepal.Width, colour = Species)) +
geom_boxplot() + ggtitle(i)
plot_list[[i]] <- temp_plot
print(plot_list[[i]])
}
dev.off()

Related

for-loop to create ggplots

I trying to make boxplots with ggplot2.
The code I have to make the boxplots with the format that I want is as follows:
p <- ggplot(mg_data, aes(x=Treatment, y=CD68, color=Treatment)) +
geom_boxplot(mg_data, mapping=aes(x=Treatment, y=CD68))
p+ theme_classic() + geom_jitter(shape=16, position=position_jitter(0.2))
I can was able to use the following code to make looped boxplots:
variables <- mg_data %>%
select(10:17)
for(i in variables) {
print(ggplot(mg_data, aes(x = Treatment, y = i, color=Treatment)) +
geom_boxplot())
}
With this code I get the boxplots however, they do not have the name label of what variable is being select for the y-axis, unlike the original code when not using the for loop. I also do not know how to add the formating code to the loop:
p + theme_classic() + geom_jitter(shape=16, position=position_jitter(0.2))
Here is a way. I have tested with built-in data set iris, just change the data name and selected columns and it will work.
suppressPackageStartupMessages({
library(dplyr)
library(ggplot2)
})
variables <- iris %>%
select(1:4) %>%
names()
for(i in variables) {
g <- ggplot(iris, aes(x = Species, y = get(i), color=Species)) +
geom_boxplot() +
ylab(i)
print(g)
}
Edit
Answering to a comment by user TarJae, reproduced here because answers are less deleted than comments:
Could you please expand with saving all four files. Many thanks.
The code above can be made to save the plots with a ggsave instruction at the loop end. The filename is the variable name and the plot is the default, the return value of last_plot().
for(i in variables) {
g <- ggplot(iris, aes(x = Species, y = get(i), color=Species)) +
geom_boxplot() +
ylab(i)
print(g)
ggsave(paste0(i, ".png"), device = "png")
}
Try this:
variables <- mg_data %>%
colnames() %>%
`[`(10:17)
for (i in variables) {
print(ggplot(mg_data, aes(
x = Treatment, y = {{i}}, color = Treatment
)) +
geom_boxplot())
}
Another option is to use lapply. It's approximately the same as using a loop, but it hides the actual looping part and can make your code look a little cleaner.
variables = iris %>%
select(1:4) %>%
names()
lapply(variables, function(x) {
ggplot(iris, aes(x = Species, y = get(x), color=Species)) +
geom_boxplot() + ylab(x)
})

Save multiple plots in loop in R

I want to save multiple plots as png using a loop. Unfortunately the loop doesn't seem to work, as the saving and plotting of one single plot works but if I do it within the loop, nothing is saved. I don't receive a error message either. Just nothing happens.
Here is the code that works:
name = main_emo[i]
mypath=file.path("/Users/Jasmin/Documents/Psychologie/Master/Masterarbeit/Working directory", name)
png(mypath)
qplot(x_emo,y_emo, main = main_emo[i]) + geom_errorbar(aes(x=x_emo, ymin=y_emo-sd, ymax=y_emo+sd), width=0.25) + ylab("Rating") + xlab("Emotion")+
theme(panel.grid.major = element_blank()) + scale_y_continuous(breaks=seq(1,7,1)) + expand_limits(y=7)
dev.off()
and this is the loop where it doesn't work anymore:
main_emo <- c("Emotion Profile Funeral", "Emotion Profile Wedding", "Emotion Profile Destroyed Street","Emotion Profile Destroyed Street")
frame_name <- c("nice", "wedd", "des", "fun")
emo_mean <- c("rmean_EM_Trauer_", "rmean_EM_Freude_","rmean_EM_Angst_", "rmean_EM_Aerger_", "rmean_EM_Ekel_", "rmean_EM_Ueber_")
for (i in 1: length(frame_name)) {
y_emo <- c()
sd <- c()
x_emo <- c("Trauer", "Freude", "Angst", "Aerger", "Ekel", "Üeberraschung")
for (j in 1: length(emo_mean)) {
y_col <- unlist(pre_sub[colnames(pre_sub) == paste0(emo_mean[j], frame_name[i])], use.names=FALSE)
y_emo <- c(y_emo, mean(y_col, na.rm=TRUE))
sd <- c(sd, sd(y_col, na.rm=TRUE))
}
name = main_emo[i]
mypath=file.path("/Users/Jasmin/Documents/Psychologie/Master/Masterarbeit/Working directory", name)
png(mypath)
qplot(x_emo,y_emo, main = main_emo[i]) + geom_errorbar(aes(x=x_emo, ymin=y_emo-sd, ymax=y_emo+sd), width=0.25) + ylab("Rating") + xlab("Emotion")+
theme(panel.grid.major = element_blank()) + scale_y_continuous(breaks=seq(1,7,1)) + expand_limits(y=7)
dev.off()
}
Thanks for your help!
Use ggsave()
Doesn't work:
library("ggplot2")
for (i in unique(diamonds$color)) {
png(paste0("~/Desktop/colour_", i, ".png"))
ggplot(diamonds, aes(carat, price)) + geom_point()
dev.off()
}
Does work:
for (i in unique(diamonds$color)) {
ggplot(diamonds, aes(carat, price)) + geom_point()
ggsave(paste0("~/Desktop/color_", i, ".png"))
}

saving each modified facet in ggplot2

I try to save each Species data in iris data set to .png file using for loop. But before, that I would like to modify facet strip thickness as I needed to do in my real data plotting process.
However, when I attempted to write each facet
the following code below it just giving me the empty plots for each of these Species.
Here is my attempt,
library(ggplot2)
plot_list = list()
for (i in unique(iris$Species)) {
p = ggplot(iris[iris$Species == i, ], aes(x=Sepal.Length, y=Sepal.Width)) +
geom_point(size=3, aes(colour=Species))+
facet_wrap(~Species)
#this part to modify facet_wrap strips
g1 = ggplotGrob(p)
pos = c(unique(subset(g1$layout, grepl("panel", g1$layout$name), select = t)))
for(i in pos) g1$heights[i-1] = unit(0.4,"cm")
grobs = which(grepl("strip", g1$layout$name))
for(i in grobs) g1$grobs[[i]]$heights <- unit(1, "npc")
grid.newpage()
grid.draw(g1)
plot_list[[i]] = g1
}
#finally write the modified graphs to file
for (i in 1:3) {
file_name = paste("iris_plot_", i, ".png", sep="")
tiff(file_name)
print(plot_list[[i]])
dev.off()
}
Currently this code is producing the empty graphs and do not know why! Any help will be appreciated!
You don't need to modify strip height using ggplotGrob. Setting the relevant parameter in ggplot's theme() would do:
p1 = ggplot(iris[iris$Species == "setosa",],
aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
facet_wrap(~Species)
p2 = p1 + theme(strip.text.x = element_text(margin = margin(t = 10, b = 10)))
# note: default margin for top & bottom is 5.5
gridExtra::grid.arrange(p1, p2, ncol = 2)
As for the rest, you may wish to check the length of plot_list after the first loop. You initially assigned i to take on the unique values of iris$Species, then tried to use it as index for the list of plots. The first three elements of plot_list did not contain plots.
The following would work in this example. You probably need to make some modifications for the actual use case:
plot_list = list()
loop.list <- unique(iris$Species)
for (i in seq_along(loop.list)) {
p = ggplot(iris[iris$Species == loop.list[i], ],
aes(x = Sepal.Length, y=Sepal.Width)) +
geom_point(size = 3, aes(colour = Species))+
facet_wrap(~Species) +
theme(strip.text.x = element_text(margin = margin(t = 11, b = 11)))
plot_list[[i]] <- ggplotGrob(p)
}
for (i in 1:3) {
file_name = paste("iris_plot_", i, ".png", sep="")
tiff(file_name)
grid.draw(plot_list[[i]])
dev.off()
}

R ggplot2 for loop plots same data

I have put together a simple for loop to generate a series of plots and then use grid.arrange to plot them. I have two problems:
The axes of the plots change correctly to the column names, but the same data is plotted on each graph. Having put in a breakpoint and stepped through the code it appears to be incrementing correctly so I'm not sure why.
I have set the plot aesthetic to group on year, however this produces intermediate .5 years that appear in the legend. This hasn't happened to me before.
Should all be reproducible using mtcars.
library(ggplot2)
library(gridExtra)
result <- mtcars
for(i in 1:2) {
nam <- paste("p", i, sep = "")
assign(
nam, ggplot(result, aes(x = disp, y = results[i+4], group = gear, color = gear)) +
geom_line() +
geom_point() +
scale_colour_distiller(palette = "Dark2", direction = -1, guide = "legend") +
scale_y_continuous(name = colnames(results[i+4])) +
scale_x_continuous(name = "x")
)
}
plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)
I think trying to access the columns by their number in the aes mapping is confusing ggplot. This works:
for(i in 1:2) {
nam <- paste("p", i, sep = "")
assign(
nam, ggplot(result,aes_string(x="disp",y=colnames(result)[i+4], group="gear", color="gear")) +
geom_line() +
geom_point() +
scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
scale_y_continuous(name=colnames(result[i+4])) +
scale_x_continuous(name="x")
)
}
I would suggest iterating over the names though; this makes the code much clearer. Here's a version that does this and skips the detour around the environment:
plots <- lapply(c("drat", "wt"), function(column) {
ggplot(result,aes_string(x="disp",y=column, group="gear", color="gear")) +
geom_line() + geom_point() +
scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
scale_y_continuous(name=column) +
scale_x_continuous(name="x")}) %>%
do.call(grid.arrange, .)
do.call(grid.arrange, plots)
Your using results and result. And you should use aes_string and then refer to the variables by string name:
You should also avoid to make tons of assignments. Just put it all into a list()
library(ggplot2)
library(gridExtra)
result<-mtcars
for(i in 1:2) {
nam <- paste("p", i, sep = "")
assign(
nam, ggplot(result,aes_string(x="disp",y=names(result)[i+4], group="gear", color="gear")) +
geom_line() +
geom_point() +
scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
scale_y_continuous(name=colnames(result[i+4])) +
scale_x_continuous(name="x")
)
}
plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)
The problem is that the plot is generated in the for loop, but evaluated in the do.call. Since i has changed in the for loop, both are evaluated with i = 2. You can confirm this with:
i <- 3
do.call(grid.arrange, plist)
A small adjustment to your code fixes the issue:
for(i in 1:2) {
nam <- paste("p", i, sep = "")
coln <- colnames(result[i+4])
assign(
nam, ggplot(result,aes_(x=~disp,y=as.name(coln), group=~gear, color=~gear)) +
geom_line() +
geom_point() +
scale_colour_distiller(palette = "Dark2", direction=-1, guide="legend") +
scale_y_continuous(name=coln) +
scale_x_continuous(name="x")
)
}
plist <- mget(paste0("p", 1:2))
do.call(grid.arrange, plist)
You should take full advantage of ggplot::facet_wrap
This means tidying your data to a single data frame that's interpretable to ggplot
Data
temp <- mtcars
Tidy data
library(purrr)
library(dplyr)
Names <- map_chr(1:2, ~names(temp)[.x+4])
# "drat" "wt"
data <- map_df(1:2, ~temp[,c("cyl", names(temp)[.x+4])] %>% setNames(c("cyl", "value")), .id="iteration") %>%
mutate(iteration = Names[as.numeric(iteration)])
plot with facet_wrap
ggplot(data=data, aes(x=cyl, y=value, label=iteration)) +
geom_line() +
geom_point() +
facet_wrap(~iteration)

for loop issue in ggplot2

I would like to output multiple graphs from ggplot2. I found very nice examples but still could not find what I want to achieve.
r-saving-multiple-ggplots-using-a-for-loop
by using similar example, I only want to output three different graphs for each species so far I am outputting same three combined graph.
library(dplyr)
fill <- iris%>%
distinct(Species,.keep_all=TRUE)
plot_list = list()
for (i in 1:length(unique(iris$Species))) {
p = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) +
geom_point(size=3, aes(colour=Species))
geom_rect(data=fill,aes(fill = Petal.Width),xmin = -Inf,xmax = Inf,ymin = -Inf,ymax = Inf,alpha = 0.5)+ ## added later to OP
plot_list[[i]] = p
}
# Save plots to tiff. Makes a separate file for each plot.
for (i in 1:3) {
file_name = paste("iris_plot_", i, ".tiff", sep="")
tiff(file_name)
print(plot_list[[i]])
dev.off()
}
What I am missing?
You are not filtering the dataset inside the for-loop, and so the same graph is repeated three times without change.
Note the changes here:
plot_list = list()
for (i in unique(iris$Species)) {
p = ggplot(iris[iris$Species == i, ], aes(x=Sepal.Length, y=Sepal.Width)) +
geom_point(size=3, aes(colour=Species))
plot_list[[i]] = p
}
Addressing the OP update, this works for me:
fill <- iris %>%
distinct(Species, .keep_all=TRUE)
for (i in unique(iris$Species)) {
p = ggplot(iris[iris$Species == i, ], aes(x=Sepal.Length, y=Sepal.Width)) +
geom_rect(data = fill, aes(fill = Petal.Width),xmin = -Inf,xmax = Inf,ymin = -Inf,ymax = Inf,alpha = 0.5) +
geom_point(size = 3, aes(colour = Species))
plot_list[[i]] = p
}

Resources