R: knit a list of ggplotly generated figures in Rmarkdown - r

I have searched in stackoverflow, and there are similar questions, but the answers did not work in my case.
I want to generate a list of plots, and output them in HTML by knitting Rmarkdown file.
Here is a very simple demo code:
library(ggplot2)
library(plotly)
DF <- data.frame(A = c(1:10), B = c(1:10), C = (1:10))
myplots <- vector('list', ncol(DF))
for (i in 1: dim(DF)[2]) {
p = ggplot(DF, aes(x = DF[, i], y = C)) +
geom_point()
myplots[[i]] = plotly::ggplotly(p)
}
myplots[[1]]
myplots[[2]]
myplots[[3]]
If I index them, they can be plotted in HTML file.
myplots[[1]]
myplots[[2]]
myplots[[3]]
However, if I directly use the list object or loop it, none of the method worked:
# method 1
myplots
# method 2
for (i in seq_along(myplots)) print(myplots[[i]])
#nethod 3
for (i in 1:length(myplots)) print(myplots[[i]])
I don't understand the problem. Thanks a lot for your help.

Here is my complete answer, thanks a lot #user2554330
I need to first convert the list into taglist, and then convert it into a plotly htmlwidget object.
library(ggplot2)
library(plotly)
DF <- data.frame(A = c(1:10), B = c(1:10), C = (1:10))
myplots <- htmltools::tagList()
for (i in 1: dim(DF)[2]) {
p = ggplot(DF, aes(x = DF[, i], y = C)) +
geom_point()
myplots[[i]] = plotly::as_widget(plotly::ggplotly(p))
}
myplots

Related

How to generate multiple ggplots using a for loop [duplicate]

This question already has answers here:
Save multiple ggplots using a for loop
(3 answers)
Closed 2 years ago.
I was wondering if someone could help me get this code to return multiple graphs. I would like each graph to be labelled "plot_i" (plot_G1, plot_G2). I am at a loss as to how to get my function to return this. Any help would be appreciated!
library(lubridate)
library(tidyverse)
#Dummy Data Frame
DateTime <- c("1999/01/01 11:00","1999/01/02 11:00","1999/01/03 11:00","1999/01/01 11:00","1999/01/02 11:00","1999/01/03 11:00","1999/01/01 11:00","1999/01/02 11:00","1999/01/03 11:00")
Step <- c("Condition1","Condition1","Condition1","Condition2","Condition2","Condition2","Condition3","Condition3","Condition3")
G1 <- runif(9)
G2 <- runif(9)
G3 <- runif(9)
G4 <- runif(9)
test_df <- data.frame(DateTime = DateTime, Step = Step, G1 = G1, G2 = G2, G3 = G3, G4 = G4)
test_df$DateTime.lub <- ymd_hm(test_df$DateTime)
test_df
#Want to create a function that will provide graphs for every G1, G2, G3 and G4 and return them!
list <- colnames(test_df)
list <- list[-c(1,2,7)]
list
#test plot - works
ggplot(data = test_df, aes(x= DateTime.lub, y = G1))+
geom_line(aes(size = Step))
#Function does not return graph
for (i in list){
ggplot(data = test_df, aes(x= DateTime.lub, y = i))+
geom_line(aes(colour = Step))
}
Try with this:
library(ggplot2)
#Function does not return graph
for (i in list){
var <- sym(i)
print(ggplot(data = test_df, aes(x= DateTime.lub, y = !!var))+
geom_line(aes(colour = Step))+
ggtitle(paste0('plot_',i)))
}
For anyone else using this, if you want to export graphs see below:
plot_list = list()
for (i in list) {
var <- sym(i)
p = ggplot(test_df, aes(x=DateTime.lub, y=!!var)) +
geom_line(aes(colour=Step))
print(p)
plot_list[[i]] = p
}
setwd("~/WD")
for (i in list) {
file_name = paste("plot_", i, ".tiff", sep="")
tiff(file_name)
print(plot_list[[i]])
dev.off()
}

Creating a list of plots using a for loop

