<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/animating-mode-variability-with-tidyverse-and-tweenr/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.questionflow.org/2018/06/14/animating-mode-variability-with-tidyverse-and-tweenr/"> QuestionFlow </a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p> Provided different probability distributions, animate independent sample distributions to demonstrate mode variability. There is a thorough code description with some subtle tips and tricks.</p>
<div>
<h1>Prologue</h1>
<p>Not so long time ago I encountered the following task: given several groups of samples (one group – several samples from one distribution) make a visual presentation of <a rel="nofollow" href="https://en.wikipedia.org/wiki/Mode_(statistics)#Mode_of_a_sample" target="_blank">sample mode</a> variability in different groups (how sample mode changes between different samples). I decided to do this by animating these distributions with respect to their mode. The whole process can be summarised as follows:</p>
<ul>
<li><strong>For every sample</strong>:
<ul>
<li><strong>Count its values</strong>. Sample values are considered to a certain degree of precision, e.g. to the third digit, so talking about “counting values” has reasonable background.</li>
<li><strong>Divide counts by maximum count</strong>. The output is named “mode share distribution” (made up term, didn’t find any present one). For every unique value in sample the outcome is a number between 0 (value is totally absent) and 1 (value is a strict mode). Here value is considered to be “mode” if its “mode share” is above some threshold, say 0.9. For strict thresholds 1 is used.</li>
</ul>
</li>
<li>For every set of group samples (first samples within groups, second samples, and so on) <strong>plot their “mode share distribution”</strong>. This is done by plotting several “mode share distributions” at once, in non-overlapping <a rel="nofollow" href="https://cran.r-project.org/web/packages/ggridges/index.html" target="_blank">ridgeline-like</a> fashion.</li>
<li><strong>Animate between plots</strong>. This simultaneously shows a mode variability in different groups. As just changing pictures didn’t seem like a challenge, I decided to make smooth transitions between plots. Packages <a rel="nofollow" href="https://cran.r-project.org/web/packages/tweenr/tweenr.pdf" target="_blank">tweenr</a> (CRAN version) and <a rel="nofollow" href="https://github.com/dgrtwo/gganimate" target="_blank">gganimate</a> (original one by David Robinson, not a <a rel="nofollow" href="https://twitter.com/thomasp85/status/1004068316611260416" target="_blank">soon-to-be-revolutional one</a> by Thomas Lin Pedersen) provide core functionality for this.</li>
</ul>
<p>Methods I ended up using (some of them were discovered during solving this task) contain surprisingly many subtle <em>base R</em> and <em>tidyverse</em> tricks. This motivated me to write a post about my solution. It heavily uses core <a rel="nofollow" href="https://www.tidyverse.org/" target="_blank">tidyverse</a> packages.</p>
<p>For educational purposes, I will slightly change the task: <strong>provided different probability distributions (by random generation R functions like <code>rnorm</code>), animate independent sample distributions to demonstrate mode variability</strong>.</p>
</div>
<div>
<h1>Overview</h1>
<p>The main point of this post is to provide a thorough code description with some highlighted tips and tricks. Considering this, the most information will be provided in code comments with some tricks described in text. I can see that provided solutions might be slightly overcomplicated but they seem to demonstrate stable behavior. <strong>Please note</strong> that this post, probably, won’t be that helpful for beginners in R, and some confident knowledge of R and tidyverse tools is needed.</p>
<p>Most of the code will be hidden under spoilers (text which appears after clicking on its summary, usually beginning with “Code for …”) to shrink initial post size, but I really encourage you to read them. However, only looking at plots and animations is, of course, completely fine <img alt="🙂" src="https://s.w.org/images/core/emoji/2.4/72x72/1f642.png" class="wp-smiley"> They are considered to be a valuable by-product.</p>
<p>This post is organized as follows:</p>
<ul>
<li><strong>Data generation</strong> describes the process of creating new samples from given random generators.</li>
<li><strong>Static plots</strong> describes the format of plotting data and a process of building a plot. There are also some example plots.</li>
<li><strong>Animation</strong> describes the logic behind transition between different plots and the process of creating animations. There are also some example animations.</li>
<li><strong>Bonus accidental art</strong> has an example of “accidental art” which was produced unintentionally but has an interesting look.</li>
<li><strong>Conclusion</strong> lists some lessons learned and some of my favorite tricks from this post.</li>
</ul>
<p>We will need the following setup:</p>
<details>

<div>
<pre><code># Used tidyverse packages
suppressPackageStartupMessages(library(dplyr))
library(tidyr)
library(purrr)
library(ggplot2)

# Using current CRAN version 0.1.5
library(tweenr)

# Using current github 'dgrtwo/gganimate' version 0.1.0.9000 (commit bf82002)
library(gganimate)

theme_set(theme_bw())

animation::ani.options(interval = 1/24)

# Very important step for reproducibility
set.seed(20180614)

# Data about distributions of interest and sample size
r_funs &lt;- list(
  # Using `purrr::partial()` to create functions that expect only `n` argument
  &quot;runif&quot; = partial(runif),
  &quot;rnorm&quot; = partial(rnorm, mean = 0.5, sd = 0.25),
  &quot;rbeta&quot; = partial(rbeta, shape1 = 5, shape2 = 1)
)
n_sample &lt;- 1000</code></pre>
</div>
</details>
</div>
<div>
<h1>Data generation</h1>
<details>

<div>
<pre><code># Generate data by sampling from different distributions
# Note that all elements of `r_fun_list` should have names, which will be used
  # as distribution names.
# Elements of `r_fun_list` should be functions which take only one argument `n`
  # for a sample size to be generated. Use `purrr::partial` to create those.
generate_data &lt;- function(r_fun_list, n_sample) {
  pmap_dfr(
    list(names(r_fun_list), r_fun_list, n_sample),
    # Interestingly, due to implementation of anonymous formula functions, you
      # can't use `..i` placeholders if they represent functions to be called.
    ~ tibble(distr = .x, value = .y(n = ..3))
  )
}</code></pre>
</div>
</details>
<p>Considering future parallel animation, I decided to organize data “per plot”. That is: one <a rel="nofollow" href="http://tibble.tidyverse.org/" target="_blank">tibble</a> contains information about one sample for every distribution and multiple samples should be stored in list. Function <code>generate_data()</code> creates one tibble, which in combination with <code>purrr::rerun()</code> can create a list of grouped samples. <strong>Note</strong> that, for reasonable results, numbers in <code>value</code> columns should be rounded.</p>
<pre><code>sample_data &lt;- rerun(10, generate_data(r_funs, n_sample))

# One set of samples for examples
distr_data &lt;- sample_data[[1]] %>% mutate(value = round(value, 2))
distr_data
## # A tibble: 3,000 x 2
##   distr value
##   </code></pre></div>