clc
clc

Reputation: 107

Create different types of plots within list of plot objects created with lapply

I have a function that creates a list of plots based on unique values of 'gear' from mtcars

library(datasets) 
library(magrittr)
library(ggplot2)
library(dplyr)

make_plots <- function(data) {

  ### create list of plot objects for every unique value of 'gear' (from mtcars)
  p_list <- lapply(sort(unique(data$gear)), function(i) {

    ggplot2::ggplot(data[data$gear == i,], ggplot2::aes(x = wt, y = mpg, color = factor(cyl))) +
      ggplot2::geom_point() +
      ggplot2::facet_wrap(~ gear) +
      ggplot2::scale_color_discrete(name = "cyl")
  })

  p_list
}

### output list of plots
example_output <- make_plots(mtcars)

What I would like: A list of plots based on unique values of 'gear', but have a different type of plot output depending on each 'gear' value's associated 'plot_type', which I created as another column in the mtcars dataframe. So same number of plots, but different types of plots.

### create new column of 'plot_type', where every unique gear value has the same 'plot_type', i.e., 
### all gears of 3 are of type 'scatter', all gears of 4 are of type 'bar', and all gear of 5 are of type 
### 'log' 
mtcars %>%
  dplyr::mutate(plot_type = case_when(
    gear == 3 ~ "scatter",
    gear == 4 ~ "bar",
    gear == 5 ~ "log"
  ))

I envisioned something roughly like below, but am obviously having trouble.

make_plots <- function(data) {
  
  ### creates list of dataframes, with one dataframe per unique value of 'plot_type'
  split_data <- data %>% 
    dplyr::group_split(plot_type)
  
  p_type <- lapply(split_data[split_data$plot_type == i,], function(i) {
    
    if(split_data[split_data$plot_type == "scatter"]) {
      
      p_list <- lapply(sort(unique(split_data$gear)), function(i) {
        
        ggplot2::ggplot(split_data[split_data$gear == i,], ggplot2::aes(x = wt, y = mpg, color = factor(cyl))) +
          ggplot2::geom_point() +
          ggplot2::facet_wrap(~ gear) 
        
      })
      
      p_list

    }
  })
  
  p_type
}

Upvotes: 1

Views: 175

Answers (1)

stefan
stefan

Reputation: 125268

Instead of putting everything inside one function you could

  1. make use separate functions for each plot type along the lines of your first make_plots function.

  2. make a wrapper for the outer loop which calls the plot type functions were I make use of purrr::imap instead of lapply to pass the name of the plot type.

Note: I dropped the log type and just illustrate the approach with a scatter and bar chart.

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

mtcars2 <- mtcars %>%
  dplyr::mutate(plot_type = case_when(
    gear == 3 ~ "scatter",
    gear %in% c(4, 5) ~ "bar"
  ))

make_scatter <- function(data) {
  lapply(sort(unique(data$gear)), function(i) {
    ggplot2::ggplot(data[data$gear == i, ], ggplot2::aes(x = wt, y = mpg, color = factor(cyl))) +
      ggplot2::geom_point() +
      ggplot2::facet_wrap(~gear) +
      ggplot2::scale_color_discrete(name = "cyl")
  })
}

make_bar <- function(data) {
  lapply(sort(unique(data$gear)), function(i) {
    ggplot2::ggplot(data[data$gear == i, ], ggplot2::aes(x = cyl, fill = factor(cyl))) +
      ggplot2::geom_bar() +
      ggplot2::facet_wrap(~gear) +
      ggplot2::scale_color_discrete(name = "cyl")
  })
}

make_plots <- function(data) {
  split_data <- split(data, data$plot_type)

  p_type <- purrr::imap(split_data, function(x, plot_type) {
    if (plot_type == "scatter") {
      make_scatter(x)
    } else if (plot_type == "bar") {
      make_bar(x)
    }
  })

  p_type
}

make_plots(mtcars2)
#> $bar
#> $bar[[1]]

#> 
#> $bar[[2]]

#> 
#> 
#> $scatter
#> $scatter[[1]]

Upvotes: 1

Related Questions