简体   繁体   中英

Error while plotting with ggsave and other save functions

I have a problem concerning the function ggsave() and I would be really grateful for any help and or suggestions/solutions. I am creating four plots and put them all in one big plot, and since I want to loop the whole function using all columns in my dataframe I want to save the created plots in a specified folder (preferably with an identifying name).

    plotting_fun3 <- function(Q){
  
  plot1 <- plot_likert(
    t(Q),
    title = "Total population",
    legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
    grid.range = c(1.6, 1.1),
    expand.grid = FALSE,
    axis.labels = c(" "),
    values = "sum.outside",
    show.prc.sign = TRUE,
    catcount = 4,
    cat.neutral = 3,
    
  )
  
  plot2 <- plot_likert(
    t(Q[survey$animal=="Dogs"]),
    title = "Female",
    legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
    grid.range = c(1.6, 1.1),
    expand.grid = FALSE,
    axis.labels = c(" "),
    values = "sum.outside",
    show.prc.sign = TRUE,
    catcount = 4,
    cat.neutral = 3,
    
  )
  
  plot3 <- plot_likert(
    t(Q[survey$animal=="Cats"]),
    title = "Male",
    legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
    grid.range = c(1.6, 1.1),
    expand.grid = FALSE,
    axis.labels = c(" "),
    values = "sum.outside",
    show.prc.sign = TRUE,
    catcount = 4,
    cat.neutral = 3,
    
  )
  
  plot4 <- plot_likert(
    t(Q[survey$animal=="Turtle"]),
    title = "Others",
    legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
    grid.range = c(1.6, 1.1),
    expand.grid = FALSE,
    axis.labels = c(" "),
    values = "sum.outside",
    show.prc.sign = TRUE,
    catcount = 4,
    cat.neutral = 3,
    
  )
  
  theplot <- ggarrange(plot1, plot2, plot3, plot4, 
                       labels = NULL,
                       common.legend = TRUE,
                       legend = "bottom",
                       ncol = 1, nrow = 4)
  
  #ggsave(filename=paste(Q,".png",sep=""), plot=theplot, device = "png")
  
  #ggsave(filename=paste("animal_plot", ID, ".jpeg"), plot=plots[[x]])
  
  #ggsave(path = "/myDirectory",
  #       device = "png", filename = "animal_plot", plot = theplot)
  
  #save_plot(filename = "hello", plot = theplot, 
  #          "/myDirectory",
  #          device = "png")

  #ggsave(sprintf("%s.pdf", Q), device = "pdf")
  
  return(theplot)
}

The commented lines show all kinds of ways I have tried to save the plot in my directory. I encounter 2 different problems:

Either: Most of the ggsave suggestions I found on stack overflow. Several of them did not include the line device = "png" . If I leave out this line of code I always get something like this:

 Fehler: `device` must be NULL, a string or a function.
Run `rlang::last_error()` to see where the error occurred. 

If I follow that command I get:

<error/rlang_error>
`device` must be NULL, a string or a function.
Backtrace:
 1. global::plotting_fun3(survey[, 9])
 2. ggplot2::ggsave(sprintf("%s.pdf", Q))
 3. ggplot2:::plot_dev(device, filename, dpi = dpi)
Run `rlang::last_trace()` to see the full context.
> rlang::last_trace()
<error/rlang_error>
`device` must be NULL, a string or a function.
Backtrace:
    █
 1. └─global::plotting_fun3(survey[, 9])
 2.   └─ggplot2::ggsave(sprintf("%s.pdf", Q))
 3.     └─ggplot2:::plot_dev(device, filename, dpi = dpi)

So online I found people with the same or similar problem and the suggestion has always been to use device = "png" or similar.

Now if I do this I encounter a different problem: The plots are saved in the right directory but the name is wrong. Usually the name is "3.png" or "3.pdf" or depending on what I create. If "3.png" already exists it gives the file another number.

I had this problem in an older project three months ago and couldn't solve it and now I have it again.

For what it's worth, I use macOS Mojave 10.14.6, my R version is Version 1.3.1093

Thank you in advance for any thoughts, suggestions or other comments.

[EDIT]

Here is some sample data:

 > str(myDF[,c(2,9:10)])
 data.frame':   123 obs. of  3 variables:
 $ animal: chr  "Cats" "Cats" "Turtles" "Cats" ...
 $ q8    : int  3 5 5 3 4 4 2 5 3 5 ...
 $ q9.1  : int  4 5 5 4 3 4 2 4 2 4 ...

