Repeat a ggplot for each value of a variable in the dataframe

Viewed 401

I want to make a graph for each value of a variable in my dataframe, and then pass that value through to the graph as the title. I think the best way to do this is by using the apply() family of functions, but i'm a bit of a novice and can't figure out how to do that.

For example, say I have this dataframe:

df <- data.frame(month=c("Chair", "Table", "Rug", "Wardrobe", "Chair", "Desk", "Lamp", "Shelves", "Curtains", "Bed"),
                 cutlery=c("Fork", "Knife", "Spatula", "Spoon", "Corkscrew", "Fork", "Tongs", "Chopsticks", "Spoon", "Knife"),
                 type=c("bbb", "ccc", "aaa", "bbb", "ccc", "aaa", "bbb", "ccc", "aaa", "bbb"),
                 count=c(341, 527, 2674, 811, 1045, 4417, 1178, 1192, 4793, 916))

I could manually go through and select on the value of type doing this:

df %>% 
  filter(type=='aaa') %>% 
  ggplot() +
  geom_col(aes(month, count)) +
  labs(title = 'value of {{type}} being plotted')

df %>% 
  filter(type=='bbb') %>% 
  ggplot() +
  geom_col(aes(month, count)) +
  labs(title = 'value of {{type}} being plotted')

df %>% 
  filter(type=='ccc') %>% 
  ggplot() +
  geom_col(aes(month, count)) +
  labs(title = 'value of {{type}} being plotted')

But this quickly becomes a lot of code, with enough levels of type and assuming a fair amount of additional code for each plot. Let's also assume that I don't want to use facet_wrap(~type). As you can see, the values of the x variable vary quite a lot across values of type so facet_wrap() results in lots of missing spaces along the x-axis. Ideally i'd just create a function that takes as an input the x and y variables, and type and then filters on type, makes the plot, and extracts the value of type to use in the title.

Can anyone help me out with this?

3 Answers

Or you can create your custom function and then lapply over the levels of type

myplot <- function(var){
  df %>% 
    filter(type==var) %>% 
    ggplot() +
    geom_col(aes(month, count)) +
    labs(title = paste0("value of ",var))
}
plot.list <- lapply(unique(df$type), myplot)
plot.list[[1]]
plot.list[[2]]
plot.list[[3]]

EDIT

to include the x variable as argument::

myplot <-
  function(var, xvar) {
    df %>%   
      filter(type == var) %>%   
      ggplot() + 
      geom_col(aes(x={{xvar}}, count)) +   
      labs(title = paste0("value of ", var))
  }

plot.list <- lapply(unique(df$type), myplot,xvar=cutlery)

you miss the {{}} (aka 'curly curly') operator that replaces the approach of quoting with enquo and unquoting with !! (aka 'bang-bang'), and the argument xvar has to be passed as an extra argument of lapply and not of the function inside lapply

You can split the data for each value of type and generate a list of plots.

library(tidyverse)

df %>%
  group_split(type) %>%
  map(~ggplot(.x) +
        geom_col(aes(month, count)) +
        labs(title = sprintf('value of %s being plotted', 
                              first(.x$type)))) -> plot_list

plot_list[[1]] returns :

enter image description here

and plot_list[[2]] returns -

enter image description here

From your statement "Ideally i'd just create a function that takes as an input the x and y variables, and type ..." I assume you specifically want to have a function that takes x and y as different variables (e.g. vectors) as inputs rather than taking the whole dataframe as an input. In this case, this function may suit your needs:

library(ggplot2)
library(dplyr)

myPlot_function = function(x, y, type) {
        
        gg_list = list() # empty list
        df = data.frame(x, y, type)
        type_n = length(unique(df$type)) # number of each type
        
        for (i in 1:type_n){ # loop over each type
                
                g = df %>%
                        filter(type == type[i]) %>%
                        ggplot() +
                        geom_col(aes(x, y)) +
                        labs(title = paste0("Value of ", type[i], " being plotted"))
                gg_list[[paste0("plot_", i)]] = g
        }
        return(gg_list)
}

And then, you can specify your x and y and type as vectors. For example:

some_plots = myPlot_function(x = df$month, y = df$count, type = df$type)

The function myPlot_function returns a list containing your plots. You can now either use some_plots$plot_1 or some_plots[[1]] to see your plot. For example:

some_plots$plot_1

enter image description here

Related