2

I am seeking for a way to use NSE inside argument (in this case, intersect) in dplyr using rlang package.

Data frame:

df <- data.frame(time=as.factor(c(10,10,10,10,20,20,20,20,10,10,10,10,20,20,20,20)),
                 cost=as.factor(c(10,20,30,40,10,20,30,40,10,20,30,40,10,20,30,40)),
                 type=c("a","a","a","a","a","a","a","a","b","b","b","b","b","b","b","b"),
                 value=c(40,20,25,10,80,50,30,60,15,70,80,10,50,20,30,40))

## Set variables for NSE
a <- "time"
b <- "cost"
c <- "type"
d <- "value"

nse_a <- sym(a)
nse_b <- sym(b)
nse_c <- sym(c)
nse_d <- sym(d)

I can plot properly in SE.

## Plot in SE
df %>% ggplot(aes(x=cost, y=value, group=interaction(time,type), color=time, linetype=type)) + geom_line(size=1.2)

enter image description here

However, when I use NSE, it occurs an error:

## Plot in NSE
df %>% ggplot(aes_(x=nse_b, y=nse_d, group=interaction(nse_a,nse_c), color=nse_a, linetype=nse_c)) + geom_line(size=1.2)

Error: unique.default(x, nmax = nmax)
unique() applies only to vectors

It works if I remove group=intersection(...). I suppose the reason may be using NSE in a nested argument 'intersect(...)' inside aes_.

Do you have any solution to avoid this error?

I searched similar topics and tried to apply some examples such as unquoting by !!nse_a but it did not not work. I am new to 'NSE' and still do not well understand its manipulation manner.

HSJ
  • 687
  • 6
  • 16
  • care to explain NSE and SE? – mnm May 09 '18 at 10:23
  • Why are you using NSE anyway? You are working with data frame columns, it seems like an unnecessary layer of complexity. Are you writing your own function? Is it really such a gain not to just put the relevant column names in quotes? –  May 09 '18 at 10:43
  • Thank you for your attention. Though there are limited number of columns in this example, a number of fields are set in the actual data frame which should be tabulated based on the needs. Actually I set a function and change definition of, in this example, a, b, c, d, for flexible tabulation. That is why I need to use non-standard evaluation as it allows to chagne variables in the function. – HSJ May 14 '18 at 14:23

2 Answers2

2

You can only pass quoted arguments to aes_(), so the interaction has to be quoted, but it itself needs unquoted arguments (not really sure about the terminology here, sorry for any confusion)

library(rlang)
library(ggplot2)


interact <- quo(interaction(!!nse_a, !!nse_c))

df %>%
ggplot(aes_(x=nse_b, 
            y=nse_d, 
            group=interact, 
            color=nse_a, 
            linetype=nse_c)) + 
    geom_line(size=1.2)

# or equally

df %>% 
  ggplot(aes_(x=nse_b, 
              y=nse_d, 
              group=quo(interaction(!!nse_a, !!nse_c)), 
              color=nse_a, 
              linetype=nse_c)) + 
  geom_line(size=1.2)

Created on 2018-05-09 by the reprex package (v0.2.0).

GGamba
  • 13,140
  • 3
  • 38
  • 47
0

Base R's interaction doesn't work with rlang, which in general is for the tidyverse only. (EDIT: but see GGamba's answer which shows how to use !! to pass NSE arguments in to standard functions.)

Almost certainly the simplest solution is to create the interaction variable yourself.

df$mygroup <- interaction(df$time, df$type)

Now use mygroup inside your ggplot call.

By doing this you avoid NSE hell.

  • Thank you for your suggestion. However I need to keep using NSE as plotting should be done by changing its variables based on the needs. Anyway thanks for your suggestion! – HSJ May 09 '18 at 10:57
  • Right, but why not just do e.g. `df$mygroup <- interaction(df[[var1]], df[[var2]])` where `var1` and `var2` are passed into your function? –  May 09 '18 at 16:27
  • I appreciate your suggestion and let me try to apply it in the actual use case to fully understand it. I suppose I still need further investigation on it. – HSJ May 14 '18 at 14:28