Search code examples
rdataframeloopsggplot2eval

Create ggplot multiple graphs dynamically with loop in R


I am trying to build multiple graphs with ggplot in batch. The graphs all come from the same dataframe, the only thing I need to change is the metric (y axis) that I observe.

What I am doing now is far from efficient as I am copy-pasting the ggplot setup for each graph and just changing the metric where it needs to be modified.

I know there is a way, to dynamically create these graphs by just listing all the metrics that need to change dynamically so that I only need to use ggplot once in a loop.

I think in the past I managed to do it using eval() , get() and maybe assign() but I can't remember how I had done it.

Ideally, in the end I would have the different graphs created with each a unique name based on the metric: Forecast_Monthly_Visits_FR_Graph, Forecast_Monthly_Sales_FR_Graph etc. Below a reproducible example. Thanks a lot.

library(ggplot2)

Date <- as.Date(c('2022-01-01','2022-01-02','2022-01-03','2022-01-01','2022-01-02','2022-01-03'))
Type <- c("Actual", "Actual", "Actual", "Forecast", "Forecast", "Forecast")
Visits <- c(67398,63398,61398,53422,72726,92822)
Sales <- c(17398,23398,41398,12422,33726,53822)
Actual_Forecast_Monthly_France <- data.frame(Date , Type , Visits, Sales)

Forecast_Monthly_Visits_FR_Graph <-
  ggplot(data=Actual_Forecast_Monthly_France, aes(x=Date, y=Visits, group=Type,  linetype = factor(Type) , show.legend = FALSE)) +
  geom_line(aes(color=Type)) +
  geom_point(size = 0.5) +
  geom_text(aes(label=round(Visits)), size = 3) +
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title = "Visits") +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_color_manual(values= c("#03a623", "#030063", "#ffaad7", "#b6b6b6"))

Forecast_Monthly_Visits_FR_Graph

 Forecast_Monthly_Sales_FR_Graph <-
  ggplot(data=Actual_Forecast_Monthly_France, aes(x=Date, y=Sales, group=Type,  linetype = factor(Type) , show.legend = FALSE)) +
  geom_line(aes(color=Type)) +
  geom_point(size = 0.5) +
  geom_text(aes(label=round(Sales)), size = 3) +
  theme(axis.text.x = element_text(angle = 90)) +
  labs(title = "Sales") +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_color_manual(values= c("#03a623", "#030063", "#ffaad7", "#b6b6b6"))

Forecast_Monthly_Sales_FR_Graph 

Solution

  • You can create a function which includes the y variable you want to plot. Then it becomes relatively simple to create a for loop to cycle through multiple y variable options or you could use a function from purrr. Now included the loop, and I've had to go down the route of quoted variables names as @stefan explained.

    library(ggplot2)
    library(purrr)
    
    gg_fun <- function(y_var){
      Forecast_Monthly_Visits_FR_Graph <-
        ggplot(data=Actual_Forecast_Monthly_France, aes(x=Date, y=!!sym(y_var), group=Type,  linetype = factor(Type) , show.legend = FALSE)) +
        geom_line(aes(color=Type)) +
        geom_point(size = 0.5) +
        geom_text(aes(label=round(Visits)), size = 3) +
        theme(axis.text.x = element_text(angle = 90)) +
        labs(title = y_var) +
        theme(plot.title = element_text(hjust = 0.5)) +
        scale_color_manual(values= c("#03a623", "#030063", "#ffaad7", "#b6b6b6"))
      
      return(Forecast_Monthly_Visits_FR_Graph)
      
    }
    
    gg <- map(c("Visits", "Sales"), gg_fun)
    
    
    gg[[1]]
    

    gg[[2]]
    

    Created on 2022-09-13 with reprex v2.0.2

    data

    Date <- as.Date(c('2022-01-01','2022-01-02','2022-01-03','2022-01-01','2022-01-02','2022-01-03'))
    Type <- c("Actual", "Actual", "Actual", "Forecast", "Forecast", "Forecast")
    Visits <- c(67398,63398,61398,53422,72726,92822)
    Sales <- c(17398,23398,41398,12422,33726,53822)
    Actual_Forecast_Monthly_France <- data.frame(Date , Type , Visits, Sales)
    

    Created on 2022-09-13 with reprex v2.0.2