The values stay between 1 and 5 for all observations. They actually represent answers such as "strongly agree", "agree", "neither agree nor disagree"...etc.

Alternatively, if you prefer this to the other one:

> myDF[,c(2,9:10)]
     animal q8 q9.1
1      Cats  3    4
2      Cats  5    5
3   Turtles  5    5
4      Cats  3    4
5   Turtles  4    3
6   Turtles  4    4
7   Turtles  2    2
8      Cats  5    4
9      Cats  3    2
10  Turtles  5    4
11  Turtles  4    3
12  Turtles  3    3
13     Dogs  3    3
14     Cats  3    3
15     Dogs  1    1
16     Dogs  1    3

The issue with file name is due to you use Q which is a dataframe in the filename defintion so it will result in some very messy way depend on how your system handling filename.

# This command result in a few long character depend on number of columns in Q.
# 4 columns w+ill result 4 long character and ggsvave will return the error
# Error: `device` must be NULL, a string or a function.
ggsave(filename=paste(Q,".png",sep=""), plot=theplot, device = "png")
  
# Again not sure what ID is here but if it was a dataframe you got
# same error with previous one.
ggsave(filename=paste("animal_plot", ID, ".jpeg"), plot=plots[[x]])

# This one it doesn't specific a file name but a directory
# ggsave will return an error:
# Error: Unknown graphics device ''
# If you specify device = "png" - error will be:
# Error in grid.newpage() : could not open file '/home/sinh' 
ggsave(path = "/myDirectory",
       device = "png", filename = "animal_plot", plot = theplot)

# Why there is a param "/myDirectory" here? and you should specify the extention
# in the file name. So the correct param is:
# filename = "/myDirectory/hello.png"
save_plot(filename = "hello", plot = theplot, 
          "/myDirectory",
          device = "png")

Here is one that should work properly but you need to input file name manually:

character_variable <- "my_character_variable_here_"
index_number <- 20
# If you specify sep = "" then just need to use paste0
file_name <- paste0(character_variable, index_number)
ggsave(filename=paste(file_name, ".jpeg"), plot=plots[[x]], device = "png")

And here is my rewrite function based on your function. You may try it out and tweak it a bit

# df is your survey data.frame
# q_column_name is the name of questionare column that you want to graph.
# the final output file will use q_column_name as file name.
plotting_fun3 <- function(df, q_column_name){
  
  require(foreach)
  require(dplyr)
  require(tidyr)
  
  graph_data <- df %>% select(one_of("animal", q_column_name))
  
  plot1 <- plot_likert(
    t(graph_data),
    title = "Total population",
    legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
    grid.range = c(1.6, 1.1),
    expand.grid = FALSE,
    axis.labels = c(" "),
    values = "sum.outside",
    show.prc.sign = TRUE,
    catcount = 4,
    cat.neutral = 3,
  )
  
  animal_plots <- foreach(current_animal = c("Dog", "Cats", "Turtle")) %do% {
    plot_likert(
      t(graph_data %>% filter(animal == current_animal)),
      title = "Female",
      legend.labels = c("strongly disagree","disagree", "neither nor", "agree", "strongly agree"),
      grid.range = c(1.6, 1.1),
      expand.grid = FALSE,
      axis.labels = c(" "),
      values = "sum.outside",
      show.prc.sign = TRUE,
      catcount = 4,
      cat.neutral = 3
    )
  }
  
  theplot <- ggarrange(plot1, animal_plots[[1]],
                       animal_plots[[2]], animal_plots[[3]], 
                       labels = NULL,
                       common.legend = TRUE,
                       legend = "bottom",
                       ncol = 1, nrow = 4)
  
  ggsave(filename=paste(q_column_name, ".png",sep=""), plot=theplot, device = "png")
  
  return(theplot)
}

Here is how to use the function

# Assume that your survey dataframe variable is myDF
my_new_plot <- plotting_fun3(df = myDF, q_column_name = "q8")

[Updated] - Added the function to solve the graph issue.

For anyone encountering a similar problem in a less complicated setting: double check if you are passing a valid path/filename string to ggsave() !

In my case, I made a mistake with string processing using str_split() and path concatenation. Therefore, ggsave() was not given a valid single-string path, promting the Error: 'device' must be NULL, a string or a function. The error had nothing to do with my 'device' but I was simply not passing a proper string. Once I fixed the path, the issue was solved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM