Search code examples
rggplot2nsenon-standard-evaluation

How to user NSE inside fct_reorder() in ggplot2


I would like to know how to use NSE (Non-Standard Evaluation) expression in fct_reorder() in ggplot2 to replicate charts for different data frames.

This is an example of data frame that I use to draw a chart:

   travel_time_br30 travel_time_br30_int time_reduction shift not_shift total
1              0-30                    0             10  2780      3268  6048
2              0-30                    0             20  2779      3269  6048
3              0-30                    0             30  2984      3064  6048
4              0-30                    0             40  3211      2837  6048
5             30-60                   30             10  2139      2007  4146
6             30-60                   30             20  2159      1987  4146
7             30-60                   30             30  2363      1783  4146
8             30-60                   30             40  2478      1668  4146
9             60-90                   60             10   764       658  1422
10            60-90                   60             20   721       701  1422
11            60-90                   60             30   782       640  1422
12            60-90                   60             40   801       621  1422
13           90-120                   90             10   296       224   520
14           90-120                   90             20   302       218   520
15           90-120                   90             30   317       203   520
16           90-120                   90             40   314       206   520
17          120-150                  120             10    12        10    22
18          120-150                  120             20    10        12    22
19          120-150                  120             30    10        12    22
20          120-150                  120             40    13         9    22
21          150-180                  150             10    35        21    56
22          150-180                  150             20    40        16    56
23          150-180                  150             30    40        16    56
24          150-180                  150             40    35        21    56
      share
1  45.96561
2  45.94907
3  49.33862
4  53.09193
5  51.59190
6  52.07429
7  56.99469
8  59.76845
9  53.72714
10 50.70323
11 54.99297
12 56.32911
13 56.92308
14 58.07692
15 60.96154
16 60.38462
17 54.54545
18 45.45455
19 45.45455
20 59.09091
21 62.50000
22 71.42857
23 71.42857
24 62.50000

These are the scripts to draw a chart from above data frame:

g.var <- "travel_time_br30"
go.var <- "travel_time_br30_int"

test %>% ggplot(.,aes_(x=as.name(x.var),y=as.name("share"),group=as.name(g.var))) +
    geom_line(size=1.4, aes(
                color=fct_reorder(travel_time_br30,order(travel_time_br30_int)))) 

enter image description here

As I have several data frames which has different fields such as access_time_br30, access_time_br30_int instead of travel_time_br30 and travel_time_br30_int in the data frame, I set two variables (g.var and go.var) to easily replicate multiple chars in the same scripts.

As I need to reorder the factor group numerically, in particular, changing order of travel_time_br30 by travel_time_br30_int, I am using fct_reorder function in ggplot2(., aes_(...)). However, if I use aes_ with fct_reorder() in geom_line() as shown as an example in the following script, it returns an error saying Error:fmust be a factor (or character vector).

geom_line(size=1.4, aes_(color=fct_reorder(as.name(g.var),order(as.name(go.var)))))

Fct_reorder() does not seem to have an NSE version like fct_reorder_(). Is it impossible to use both aes_ and fct_reorder() in a sequence of scripts or are there any other solutions?


Solution

  • Based on my novice working knowledge of tidy-eval, you could transform your factor order in mutate() before passing the data into ggplot() and acheive your result.

    Sorry I couldn't easily read in your table above, because of the line return so I made a new example off of mtcars that I think captures your intent. (let me know if it doesn't)

    mtcars2 <- mutate(mtcars,
                      gear_int = 6 - gear,
                      gear_intrev = rev(gear_int)) %>%
        mutate_at(vars(cyl, gear), as.factor)
    
    
    library(rlang)
    
    gg_reorder <- function(data, col_var, col_order) {
    
        eq_var <- sym(col_var) # sym is flexible and my novice preference
        eq_ord <- sym(col_order)
    
        data %>% mutate(!!quo_name(eq_var) := fct_reorder(!!eq_var, !!eq_ord) ) %>%
            ggplot(aes_(~mpg, ~hp, color = eq_var)) +
              geom_line()
    
    }
    

    And now put it to use plotting...

    gg_reorder(mtcars2, "gear", "gear_int")
    

    enter image description here

    gg_reorder(mtcars2, "gear", "gear_intrev")
    

    enter image description here

    I didn't specify all of the aes_() variables as strings but you could pass those as text and use the as.name() pattern. If you want more tidy-eval patterns Edwin Thoen wrote up a bunch of common cases.