Saving a List of Plots by Their Names()

Saving a list of plots by their names()

probably you need to pass the names of list:

lapply(names(plots), 
function(x)ggsave(filename=paste(x,".jpeg",sep=""), plot=plots[[x]]))

How to save plots by names of items in a list

(Disregard my previous suggestion using Map.)

The big takeaway is how to derive the formula dynamically. One way is with as.formula, which takes a string and converts into a formula that can be used in a model-generating function (for example).

One problem with using lapply(as.list(delm2[,c('N','B')]), ...) is that the remainder of the data (i.e., columns t1 and t3) are not passed, just one vector at a time. (I'm wondering if your reference to del is a typo, un-released/hidden data, or something else.)

Try this:

lapply(c("N", "B"), function(nm) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
dev.off()
})

In general, I don't like breaching scope inside these functions. That is, I try to not reach outside lapply for data when I can pass it fairly easily. The above in a pedantic-language way could look like:

lapply(c("N", "B"), function(nm, x) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
dev.off()
}, x = delm2)

While this preserves scope, it may be confusing if you do not understand what is going on.

This might be a great time to use for instead of one of the *apply* functions. Everything you want is in side-effect, and since for and *apply are effectively the same speed, you gain readability:

for (nm in c("N", "B")) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = delm2))
dev.off()
}

(In this case, there is no "scope breach", so I used the original variable.)


Parenthetically, to tie-in my now-edited-out and incorrect answer that included Map. Here's an example using Map that does more to demonstrate what Map (and mapply) are doing, vice actually improving on your immediate need.

If for some reason you wanted them named something distinct from "N.bmp", you could do this:

Map(function(fn, vn, x) {
bmp(filename = paste(nm, ".bmp"), width = 350, height = 400)
glm.diag.plots(glm(as.formula(paste(nm, "~ t1*t3")), data = x))
dev.off()
}, c("N2.bmp", "b3456.bmp"), c("N", "B"), list(delm2))

