rpdfeulerr

Damaged PDF from R PDF Graphics Device


I have a list (eulerr.list) that contains data frames that can plot Euler diagrams with eulerr. I want to plot and save Euler diagrams for each data frame in the list. To this end I wrote the following code:

for (j in 1: length(eulerr.list)) {
        
        pdf(file=paste0("output/","triple_","eulerr_",names(eulerr.list[j]),".pdf"))
        plot(eulerr.list[[j]],
             fills = c("red", "forestgreen", "mediumorchid"),
             quantities = TRUE,
             alpha = 0.5,
             labels = c("A", 
                        "B", 
                        names(eulerr.list[j])),
             adjust_labels = TRUE)
        dev.off()
        
}

When I run the loop (RStudio Version 1.3.959), I get the files that I expect, but all the file are damaged (cannot be opened by Preview on my Mac (OSX 10.12.6)). When the loop is finished there are no error messages and Rstudio return an empty prompt. When I assign a value of 1 to j manually and run the code inside the loop:

pdf(file=paste0("output/","triple_","eulerr_",names(eulerr.list[j]),".pdf"))
        plot(eulerr.list[[j]],
             fills = c("red", "forestgreen", "mediumorchid"),
             quantities = TRUE,
             alpha = 0.5,
             labels = c("A", 
                        "B", 
                        names(eulerr.list[j])),
             adjust_labels = TRUE)
        dev.off()

then the file is generated properly (can be viewed in Preview) and RStudio returns this:

> dev.off()
RStudioGD 
        2

Why does the for loop generate damaged PDF files?


Solution

  • What's happening here is that the plot.euler() returns an "eulergram" object. To then actually draw this plot on the current device, the print.eulergram() (or plot.eulergram()) method has to be invoked, but it's not because the call is inside a for loop. When you call plot() interactively, the object that is returned actually has its print() method called implicitly. This is exactly the same issue that people have with ggplot or lattice.

    What you need to do is to save the object from plot() and invoke print() (or plot()) on it, like so:

    for (j in 1: length(eulerr.list)) {  
      pdf(file=paste0("output/","triple_","eulerr_",names(eulerr.list[j]),".pdf"))
      p <- plot(eulerr.list[[j]],
                fills = c("red", "forestgreen", "mediumorchid"),
                quantities = TRUE,
                alpha = 0.5,
                labels = c("A", 
                           "B", 
                           names(eulerr.list[j])),
                adjust_labels = TRUE)
      print(p)
      dev.off()
    }