C.Robin
C.Robin

Reputation: 1102

Pass a column value through to the title of a ggplot function

Say I have this tibble:

df <- tibble(question_text  = c('Did they do the thing?', 'Did they do the thing?','Did they do the thing?', 'Did they do the thing?'),
             answer_text    = c('They did', 'They did', 'They did not', 'They did not'),
             answer_numeric = c(3, 3, 2, 2),
             gender         = c('Female', 'Male', 'Female', 'Male'),
             n              = c(82000, 41000, 12000, 39000))

df
# A tibble: 4 x 5
  question_text          answer_text  answer_numeric gender     n
  <chr>                  <chr>                 <dbl> <chr>  <dbl>
1 Did they do the thing? They did                  3 Female 82000
2 Did they do the thing? They did                  3 Male   41000
3 Did they do the thing? They did not              2 Female 12000
4 Did they do the thing? They did not              2 Male   39000

I want to write a function that prints a ggplot graph and which passes through the value of question_text to the title. (in practice my dataset has many more question-answer combinations than in the tibble shown, but the code below replicates the error i'm getting).

And this is the code I have:

library(tidyverse)
library(scales)
library(viridis)

graph_fcn <- function(catvar, ft_size=12, title, scales){
  df %>%
    ggplot() +
    geom_col(aes(x = reorder(answer_text, answer_numeric), y = n, fill = answer_text)) +
    scale_y_continuous(labels = comma) +
    theme(legend.position = 'none',
          axis.title = element_blank(),
          axis.text=element_text(size={{ft_size}})) +
    scale_fill_viridis(discrete = TRUE, alpha=0.6) +
    ggtitle(paste0("\"",  question_text, "\"", {{title}})) +
    facet_wrap(vars({{catvar}}), scales={{scales}})
}

graph_fcn(catvar = gender,
          ft_size = 8,
          title = 'by gender',
          scales = 'fixed')

If you run the above it will return the error:

Error in paste0("\"", { : object 'question_text' not found

I've tried numerous things to try and solve this:

  1. Putting question_text inside double curly brackets, i.e. {{}}
  2. Passing question_text through to the function argument and setting the default as question_text
  3. Passing question_text through to the function argument and then explicitly setting question_text = question_text in the function call

None of the above work though. Does anyone know what i'm doing wrong here? And how I can pass the value of question_text through to ggtitle()?

If I remove question_text from the line ggtitle(paste0("\"", question_text, "\"", {{title}})) the graph looks like this:

enter image description here

Addendum

As my df actually contains many more question-answer combinations, in practice what i'm doing is performing various mutations and then piping that directly into the ggplot() command, within the function. I.e.

graph_fcn <- function(que_id, catvar, ft_size=12, title, scales){
  df %>%
  filter(question_id=={{que_id}}) %>%
  group_by(question_text, answer_text, answer_numeric, {{catvar}}) %>% count() %>% 
  filter(!is.na({{catvar}})) %>%
    ggplot() +
    geom_col(aes(x = reorder(answer_text, answer_numeric), y = n, fill = answer_text)) +
    scale_y_continuous(labels = comma) +
    theme(legend.position = 'none',
          axis.title = element_blank(),
          axis.text=element_text(size={{ft_size}})) +
    scale_fill_viridis(discrete = TRUE, alpha=0.6) +
    ggtitle(paste0("\"",  question_text, "\"", {{title}})) +
    facet_wrap(vars({{catvar}}), scales={{scales}})
}

graph_fcn(catvar = gender,
          ft_size = 8,
          title = 'by gender',
          scales = 'fixed')

So if I put df$question_text[1] inside ggtitle() it pulls the first value from the main df rather than the much smaller one that only contains a single question value.

Additional solution:

The below solutions work well for a small df with only one question-answer combination, and Sonak's is great if you want to make plots for all questions. I found the simplest though is actually to assign the dplyr transformations to a temp_df within the function, then separately within the function pass the temp_df into the ggplot call.

I.e.

graph_fcn <- function(que_id, catvar, ft_size=12, title, scales){
  temp_df <- df %>%
  filter(question_id=={{que_id}}) %>%
  group_by(question_text, answer_text, answer_numeric, {{catvar}}) %>% count() %>% 
  filter(!is.na({{catvar}}))

temp_df %>%
    ggplot() +
    geom_col(aes(x = reorder(answer_text, answer_numeric), y = n, fill = answer_text)) +
    scale_y_continuous(labels = comma) +
    theme(legend.position = 'none',
          axis.title = element_blank(),
          axis.text=element_text(size={{ft_size}})) +
    scale_fill_viridis(discrete = TRUE, alpha=0.6) +
    ggtitle(paste0("\"",  temp_df$question_text[1], "\"", {{title}})) +
    facet_wrap(vars({{catvar}}), scales={{scales}})
}

Upvotes: 3

Views: 2115

Answers (2)

Ronak Shah
Ronak Shah

Reputation: 388807

library(tidyverse)
library(scales)
library(viridis)

graph_fcn <- function(df, catvar, ft_size=12, title, scales){

    ggplot(df) +
     geom_col(aes(x = reorder(answer_text, answer_numeric), 
                  y = n, fill = answer_text)) +
    scale_y_continuous(labels = comma) +
    theme(legend.position = 'none',
          axis.title = element_blank(),
          axis.text=element_text(size=ft_size)) +
    scale_fill_viridis(discrete = TRUE, alpha=0.6) +
    ggtitle(paste(df$question_text[1], title)) +
    facet_wrap(vars({{catvar}}), scales=scales)
}

You don't need

  • scales={{scales}}
  • size={{ft_size}})
  • {{title}})

Those values can be directly passed.

df$question_text has multiple values , it is better to select specific one which you are interested in.


To apply the function to multiple question id use -

df %>%
  group_split(question_id) %>%
  purrr::map(~graph_fcn(.x, catvar = gender,
                 ft_size = 8,
                 title = 'by gender',
                 scales = 'fixed')) -> list_plots

list_plots

Upvotes: 2

user438383
user438383

Reputation: 6206

Adding df$question_text works:

graph_fcn <- function(catvar, ft_size=12, title, scales){
  df %>%
    ggplot() +
    geom_col(aes(x = reorder(answer_text, answer_numeric), y = n, fill = answer_text)) +
    # scale_y_continuous(labels = 'comma') +
    theme(legend.position = 'none',
          axis.title = element_blank(),
          axis.text=element_text(size={{ft_size}})) +
    scale_fill_viridis(discrete = TRUE, alpha=0.6) +
    ggtitle(paste0("\"",  df$question_text, "\"", {{title}})) +
    facet_wrap(vars({{catvar}}), scales={{scales}})
}

enter image description here

Upvotes: 1

Related Questions