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 justdelm2
(nolist(...)
), then it would try to use the first column ofdelm2
with each of the first elements. This might be useful in other scenarios, but in yourglm
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", and
xis the full dataset of
delm2. The second time the anon-func is called,
fnis
"b3456.bmp",
vnis
"B", and
xis again the full dataset of
delm2`.
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
Names' Attribute Must Be the Same Length as the Vector
How to Pass Data Between Functions in a Shiny App
How to Use Aws Cli to Only Copy Files in S3 Bucket That Match a Given String Pattern
How to Show Corpus Text in R Tm Package
How to Print the Structure of an R Object to the Console
Scoping and Functions in R 2.11.1:What's Going Wrong
R Markdown Math Equation Alignment
Execute a Set of Lines from Another R File
With the R Package Xlsx, How to Set Na.Strings When Reading an Excel File
Remove White Space Between Plots and Table in Grid.Arrange
Adding Scale Bar to Ggplot Map
Different Font Faces and Sizes Within Label Text Entries in Ggplot2
Taking a Disproportionate Sample from a Dataset in R
Changing Tick Intervals When X Axis Values Are Dates