2

I have a function that I'm trying to create using filter !=, but it doesn't work. I wonder if it is due to something related with tidy evaluation.

This is what I tried:

library(haven)
library(dplyr)
library(labelled)
library(sjlabelled)

data <- read_spss("http://staff.bath.ac.uk/pssiw/stats2/SAQ.sav")
data$Q01_L <- as_label(data$Q01)

This is the function I tried to write:

    bar_plot <- function(data, var) {
      var <- rlang::ensym(var)
      
      data %>% 
        filter(!var == "Neither") %>% 
        ggplot(aes(!!var)) +
        geom_bar() +
        coord_flip() +
        theme_classic() +
        labs(x = "Question", y = "Count", title = var_label(data$var)) 
    }
    
    
    bar_plot(data, Q01_L)

What I am trying to achieve is to remove "Neither" values and I tried this using filter(!var == "Neither") but that doesn't work and I'm still getting "Neither" plotted. And I also lost the title of the chart.

enter image description here

This is what I'm trying to achieve:

enter image description here

I was able to do this with a few lines of code:

data %>% 
  filter(!Q01_L == "Neither") %>% 
  ggplot(aes(Q01_L)) +
  geom_bar() +
  coord_flip() +
  theme_classic() +
  labs(x = "Question", y = "Count", title = var_label(data$Q01_L)) 

But I'm not able to figure out how to convert it into a function.

Darren Tsai
  • 32,117
  • 5
  • 21
  • 51
writer_typer
  • 708
  • 7
  • 25
  • 1
    @Typer Writer I strongly recommend to read the chapters about meta programming in [advanced R](https://adv-r.hadley.nz/quasiquotation.html) and have a look at how to specifically [use the new evaluation style in `dplyr`](https://dplyr.tidyverse.org/articles/programming.html) – starja Sep 11 '20 at 15:57
  • I'm trying to include this process ```data$Q01_L <- as_label(data$Q01)``` within the function in this question: https://stackoverflow.com/questions/63851542/how-to-add-as-label-within-a-function. – writer_typer Sep 11 '20 at 17:33

3 Answers3

4

enter image description here

Try eval as filter(!eval(var) == "Neither")

 bar_plot <- function(.data, var) {
    var <- rlang::ensym(var)
    
    data %>% 
        filter(!eval(var) == "Neither") %>% 
        ggplot(aes(!!var)) +
        geom_bar() +
        coord_flip() +
        theme_classic() +
        labs(x = "Question", y = "Count", title = var_label(data[var])) 
}


bar_plot(data, Q01_L)
Liman
  • 1,270
  • 6
  • 12
3

You can also use !! (credits @DarrenTsai) and !=:

#Plot
bar_plot <- function(.data, var) {
  var <- rlang::ensym(var)
  
  data %>% 
    filter(!!var != "Neither") %>% 
    ggplot(aes(!!var)) +
    geom_bar() +
    coord_flip() +
    theme_classic() +
    labs(x = "Question", y = "Count", title = var_label(data[,var])) 
}


bar_plot(data, Q01_L)

Output:

enter image description here

Duck
  • 39,058
  • 13
  • 42
  • 84
  • 1
    No need of `sym()`. `filter(!!var != "Neither")` is ok. – Darren Tsai Sep 11 '20 at 15:33
  • @DarrenTsai Yeah, it also works in that way thanks! I will update the answer with your information !!! – Duck Sep 11 '20 at 15:36
  • The filter works great. But I'm getting this error when I used `data[,var]` : ```Error in .subset(x, j) : invalid subscript type 'symbol'``` – writer_typer Sep 11 '20 at 15:43
  • 1
    @TyperWriter Try changing to this `title = var_label(data[[var]])`. It looks like the variable might be missing but as you saw with your data the plot is produced as you want. Also maybe `labelled` package version. I have the last version. – Duck Sep 11 '20 at 15:46
  • @TyperWriter I have `labelled_2.6.0`. – Duck Sep 11 '20 at 15:47
3

You can use the curly-curly operator in a function, so that var <- rlang::ensym(var) can be removed.

From help("nse-force"):

The curly-curly operator {{ }} for function arguments is a bit special because it forces the function argument and immediately defuses it. The defused expression is substituted in place, ready to be evaluated in another context, such as the data frame.

bar_plot <- function(data, var) {
  
  data %>% 
    filter({{var}} != "Neither") %>% 
    ggplot(aes( {{var}} )) +
    geom_bar() +
    coord_flip() +
    theme_classic() +
    labs(x = "Question", y = "Count", title = var_label(pull(data, {{var}})))
}

bar_plot(data, Q01_L)
Darren Tsai
  • 32,117
  • 5
  • 21
  • 51
  • 1
    please note that there is still a very subtle error that comes from OP's code: the argument name is `.data`, not `data` – starja Sep 11 '20 at 15:51
  • 1
    I think your answer is the best for the new `tidyverse` approach – starja Sep 11 '20 at 15:51
  • @starja I discover it at the beginning, but forget to fix it when writing the answer! Thanks for your reminding! – Darren Tsai Sep 11 '20 at 15:52
  • btw.: in the `tidyverse`, the `data` argument for functions that can be used with a pipe are usually named `.data`, so I think it makes sense to keep this name – starja Sep 11 '20 at 15:55