rfunctionggplot2purrrpmap

How to coerce custom function in R to yield multiple outputs/plots in a set order when iterating with purrr?


I have a custom function that makes 3 plots for each cut of the data. The first plot is the overall results, and it should be followed by the breakdown of results by location and level (although whether location or level comes second or third is okay, as long as it's consistent).

Though my function works, it puts the location plot first, then the overall, and then the level. I'm confused why this is happening because the 2 subplots are made in plot2, and in my output, I explicitly specify that the overall plot should come first.

This post was extremely helpful in getting my custom function to produce 2 outputs, but this post didn't cover how to constrain your output to be in a certain order.

Here's my code:


#Data
test <- tibble(s1 = c("Agree", "Neutral", "Strongly disagree"),
               s2rl = c("Agree", "Neutral", "Strongly disagree"),
               f1 = c("Strongly agree", "Disagree", "Strongly disagree"),
               f2rl = c("Strongly agree", "Disagree", "Strongly disagree"),
               level = c("Manager", "Employee", "Employee"),
               location = c("USA", "USA", "AUS"))

#Get just test items for name
test_items <- test %>%
  dplyr::select(s1, s2rl, f1, f2rl)

#titles of plots for R to iterate over
titles <- c("S1 results", "Results for S2RL", "Fiscal Results for F1", "Financial Status of F2RL")


#group levels
group_name <- c("level", "location")

#custom ggplot function
faceted_plots = function(variable, group, title) {
  
  plot1 <- test %>%
    count(.data[[variable]]) %>%
    mutate(percent = 100*(n / sum(n, na.rm = TRUE))) %>%
    ggplot(aes(x = .data[[variable]], y = percent, fill = .data[[variable]])) + 
    geom_bar(stat = "identity") +
    ggtitle(title)

  plot2 <- test %>%
    count(.data[[group]], .data[[variable]]) %>%
    mutate(percent = 100*(n / sum(n, na.rm = TRUE))) %>%
    drop_na() %>%
    ggplot(aes(x = .data[[variable]], y = percent, fill = .data[[variable]])) + 
    geom_bar(stat = "identity") +
    geom_text(aes(label= paste0(percent, "%"), fontface = "bold", family = "Arial", size=14), vjust= 0, hjust = -.5) +
    labs(
      title = title) +
    facet_grid(~.data[[group]])
  
  output <- list(plot1, plot2)
  return(output)
}

#pmap call
my_plots <- expand_grid(tibble(item = names(test_items), title=titles),
                        group = group_name) %>%
  pmap(function(item, group, title)
    faceted_plots(item, group, title))

my_plots

Solution

  • Though I didn't figure out how to coerce the elements in a certain order, I was able to find how to remove duplicates (which was the issue in my above example--the overall plot, or plot1, was being produced twice) based on this answer.

    Adapted for this example, that would be:

    # make a copy of my original list of plots to avoid duplicates
    my_plots_duplicate <- my_plots
    # take set difference between contents of list elements and accumulated elements
    my_plots_duplicate[-1] <- mapply(setdiff, my_plots_duplicate[-1],
                           head(Reduce(c, my_plots, accumulate=TRUE), -1))
    
    my_plots_duplicate