<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/simplifying-ggplot2-code-by-doing-nothing/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://tjmahr.github.io/ggplot2-how-to-do-nothing/"> Higher Order Functions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Recently, I joined the development team for<br>
<a rel="nofollow" href="http://mc-stan.org/bayesplot/" target="_blank">bayesplot</a>, an R package by the Stan team for<br>
plotting Bayesian models. Because visualizing Bayesian models in ggplot2 is a<br>
<a rel="nofollow" href="https://tjmahr.github.io/visualizing-uncertainty-rstanarm/" target="_blank">recurring</a><br>
<a rel="nofollow" href="https://tjmahr.github.io/plotting-partial-pooling-in-mixed-effects-models/" target="_blank">topic</a><br>
<a rel="nofollow" href="https://tjmahr.github.io/bayesian-fisher-exact-test/" target="_blank">here</a>, it was a natural fit. So from time to<br>
time, I’ll post about some programming techniques and new features we develop in<br>
the bayesplot package.</p>
<p>For this post, I describe one of strategies I have been<br>
using to clean up and simplify some of the plotting code in the package: <strong>avoid<br>
if-branches by sometimes plotting nothing</strong>.</p>
<h2>Warm-up example</h2>
<p>Let’s start with a non-plotting example. We consider a function<br>
that takes a list of counts of people and returns the total number of people.<br>
That sum, however, is controlled by some of the function’s arguments:</p>
<div>
<pre><code><span>head_count</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>data</span><span>,</span><span> </span><span>staff</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>faculty</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span> </span><span>{</span><span>
</span><span>total</span><span> </span><span>&lt;-</span><span> </span><span>data</span><span>[[</span><span>&quot;students&quot;</span><span>]]</span><span>
</span><span>if</span><span> </span><span>(</span><span>staff</span><span>)</span><span> </span><span>{</span><span>
</span><span>total</span><span> </span><span>&lt;-</span><span> </span><span>total</span><span> </span><span>+</span><span> </span><span>data</span><span>[[</span><span>&quot;staff&quot;</span><span>]]</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>faculty</span><span>)</span><span> </span><span>{</span><span>
</span><span>total</span><span> </span><span>&lt;-</span><span> </span><span>total</span><span> </span><span>+</span><span> </span><span>data</span><span>[[</span><span>&quot;faculty&quot;</span><span>]]</span><span>
</span><span>}</span><span>
</span><span>total</span><span>
</span><span>}</span><span>
</span><span>data</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>students</span><span> </span><span>=</span><span> </span><span>10</span><span>,</span><span> </span><span>staff</span><span> </span><span>=</span><span> </span><span>3</span><span>,</span><span> </span><span>faculty</span><span> </span><span>=</span><span> </span><span>2</span><span>)</span><span>
</span><span>head_count</span><span>(</span><span>data</span><span>)</span><span>
</span><span>#> [1] 10
</span><span>head_count</span><span>(</span><span>data</span><span>,</span><span> </span><span>staff</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] 13
</span><span>head_count</span><span>(</span><span>data</span><span>,</span><span> </span><span>faculty</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] 12
</span></code></pre>
</div>
<p>The function as it’s written works fine… but the if-branches get in the<br>
way. The main job of the function is to assemble something (a sum) from<br>
pieces of data, but that assembly is split across the if-branches. The <code>total</code><br>
is updated in-place twice (<code>total &lt;- total + ...</code>). I would rather combine all<br>
the data in one fell swoop.</p>
<p>One way to move the data-assembly out of these if-branches is to make <em>the data</em><br>
conditional. That is, instead of doing the addition in the <code>if</code> statements, we<br>
do all the addition at once but just add 0 when a piece of data isn’t<br>
needed. This technique simplifies the function definition:</p>
<div>
<pre><code><span>head_count</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>data</span><span>,</span><span> </span><span>staff</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>faculty</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span> </span><span>{</span><span>
</span><span>staff</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>staff</span><span>)</span><span> </span><span>data</span><span>[[</span><span>&quot;staff&quot;</span><span>]]</span><span> </span><span>else</span><span> </span><span>0</span><span>
</span><span>faculty</span><span> </span><span>&lt;-</span><span> </span><span>if</span><span> </span><span>(</span><span>faculty</span><span>)</span><span> </span><span>data</span><span>[[</span><span>&quot;faculty&quot;</span><span>]]</span><span> </span><span>else</span><span> </span><span>0</span><span>
</span><span>data</span><span>[[</span><span>&quot;students&quot;</span><span>]]</span><span> </span><span>+</span><span> </span><span>staff</span><span> </span><span>+</span><span> </span><span>faculty</span><span>
</span><span>}</span><span>
</span><span>head_count</span><span>(</span><span>data</span><span>)</span><span>
</span><span>#> [1] 10
</span><span>head_count</span><span>(</span><span>data</span><span>,</span><span> </span><span>staff</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] 13
</span><span>head_count</span><span>(</span><span>data</span><span>,</span><span> </span><span>faculty</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] 12
</span></code></pre>
</div>
<p>For operations where we combine things to get a new thing, there’s often an<br>
identity element: a value we can plug in as a placeholder value without changing<br>
the results. Some examples:</p>
<div>
<pre><code><span># multiplication
</span><span>pi</span><span> </span><span>*</span><span> </span><span>1</span><span>
</span><span>#> [1] 3.141593
</span><span>
</span><span># string concatenation
</span><span>paste0</span><span>(</span><span>&quot;a&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>#> [1] &quot;a&quot;
</span><span>
</span><span># combining things
</span><span>c</span><span>(</span><span>1</span><span>,</span><span> </span><span>2</span><span>,</span><span> </span><span>3</span><span>,</span><span> </span><span>c</span><span>())</span><span>
</span><span>#> [1] 1 2 3
</span><span>
</span><span># data-frame binding
</span><span>rbind</span><span>(</span><span>head</span><span>(</span><span>iris</span><span>),</span><span> </span><span>list</span><span>())</span><span>
</span><span>#> Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1 5.1 3.5 1.4 0.2 setosa
#> 2 4.9 3.0 1.4 0.2 setosa
#> 3 4.7 3.2 1.3 0.2 setosa
#> 4 4.6 3.1 1.5 0.2 setosa
#> 5 5.0 3.6 1.4 0.2 setosa
#> 6 5.4 3.9 1.7 0.4 setosa
</span><span>
</span><span># magrittr pipes
</span><span>f</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>x</span><span>
</span><span>1</span><span>:</span><span>2</span><span> </span><span>%>%</span><span> </span><span>f</span><span>()</span><span>
</span><span>#> [1] 1 2
</span></code></pre>
</div>
<p>Below, I demonstrate two examples of how I applied a similar strategy in<br>
bayesplot. In ggplot2, we assemble plots by adding layers and options to a plot<br>
by stringing together statements with <code>+</code>. To handle conditional plotting<br>
elements and construct the plot all in one pass, I took advantage of ways to<br>
adding nothing to a ggplot2 plot.<sup><a rel="nofollow" href="https://tjmahr.github.io/ggplot2-how-to-do-nothing/#fn:monoids" target="_blank">1</a></sup></p>
<h2>Posterior interval plots</h2>
<p>Here are some posterior samples for a Bayesian model, in this case the <a rel="nofollow" href="http://andrewgelman.com/2014/01/21/everything-need-know-bayesian-statistics-learned-eight-schools/" target="_blank">“eight schools”</a> meta-analysis example. We want to create a plot that<br>
shows the 90% and 50% uncertainty intervals for each parameter.</p>
<p>We first use a helper function to clean up the data to prepare it for plotting.<br>
(At the time of writing, <code>mcmc_intervals_data()</code> is not yet in the CRAN version<br>
of bayesplot.)</p>
<div>
<pre><code><span>library</span><span>(</span><span>dplyr</span><span>,</span><span> </span><span>warn.conflicts</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span><span>library</span><span>(</span><span>bayesplot</span><span>)</span><span>
</span><span>#> This is bayesplot version 1.4.0.9000
#> - Plotting theme set to bayesplot::theme_default()
#> - Online documentation at mc-stan.org/bayesplot
</span><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>theme_set</span><span>(</span><span>theme_grey</span><span>())</span><span>
</span><span>interval_data</span><span> </span><span>&lt;-</span><span> </span><span>shinystan</span><span>::</span><span>eight_schools</span><span>@</span><span>posterior_sample</span><span> </span><span>%>%</span><span> </span><span>mcmc_intervals_data</span><span>(</span><span>pars</span><span> </span><span>=</span><span> </span><span>&quot;mu&quot;</span><span>,</span><span> </span><span>regex_pars</span><span> </span><span>=</span><span> </span><span>&quot;theta&quot;</span><span>)</span><span> </span><span>%>%</span><span> </span><span>mutate_if</span><span>(</span><span>is.numeric</span><span>,</span><span> </span><span>round</span><span>,</span><span> </span><span>2</span><span>)</span><span> </span><span>interval_data</span><span>
</span><span>#> # A tibble: 9 x 9
#> parameter outer_width inner_width point_est ll l m h
#> </span></code></pre></div>