Reputation: 107
I have a list of data frames and want to make a plot of each of them, for which I want to have a single code. The code I wrote works when I work with each data frame separately, but not when I use a for-loop, I can't find out what's going on.
library(dplyr)
#example data set:
df1 <- data.frame(colA=c("AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ"),
colB=sample(1:100,10),
colC=1:10,
colD=c(22,13,13,5,4,4,3,2,2,2),
colE=c("1.AA","2.AB","3.AC","4.AD","5.AE","6.AF","7.AG","8.AH","9.AI","10.AJ"))
df2 <- data.frame(colA=c("BA","AA","AC","AD","AE","AF","AG","AH","AI","AJ"),
colB=sample(1:100,10),
colC=1:10,
colD=c(13,11,8,8,6,4,4,3,2,2),
colE=c("1.BA","2.AA","3.AC","4.AD","5.AE","6.AF","7.AG","8.AH","9.AI","10.AJ"))
df3 <- data.frame(colA=c("CA","CB","AC","AD","AA","AF","AG","AH","AI","AJ"),
colB=sample(1:100,10),
colC=1:10,
colD=c(13,11,8,8,6,4,4,3,2,2),
colE=c("1.CA","2.CB","3.AC","4.AD","5.AA","6.AF","7.AG","8.AH","9.AI","10.AJ"))
toy_top_list <- list(df1, df2, df3)
names(toy_top_list) <- c("a","b","c")
#code for plotting one of the data frames:
#first setting some custom values for colors and labels:
slice_colors_a <- ifelse(toy_top_list[[1]][1]=="AA", "red","grey")
perc21_a <- toy_top_list[[1]] %>% filter(colA=="AA") %>% select(colD)
my_label_a <- ifelse(toy_top_list[[1]][1]=="AA", paste(perc21_a,"%",sep = ""),"")
#then the plot itself, for one of the data frames
toy_top_list[[1]] %>% ggplot(aes(x="",y=colD,fill=colE,width=1)) +
geom_col(col="white", width = 2) +
scale_fill_manual(values=slice_colors_a, name="colA") +
geom_text(aes(x=1.3,label=my_label_a),
position=position_stack(vjust=0.5),
col="white", fontface="bold") +
ggtitle(names(toy_top_list)[1]) +
theme(axis.title=element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank(),
panel.grid=element_blank(),
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(3,1,3,1), "pt")) +
coord_polar("y",direction = -1)
And with this I get what I want:
#Now I want to automate this with a for-loop
#I create a list where I will store each plot
toy_pie_list <- vector(mode = "list",length=length(toy_top_list))
#now the for loop
for(i in 1:length(toy_top_list)){
slice_colors_i <- ifelse(toy_top_list[[i]][1]=="AA", "red","grey")
perc21_i <- toy_top_list[[i]] %>% filter(colA=="AA") %>% select(colD)
my_label_i <- ifelse(toy_top_list[[i]][1]=="AA", paste(perc21_i,"%",sep = ""),"")
toy_pie_list[[i]] <- toy_top_list[[i]] %>% ggplot(aes(x="",y=colD,fill=colE,width=1)) +
geom_col(col="white", width = 2) +
scale_fill_manual(values=slice_colors_i, name="colA") +
geom_text(aes(x=1.3,label=my_label_i),
position=position_stack(vjust=0.5),
col="white", fontface="bold") +
ggtitle(names(toy_top_list)[i]) +
theme(axis.title=element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank(),
panel.grid=element_blank(),
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(3,1,3,1), "pt")) +
coord_polar("y",direction = -1)
}
names(toy_pie_list) <- names(toy_top_list)
toy_pie_list$a
But the plots it has created are not what I wanted:
When I copy paste the code using the different list indices, I get the plots I want for each data frame, but when I use the for-loop the plots created are completely different. Can anybody please help?
Upvotes: 1
Views: 45
Reputation: 123963
I have not checked out what exactly goes wrong with your for loop. However, in general I would suggest to put the plotting code inside a function if you want to make several plots using a loop. Makes the code much easier to read and to check.
Additionally my approach
Adds columns for the label and the colors based on your condition ifelse(colA == "AA", ...
Uses a named color vector to make sure that colors are assigned to the right values
library(dplyr)
library(ggplot2)
# example data set:
df1 <- data.frame(
colA = c("AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(22, 13, 13, 5, 4, 4, 3, 2, 2, 2),
colE = c("1.AA", "2.AB", "3.AC", "4.AD", "5.AE", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
df2 <- data.frame(
colA = c("BA", "AA", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(13, 11, 8, 8, 6, 4, 4, 3, 2, 2),
colE = c("1.BA", "2.AA", "3.AC", "4.AD", "5.AE", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
df3 <- data.frame(
colA = c("CA", "CB", "AC", "AD", "AA", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(13, 11, 8, 8, 6, 4, 4, 3, 2, 2),
colE = c("1.CA", "2.CB", "3.AC", "4.AD", "5.AA", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
toy_top_list <- list(df1, df2, df3)
names(toy_top_list) <- c("a", "b", "c")
toy_pie_list <- vector(mode = "list", length = length(toy_top_list))
plot_pie <- function(d, title) {
# Add colums with the colors and the labels
d <- d %>%
mutate(color = ifelse(colA == "AA", "red", "grey"),
label = ifelse(colA == "AA", paste0(colD, "%"), ""))
# Make a named vector of colors
slice_colors <- select(d, colE, color) %>%
tibble::deframe()
ggplot(d, aes(x = "", y = colD, fill = colE)) +
geom_col(col = "white", width = 2) +
scale_fill_manual(values = slice_colors, name = "colA") +
geom_text(aes(x = 1.3, label = label),
position = position_stack(vjust = 0.5),
col = "white", fontface = "bold"
) +
ggtitle(title) +
theme(
axis.title = element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank(),
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(3, 1, 3, 1), "pt")
) +
coord_polar("y", direction = -1)
}
# for loop
for(i in names(toy_top_list)){
toy_pie_list[[i]] <- plot_pie(toy_top_list[[i]], i)
}
# or do it with lapply
toy_pie_list <- lapply(names(toy_top_list), function(x) plot_pie(toy_top_list[[x]], x))
# set names
toy_pie_list <- setNames(toy_pie_list, names(toy_top_list))
toy_pie_list$c
Upvotes: 2