Two things to note from this:

  • The use of list(delm2) is to wrap that structure into a single "thing" that is passed repeated to the mapped function. If we did just delm2 (no list(...)), then it would try to use the first column of delm2 with each of the first elements. This might be useful in other scenarios, but in your glm example you need other columns present, so you cannot include just one column at a time. (Well, there are ways to do that, too ... but important at the moment.)
  • The first time the anonymous function is called, fn is "N2.bmp", vnis"N", andxis the full dataset ofdelm2. The second time the anon-func is called,fnis"b3456.bmp",vnis"B", andxis again the full dataset ofdelm2`.

I label this portion "parenthetic" because it really doesn't add to this problem, but since I started that way in my first-cut answer, I thought I'd continue with the methodology, the "why" of my choice of Map. In the end, I think the for solution or one of the lapply solutions should be fine for you.

Saving plots generated from list using names in list using lapply

The problem with your code is that when you apply your function to each data.frame in your list then names(input) gives you the column names of the data.frame. See this example.

data(mtcars)
l = list()
l$a = mtcars[, 1:2]
l$b = mtcars[, 2:3]

lapply(l, names)
$a
[1] "mpg" "cyl"

$b
[1] "cyl" "disp"

To resolve this change the function to take a second argument name.

volc = function(input, name) {
ggplot(input, aes(logFC, negLogPval)) +
geom_point()
ggsave(paste0("Volcano_", name, ".png"), device = "png")
}

Now you can use Map to archieve your goal:

Map(volc, list, names(list))

R, from a list create plots and save it with his name

Using for loop or apply:

# dummy data
ssamblist <- list(a = mtcars[1:10, 1:4], b = mtcars[11:20, 1:4], c = mtcars[21:30, 1:4])

# using for loop
for(i in names(ssamblist)) {
svg(paste0("Corr_", i, ".svg"))
pairs(ssamblist[[i]], main = i)
dev.off()}

# using apply
sapply(names(ssamblist), function(i){
svg(paste0("Corr_", i, ".svg"))
pairs(ssamblist[[i]], main = i)
dev.off()})

Save a list of plots dynamically

We need to make sure the ggplot object is being passed as the first argument, using the tag argument in the labs() function allows us to assign the plot to a "variable".

imap(.x = combined_mtcars, ~ggplot(.x, aes(x = hp, y = mpg, group = cyl)) +
geom_line() +
labs(title = .y, tag="Plot")%>%
imap(~ggsave(plot = Plot, file = paste0("/plots/", .y, ".png")))

If that does not work, try this since ggsave may default to the correct plot.

 imap(.x = combined_mtcars, ~ggplot(.x, aes(x = hp, y = mpg, group = cyl)) +
geom_line() +
ggtitle(.y)) %>%
imap(~ggsave(file = paste0("/plots/", .y, ".png")))

How to save several plots from an own function into a list in R?

Although I couldn't find the way to save the plots into an object, I found a way to create a presentation with those images thanks to this post and the export package.

library(export) 

list_genes <- c("GEN1", "GEN2", "GEN3")

myfunction <- function(x,y){
for(gene in list_genes){
# This to draw both plots
par(mfrow=c(2,1))

plot(x,y, main=paste0("Plot of ", gene))

hist(x, main=paste0("Plot of ", gene))
graph2ppt(file="plots.pptx", width=6, height=5,append=TRUE) } }

myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))

Of course, the width and height of the plots can be changed or put them as a parameter in the function.

Since the package is not available in CRAN for my current R version (4.1.2), I downloaded it from GitHub:
devtools::install_github("tomwenseleers/export")

In addition, I have found another package that I can use for the same purpose (although it adds one extra slide at the beginning, I don't know why)

library(eoffice)

list_genes <- c("GEN1", "GEN2", "GEN3")

myfunction <- function(x,y){

for(gene in list_genes){
# This to draw both plots
par(mfrow=c(2,1))

plot(x,y, main=paste0("Plot of ", gene))

hist(x, main=paste0("Plot of ", gene))
topptx(file="plots.pptx", width=6, height=5,append=TRUE)
}
}

myfunction(x=c(1,5,6,2,4),y=c(6,10,53,1,5))

PS: I found the solution to create a presentation --> How to create a presentation in R with several plots obtained by a function?

exporting and saving a list of ggplots objects with names based on a column

One option would be to name your lists of plots and use purrr::imap or purrr::iwalk to loop over the list of plots to save them.

For convenience I use split to first split you data by location which will create a named list of dataframe on which I apply your function using lapply before passing it to iwalk to save the plots using ggsave:

library(ggplot2)
library(dplyr)
library(tidyr)

split(dat1, dat1$location) |>
lapply(plot.func) |>
purrr::iwalk(~ ggsave(paste(.y, "barchart", "pdf", sep = "."), plot = .x))
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image
#> Saving 7 x 5 in image

Storing ggplot objects in a list from within loop in R

In addition to the other excellent answer, here’s a solution that uses “normal”-looking evaluation rather than eval. Since for loops have no separate variable scope (i.e. they are performed in the current environment) we need to use local to wrap the for block; in addition, we need to make i a local variable — which we can do by re-assigning it to its own name1:

myplots <- vector('list', ncol(data2))

for (i in seq_along(data2)) {
message(i)
myplots[[i]] <- local({
i <- i
p1 <- ggplot(data2, aes(x = data2[[i]])) +
geom_histogram(fill = "lightgreen") +
xlab(colnames(data2)[i])
print(p1)
})
}

However, an altogether cleaner way is to forego the for loop entirely and use list functions to build the result. This works in several possible ways. The following is the easiest in my opinion:

plot_data_column = function (data, column) {
ggplot(data, aes_string(x = column)) +
geom_histogram(fill = "lightgreen") +
xlab(column)
}

myplots <- lapply(colnames(data2), plot_data_column, data = data2)

This has several advantages: it’s simpler, and it won’t clutter the environment (with the loop variable i).


1 This might seem confusing: why does i <- i have any effect at all? — Because by performing the assignment we create a new, local variable with the same name as the variable in the outer scope. We could equally have used a different name, e.g. local_i <- i.



Related Topics



Leave a reply



Submit