I'm having trouble with creating a list of plots using for loops, and I don't know why.
Here's the code that doesn't work (i.e. returns aplotfinal as an empty list)
aplotfinal <- list()
for(i in 1:length(Rlist)){
a <- Rlist[[i]] %>%
select(Frame_times, average)
del <- 0.016667
x.spec <- spectrum(a$average, log = "no", plot = FALSE)
spx <- x.spec$freq/del
spy <- 2*x.spec$spec
aplotfinal[[i]] <- plot(spy~spx, main = names(Rlist)[i], xlab = "frequency", ylab = "spectral density", type = "l")
}
The plot function works, I just want to apply it for a list of dataframes that I have (i.e. Rlist). Thank you!
the base R plot() does not return an object, it just draws on the device. So you have to do a multiplot or save onto a pdf to have a record of the plots.
To store it in a list, I guess you need something like ggplot, for example:
library(ggplot2)
library(gridExtra)
Rlist = lapply(1:5,function(i){
data.frame(Frame_times = seq(0,1,length.out=100),average=runif(100))
})
names(Rlist) = letters[1:5]
aplotfinal <- lapply(1:length(Rlist),function(i){
a <- Rlist[[i]] %>% select(Frame_times, average)
del <- 0.016667
x.spec <- spectrum(a$average, log = "no", plot = FALSE)
spx <- x.spec$freq/del
spy <- 2*x.spec$spec
aplotfinal[[i]] <- qplot(y = spy,x=spx,geom="line") +
ggtitle(names(Rlist)[i]) +
xlab("frequency")+ylab("spectral density")
})
grid.arrange(grobs=aplotfinal,ncol=5)
Here is an example you can use to tweak your code. Plots get saved to the plot_list variable and then to pdf residing at path/to/pdf. Note that you have to initiate a device first (in my case, pdf).
library(ggplot2)
library(dplyr)
df <- data.frame(country = c(rep('USA',20), rep('Canada',20), rep('Mexico',20)),
wave = c(1:20, 1:20, 1:20),
par = c(1:20 + 5*runif(20), 21:40 + 10*runif(20), 1:20 + 15*runif(20)))
countries <- unique(df$country)
plot_list <- list()
i <- 1
for (c in countries){
pl <- ggplot(data = df %>% filter(country == c)) +
geom_point(aes(wave, par), size = 3, color = 'red') +
labs(title = as.character(c), x = 'wave', y = 'value') +
theme_bw(base_size = 16)
plot_list[[i]] <- pl
i <- i + 1
}
pdf('path/to/pdf')
pdf.options(width = 9, height = 7)
for (i in 1:length(plot_list)){
print(plot_list[[i]])
}
dev.off()

Generate a multi-page pdf file of a grid of ggplot plots [duplicate]

This question already has answers here:
Plot over multiple pages
(3 answers)
Closed 3 years ago.
I am trying to generate a multi-page pdf of a grid of ggplots from a list of ggplots. I have tried very many ways to do this and have not succeeded. Here is a reproducible equivalent to what I have been working with:
library(ggplot2)
# generate a data frame w same structure as the one I'm working with
time <- c(1:10)
veclist <- list()
veclist[[1]] <- time
for (i in 2:25){
veclist[[i]] <- as.vector(c(runif(10,-2,2)))
}
d <- as.data.frame(do.call(rbind, veclist))
d <- as.data.frame(t(d))
colnames(d)[1] <- "time"
for (i in 2:length(d)){
colnames(d)[i] <- paste("name",i,sep=" ")
}
# for a common axis
numericvalues <- d[,2:length(d)]
# generate plot(s)
name_list = paste("`",names(d),"`",sep="")
plot_list = list()
for (i in 2:length(d)) {
p = ggplot(d, aes_string(x=name_list[[1]], y=name_list[[i]])) +
geom_point() +
labs(x="time",title=paste(strwrap(names(d[i]), width = 30),collapse = "\n")) +
theme(plot.title = element_text(size=10,hjust = 0.5),axis.text.x=element_text(size=6)) +
coord_cartesian(ylim = c(min(numericvalues, na.rm = TRUE), max(numericvalues, na.rm = TRUE)))
plot_list[[i]] = p
}
What I am looking for would generate a multi-page pdf grid of the plots in plot_list (ideally with 3 columns, 4 rows of plots per page).
A few things I have tried:
pdf("test.pdf")
do.call("marrangeGrob",c(plot_list,ncol=3,nrow=2))
produces an unreadable pdf file.
pdf("test.pdf")
do.call("grid.arrange",c(plot_list))
returns only 'grobs' allowed in "gList" error.
This one produces a multipage layout:
library(gridExtra)
...
plot_list = list()
for (i in 2:length(d)) {
p = ggplot(...)
plot_list[[i]] = ggplotGrob(p)
}
class(plot_list) <- c("arrangelist", class(plot_list))
ggsave("multipage.pdf", plot_list)
your plot list seems to have a missing item. Here's a minimal example
library(ggplot2)
pl <- replicate(13, ggplot(), simplify = FALSE)
ggsave("mp.pdf", gridExtra::marrangeGrob(grobs = pl, nrow=3, ncol=2))
Notes:
you were missing dev.off() hence the invalid pdf
do.call is no longer necessary in (m)arrangeGrob, use the grobs argument
Here's a solution with gridExtra and tidyr
(i) transform the wide data to long-format, and split into a list of data.frame based on each name:
library(tidyr)
df <- d %>% gather(var, val, -time)
df_list <- split(df, df$var)
(ii) plot for each name with lapply function
plots <- lapply(names(df_list), function(x){
ggplot(df_list[[x]], aes(time, val)) +
geom_point() +
labs(x="time", title=x)
})
(iii) using gridExtra to print 12 plots each on two pages of the pdf:
library(gridExtra)
pdf("something.pdf")
do.call(grid.arrange, c(plots[1:12], nrow=4))
do.call(grid.arrange, c(plots[13:24], nrow=4))
dev.off()

