1

I have a list of df Measurements_l for which I used to work with lapply and a function containing ggplot to plot each list :

Measurements_l <- split(Measurements,list(Measurements$Sample.type,Measurements$Site), drop=TRUE)
      lapply(names(Measurements_l), function(i){
        ggplot(Measurements_l[[i]], aes(Date, Activity, group = Nuclides, col = as.factor(Nuclides))) +
          geom_line() +
          geom_point() +
          facet_grid(rows = vars(Locality)) +
          xlab("Date") +
          ylab(paste("Concentration in", Measurements_l[[ i ]]$Measuring.Unit[ 1 ])) +
          theme(legend.title=element_blank(),
          guides(col=guide_legend(ncol=1)) +
          ggsave(paste(i, ".png", sep = ""),  dpi = 600, width = 30, height = 22, units = "cm")
      })
      dev.off()

With the latest R version (4.1.2), I got some issues :

Error in `ggplot_add()`:
! Can't add `ggsave(paste(i, ".png", sep = ""), dpi = 600, width = 30, height = 20, ` to a ggplot object.
* Can't add `    units = "cm")` to a ggplot object.
Run `rlang::last_error()` to see where the error occurred.
Called from: signal_abort(cnd, .file)
Browse[1]> dev.off()
Error during wrapup: cannot shut down device 1 (the null device)
Error: no more error handlers available (recursive errors?); invoking 'abort' restart

ggsave being included in my ggplot function, I do not know how to tackle this issue. Any idea ? I do not want to rewrite all my functions in all my scripts because of this newer version.

Moreover, why is it no longer possible to use "cm" units to a ggplot object ?

REPRODUCIBLE EXAMPLE (leading to 4 graphs)

Measurements 

Locality Sample Nuclides    Activity    Measuring Unit  Date
PARIS    MILK   I-131          1            BQ/L        2010
PARIS    MILK   I-131          2            BQ/L        2020
PARIS    WATER  I-131          3            BQ/L        2010
PARIS    WATER  I-131          4            BQ/L        2020
BRUSSELS MILK   I-131          5            BQ/L        2010
BRUSSELS MILK   I-131          6            BQ/L        2020
BRUSSELS WATER  I-131          7            BQ/L        2010
BRUSSELS WATER  I-131          8            BQ/L        2020

Measurements_l <- split(Measurements,list(Measurements$Sample,Measurements$Locality), drop=TRUE)
      lapply(names(Measurements_l), function(i){
        ggplot(Measurements_l[[i]], aes(Date, Activity, group = Nuclides, col = as.factor(Nuclides))) +
          geom_line() +
          geom_point() +
          facet_grid(rows = vars(Locality)) +
          ggsave(paste(i, ".png", sep = ""),  dpi = 600, width = 30, height = 22, units = "cm")
      })
      dev.off()
Sylvain
  • 133
  • 1
  • 10
  • 4
    Assign ggplot as object, feed object to ggsave. See [related blog](https://www.tidyverse.org/blog/2021/06/off-label-uses-in-ggplot2/). It's not the R version that has caused this, it's an intentional change by ggplot2. – teunbrand Feb 09 '22 at 11:48
  • Practically speaking, I am not sure I see how to do it – Sylvain Feb 09 '22 at 12:04
  • 1
    First `g <- ggplot(...) + ...`, then `ggsave("filename", plot = g, ...)`. All inside the lapply loop. – teunbrand Feb 09 '22 at 12:17
  • But initially, I have a list of df and I wish to apply this function to the name of each element of my list. And at the end, all my plots have the name of each element in the list ("blabla1".png, "blabla2".png,...). How to deal with the initial list ? – Sylvain Feb 09 '22 at 12:23
  • 1
    Yeah I don't know exactly what you mean by describing it. Could you make a reproducible example that we can run on our machines that expose the problem? – teunbrand Feb 09 '22 at 12:34
  • I did my best to produce a reproductible example. Tell me if it is not sufficient for you – Sylvain Feb 09 '22 at 12:58

1 Answers1

2

The following, which I had suggested in the comments, works for me:

library(ggplot2)

Measurements <- data.frame(
  Locality = rep(c("PARIS", "BRUSSELS"), each = 4),
  Sample   = rep(rep(c("MILK", "WATER"), each = 2), 2),
  Nuclides = "I-131",
  Activity = 1:8,
  Measuring_Unit = "BQ/L",
  Date     = rep(c(2010, 2020), 4)
)

Measurements_l <- split(Measurements,list(Measurements$Sample,Measurements$Locality), drop=TRUE)

lapply(names(Measurements_l), function(i){
  g <- ggplot(Measurements_l[[i]], 
              aes(Date, Activity, group = Nuclides, col = as.factor(Nuclides))) +
    geom_line() +
    geom_point() +
    facet_grid(rows = vars(Locality))
  
  ggsave(paste(i, ".png", sep = ""), plot = g, 
         dpi = 600, width = 30, height = 22, units = "cm")
})

It yields 4 plots with the names 'WATER.BRUSSELS.png', 'WATER.PARIS.png', 'MILK.BRUSSELS.png' and 'MILK.PARIS.png' in the working directory.

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Ho, thank's a lot, it works too! Actually, I have misunderstood, I thought that g had to be outside the function. – Sylvain Feb 09 '22 at 13:55