rpurrrpmap

In R's purrr, why does pmap through Error in FUN(X[[i]], ...) : object '.z' not found when .z is clearly defined?


I'm trying to get better with pmap(), but I'm hitting some errors. In this example, I have a simple graphing function that I want to iterate over. My understanding of pmap() is that I can set and define an infinite number of parameters. However, I'm confused why it is saying that .z isn't defined when I so clearly have it defined.

Unless necessary, I'm not interested in changing any of the ways the arguments are defined--I just want to understand and fix why I can't have this 3rd argument, even though .x and .y work fine (even if I switch around what is defined as .x, .y, and .z).

library(purrr)
library(ggplot2)
library(dplyr)

#Plot function

make_chart <- function(data, x, y, xtitle){
  
  require(stringr)
    
  ggplot(data, aes(x = as.factor({{x}}), y = {{y}})) +
    geom_col() +
    ggtitle(paste0("Number of ", str_to_title({{xtitle}}), " by MPG")) +
    xlab({{xtitle}})
  
}

#Define x variables
x_variables <- c("cyl", "vs", "am", "gear", "carb")


#pmap it--why is .z not found and how do I get it to be?

pmap(list(.x = mtcars %>% dplyr::select(matches(x_variables)),
          .y = x_variables,
          .z = mtcars %>% dplyr::select(mpg)),
     ~mtcars %>%
       make_chart(x = .x, xtitle = .y, y = .z))

Solution

  • Another option to the ones offered by @shafee would be to pass a named list to pmap with the names of the function arguments. Doing so we don't need an anonymous function which merely maps the names of the list passed to pmap to the names of the function arguments.

    Moreover, at least from a ggplot2 standpoint best practice to create your loop would be to loop over the column names (and making use of the .data pronoun) instead of passing vectors to your function. Actually, doing so you could get rid of the xtitle argument and replace xtitle by x in the plotting function.

    library(purrr)
    library(ggplot2)
    library(stringr)
    
    make_chart <- function(data, x, y, xtitle) {
      ggplot(data, aes(x = as.factor(.data[[x]]), y = .data[[y]])) +
        geom_col() +
        ggtitle(paste0("Number of ", str_to_title(xtitle), " by MPG")) +
        xlab(xtitle)
    }
    
    x_variables <- c("cyl", "vs", "am", "gear", "carb")
    
    pmap(
      list(
        x = x_variables,
        xtitle = x_variables,
        y = "mpg"
      ),
      make_chart,
      data = mtcars
    )
    #> [[1]]
    

    #> 
    #> [[2]]