Yulia Kentieva
Yulia Kentieva

Reputation: 710

how to change titles in ggplot for series of plots?

I created a function that splits a dataframe by group variable 'gear' and makes plots for each new df. How do I change the title for each plot then?

    rank20 <- function(df){
      sdf <- df
      clusterName <- paste0("cluster",sdf$gear)
      splitData <- split(sdf,clusterName)
      plot <- lapply(splitData, function (x) {ggplot(x, aes(mpg, cyl)) + geom_point()+
          labs(x="mpg", y="cyl",
               title="This Needs To Be Changed") + 
          theme_minimal()})
      do.call(grid.arrange,plot)
    }
    rank20(mtcars)

I want the following titles: gear3, gear4, etc. (corresponding to their gear value) enter image description here

UPD: both results are right if using mtcars. But in my real case, I transform my initial df. So, I should have put my question in the different way. I need to take the titles from splitData df name itself rather than from the column.

Upvotes: 1

Views: 689

Answers (2)

tjebo
tjebo

Reputation: 23727

May I suggest a slightly different approach (yet also using the loop over indices as suggested in user Jonny Phelps answer). I am creating a list of plots and then using patchwork::wrap_plots for plotting. I find it smoother.

library(tidyverse)
library(patchwork)

len_ind <- length(unique(mtcars$cyl))

ls_plot <-
  mtcars %>%
  split(., .$cyl) %>%
  map2(1:len_ind, ., function(x, y) {
    ggplot(y, aes(mpg, cyl)) +
      geom_point() +
      labs(x = "mpg", y = "cyl", 
           title = names(.)[x]
      ) +
      theme_minimal()
  })

wrap_plots(ls_plot) + plot_layout(ncol = 1)

Just noticed this was the wrong column - using cyl instead of gear. Oops. It was kind of fun to wrap this into a function:

plot_col <- function(x, col, plotx, ploty){
len_ind <- length(unique(mtcars[[col]]))
x_name <- deparse(substitute(plotx))
y_name <- deparse(substitute(ploty))

ls_plot <-
  mtcars %>%
  split(., .[[col]]) %>%
  map2(1:len_ind, ., function(x, y) {
    ggplot(y, aes({{plotx}}, {{ploty}})) +
      geom_point() +
      labs(x = x_name, y = y_name,
           title = names(.)[x]
      ) +
      theme_minimal()
  })

wrap_plots(ls_plot) + plot_layout(ncol = 1)
}

plot_col(mtcars, "gear", mpg, cyl)

Upvotes: 2

Jonny Phelps
Jonny Phelps

Reputation: 2717

I find it easier with lapply to use the indexes as the input. Provides more flexibility if you need to link the list to another element eg the name of the list:

rank20 <- function(df, col="gear"){
  sdf <- df
  clusterName <- paste0("cluster", sdf[[col]])
  splitData <- split(sdf, clusterName)
  # do the apply across the splitData indexes instead and pull out cluster
  # name from the column
  plot <- lapply(seq_along(splitData), function(i) {
    X <- splitData[[i]]
    i_title <- paste0(col, X[[col]][1])
    ## to use clusterName instead eg cluster3 instead of gear3:
    #i_title <- paste0(col, names(splitData)[i])
    ggplot(X, aes(mpg, cyl)) + 
      geom_point() +
      labs(x="mpg", y="cyl", title=i_title) + 
      theme_minimal()
  })
  do.call(grid.arrange,plot)
}
rank20(mtcars)

As you say you wanted the name to be gear2, gear3 I've gone with this but hashed out the alternative i_title that uses the clusterName value instead.

In the input of the function you can change the col value to switch to a different column so gear isn't hard-coded

Upvotes: 2

Related Questions