<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/writing-better-r-functions-part-two-april-10-2018/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://ibecav.github.io/betterfunctions2/"> Chuck Powell</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a rel="nofollow" href="https://ibecav.github.io/betterfunctions/" target="_blank">In my last post</a> I started<br>
to build two functions that took pairs of variables from a dataset and<br>
produced some nice useful <code>ggplot</code> plots from them. We started with the<br>
simplest case, plotting counts of how two variables cross-tabulate. Then<br>
we worked our way up to being able to automate the process of plotting<br>
lots of pairings of variables from the same dataframe. Today we’ll<br>
improve our functions and add a <strong>feature</strong>. For now, we’re going to<br>
continue to make use of the built in dataframe known as <code>mtcars</code>. We’re<br>
doing that to make sure that whatever we do in this post today, it works<br>
on a known start point so we can compare and contrast.</p>
<blockquote>
<p><strong>I’m going to output all the plots in a smaller size for the benefit<br>
of you the readers. I’m doing that via RMarkdown and it won’t happen<br>
automatically for you if you download and use the code. I’ll be using<br>
, fig.width=4.5, fig.height=2</strong></p>
</blockquote>
<h2>Background and catch-up</h2>
<p>Some quick setup.</p>
<div>
<div>
<pre><code><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>theme_set</span><span>(</span><span>theme_bw</span><span>())</span><span> </span><span># set theme to my personal preference</span><span>
</span></code></pre>
</div>
</div>
<p>We started with a simple task in the console. Take two of the <code>mtcars</code><br>
variables, in this case <code>am</code> and <code>cyl</code>, and conduct a cross tabulation<br>
and then plot it.</p>
<div>
<div>
<pre><code><span>### with dplyr and ggplot manually</span><span>
</span><span>mtcars</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>am</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>cyl</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>am</span><span>,</span><span>cyl</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>fill</span><span>=</span><span>am</span><span>,</span><span> </span><span>y</span><span>=</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>cyl</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better1-1.png?w=456" data-recalc-dims="1"></p>
<p><a rel="nofollow" href="https://ibecav.github.io/betterfunctions/" target="_blank">By the end of the last post</a><br>
we had accomplished the following tasks:</p>
<ol>
<li>Our function (called <code>PlotMe</code>) was a lot more robust. It checked for<br>
basic user entry errors, added a useful title and generally did what<br>
we wanted.</li>
<li>Along the way we learned the <strong>“tricks”</strong> of working with <code>dplyr</code><br>
and <code>ggplot2</code> inside of functions.</li>
</ol>
<p>Here’s the <code>PlotMe</code> function as we left it.</p>
<div>
<div>
<pre><code><span>PlotMe</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span>x</span><span>,</span><span>y</span><span>){</span><span>
</span><span># error checking</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>require</span><span>(</span><span>ggplot2</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Can't continue can't load ggplot2&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>theme_set</span><span>(</span><span>theme_bw</span><span>())</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>require</span><span>(</span><span>dplyr</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Can't continue can't load dplyr&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>dataframe</span><span>)</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>x</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>y</span><span>)</span><span>
</span><span>if</span><span> </span><span>(</span><span>length</span><span>(</span><span>match.call</span><span>())</span><span> </span><span>&lt;=</span><span> </span><span>3</span><span>)</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Not enough arguments passed... requires a dataframe, plus two variables&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>exists</span><span>(</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>))))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;The first item in your list does not exist&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>is</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>&quot;data.frame&quot;</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;The first name you passed does not appear to be a data frame&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>x</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>paste0</span><span>(</span><span>&quot;'&quot;</span><span>,</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>x</span><span>)),</span><span> </span><span>&quot;' is not the name of a variable in '&quot;</span><span>,</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>)),</span><span>&quot;'&quot;</span><span>))</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>y</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>paste0</span><span>(</span><span>&quot;'&quot;</span><span>,</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>y</span><span>)),</span><span> </span><span>&quot;' is not the name of a variable in '&quot;</span><span>,</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>)),</span><span>&quot;'&quot;</span><span>),</span><span> </span><span>call.</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span><span>}</span><span>
</span><span>missing</span><span> </span><span>&lt;-</span><span> </span><span>apply</span><span>(</span><span>is.na</span><span>(</span><span>dataframe</span><span>[,</span><span>c</span><span>(</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>x</span><span>)),</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>y</span><span>)))]),</span><span> </span><span>1</span><span>,</span><span> </span><span>any</span><span>)</span><span>
</span><span>if</span><span> </span><span>(</span><span>any</span><span>(</span><span>missing</span><span>))</span><span> </span><span>{</span><span>
</span><span>warning</span><span>(</span><span>paste</span><span>(</span><span>sum</span><span>(</span><span>missing</span><span>)),</span><span> </span><span>&quot; row(s) not plotted because of missing data&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span># end of error checking</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs&quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>.</span><span>(</span><span>aaa</span><span>)</span><span>~</span><span>&quot;by&quot;</span><span>*</span><span>.</span><span>(</span><span>bbb</span><span>)))</span><span> </span><span>+</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>)</span><span> </span><span>-></span><span>p</span><span>
</span><span>plot</span><span>(</span><span>p</span><span>)</span><span>
</span><span>}</span><span>
</span><span>PlotMe</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>cyl</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better2-1.png?w=456" data-recalc-dims="1"></p>
<h2>Making our function better</h2>
<p>Our next step is to allow the user to choose which of three plot types<br>
they’d like. We have been focusing on simple side by side grouped bars<br>
that are obtained with <code>geom_bar(position=&quot;dodge&quot;, stat=&quot;identity&quot;)</code></p>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better3-1.png?w=456" data-recalc-dims="1"></p>
<p>But we can also <em>“stack”</em> the bars with by changing to<br>
<code>geom_bar(stat=&quot;identity&quot;)</code></p>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better4-1.png?w=456" data-recalc-dims="1"></p>
<p>Or focus on percentages of the category totals with<br>
<code>geom_bar(stat=&quot;identity&quot;, position=&quot;fill&quot;)</code>…</p>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better5-1.png?w=456" data-recalc-dims="1"></p>
<p>The key is that our entire function is the same, except for one part of<br>
one line in the function the <code>geom_bar()</code>. The last thing we want to do<br>
is write three different functions, or replicate too much code within<br>
one function. Let’s say, for the sake of argument, we’d like to simply<br>
have the user specify whether they want type “side”, “stack” or<br>
“percent”. (We could choose any names we like but these will do for<br>
now). Let’s say, that we’d like to call this variable within our<br>
function <code>plottype</code>. We’d make <code>side</code> the default, but allow the user to<br>
override that and choose either <code>stack</code> or <code>percent</code> instead. So, at the<br>
beginning of the function we’ll add…</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span></code></pre>
</div>
</div>
<p>Depending on their choice we’ll set the <code>geom_bar()</code> details. So it’s a<br>
kind of a <code>switch</code> <strong>hint, hint</strong>. Inside of the switch we’ll use the<br>
fact that we can pass <code>ggplot</code> list items. Each choice <code>&quot;side&quot;</code>,<br>
“<code>stack</code>”, or “<code>percent</code>” causes us to set two things:</p>
<ol>
<li>the parameters to <code>geom_bar</code> and,</li>
<li>the Y axis label <code>ylab</code> (since in two cases it’s a count and in one<br>
it’s a percent).</li>
</ol>
<p></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span><span>switch</span><span>(</span><span>plottype</span><span>,</span><span>
</span><span>side</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>stack</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>percent</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span>=</span><span>&quot;fill&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Percent&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>
</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p>Notice that based upon the value going into the <code>switch</code> we are<br>
assigning the proper information to an object called <code>whichbar</code>. Later<br>
in our function we’ll insert that into our <code>ggplot</code> flow…</p>
<div>
<div>
<pre><code><span> </span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs&quot;</span><span>~</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>.</span><span>(</span><span>aaa</span><span>)</span><span>~</span><span>&quot;by&quot;</span><span>*</span><span>.</span><span>(</span><span>bbb</span><span>)))</span><span> </span><span>-></span><span>p</span><span>
</span></code></pre>
</div>
</div>
<p>Here’s our new version of the function. Temporarily named PlotMeX, and<br>
with the error checking removed just for brevity, but it’s what we want.<br>
Let’s test it against <code>am</code> by <code>vs</code> just for a variable change of pace.</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span><span>switch</span><span>(</span><span>plottype</span><span>,</span><span>
</span><span>side</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>stack</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>percent</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span>=</span><span>&quot;fill&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Percent&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>
</span><span>)</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>x</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>y</span><span>)</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>dataframe</span><span>)</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs&quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>.</span><span>(</span><span>aaa</span><span>)</span><span>~</span><span>&quot;by&quot;</span><span>*</span><span>.</span><span>(</span><span>bbb</span><span>)))</span><span> </span><span>-></span><span>p</span><span>
</span><span>plot</span><span>(</span><span>p</span><span>)</span><span>
</span><span>}</span><span>
</span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better9-1.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>,</span><span> </span><span>&quot;stack&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better9-2.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>,</span><span> </span><span>&quot;percent&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better9-3.png?w=456" data-recalc-dims="1"></p>
<p>Looks good!</p>
<h3>Automating even more</h3>
<p>A few posts back we also recognized that if we need to work on multiple<br>
pairs of variables in the same dataframe (not uncommon in my field). It<br>
would be very tedious to keep running the <code>PlotMeX</code> function over and<br>
over again. So we developed a block of code that does something<br>
important for us. We feed it the <strong>column numbers</strong> of the variables we<br>
want to pair, accounting for which side of the plot (dependent or<br>
independent) we want them on, and the code produces two lists that we<br>
can systematically feed to our <code>PlotMeX</code> function and produce lots of<br>
plots.</p>
<p>There are any number of ways we could pass the columns, by quoted name,<br>
by bare name or as I have done with simple column numbers. I honestly<br>
prefer just looking up the numbers or a range of numbers. Far less<br>
typing for me and the ability to incorporate lots of variables with the<br>
colon <code>:</code> shortcut, e.g. <code>3:333</code>.</p>
<p>So the process would be to choose some variables for one side of the<br>
<code>by</code>, in this case let’s say <code>gear</code> and <code>carb</code> those are columns 10 &amp; 11<br>
so we can write <code>c(10:11)</code> on the other side <code>cyl</code> &amp; <code>am</code> written as<br>
<code>c(2,9)</code>.</p>
<div>
<div>
<pre><code><span># Build two vectors</span><span>
</span><span>xwhich</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>10</span><span>:</span><span>11</span><span>)</span><span> </span><span># let's put gear and carb in here</span><span>
</span><span>ywhich</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>2</span><span>,</span><span>9</span><span>)</span><span> </span><span># let's put cyl and am in here</span><span>
</span></code></pre>
</div>
</div>
<p>Then we create two empty lists that we will insert the variable names<br>
into and a counter variable (not strictly necessary but I’ll actually<br>
use it in a minute). We could of course rewrite our function to accept<br>
column numbers instead of variable names right from the outset. But I’m<br>
choosey. When I work in small batches I want to be able to use names,<br>
it’s only when I have a lot of names I prefer to operate by number. It<br>
is essential to initialize the lists, and if I were ever to intend to<br>
have large lists it would be preferable to specifiy a length in advance<br>
for performance reasons. Something like <code>indvars &lt;- vector(&quot;list&quot;,<br>
length(xwhich)*length(ywhich))</code> but for now I’m going to keep it simple.</p>
<div>
<div>
<pre><code><span>indvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>depvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>1</span><span> </span><span># keep track of where we are</span><span>
</span></code></pre>
</div>
</div>
<p>Now we take <code>xwhich</code> and <code>ywhich</code> and run them through some nested loops<br>
and see if we get the four possible pairings we are expecting.</p>
<div>
<div>
<pre><code><span># loop through the vectors and build our lists</span><span>
</span><span>for</span><span> </span><span>(</span><span>j</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>for</span><span> </span><span>(</span><span>k</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>depvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>mtcars</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]]))</span><span>
</span><span>indvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>mtcars</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]]))</span><span>
</span><span>cat</span><span>(</span><span>&quot;iteration #&quot;</span><span>,</span><span> </span><span>totalcombos</span><span>,</span><span> </span><span>&quot; xwhich is &quot;</span><span>,</span><span> </span><span>xwhich</span><span>[[</span><span>j</span><span>]],</span><span> </span><span>&quot; so depvars = &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>mtcars</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]])),</span><span>
</span><span>&quot; ywhich is &quot;</span><span>,</span><span> </span><span>ywhich</span><span>[[</span><span>k</span><span>]],</span><span> </span><span>&quot; so indvars = &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>mtcars</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]])),</span><span>
</span><span>&quot;\n&quot;</span><span>,</span><span> </span><span>sep</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>totalcombos</span><span> </span><span>+1</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## iteration #1 xwhich is 10 so depvars = gear ywhich is 2 so indvars = cyl
## iteration #2 xwhich is 10 so depvars = gear ywhich is 9 so indvars = am
## iteration #3 xwhich is 11 so depvars = carb ywhich is 2 so indvars = cyl
## iteration #4 xwhich is 11 so depvars = carb ywhich is 9 so indvars = am
</code></pre>
</div>
</div>
<p>Yes that looks like what we want. It’s a bit trivial for 4 plots but<br>
imagine the effort savings if you had 5 variables on each side. Keeping<br>
track of 25 possibilities by hand is annoying. So the simplest case of<br>
our function is <code>PlotMeX(mtcars, am, cyl)</code>. We’ll feed our function and<br>
our two lists to <code>mapply</code> and let it do the tedious work for us.<br>
<strong>N.B.</strong> If you don’t wrap it with <code>invisible</code> <code>mapply</code> will actually<br>
return two copes of the plots. More on that in a bit.</p>
<div>
<div>
<pre><code><span>#PlotMeX(mtcars,am,cyl)</span><span>
</span><span>invisible</span><span>(</span><span>mapply</span><span>(</span><span>PlotMeX</span><span>,</span><span> </span><span>x</span><span>=</span><span>indvars</span><span>,</span><span> </span><span>y</span><span>=</span><span>depvars</span><span>,</span><span> </span><span>MoreArgs</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>dataframe</span><span>=</span><span>mtcars</span><span>),</span><span> </span><span>SIMPLIFY</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>USE.NAMES</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better13-1.png?w=456" data-recalc-dims="1"><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better13-2.png?w=456" data-recalc-dims="1"><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better13-3.png?w=456" data-recalc-dims="1"><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better13-4.png?w=456" data-recalc-dims="1"></p>
<p>Notice that <code>MoreArgs</code> is a list. We are passing it the name of the<br>
<code>mtcars</code> dataset but we can also pass it other parameters such as our<br>
<code>plottype</code><br>
preference.</p>
<div>
<div>
<pre><code><span>invisible</span><span>(</span><span>mapply</span><span>(</span><span>PlotMeX</span><span>,</span><span> </span><span>x</span><span>=</span><span>indvars</span><span>,</span><span> </span><span>y</span><span>=</span><span>depvars</span><span>,</span><span> </span><span>MoreArgs</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>dataframe</span><span>=</span><span>mtcars</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;percent&quot;</span><span>),</span><span> </span><span>SIMPLIFY</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>USE.NAMES</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better14-1.png?w=456" data-recalc-dims="1"><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better14-2.png?w=456" data-recalc-dims="1"><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better14-3.png?w=456" data-recalc-dims="1"><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better14-4.png?w=456" data-recalc-dims="1"></p>
<p>Now we can turn this working code into a function so we can reuse it. To<br>
do that we’ll have the user specify the <code>dataframe</code>, <code>xwhich</code> and<br>
<code>ywhich</code> as parameters to the function. Then inside the function we’ll<br>
do the work and return the user the two lists that can be used to “feed”<br>
<code>mapply</code>. I’m personally a fan of providing some feedback in the console<br>
to inform the user of what’s going on, even though the actual output<br>
product of the function is just a list with two sublists nested inside.<br>
On the other hand we’ll return the list “invisibly” since we don’t<br>
really need to print out the list structure.</p>
<div>
<div>
<pre><code><span>CrossXYs</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>xwhich</span><span>,</span><span> </span><span>ywhich</span><span>){</span><span>
</span><span># Build two vectors</span><span>
</span><span>indvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>depvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>1</span><span> </span><span># keep track of where we are</span><span>
</span><span>message</span><span>(</span><span>&quot;Creating the variable pairings...&quot;</span><span>)</span><span>
</span><span>for</span><span> </span><span>(</span><span>j</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>for</span><span> </span><span>(</span><span>k</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>depvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]]))</span><span>
</span><span>indvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]]))</span><span>
</span><span>cat</span><span>(</span><span>&quot;Pairing #&quot;</span><span>,</span><span> </span><span>totalcombos</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]])),</span><span>
</span><span>&quot; with &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]])),</span><span> </span><span>&quot;\n&quot;</span><span>,</span><span> </span><span>sep</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>totalcombos</span><span> </span><span>+1</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span><span>return</span><span>(</span><span>invisible</span><span>(</span><span>list</span><span>(</span><span>depvars</span><span>=</span><span>depvars</span><span>,</span><span>indvars</span><span>=</span><span>indvars</span><span>)))</span><span>
</span><span>}</span><span>
</span><span>CrossXYs</span><span>(</span><span>mtcars</span><span>,</span><span>c</span><span>(</span><span>10</span><span>:</span><span>11</span><span>),</span><span>c</span><span>(</span><span>2</span><span>,</span><span>9</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 gear with cyl
## Pairing #2 gear with am
## Pairing #3 carb with cyl
## Pairing #4 carb with am
</code></pre>
</div>
</div>
<p>This code produces the two lists with the column names varying in the<br>
way we want them. So the next step it to put them somewhere (we’ll call<br>
that <code>bothlists</code>)</p>
<div>
<div>
<pre><code><span>bothlists</span><span> </span><span>&lt;-</span><span> </span><span>CrossXYs</span><span>(</span><span>mtcars</span><span>,</span><span>c</span><span>(</span><span>10</span><span>:</span><span>11</span><span>),</span><span>c</span><span>(</span><span>2</span><span>,</span><span>9</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 gear with cyl
## Pairing #2 gear with am
## Pairing #3 carb with cyl
## Pairing #4 carb with am
</code></pre>
</div>
</div>
<p>Then we can use them as part of our <code>mapply</code> call by addressing them as<br>
<code>bothlists$indvars</code> &amp; <code>bothlists$depvars</code>, otherwise our command remains<br>
the<br>
same.</p>
<div>
<div>
<pre><code><span>invisible</span><span>(</span><span>mapply</span><span>(</span><span>PlotMeX</span><span>,</span><span> </span><span>x</span><span>=</span><span>bothlists</span><span>$</span><span>indvars</span><span>,</span><span> </span><span>y</span><span>=</span><span>bothlists</span><span>$</span><span>depvars</span><span>,</span><span> </span><span>MoreArgs</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>dataframe</span><span>=</span><span>mtcars</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;stack&quot;</span><span>),</span><span> </span><span>SIMPLIFY</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>USE.NAMES</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better17-1.png?w=456" data-recalc-dims="1"><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better17-2.png?w=456" data-recalc-dims="1"><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better17-3.png?w=456" data-recalc-dims="1"><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better17-4.png?w=456" data-recalc-dims="1"></p>
<p>Appears to be working as we want it to. Which means it’s a good time to<br>
test it on some other data and see if anything breaks. Let’s try the<br>
esoph dataset… First we’ll call <code>PlotMeX</code> with <code>alcgp</code> by <code>tobgp</code>. Then<br>
we’ll make <code>CrossXYs</code> give us lists for <code>agegp</code> by <code>alcgp</code> &amp; <code>tobgp</code>.<br>
That should reassure us that all is well.</p>
<div>
<div>
<pre><code><span>str</span><span>(</span><span>esoph</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## 'data.frame':    88 obs. of  5 variables:
##  $ agegp    : Ord.factor w/ 6 levels &quot;25-34&quot;&lt;&quot;35-44&quot;&lt;..: 1 1 1 1 1 1 1 1 1 1 ...
##  $ alcgp    : Ord.factor w/ 4 levels &quot;0-39g/day&quot;&lt;&quot;40-79&quot;&lt;..: 1 1 1 1 2 2 2 2 3 3 ...
##  $ tobgp    : Ord.factor w/ 4 levels &quot;0-9g/day&quot;&lt;&quot;10-19&quot;&lt;..: 1 2 3 4 1 2 3 4 1 2 ...
##  $ ncases   : num  0 0 0 0 0 0 0 0 0 0 ...
##  $ ncontrols: num  40 10 6 5 27 7 4 7 2 1 ...
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>esoph</span><span>,</span><span>alcgp</span><span>,</span><span>tobgp</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/better18-1.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>bothlists</span><span> </span><span>&lt;-</span><span> </span><span>CrossXYs</span><span>(</span><span>esoph</span><span>,</span><span>1</span><span>,</span><span>c</span><span>(</span><span>2</span><span>:</span><span>3</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 agegp with alcgp
## Pairing #2 agegp with tobgp
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>invisible</span><span>(</span><span>mapply</span><span>(</span><span>PlotMeX</span><span>,</span><span> </span><span>x</span><span>=</span><span>bothlists</span><span>$</span><span>indvars</span><span>,</span><span> </span><span>y</span><span>=</span><span>bothlists</span><span>$</span><span>depvars</span><span>,</span><span> </span><span>MoreArgs</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>dataframe</span><span>=</span><span>esoph</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;percent&quot;</span><span>),</span><span> </span><span>SIMPLIFY</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>USE.NAMES</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/better18-2.png?w=456" data-recalc-dims="1"><img alt="" src="https://i2.wp.com/ibecav.github.io/images/better18-3.png?w=456" data-recalc-dims="1"></p>
<p>Very nice! We seem to have accomplished what we set out to do.</p>
<h2>All done (not yet!)</h2>
<p>This has become a very long post so I’m going to end here. But the<br>
astute among you have probably detected we’re still being inefficient.<br>
Be nice if we could integrate these two functions a little better so we<br>
didn’t have to think of it as a two step process. Great idea for a next<br>
post on a future day.</p>
<p>I hope you’ve found this useful. I am always open to comments,<br>
corrections and suggestions.</p>
<p>Chuck (ibecav at gmail dot<br>
com)</p>
<h3>License</h3>
<p><a rel="nofollow" href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank"><img alt="Creative Commons License" src="https://i1.wp.com/i.creativecommons.org/l/by-sa/4.0/88x31.png?w=456&ssl=1" data-recalc-dims="1"></a><br>This<br>
work is licensed under a<br>
<a rel="nofollow" href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative<br>
Commons Attribution-ShareAlike 4.0 International License</a>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://ibecav.github.io/betterfunctions2/"> Chuck Powell</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/F8N79Sp2-TM" height="1"></a></div>