J.Sabree
J.Sabree

Reputation: 2536

In R, why does map make the wrong plot, but the same code works when I do not map?

I want to map a ggplot over a pre-set vector of x variables. The code does generate the plots, but it looks wrong when I use map()--it collapses all the factors into one group. However, this does not happen when I do not use map. Why is this happening? I explicitly call for these variables to be a factor:

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


data('mtcars')

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

#Create function

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

#This runs--but collapses results across factors
  map(.x = x_variables,
      ~mtcars %>%
        make_chart(x = .x, y = mpg))
  
  #This looks right
  make_chart(data = mtcars, x = gear, y = mpg)

Upvotes: 1

Views: 63

Answers (2)

jared_mamrot
jared_mamrot

Reputation: 26515

I think Allan Cameron's answer clearly illustrates and solves the problem (brilliant solution!), but another potential approach is to adjust make_chart(), rather than map(), e.g.

library(tidyverse)
data('mtcars')

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

#Create function
make_chart <- function(data, x, y){
  ggplot(data, aes(x = as.factor(!!sym(x)), y = !!enquo(y))) +
    geom_col() +
    ggtitle(paste0("Number of ", x, " by MPG")) +
    xlab(x)
}

map(.x = x_variables,
    ~mtcars %>%
      make_chart(x = .x, y = mpg))
#> [[1]]

#> 
#> [[2]]

#> 
#> [[3]]

#> 
#> [[4]]

#> 
#> [[5]]

Created on 2023-03-03 with reprex v2.0.2

This is a lot 'simpler' than your example, and it may not translate to your real world scenario, but adapting this approach to suit your use-case might be worth investigating.

Upvotes: 1

Allan Cameron
Allan Cameron

Reputation: 173803

You could use do.call here, ensuring to wrap your .x variable in ensym:

plot_list <- map(.x = x_variables,
                 ~ do.call(make_chart, 
                    list(data = mtcars, x = rlang::ensym(.x), y = quote(mpg))))

So, for example, to plot all the generated images at once, we can do:

library(patchwork)

(plot_list[[1]] + plot_list[[2]]) / 
  (plot_list[[3]] + plot_list[[4]] + plot_list[[5]])

Created on 2023-03-02 with reprex v2.0.2

Upvotes: 2

Related Questions