<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/beneath-the-canvas/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.data-imaginist.com/2017/Beneath-the-canvas/"> Data Imaginist - R posts</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Recently a <a rel="nofollow" href="https://ikashnitsky.github.io/2017/ggplot2-microbenchmark/" target="_blank">blog<br>
post</a> made its<br>
rounds on the internet describing how it is possible to speed up plot creation<br>
in <code>ggplot2</code> by first creating a blank canvas and then later adding the plot<br>
elements on top of it. The main takeaway plot is reproduced below:</p>
<p><img alt="rendering comparison" src="https://i1.wp.com/ikashnitsky.github.io/images/170704/fig-01-test-simple.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The blog post is in generally well reasoned and I love how it moves from a<br>
curious observation to an investigation and ends with a solid recommendation.<br>
Alas, I don’t agree with the recommendation (that you shold create a <em>canvas</em><br>
for subsequent use). Most of the misunderstanding in the blog post comes from<br>
the fact that <code>ggplot2</code> in many ways seems to be fueled by magic and unicorn<br>
blood — what arises when you write <code>ggplot()</code> and hit enter is far from clear. I<br>
would like to spend most of the time on this point so I’m just going to get a<br>
more general point out of the way first.</p>
<h2>Premature optimisation is premature</h2>
<p>When looking for ways to optimise your code, one must always ask whether the<br>
code needs optimisation in the first place, and then whether the changes made<br>
successfully makes a meaningful impact. What the plot above shows is that<br>
caching the <code>ggplot()</code> call leads to a <em>statistically significant</em> performance<br>
improvement meassured in &lt;10 ms. This means that in order to get a percievable<br>
runtime difference, it would be necessary to generate hundreds of plots, or<br>
thousands of plots to get a meaningful difference. My own rule of thumb is that<br>
you should not give up coding conventions unless there’s a tangible result, and<br>
in this case I don’t see any. Does this mean you should never strive for<br>
millisecond improvements? No, if you expect your piece of code to be called<br>
thousands of times and compounding the effect this would be worthwhile. This is<br>
why you sometimes see code where the square root of a variable is saved in a new<br>
variable rather than being computed on the fly every time. In this case you<br>
should ask yourself whether you mean to generate a 1000 plots with your code in<br>
one go, and if so, whether an additional second is really worth it.</p>
<h2>There is no <del>spoon</del> canvas</h2>
<p>The notion that <code>ggplot()</code> creates a canvas for subsequent calls to add onto is<br>
a sensible one, supported by the <code>ggplot2</code> API where layers are added to the<br>
initial plot. Further, if we simply write <code>ggplot()</code> and hits enter we get this:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>ggplot</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-07-24-Beneath-the-canvas/unnamed-chunk-2-1.png?w=456" data-recalc-dims="1"></p>
<p>Which sure looks like a blank canvas. This is all magic and unicorns though –<br>
the call to <code>ggplot()</code> doesn’t actually draw or render anything on the device.<br>
In order to understand what is going on, let’s have a look at the code<br>
underneath it all:</p>
<figure>
<pre><code data-lang="r"><span>ggplot</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">#> function (data = NULL, mapping = aes(), ..., environment = parent.frame()) 
#> {
#>     UseMethod(&quot;ggplot&quot;)
#> }
#> </code></pre></figure>