title: Lazy evaluation for ggplot2 inside a function
body: <p>I use mostly <code>ggplot2</code> for visualizations. Typically, I design the plot
  interactively (i.e. raw <code>ggplot2</code> code that uses NSE) but in the end, I
  frequently end up wrapping up that code into a function that receives
  the data and variables to plot. And this is always a little bit of a
  nightmare.</p>
  
  <p>So, the typical situations looks like this. I have some data and I
  create a plot for it (in this case, a very very simple example, using
  the mpg dataset that comes with <code>ggplot2</code>).</p>
  
  <pre><code>library(ggplot2)
  data(mpg)
  
  ggplot(data = mpg, 
         mapping = aes(x = class, y = hwy)) +
      geom_boxplot() + 
      geom_jitter(alpha = 0.1, color = "blue")
  </code></pre>
  
  <p><img src="https://i.imgur.com/ZM0edEE.png" alt=""><br>
  And when I finish designing the plot, I typically want to use it for
  different variables or data, etc. So I create a function that receives
  the data and variables for the plot as arguments. But due to NSE, it is
  not as easy as to write function header and then copy/paste and replace
  variables for function arguments. That would not work, as shown below.</p>
  
  <pre><code>mpg &lt;- mpg
  plotfn &lt;- function(data, xvar, yvar){
      ggplot(data = data, 
             mapping = aes(x = xvar, y = yvar)) +
      geom_boxplot() + 
      geom_jitter(alpha = 0.1, color = "blue")
  }
  plotfn(mpg, class, hwy) # Can't find object
  
  ## Don't know how to automatically pick scale for object of type function. Defaulting to continuous.
  
  ## Warning: restarting interrupted promise evaluation
  
  ## Error in eval(expr, envir, enclos): object 'hwy' not found
  
  plotfn(mpg, "class", "hwy") # 
  </code></pre>
  
  <p><img src="https://i.imgur.com/kxl35Al.png" alt=""><br>
  So I have to go back and fix the code, for example, using <code>aes_string</code>
  intead of the <code>aes</code> that uses NSE (in this example it is rather easy, but
  for more complicated plots, with lots of transformations and layers,
  this becomes a nightmare).</p>
  
  <pre><code>plotfn &lt;- function(data, xvar, yvar){
      ggplot(data = data, 
             mapping = aes_string(x = xvar, y = yvar)) +
      geom_boxplot() + 
      geom_jitter(alpha = 0.1, color = "blue")
  }
  plotfn(mpg, "class", "hwy") # Now this works
  </code></pre>
  
  <p><img src="https://i.imgur.com/PE3bpoz.png" alt=""><br>
  And the thing is that I find very convenient NSE and also <code>lazyeval</code>. So
  I like to do something like this.</p>
  
  <pre><code>mpg &lt;- mpg
  plotfn &lt;- function(data, xvar, yvar){
      data_gd &lt;- data.frame(
          xvar = lazyeval::lazy_eval(substitute(xvar), data = data),
          yvar = lazyeval::lazy_eval(substitute(yvar), data = data))
  
      ggplot(data = data_gd, 
             mapping = aes(x = xvar, y = yvar)) +
      geom_boxplot() + 
      geom_jitter(alpha = 0.1, color = "blue")
  }
  plotfn(mpg, class, hwy) # Now this works
  </code></pre>
  
  <p><img src="https://i.imgur.com/Zw7J4mx.png" alt="">  </p>
  
  <pre><code>plotfn(mpg, "class", "hwy") # This still works
  </code></pre>
  
  <p><img src="https://i.imgur.com/1DbwwTy.png" alt="">  </p>
  
  <pre><code>plotfn(NULL, rep(letters[1:4], 250), 1:100) # And even this crazyness works
  </code></pre>
  
  <p><img src="https://i.imgur.com/7UkWiVx.png" alt=""><br>
  This gives my plot function a lot of flexibility. For example, you can
  pass quoted or unquoted variable names and even the data directly
  instead of a variable name (kind of abusing of lazy evaluation).</p>
  
  <p>But this has a huge problem. The function cannot be used
  programmatically.</p>
  
  <pre><code>dynamically_changing_xvar &lt;- "class"
  plotfn(mpg, dynamically_changing_xvar, hwy) 
  
  ## Error in eval(expr, envir, enclos): object 'dynamically_changing_xvar' not found
  
  # This does not work, because it never finds the object 
  # dynamically_changing_xvar in the data, and it does not get evaluated to 
  # obtain the variable name (class)
  </code></pre>
  
  <p>So I cannot use loops (e.g. lapply) to produce the same plot for
  different combinations of variables, or data.</p>
  
  <p>So I thought to abuse even more of lazy, standard and non-standard
  evaluation, and try to combine them all so I have both, the flexibility
  shown above and the ability to use the function programmatically.
  Basically, what I do is to use <code>tryCatch</code> to first <code>lazy_eval</code> the
  expression for each variable and if it fails, to evaluate the parsed
  expression.</p>
  
  <pre><code>plotfn &lt;- function(data, xvar, yvar){
      data_gd &lt;- NULL
      data_gd$xvar &lt;- tryCatch(
          expr = lazyeval::lazy_eval(substitute(xvar), data = data),
          error = function(e) eval(envir = data, expr = parse(text=xvar))
      )
      data_gd$yvar &lt;- tryCatch(
          expr = lazyeval::lazy_eval(substitute(yvar), data = data),
          error = function(e) eval(envir = data, expr = parse(text=yvar))
      )
  
  
      ggplot(data = as.data.frame(data_gd), 
             mapping = aes(x = xvar, y = yvar)) +
      geom_boxplot() + 
      geom_jitter(alpha = 0.1, color = "blue")
  }
  
  plotfn(mpg, class, hwy) # Now this works, again
  </code></pre>
  
  <p><img src="https://i.imgur.com/c3MEkPb.png" alt="">  </p>
  
  <pre><code>plotfn(mpg, "class", "hwy") # This still works, again
  </code></pre>
  
  <p><img src="https://i.imgur.com/tRReSbK.png" alt="">  </p>
  
  <pre><code>plotfn(NULL, rep(letters[1:4], 250), 1:100) # And this crazyness still works
  </code></pre>
  
  <p><img src="https://i.imgur.com/Qr9xkag.png" alt="">  </p>
  
  <pre><code># And now, I can also pass a local variable to the function, that contains
  # the name of the variable that I want to plot
  dynamically_changing_xvar &lt;- "class"
  plotfn(mpg, dynamically_changing_xvar, hwy) 
  </code></pre>
  
  <p><img src="https://i.imgur.com/XKNxzTi.png" alt=""><br>
  So, in addition to the aforementioned flexibility, now I can use
  one-liner or so, to produce many of the same plot, with different
  variables (or data).</p>
  
  <pre><code>lapply(c("class", "fl", "drv"), FUN = plotfn, yvar = hwy, data = mpg)
  
  ## [[1]]
  </code></pre>
  
  <p><img src="https://i.imgur.com/hTLqh9S.png" alt="">  </p>
  
  <pre><code>## 
  ## [[2]]
  </code></pre>
  
  <p><img src="https://i.imgur.com/2djtQuA.png" alt="">  </p>
  
  <pre><code>## 
  ## [[3]]
  </code></pre>
  
  <p><img src="https://i.imgur.com/xXxSO79.png" alt=""><br>
  Even though it is very practical, I suspect this is not good practice. But
  how bad practice it is? That's my key question. What other alternatives
  can I use to have the best of both worlds?</p>
  
  <p>Of course, I can see this pattern can create problems. For example.</p>
  
  <pre><code># If I have a variable in the global environment that contains the variable
  # I want to plot, but whose name is in the data passed to the function, 
  # then it will use the name of the variable and not its content
  drv &lt;- "class"
  plotfn(mpg, drv, hwy) # Here xvar on the plot is drv and not class
  </code></pre>
  
  <p><img src="https://i.imgur.com/2MmWtAi.png" alt=""><br>
  And some (many?) other problems. But it seems to me that the benefits in terms
  of syntax-flexibility outweigh those other issues. Any thoughts on this?</p>