1

I'm trying to use double curly brackets in a function that makes a timeseries plot, and I've hit a wall, despite reading this overview on how double curly brackets generally work.

In this function, users specify the time period that they want the plot to focus on (week or month). If the user chooses "Month", then the plot's X axis should be the Month date, and the Y axis should be the Month_score column.

I thought I understood how this worked, but my plot shows no data:

library(dplyr)
library(ggplot2)
library(lubdridate)

#Sample data
test <- tibble(Week = seq(as.Date("2014/09/04"), by = "week", length.out = 8),
               Month = ymd(rep('2014-09-01', 4), rep('2014-10-01', 4)),
               Week_score = c(2, 3, 4, 6, 5, 7, 8, 9),
               Month_score = c(15, NA, NA, NA, 29, NA, NA, NA))

#My function
make_time_plot <- function(data, time_period = c("Week", "Month")) {

  time_period_score <- paste0(time_period, "_score")
  
  data %>%
    ggplot(aes(x = {{time_period}}, y = {{time_period_score}})) +
    geom_line()
}

#Proof that it doesn't work :-(
make_time_plot(data = test, time_period = "Month")

Comically Wrong Output:

enter image description here

J.Sabree
  • 2,280
  • 19
  • 48
  • 2
    As you are passing the column names as quoted strings `{{` is not needed. Instead try with the `.data` pronoun, i.e. `aes(x = .data[[time_period]], y = .data[[time_period_score]])` – stefan Apr 02 '22 at 14:15
  • 1
    Instead of the double curly braces, use [`aes_string`](https://ggplot2.tidyverse.org/reference/aes_.html). – Rui Barradas Apr 02 '22 at 14:16

2 Answers2

1

The double curly braces work with unquoted variables names. With variables names as character strings, use aes_string, see also here.

suppressPackageStartupMessages({
  library(dplyr)
  library(ggplot2)
  library(lubridate)
})

#Sample data
test <- tibble(Week = seq(as.Date("2014/09/04"), by = "week", length.out = 8),
               Month = ymd(rep('2014-09-01', 4), rep('2014-10-01', 4)),
               Week_score = c(2, 3, 4, 6, 5, 7, 8, 9),
               Month_score = c(15, NA, NA, NA, 29, NA, NA, NA))

#My function
make_time_plot <- function(data, time_period = c("Week", "Month")) {
  
  time_period <- match.arg(time_period)
  time_period_score <- paste0(time_period, "_score")
  
  data %>%
    ggplot(aes_string(x = time_period, y = time_period_score)) +
    geom_line()
}

#make_time_plot(data = test, time_period = "Month")
make_time_plot(data = test, time_period = "Week")

Created on 2022-04-02 by the reprex package (v2.0.1)

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
1

There are several things going on here. {{}} work on unquoted variables, and cannot be mixed and matched with strings.

For example: when you write mtcars %>% select(hp), you don't need to write "hp". This is due to "data masking", a process which makes R understand that hp is a variable in mtcars, and not a variable in your environment. It´t the process that makes this code work:

# Defining an env-variable
cyl <- 1000

# Referring to a data-variable
dplyr::summarise(mtcars, mean(cyl))
#>   mean(cyl)
#> 1    6.1875

Created on 2022-04-02 by the reprex package (v2.0.1)

How to fix your function

There are easier ways to fix your function, without using {{}}, but if you want to see how to do it with {{}} I've included an example here.

make_time_plot <- function(data, time_period) {
  
  time_period_score <- paste0(rlang::as_name(enquo(time_period)), "_score")
  
  data %>%
    ggplot(
      aes(
        x = {{time_period}},
        y = .data[[time_period_score]]
      )
    ) +
    geom_line()
}

make_time_plot(data = test, time_period = Week)

Created on 2022-04-02 by the reprex package (v2.0.1)

I've changed the following:

  • Since you want to paste a string to time_period, and time_period is a unquoted variable, you need to make it into a string using rlang::as_name(enquo(time_period)).
  • Since time_period_score is a string, you need to supply it to aes() as a string. Since time_period is not a string, you cannot use aes_string(), so instead I use the .data pronoun with .data[[time_period_score]].

You can find more information about {{}} here.

jpiversen
  • 3,062
  • 1
  • 8
  • 12