how to save ggplots as separate R-objects using For loop

It is intended to produce a number of plots and then merge them freely together using multiplot function. Please could you tell me how to save each plot as a separate R-object instead of having it printed as png file:
Examplary dataframe:
df1 <- data.frame(A = rnorm(50), B = rnorm(50), C = rnorm(50), group = rep(LETTERS[24:25], 25))
we use a for loop to produce pictures and save them in a file:
And the loop to change:
for(i in names(df1)[1:3]) {
png(paste(i, "png", sep = "."), width = 800, height = 600)
df2 <- df1[, c(i, "group")]
print(ggplot(df2) + geom_boxplot(aes_string(x = "group", y = i, fill = "group")) + theme_bw())
dev.off()
}
Could you please help with changing the code in order to save each plot as R-object on my screen?
Big Thanks in advance!
I'm not sure what you are talking about with "merge them freely together using multiplot function", but you can save ggplot objects using the standard assignment operator. Like any R object, they can be stored in a list.
# empty list for storage
gg_list <- list()
# if you must use a loop, loop through an indexing vector
for(i in 1:3) {
# if you need the i'th name in df1 use:
names(df1)[i]
# assign your ggplot call to the i'th position in the list
gg_list[[i]] <- ggplot(...)
}
# Now you can recall the ggplots by reference to the list.
# E.g., display the 1st one:
print(gg_list[[1]])
Instead of using a for loop, if you're gonna store in a list you could just use lapply:
df1 <- data.frame(A = rnorm(50),
B = rnorm(50),
C = rnorm(50),
group = rep(LETTERS[24:25], 25))
gg_list <- lapply(names(df1)[1:3], function(i) {
df2 <- df1[, c(i, "group")]
ggplot(df2) +
geom_boxplot(aes_string(x = "group", y = i, fill = "group")) +
theme_bw()
})
gg_list[[1]]
You can even save the list in an RDS object:
saveRDS(gg_list, file = "./gg_list.RDS")
Here's an alternative strategy that I find more straight-forward (no need to fiddle with names and aes_string): melt the data to long format, and plot subsets
df1 <- data.frame(A = rnorm(50), B = rnorm(50), C = rnorm(50),
group = rep(LETTERS[24:25], 25))
m = reshape2::melt(df1, id="group")
## base plot, all the data
p = ggplot(m) + geom_boxplot(aes(x = group, y = value)) + theme_bw()
## split-and-apply strategy, using the `%+%` operator to change datasets
pl = plyr::dlply(m, "variable", `%+%`, e1 = p)
do.call(gridExtra::grid.arrange, pl)

Error in strsplit(filename, "\\.") : non-character argument in ggplot

I am trying to make the plot with horizontal lines where the data2 and data3 points should be within data1 range. This will give an overlapping lines in different colors but I am getting an error which says:
Error in strsplit(filename, "\\.") : non-character argument
Here is the data and code. Please give me some suggestion.
data1 <- data.frame(Start=c(10),End=c(19))
data2 <- data.frame(Start=c(5),End=c(15))
data3 <- data.frame(Start=c(6),End=c(18))
filter_data2 <- data2[data2$Start >= (data1$Start-(data1$Start/2)) & data2$End <= (data1$End+(data1$End/2)), ]
filter_data3 <- data3[data3$Start >= (data1$Start-(data1$Start/2)) & data3$End <= (data1$End+(data1$End/2)), ]
data1 <- data.frame(rep(1,nrow(data1)),data1)
colnames(data1) <- c("ID","start","end")
data2 <- data.frame(rep(2,nrow(filter_data2)),filter_data2)
colnames(data2) <- c("ID","start","end")
data3 <- data.frame(rep(3,nrow(filter_data3)),filter_data3)
colnames(data3) <- c("ID","start","end")
dat1 <- rbind(data1,data2,data3)
pdf("overlap.pdf")
p <- ggplot(dat1, aes(x=(max(start)-max(start)/2), y = ID, colour=ID))
p <- p + geom_segment(aes(xend =(max(end)+max(end)/2), ystart = ID, yend = ID))
p <- p + scale_colour_brewer(palette = "Set1")
ggsave(p)
There are two problems in your code. If you want to use scale_colour_brewer() then ID values should be set as factor
p <- ggplot(dat1, aes(x=(max(start)-max(start)/2), y = ID, colour=as.factor(ID)))
Next, to save the ggplot2 plot you have two possibilities.
Using ggsave() function you should provide file name and format. In this case function pdf() is unnecessary.
ggsave(plot=p,file="plot.pdf")
Using function pdf(), you should add print(p) and then dev.off(). In this case you don't need ggsave() function.
pdf("overlap.pdf")
print(p)
dev.off()

Resources