2

How can I turn this ggplot() call into a function? I can't figure out how to get R to recognize the column names I want to pass to the function. I've come across several similar sounding questions, but I've not had success adapting ideas. See here for substitute().

# setup
  library(dplyr)
  library(ggplot2)
  set.seed(205)
  dat = data.frame(t=rep(1:2, each=10), 
                   pairs=rep(1:10,2), 
                   value=rnorm(20))

# working example
  ggplot(dat %>% group_by(pairs) %>%
           mutate(slope = (value[t==2] - value[t==1])/(2-1)),
         aes(t, value, group=pairs, colour=slope > 0)) +
    geom_point() +
    geom_line() +
    stat_summary(fun.y=mean,geom="line",lwd=2,aes(group=1))

# attempt at turning into a function
    plotFun <- function(df, groupBy, dv, time) {
    groupBy2 <- substitute(groupBy)
    dv2 <- substitute(dv)
    time2 <- substitute(time)
    ggplot(df %>% group_by(groupBy2) %>%
             mutate(slope = (dv2[time2==2] - dv2[time2==1])/(2-1)),
           aes(time2, dv2, group=groupBy2, colour=slope > 0)) +
      geom_point() +
      geom_line() +
      stat_summary(fun.y=mean,geom="line",lwd=2,aes(group=1))
  }

# error time
  plotFun(dat, pairs, value, t)

Update

I took @joran's advice to look at this answer, and here's what I came up with:

library(dplyr)
library(ggplot2)
library(lazyeval)

plotFun <- function(df, groupBy, dv, time) {
    ggplot(df %>% group_by_(groupBy) %>%
             mutate_(slope = interp(~(dv2[time2==2] - dv2[time2==1])/(2-1),
                                    dv2=as.name(dv), 
                                    time2=as.name(time))),
           aes(time, dv, group=groupBy, colour=slope > 0)) +
      geom_point() +
      geom_line() +
      stat_summary(fun.y=mean,geom="line",lwd=2,aes(group=1))
  }

plotFun(dat, "pairs", "value", "t")

The code runs but the plot is not correct:

geom_path: Each group consists of only one observation. Do you need to adjust the group aesthetic?

Community
  • 1
  • 1
Eric Green
  • 7,385
  • 11
  • 56
  • 102
  • 2
    See `group_by_` and `mutate_` for programming - take string names. – Michael Griffiths Nov 30 '16 at 21:34
  • 1
    @MichaelGriffiths is right, you should look at Non Standard Evaluation (https://cran.r-project.org/web/packages/dplyr/vignettes/nse.html) – denrou Nov 30 '16 at 21:41
  • thanks, both. that's a new concept for me. i don't think i'm quite grasping the structure. SE example: `summarise_(mtcars, "mean(mpg)")`. translating to my example: `mutate_("slope = (dv[time==2] - dv[time==1])/(2-1)")`... – Eric Green Nov 30 '16 at 21:54
  • @EricGreen I find **dplyr**'s system for this extremely confusing as well. Does [this](http://stackoverflow.com/q/27975124/324364) question help at all? – joran Nov 30 '16 at 22:16
  • @joran, thanks. I added a new attempt based on the idea you shared. Getting closer. – Eric Green Nov 30 '16 at 23:27
  • You can use `aes_string` if `groupBy` is a string. – alistaire Dec 01 '16 at 00:07
  • thanks, @alistaire, but I'm not having luck with `aes_(time, dv, group=groupBy, colour="slope" > 0))` – Eric Green Dec 01 '16 at 00:22
  • 1
    The whole thing should be `aes_string(time, dv, group = groupBy, colour = 'slope > 0'))`. Holding everything else the same, it works for me. – alistaire Dec 01 '16 at 00:31
  • Perfect, @alistaire. – Eric Green Dec 01 '16 at 00:33

1 Answers1

2

Here's the working solution informed by all of the commenters:

# setup
  library(dplyr)
  library(ggplot2)
  library(lazyeval)
  set.seed(205)
  dat = data.frame(t=rep(1:2, each=10), 
                   pairs=rep(1:10,2), 
                   value=rnorm(20))


# function
  plotFun <- function(df, groupBy, dv, time) {
      ggplot(df %>% group_by_(groupBy) %>%
             mutate_(slope = interp(~(dv2[time2==2] - dv2[time2==1])/(2-1),
                                      dv2=as.name(dv), 
                                      time2=as.name(time))),
             aes_string(time, dv, group = groupBy, 
                        colour = 'slope > 0')) +
        geom_point() +
        geom_line() +
        stat_summary(fun.y=mean,geom="line",lwd=2,aes(group=1))
  }

# plot
  plotFun(dat, "pairs", "value", "t")
Eric Green
  • 7,385
  • 11
  • 56
  • 102