<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>ggplot2 on R Views</title>
    <link>https://rviews.rstudio.com/tags/ggplot2/</link>
    <description>Recent content in ggplot2 on R Views</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 19 Sep 2019 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://rviews.rstudio.com/tags/ggplot2/" rel="self" type="application/rss+xml" />
    
    
    
    
    <item>
      <title>Accelerate your plots with ggforce</title>
      <link>https://rviews.rstudio.com/2019/09/19/intro-to-ggforce/</link>
      <pubDate>Thu, 19 Sep 2019 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2019/09/19/intro-to-ggforce/</guid>
      <description>
        


&lt;p&gt;In this post, I will walk you through some examples that show off the major features of the &lt;code&gt;ggforce&lt;/code&gt; package. The main goal is to share a few ideas about customizing visualizations that you may find useful in your everyday work.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ggforce&lt;/code&gt; package is an extension to &lt;code&gt;ggplot2&lt;/code&gt; developed by &lt;a href=&#34;https://github.com/thomasp85/&#34;&gt;Thomas Pedersen&lt;/a&gt;. Thanks to &lt;code&gt;ggforce&lt;/code&gt;, you can enhance almost any &lt;code&gt;ggplot&lt;/code&gt; by highlighting data groupings, and focusing attention on interesting features of the plot. The package contains &lt;code&gt;geoms&lt;/code&gt;, &lt;code&gt;stats&lt;/code&gt;, &lt;code&gt;facets&lt;/code&gt;, and other &lt;code&gt;ggplot&lt;/code&gt; functions. Among such functions, there are some for marking the &lt;a href=&#34;https://en.wikipedia.org/wiki/Convex_hull&#34;&gt;convex hull&lt;/a&gt; of a set of points, jittering data, and creating &lt;a href=&#34;https://en.wikipedia.org/wiki/Voronoi_diagram&#34;&gt;Voronoi plots&lt;/a&gt;.&lt;/p&gt;
&lt;div id=&#34;base-ggplot&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Base &lt;code&gt;ggplot&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The examples in this article will use data from the &lt;code&gt;nycflights13&lt;/code&gt; package. Most of the examples will build on the same basic &lt;code&gt;ggplot&lt;/code&gt; that visualizes airports by geographical location. I am using this data set because it makes it easy to plot &lt;code&gt;x&lt;/code&gt;/&lt;code&gt;y&lt;/code&gt; coordinates without having to remember what they “mean”. This basic plot will be saved to a variable, and then that variable will be used as the base of the examples of enhancing the visualization using &lt;code&gt;ggforce&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tidyverse)
library(ggforce)
library(nycflights13)

p &amp;lt;- airports %&amp;gt;%
  filter(lon &amp;lt; 0, tzone != &amp;quot;\\N&amp;quot;) %&amp;gt;%
  ggplot(aes(lon, lat, color = tzone)) + 
  geom_point(show.legend = FALSE)  

p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-1-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;make-your-mark-with-ggforce&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Make your &lt;code&gt;mark&lt;/code&gt; with &lt;code&gt;ggforce&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I have long been waiting for an easy way to draw an outline around groups of data. The &lt;code&gt;geom_mark_...()&lt;/code&gt; family of functions does exactly that. There are four &lt;code&gt;mark&lt;/code&gt; functions in &lt;code&gt;ggforce&lt;/code&gt;, all different based on the shape they draw around the group:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;code&gt;geom_mark_circle()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geom_mark_ellipse()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geom_mark_hull()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geom_mark_rect()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let’s start with &lt;code&gt;geom_mark_rect()&lt;/code&gt;; it will draw a rounded rectangle around each time zone group.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p +
  geom_mark_rect() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-2-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Like magic! The rectangles look amazing, even without modifying any arguments. Of course, more customization is possible via setting arguments. In this post, I will review some of the many great arguments available in &lt;code&gt;ggforce&lt;/code&gt; functions, but I don’t want to rob you of the fun of trying it yourself and discovering all of the different options.&lt;/p&gt;
&lt;div id=&#34;label-and-an-arrow&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Label, and an arrow!&lt;/h3&gt;
&lt;p&gt;This next addition to our plot deserves its own subheading. Adding a label and an arrow pointing to a group would typically be a major undertaking. Without &lt;code&gt;ggforce&lt;/code&gt;, this would require manually adding both the text and the arrow to the &lt;code&gt;ggplot&lt;/code&gt;. But, with &lt;code&gt;geom_mark&lt;/code&gt; it is a simple as setting the &lt;code&gt;label&lt;/code&gt; argument. So, without further ado, here is the &lt;code&gt;label&lt;/code&gt; argument in action:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_rect(aes(label = tzone)) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-3-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The labels and arrows are not only drawn, but they are also placed in an optimized location. In addition, the position will recalculate if the plot is re-sized! There are too many little details about this &lt;code&gt;label&lt;/code&gt; argument to mention. The backdrop is automatically white, the indicator is not really an arrow, it is a simple line that also underlines the text, so it is easy for the eye to know which group belongs to which label.&lt;/p&gt;
&lt;p&gt;It is now easy to finalize the plot by resetting the theme, and again suppressing the legend using &lt;code&gt;show.legend&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_rect(aes(label = tzone), show.legend = FALSE) +
  theme_void() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-4-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;hull-k-enhance&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Hull-k, enhance!&lt;/h3&gt;
&lt;p&gt;There are many cases where drawing a rectangle or circle around the groups is not ideal, or even preferable. The &lt;code&gt;geom_mark_hull()&lt;/code&gt; essentially traces a more complex polygon around the shape of the outline of the group.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_hull(aes(label = tzone)) +
  theme_void() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-5-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Again, without adding any arguments to the function, the traced outline already looks wonderful. Another option to add now is &lt;code&gt;fill&lt;/code&gt;. And since the legend table is now redundant, it can be suppressed by setting &lt;code&gt;show.legend&lt;/code&gt; to &lt;code&gt;FALSE&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_hull(aes(label = tzone, fill = tzone), show.legend = FALSE) +
  theme_void() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-6-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Notice that the fill color is not totally opaque; by default, &lt;code&gt;ggforce&lt;/code&gt; has set the translucency lower to make sure that the dots are visible. This is something that I would have done anyway, usually by adding the &lt;code&gt;alpha&lt;/code&gt; argument. In this case, it saves having to remember to add that argument.&lt;/p&gt;
&lt;p&gt;Another adjustment that I thought was important for this plot was to modify the size of the hull, to change the padding around the outline of the group. The &lt;code&gt;expand&lt;/code&gt; argument controls this aesthetic; it is possible to change it using the &lt;code&gt;units()&lt;/code&gt; command.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_hull(aes(label = tzone, fill = tzone), show.legend = FALSE, expand = unit(3, &amp;quot;mm&amp;quot;)) +
  theme_void() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-7-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;axe-theme_void&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Axe &lt;code&gt;theme_void()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;To finalize plots such as this one, it is necessary to remove most components from the default theme. Usually, &lt;code&gt;theme_void()&lt;/code&gt; does the trick. For printed or online articles with white backgrounds, which is essentially all of them, it is often hard to determine the margins of the plot. &lt;code&gt;theme_no_axes()&lt;/code&gt; provides a great compromise by removing all but the one element.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p + 
  geom_mark_hull(aes(label = tzone, fill = tzone), show.legend = FALSE, expand = unit(3, &amp;quot;mm&amp;quot;)) +
  theme_no_axes() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-8-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;another-facet-of-ggforce-and-its-magnify-cent&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Another facet of &lt;code&gt;ggforce&lt;/code&gt;, and it’s magnify-cent&lt;/h2&gt;
&lt;p&gt;It is common to produce two plots, one to show the full picture, and another to magnify or focus on a specific area. With &lt;code&gt;facet_zoom()&lt;/code&gt;, it is incredibly easy to show “macro” and “micro” in one plot by using the same &lt;code&gt;xlim&lt;/code&gt; and &lt;code&gt;ylim&lt;/code&gt; arguments to focus on an area of a plot.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p +
  facet_zoom(xlim = c(-155, -160.5), ylim = c(19, 22.3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-9-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;div id=&#34;skip-the-coordinates&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Skip the coordinates&lt;/h3&gt;
&lt;p&gt;Another cool feature of &lt;code&gt;facet_zoom()&lt;/code&gt; is the ability to set the zoom region based on a row selection. To do this, simply pass an expression that you would use in a function such as &lt;code&gt;filter()&lt;/code&gt; to the facet. So instead of using coordinates, I just tell the facet to zoom on anything that has a Pacific/Honolulu time zone.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p +
  facet_zoom(xy = tzone == &amp;quot;Pacific/Honolulu&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-10-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;putting-it-all-together-with-three-lines-of-code&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Putting it all together, with three lines of code&lt;/h2&gt;
&lt;p&gt;Using what has been covered so far, it is easy go from a very simple point plot to a sophisticated and nice-looking visualization with just three lines of code, thanks to &lt;code&gt;ggforce&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p +
  geom_mark_hull(aes(label = tzone, fill = tzone), show.legend = FALSE, expand = unit(3, &amp;quot;mm&amp;quot;)) +
  theme_no_axes() +
  facet_zoom(x = tzone == &amp;quot;America/Los_Angeles&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-11-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;what-is-a-voronoi&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;“What is a Voronoi?”&lt;/h2&gt;
&lt;p&gt;This section title is based on my first reaction when I heard the word “Voronoi”. I have since learned about it, and can see why the &lt;a href=&#34;https://en.wikipedia.org/wiki/Voronoi_diagram&#34;&gt;Voronoi Diagram&lt;/a&gt; can be useful for very specific use cases. The good news is that if you encounter one of those use cases, you know that it is easy to draw it up in &lt;code&gt;ggplot&lt;/code&gt; using &lt;code&gt;geom_voronoi_segment()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The idea behind a Voronoi diagram is to split the area of the plot into as many sections as there are points. Unlike a grid or heat map, Voronoi draws custom shapes for each point based on the proximity to other points. It returns a plot that looks like stained glass. This can be good to determine the closest point inside each area. For example, a retailer can use it to see the area their store locations cover, and can help them make decisions to optimize their location based on the size of each Voronoi shape.&lt;/p&gt;
&lt;p&gt;The following example will focus on airports in Alaska. The &lt;code&gt;ggplot&lt;/code&gt; will zoom into that state’s general location, and then trace a hull shape. The hull will provide a quasi-map overlay. The final step is to add the Voronoi diagram layer by calling the function: &lt;code&gt;geom_voronoi_segment()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p +
  geom_mark_hull(aes(fill = tzone), expand = unit(3, &amp;quot;mm&amp;quot;)) +
  coord_cartesian(xlim = c(-130, -180), ylim = c(50, 75))  +
  geom_voronoi_segment()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-12-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;parallel-to-alluvial&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Parallel to alluvial&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;geom_parallel...&lt;/code&gt; functions allow visualizing interactions between categorical variables. The implementation is generic enough to create Sankey or alluvial charts.&lt;/p&gt;
&lt;p&gt;For this, I will use the Manufacturer and Engine data from the &lt;code&gt;planes&lt;/code&gt; table inside &lt;code&gt;nycflights13&lt;/code&gt;. In this case, some simple data preparation is needed first.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prep_planes &amp;lt;- planes %&amp;gt;%
  filter(year &amp;gt; 1998, year &amp;lt; 2005) %&amp;gt;%
  filter(engine != &amp;quot;Turbo-shaft&amp;quot;) %&amp;gt;%
  select(manufacturer, engine) %&amp;gt;%
  head(500)

prep_planes&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 500 x 2
##    manufacturer     engine   
##    &amp;lt;chr&amp;gt;            &amp;lt;chr&amp;gt;    
##  1 EMBRAER          Turbo-fan
##  2 AIRBUS INDUSTRIE Turbo-fan
##  3 AIRBUS INDUSTRIE Turbo-fan
##  4 EMBRAER          Turbo-fan
##  5 AIRBUS INDUSTRIE Turbo-fan
##  6 AIRBUS INDUSTRIE Turbo-fan
##  7 AIRBUS INDUSTRIE Turbo-fan
##  8 AIRBUS INDUSTRIE Turbo-fan
##  9 AIRBUS INDUSTRIE Turbo-fan
## 10 EMBRAER          Turbo-fan
## # … with 490 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;prep-for-plotting-with-one-line&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Prep for plotting with one line&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;gather_set_data()&lt;/code&gt; is a convenience function that, just like &lt;code&gt;gather()&lt;/code&gt;, creates a single line for each combination of categorical variables. The table contains three new columns - &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;, and &lt;code&gt;y&lt;/code&gt; - which contain the combinations that each new row represents, and the row ID number from the original table.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prep_planes %&amp;gt;%
  gather_set_data(1:2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 1,000 x 5
##    manufacturer     engine       id x            y               
##    &amp;lt;chr&amp;gt;            &amp;lt;chr&amp;gt;     &amp;lt;int&amp;gt; &amp;lt;chr&amp;gt;        &amp;lt;chr&amp;gt;           
##  1 EMBRAER          Turbo-fan     1 manufacturer EMBRAER         
##  2 AIRBUS INDUSTRIE Turbo-fan     2 manufacturer AIRBUS INDUSTRIE
##  3 AIRBUS INDUSTRIE Turbo-fan     3 manufacturer AIRBUS INDUSTRIE
##  4 EMBRAER          Turbo-fan     4 manufacturer EMBRAER         
##  5 AIRBUS INDUSTRIE Turbo-fan     5 manufacturer AIRBUS INDUSTRIE
##  6 AIRBUS INDUSTRIE Turbo-fan     6 manufacturer AIRBUS INDUSTRIE
##  7 AIRBUS INDUSTRIE Turbo-fan     7 manufacturer AIRBUS INDUSTRIE
##  8 AIRBUS INDUSTRIE Turbo-fan     8 manufacturer AIRBUS INDUSTRIE
##  9 AIRBUS INDUSTRIE Turbo-fan     9 manufacturer AIRBUS INDUSTRIE
## 10 EMBRAER          Turbo-fan    10 manufacturer EMBRAER         
## # … with 990 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;ggplot&lt;/code&gt; is primed with &lt;code&gt;x&lt;/code&gt; for &lt;code&gt;x&lt;/code&gt;, and then new aesthetics: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;split&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt;. For &lt;code&gt;id&lt;/code&gt;, we pass the &lt;code&gt;id&lt;/code&gt; column, &lt;code&gt;split&lt;/code&gt; takes &lt;code&gt;y&lt;/code&gt;, and finally, &lt;code&gt;value&lt;/code&gt; is fixed to 1. The &lt;code&gt;value&lt;/code&gt; is used to express the amount of “thickness” to add to that particular relationship; using 1 means that all combinations are weighted the same. At this point, the only argument to pass &lt;code&gt;geom_parallel_sets()&lt;/code&gt; will be the color &lt;code&gt;fill&lt;/code&gt;; in this case we will use &lt;code&gt;engine&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;plotting-with-parallel&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Plotting with parallel&lt;/h3&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prep_planes %&amp;gt;%
  gather_set_data(1:2) %&amp;gt;%
  ggplot(aes(x, id = id, split = y, value = 1))  +
  geom_parallel_sets(aes(fill = engine)) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-15-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The plot shows how a specific plane’s engine relates to each of the manufacturers. Next &lt;code&gt;geom_parallel_sets_axes()&lt;/code&gt; provides a terminal box; the &lt;code&gt;axis.width&lt;/code&gt; argument is the only one necessary to use at this stage, and we will set it to 0.1. The labels are added by using &lt;code&gt;geom_parallel_sets_labels()&lt;/code&gt;, and they are automatically rotated.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prep_planes %&amp;gt;%
  gather_set_data(1:2) %&amp;gt;%
  ggplot(aes(x, id = id, split = y, value = 1))  +
  geom_parallel_sets(aes(fill = engine)) +
  geom_parallel_sets_axes(axis.width = 0.1) +
  geom_parallel_sets_labels()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-16-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The following is done to finalize the plot:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;geom_parallel_sets()&lt;/code&gt; - Hide the legend and lower the &lt;code&gt;alpha&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geom_parallel_sets_axes()&lt;/code&gt; - Change the fill color and font color&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geom_parallel_sets_labels()&lt;/code&gt; - Remove the rotation of the label&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;prep_planes %&amp;gt;%
  gather_set_data(1:2) %&amp;gt;%
  ggplot(aes(x, id = id, split = y, value = 1))  +
  geom_parallel_sets(aes(fill = engine), show.legend = FALSE, alpha = 0.3) +
  geom_parallel_sets_axes(axis.width = 0.1, color = &amp;quot;lightgrey&amp;quot;, fill = &amp;quot;white&amp;quot;) +
  geom_parallel_sets_labels(angle = 0) +
  theme_no_axes()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-17-1.png&#34; width=&#34;1152&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;danger-zone&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Danger zone!&lt;/h2&gt;
&lt;p&gt;When visualizing the combination of a continuous and a categorical variable, it is common practice to resort to a bar or column plot. Cases that require representing this in a single circle shape usually involve modifying a polar bar in &lt;code&gt;ggplot&lt;/code&gt;. But, this is much easier now with &lt;code&gt;ggforce&lt;/code&gt;. I start with the total number of planes by engine planes:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;planes %&amp;gt;%
  count(engine) &lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 6 x 2
##   engine            n
##   &amp;lt;chr&amp;gt;         &amp;lt;int&amp;gt;
## 1 4 Cycle           2
## 2 Reciprocating    28
## 3 Turbo-fan      2750
## 4 Turbo-jet       535
## 5 Turbo-prop        2
## 6 Turbo-shaft       5&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then pipe those results into &lt;code&gt;ggplot&lt;/code&gt; using &lt;code&gt;geom_arc_bar()&lt;/code&gt; to create the circle-shaped plot. The new aesthetics employed here are: &lt;code&gt;x0&lt;/code&gt;, &lt;code&gt;y0&lt;/code&gt;, &lt;code&gt;r0&lt;/code&gt;, &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt;, and &lt;code&gt;explode&lt;/code&gt;. The x, y, and r aesthetics refer to the position and the radius of the circle. Since only one plot is needed, I fix x and y to 0. For radius, the &lt;code&gt;r0&lt;/code&gt; refers to the inside of the circle, and &lt;code&gt;r&lt;/code&gt; to the outside. Setting &lt;code&gt;r0&lt;/code&gt; to 0.7 and &lt;code&gt;r&lt;/code&gt; to 1 will create a sort of doughnut with a 0.3 thickness. Finally, I use “pie” as the &lt;code&gt;stat&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;planes %&amp;gt;%
  count(engine) %&amp;gt;%
  ggplot() +
  geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0.7, r = 1, amount = n, fill = engine), alpha = 0.3, stat = &amp;quot;pie&amp;quot;) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-19-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Another cool thing this &lt;code&gt;geom&lt;/code&gt; does is to make it east to “break-away” one or several segments of the plot. The &lt;code&gt;explode&lt;/code&gt; aesthetic controls that. To break away the “Turbo-jet” results, I create a new column called &lt;code&gt;focus&lt;/code&gt;, setting it to 0.2 if it is part of that engine group, and to 0 if it is not, then finish up with &lt;code&gt;theme_no_axes()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;planes %&amp;gt;%
  count(engine) %&amp;gt;%
  mutate(focus = ifelse(engine == &amp;quot;Turbo-jet&amp;quot;, 0.2, 0)) %&amp;gt;%
  ggplot() +
  geom_arc_bar(aes(x0 = 0, y0 = 0, r0 = 0.7, r = 1, amount = n, fill = engine, explode = focus), alpha = 0.3, stat = &amp;quot;pie&amp;quot;) +
  theme_no_axes()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-09-16-intro-to-ggforce_files/figure-html/unnamed-chunk-20-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This section is titled “Danger Zone”, because hanging the &lt;code&gt;r0&lt;/code&gt; in &lt;code&gt;geom_arc_bar()&lt;/code&gt; may change the look of the plot to one that has fallen out of favor. That plot type happens to be the same name of the &lt;code&gt;stat&lt;/code&gt; that we are using.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;closing-remarks&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Closing remarks&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ggforce&lt;/code&gt; is a great package that does a lot more than what I covered today. My hope is to have shared one or two things that will encourage you to try &lt;code&gt;ggforce&lt;/code&gt; in your everyday work.&lt;/p&gt;
&lt;p&gt;Special thanks to &lt;a href=&#34;https://github.com/thomasp85/&#34;&gt;Thomas Pedersen&lt;/a&gt;, the author of the package and a co-worker of mine. His contributions to the R community also include the &lt;code&gt;tidygraph&lt;/code&gt; and &lt;code&gt;ggraph&lt;/code&gt; packages, which I &lt;a href=&#34;https://rviews.rstudio.com/2019/03/06/intro-to-graph-analysis/&#34;&gt;wrote about in this blog post&lt;/a&gt; a few months back.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2019/09/19/intro-to-ggforce/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>Graph analysis using the tidyverse</title>
      <link>https://rviews.rstudio.com/2019/03/06/intro-to-graph-analysis/</link>
      <pubDate>Wed, 06 Mar 2019 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2019/03/06/intro-to-graph-analysis/</guid>
      <description>
        


&lt;p&gt;It is because I am not a graph analysis expert that I thought it important to write this article. For someone who thinks in terms of single rectangular data sets, it is a bit of a mental leap to understand how to apply &lt;em&gt;tidy&lt;/em&gt; principles to a more robust object, such as a graph table. Thankfully, there are two packages that make this work much easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/thomasp85/tidygraph&#34;&gt;&lt;code&gt;tidygraph&lt;/code&gt;&lt;/a&gt; - Provides a way for &lt;code&gt;dplyr&lt;/code&gt; to interact with graphs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/thomasp85/ggraph&#34;&gt;&lt;code&gt;ggraph&lt;/code&gt;&lt;/a&gt; - Extension to &lt;code&gt;ggplot2&lt;/code&gt; for graph analysis&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div id=&#34;quick-intro&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Quick intro&lt;/h3&gt;
&lt;p&gt;Simply put, graph theory studies relationships between objects in a group. Visually, we can think of a graph as a series of interconnected circles, each representing a member of a group, such as people in a Social Network. Lines drawn between the circles represent a relationship between the members, such as friendships in a Social Network. Graph analysis helps with figuring out things such as the influence of a certain member, or how many friends are in between two members. A more formal definition and detailed explanation of Graph Theory can be found in &lt;a href=&#34;https://en.wikipedia.org/wiki/Graph_theory&#34;&gt;Wikipedia here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;example&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;p&gt;Using an example, this article will introduce concepts of graph analysis work, and how &lt;code&gt;tidyverse&lt;/code&gt; and &lt;code&gt;tidyverse&lt;/code&gt;-adjacent tools can be used for such analysis.&lt;/p&gt;
&lt;div id=&#34;data-source&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Data source&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/rfordatascience/tidytuesday&#34;&gt;tidytuesday&lt;/a&gt; weekly project encourages new and experienced users to use the &lt;code&gt;tidyverse&lt;/code&gt; tools to analyze data sets that change every week. I have been using that opportunity to lean new tools and techniques. One of the most recent data sets relates to French trains; it contains aggregate daily total trips per connecting stations.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(readr)

url &amp;lt;- &amp;quot;https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-02-26/small_trains.csv&amp;quot;
small_trains &amp;lt;- read_csv(url)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;head(small_trains)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 6 x 13
##    year month service departure_stati… arrival_station journey_time_avg
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt; &amp;lt;chr&amp;gt;   &amp;lt;chr&amp;gt;            &amp;lt;chr&amp;gt;                      &amp;lt;dbl&amp;gt;
## 1  2017     9 Nation… PARIS EST        METZ                        85.1
## 2  2017     9 Nation… REIMS            PARIS EST                   47.1
## 3  2017     9 Nation… PARIS EST        STRASBOURG                 116. 
## 4  2017     9 Nation… PARIS LYON       AVIGNON TGV                161. 
## 5  2017     9 Nation… PARIS LYON       BELLEGARDE (AI…            164. 
## 6  2017     9 Nation… PARIS LYON       BESANCON FRANC…            129. 
## # … with 7 more variables: total_num_trips &amp;lt;int&amp;gt;,
## #   avg_delay_all_departing &amp;lt;dbl&amp;gt;, avg_delay_all_arriving &amp;lt;dbl&amp;gt;,
## #   num_late_at_departure &amp;lt;int&amp;gt;, num_arriving_late &amp;lt;int&amp;gt;,
## #   delay_cause &amp;lt;chr&amp;gt;, delayed_number &amp;lt;dbl&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;data-preparation&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Data Preparation&lt;/h3&gt;
&lt;p&gt;Even though it was meant to analyze delays, I thought it would be interesting to use the data to understand how stations connect with each other. A new summarized data set is created, called &lt;em&gt;routes&lt;/em&gt;, which contains a single entry for each connected station. It also includes the average journey time it takes to go between stations.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(dplyr)

routes &amp;lt;- small_trains %&amp;gt;%
  group_by(departure_station, arrival_station) %&amp;gt;%
  summarise(journey_time = mean(journey_time_avg)) %&amp;gt;%
  ungroup() %&amp;gt;%
  mutate(from = departure_station, 
         to = arrival_station) %&amp;gt;%
  select(from, to, journey_time)

routes&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 130 x 3
##    from                       to                 journey_time
##    &amp;lt;chr&amp;gt;                      &amp;lt;chr&amp;gt;                     &amp;lt;dbl&amp;gt;
##  1 AIX EN PROVENCE TGV        PARIS LYON                186. 
##  2 ANGERS SAINT LAUD          PARIS MONTPARNASSE         97.5
##  3 ANGOULEME                  PARIS MONTPARNASSE        146. 
##  4 ANNECY                     PARIS LYON                225. 
##  5 ARRAS                      PARIS NORD                 52.8
##  6 AVIGNON TGV                PARIS LYON                161. 
##  7 BARCELONA                  PARIS LYON                358. 
##  8 BELLEGARDE (AIN)           PARIS LYON                163. 
##  9 BESANCON FRANCHE COMTE TGV PARIS LYON                131. 
## 10 BORDEAUX ST JEAN           PARIS MONTPARNASSE        186. 
## # … with 120 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to transform the tidy data set, into a graph table. In order to prepare &lt;em&gt;routes&lt;/em&gt; for this transformation, it has to contain two variables specifically named: &lt;em&gt;from&lt;/em&gt; and &lt;em&gt;to&lt;/em&gt;, which are the names that &lt;code&gt;tidygraph&lt;/code&gt; expects to see. Those variables should contain the name of each member (e.g., “AIX EN PROVENCE TGV”), and the relationship (“AIX EN PROVENCE TGV” -&amp;gt; “PARIS LYON”) .&lt;/p&gt;
&lt;p&gt;In graph terminology, a member of the group is called a &lt;strong&gt;node&lt;/strong&gt; (or vertex) in the graph, and a relationship between nodes is called an &lt;strong&gt;edge&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tidygraph)

graph_routes &amp;lt;- as_tbl_graph(routes)

graph_routes&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tbl_graph: 59 nodes and 130 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 59 x 1 (active)
##   name               
##   &amp;lt;chr&amp;gt;              
## 1 AIX EN PROVENCE TGV
## 2 ANGERS SAINT LAUD  
## 3 ANGOULEME          
## 4 ANNECY             
## 5 ARRAS              
## 6 AVIGNON TGV        
## # … with 53 more rows
## #
## # Edge Data: 130 x 3
##    from    to journey_time
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;        &amp;lt;dbl&amp;gt;
## 1     1    39        186. 
## 2     2    40         97.5
## 3     3    40        146. 
## # … with 127 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;as_tbl_graph()&lt;/code&gt; function splits the &lt;em&gt;routes&lt;/em&gt; table into two:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;p&gt;Node Data - Contains all of the unique values found in the &lt;em&gt;from&lt;/em&gt; and &lt;em&gt;to&lt;/em&gt; variables. In this case, it is a table with a single column containing the names of all of the stations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edge Data - Is a table of all relationships between &lt;em&gt;from&lt;/em&gt; and &lt;em&gt;to&lt;/em&gt;. A peculiarity of &lt;code&gt;tidygraph&lt;/code&gt; is that it uses the row position of the node as the identifier for &lt;em&gt;from&lt;/em&gt; and &lt;em&gt;to&lt;/em&gt;, instead of its original name.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another interesting thing about &lt;code&gt;tidygraph&lt;/code&gt; is that it allows us to attach more information about the node or edge in an additional column. In this case, &lt;em&gt;journey_time&lt;/em&gt; is not really needed to create the graph table, but it may be needed for the analysis we plan to perform. The &lt;code&gt;as_tbl_graph()&lt;/code&gt; function automatically created the column for us.&lt;/p&gt;
&lt;p&gt;Thinking about &lt;em&gt;graph_routes&lt;/em&gt; as two &lt;code&gt;tibbles&lt;/code&gt; inside a larger table graph, was one of the two major mental breakthroughs I had during this exercise. At that point, it became evident that &lt;code&gt;dplyr&lt;/code&gt; needs a way to know which of the two tables (nodes or edges) to perform the transformations on. In &lt;code&gt;tidygraph&lt;/code&gt;, this is done using the &lt;code&gt;activate()&lt;/code&gt; function. To showcase this, the nodes table will be “activated” in order to add two new string variables derived from &lt;em&gt;name&lt;/em&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(stringr)

graph_routes &amp;lt;- graph_routes %&amp;gt;%
  activate(nodes) %&amp;gt;%
  mutate(
    title = str_to_title(name),
    label = str_replace_all(title, &amp;quot; &amp;quot;, &amp;quot;\n&amp;quot;)
    )

graph_routes&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tbl_graph: 59 nodes and 130 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 59 x 3 (active)
##   name                title               label                   
##   &amp;lt;chr&amp;gt;               &amp;lt;chr&amp;gt;               &amp;lt;chr&amp;gt;                   
## 1 AIX EN PROVENCE TGV Aix En Provence Tgv &amp;quot;Aix\nEn\nProvence\nTgv&amp;quot;
## 2 ANGERS SAINT LAUD   Angers Saint Laud   &amp;quot;Angers\nSaint\nLaud&amp;quot;   
## 3 ANGOULEME           Angouleme           Angouleme               
## 4 ANNECY              Annecy              Annecy                  
## 5 ARRAS               Arras               Arras                   
## 6 AVIGNON TGV         Avignon Tgv         &amp;quot;Avignon\nTgv&amp;quot;          
## # … with 53 more rows
## #
## # Edge Data: 130 x 3
##    from    to journey_time
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;        &amp;lt;dbl&amp;gt;
## 1     1    39        186. 
## 2     2    40         97.5
## 3     3    40        146. 
## # … with 127 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It was really impressive how easy it was to manipulate the graph table, because once one of the two tables are activated, all of the changes can be made using &lt;code&gt;tidyverse&lt;/code&gt; tools. The same approach can be used to extract data from the graph table. In this case, a list of all the stations is pulled into a single character vector.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;stations &amp;lt;- graph_routes %&amp;gt;%
  activate(nodes) %&amp;gt;%
  pull(title)

stations&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##  [1] &amp;quot;Aix En Provence Tgv&amp;quot;            &amp;quot;Angers Saint Laud&amp;quot;             
##  [3] &amp;quot;Angouleme&amp;quot;                      &amp;quot;Annecy&amp;quot;                        
##  [5] &amp;quot;Arras&amp;quot;                          &amp;quot;Avignon Tgv&amp;quot;                   
##  [7] &amp;quot;Barcelona&amp;quot;                      &amp;quot;Bellegarde (Ain)&amp;quot;              
##  [9] &amp;quot;Besancon Franche Comte Tgv&amp;quot;     &amp;quot;Bordeaux St Jean&amp;quot;              
## [11] &amp;quot;Brest&amp;quot;                          &amp;quot;Chambery Challes Les Eaux&amp;quot;     
## [13] &amp;quot;Dijon Ville&amp;quot;                    &amp;quot;Douai&amp;quot;                         
## [15] &amp;quot;Dunkerque&amp;quot;                      &amp;quot;Francfort&amp;quot;                     
## [17] &amp;quot;Geneve&amp;quot;                         &amp;quot;Grenoble&amp;quot;                      
## [19] &amp;quot;Italie&amp;quot;                         &amp;quot;La Rochelle Ville&amp;quot;             
## [21] &amp;quot;Lausanne&amp;quot;                       &amp;quot;Laval&amp;quot;                         
## [23] &amp;quot;Le Creusot Montceau Montchanin&amp;quot; &amp;quot;Le Mans&amp;quot;                       
## [25] &amp;quot;Lille&amp;quot;                          &amp;quot;Lyon Part Dieu&amp;quot;                
## [27] &amp;quot;Macon Loche&amp;quot;                    &amp;quot;Madrid&amp;quot;                        
## [29] &amp;quot;Marne La Vallee&amp;quot;                &amp;quot;Marseille St Charles&amp;quot;          
## [31] &amp;quot;Metz&amp;quot;                           &amp;quot;Montpellier&amp;quot;                   
## [33] &amp;quot;Mulhouse Ville&amp;quot;                 &amp;quot;Nancy&amp;quot;                         
## [35] &amp;quot;Nantes&amp;quot;                         &amp;quot;Nice Ville&amp;quot;                    
## [37] &amp;quot;Nimes&amp;quot;                          &amp;quot;Paris Est&amp;quot;                     
## [39] &amp;quot;Paris Lyon&amp;quot;                     &amp;quot;Paris Montparnasse&amp;quot;            
## [41] &amp;quot;Paris Nord&amp;quot;                     &amp;quot;Paris Vaugirard&amp;quot;               
## [43] &amp;quot;Perpignan&amp;quot;                      &amp;quot;Poitiers&amp;quot;                      
## [45] &amp;quot;Quimper&amp;quot;                        &amp;quot;Reims&amp;quot;                         
## [47] &amp;quot;Rennes&amp;quot;                         &amp;quot;Saint Etienne Chateaucreux&amp;quot;    
## [49] &amp;quot;St Malo&amp;quot;                        &amp;quot;St Pierre Des Corps&amp;quot;           
## [51] &amp;quot;Strasbourg&amp;quot;                     &amp;quot;Stuttgart&amp;quot;                     
## [53] &amp;quot;Toulon&amp;quot;                         &amp;quot;Toulouse Matabiau&amp;quot;             
## [55] &amp;quot;Tourcoing&amp;quot;                      &amp;quot;Tours&amp;quot;                         
## [57] &amp;quot;Valence Alixan Tgv&amp;quot;             &amp;quot;Vannes&amp;quot;                        
## [59] &amp;quot;Zurich&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;visualizing&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Visualizing&lt;/h2&gt;
&lt;p&gt;In graphs, the absolute position of the each node is not as relevant as it is with other kinds of visualizations. A very minimal &lt;code&gt;ggplot2&lt;/code&gt; theme is set to make it easier to view the plotted graph.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)

thm &amp;lt;- theme_minimal() +
  theme(
    legend.position = &amp;quot;none&amp;quot;,
     axis.title = element_blank(),
     axis.text = element_blank(),
     panel.grid = element_blank(),
     panel.grid.major = element_blank(),
  ) 

theme_set(thm)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To create the plot, start with &lt;code&gt;ggraph()&lt;/code&gt; instead of &lt;code&gt;ggplot2()&lt;/code&gt;. The &lt;code&gt;ggraph&lt;/code&gt; package contains &lt;code&gt;geoms&lt;/code&gt; that are unique to graph analysis. The package contains &lt;code&gt;geoms&lt;/code&gt; to specifically plot nodes, and other &lt;code&gt;geoms&lt;/code&gt; for edges.&lt;/p&gt;
&lt;p&gt;As a first basic test, the &lt;em&gt;point&lt;/em&gt; &lt;code&gt;geom&lt;/code&gt; will be used, but instead of calling&lt;code&gt;geom_point()&lt;/code&gt;, we call &lt;code&gt;geom_node_point()&lt;/code&gt;. The edges are plotted using &lt;code&gt;geom_edge_diagonal()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggraph) 

graph_routes %&amp;gt;%
  ggraph(layout = &amp;quot;kk&amp;quot;) +
    geom_node_point() +
    geom_edge_diagonal() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-02-28-intro-to-graph-analysis_files/figure-html/unnamed-chunk-9-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;To make it easier to see where each station is placed in this plot, the &lt;code&gt;geom_node_text()&lt;/code&gt; is used. Just as with regular &lt;code&gt;geoms&lt;/code&gt; in &lt;code&gt;ggplot2&lt;/code&gt;, other attributes such as &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;color&lt;/code&gt;, and &lt;code&gt;alpha&lt;/code&gt; can be modified.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;graph_routes %&amp;gt;%
  ggraph(layout = &amp;quot;kk&amp;quot;) +
    geom_node_text(aes(label = label, color = name), size = 3) +
    geom_edge_diagonal(color = &amp;quot;gray&amp;quot;, alpha = 0.4) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-02-28-intro-to-graph-analysis_files/figure-html/unnamed-chunk-10-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;morphing-time&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Morphing time!&lt;/h2&gt;
&lt;p&gt;The second mental leap was understanding how a graph algorithm is applied. Typically, the output of a model function is a model object, not a data object. With &lt;code&gt;tidygraph&lt;/code&gt;, the process begins and ends with a graph table. The steps are these:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Start with a graph table&lt;/li&gt;
&lt;li&gt;Temporarily transform the graph to comply with the model that is requested (&lt;code&gt;morph()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add additional transformations to the morphed data using &lt;code&gt;dplyr&lt;/code&gt; (optional)&lt;/li&gt;
&lt;li&gt;Restore the original graph table, but modified to keep the changes made during the morph&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The shortest path algorithm defines the “length” as the number of edges in between two nodes. There may be multiple routes to get from point A to point B, but the algorithm chooses the one with the fewest number of “hops”. The way to call the algorithm is inside the &lt;code&gt;morph()&lt;/code&gt; function. Even though &lt;code&gt;to_shortest_path()&lt;/code&gt; is a function in itself, and it is possible run it without &lt;code&gt;morph()&lt;/code&gt;, it is not meant to be used that way. In the example, the &lt;em&gt;journey_time&lt;/em&gt; is used as &lt;code&gt;weights&lt;/code&gt; to help the algorithm find an optimal route between the &lt;em&gt;Arras&lt;/em&gt; and the &lt;em&gt;Nancy&lt;/em&gt; stations. The print output of the morphed graph will not be like the original graph table.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;from &amp;lt;- which(stations == &amp;quot;Arras&amp;quot;)
to &amp;lt;-  which(stations == &amp;quot;Nancy&amp;quot;)

shortest &amp;lt;- graph_routes %&amp;gt;%
  morph(to_shortest_path, from, to, weights = journey_time)

shortest&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tbl_graph temporarily morphed to a shortest path representation
## # 
## # Original graph is a directed simple graph with 1 component
## # consisting of 59 nodes and 130 edges&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is possible to make more transformations with the use of &lt;code&gt;activate()&lt;/code&gt; and &lt;code&gt;dplyr&lt;/code&gt; functions. The results can be previewed, or committed back to the original R variable using &lt;code&gt;unmorph()&lt;/code&gt;. By default, nodes are active in a morphed graph, so there is no need to set that explicitly.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest %&amp;gt;%
  mutate(selected_node = TRUE) %&amp;gt;%
  unmorph()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tbl_graph: 59 nodes and 130 edges
## #
## # A directed simple graph with 1 component
## #
## # Node Data: 59 x 4 (active)
##   name               title              label                 selected_node
##   &amp;lt;chr&amp;gt;              &amp;lt;chr&amp;gt;              &amp;lt;chr&amp;gt;                 &amp;lt;lgl&amp;gt;        
## 1 AIX EN PROVENCE T… Aix En Provence T… &amp;quot;Aix\nEn\nProvence\n… NA           
## 2 ANGERS SAINT LAUD  Angers Saint Laud  &amp;quot;Angers\nSaint\nLaud&amp;quot; NA           
## 3 ANGOULEME          Angouleme          Angouleme             NA           
## 4 ANNECY             Annecy             Annecy                NA           
## 5 ARRAS              Arras              Arras                 TRUE         
## 6 AVIGNON TGV        Avignon Tgv        &amp;quot;Avignon\nTgv&amp;quot;        NA           
## # … with 53 more rows
## #
## # Edge Data: 130 x 3
##    from    to journey_time
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;        &amp;lt;dbl&amp;gt;
## 1     1    39        186. 
## 2     2    40         97.5
## 3     3    40        146. 
## # … with 127 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While it was morphed, only the few nodes that make up the connections between the Arras and Nancy stations were selected. A simple &lt;code&gt;mutate()&lt;/code&gt; adds a new variable called &lt;em&gt;selected_node&lt;/em&gt;, which tags those nodes with TRUE. The new variable and value is retained once the rest of the nodes are restored via the &lt;code&gt;unmorph()&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;To keep the change, the &lt;em&gt;shortest&lt;/em&gt; variable is updated with the changes made to both edges and nodes.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest &amp;lt;- shortest %&amp;gt;%
  mutate(selected_node = TRUE) %&amp;gt;%
  activate(edges) %&amp;gt;%
  mutate(selected_edge = TRUE) %&amp;gt;%
  unmorph() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to coerce each NA into a 1, and the shortest route into a 2. This will allow us to easily re-arrange the order that the edges are drawn in the plot, ensuring that the route will be drawn at the top.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest &amp;lt;- shortest %&amp;gt;%
  activate(nodes) %&amp;gt;%
  mutate(selected_node = ifelse(is.na(selected_node), 1, 2)) %&amp;gt;%
  activate(edges) %&amp;gt;%
  mutate(selected_edge = ifelse(is.na(selected_edge), 1, 2)) %&amp;gt;%
  arrange(selected_edge)

shortest&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tbl_graph: 59 nodes and 130 edges
## #
## # A directed simple graph with 1 component
## #
## # Edge Data: 130 x 4 (active)
##    from    to journey_time selected_edge
##   &amp;lt;int&amp;gt; &amp;lt;int&amp;gt;        &amp;lt;dbl&amp;gt;         &amp;lt;dbl&amp;gt;
## 1     1    39        186.              1
## 2     2    40         97.5             1
## 3     3    40        146.              1
## 4     4    39        225.              1
## 5     6    39        161.              1
## 6     7    39        358.              1
## # … with 124 more rows
## #
## # Node Data: 59 x 4
##   name               title              label                 selected_node
##   &amp;lt;chr&amp;gt;              &amp;lt;chr&amp;gt;              &amp;lt;chr&amp;gt;                         &amp;lt;dbl&amp;gt;
## 1 AIX EN PROVENCE T… Aix En Provence T… &amp;quot;Aix\nEn\nProvence\n…             1
## 2 ANGERS SAINT LAUD  Angers Saint Laud  &amp;quot;Angers\nSaint\nLaud&amp;quot;             1
## 3 ANGOULEME          Angouleme          Angouleme                         1
## # … with 56 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A simple way to plot the route is to use the &lt;em&gt;selected_&lt;/em&gt; variables to modify the &lt;code&gt;alpha&lt;/code&gt;. This will highlight the shortest path, without completely removing the other stations. This is a personal design choice, so experimenting with different ways of highlighting the results is always recommended.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest %&amp;gt;%
  ggraph(layout = &amp;quot;kk&amp;quot;) +
    geom_edge_diagonal(aes(alpha = selected_edge), color = &amp;quot;gray&amp;quot;) +
    geom_node_text(aes(label = label, color =name, alpha = selected_node ), size = 3) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-02-28-intro-to-graph-analysis_files/figure-html/unnamed-chunk-15-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;selected_&lt;/em&gt; fields can also be used in other &lt;code&gt;dplyr&lt;/code&gt; functions to analyze the results. For example, to know the aggregate information about the trip, &lt;em&gt;selected_edge&lt;/em&gt; is used to filter the edges, and then the totals can be calculated. There is no &lt;code&gt;summarise()&lt;/code&gt; function for graph tables; this make sense because the graph table would become a summarized table with such a function. Since the end result we seek is a total rather than another graph table, a simple &lt;code&gt;as_tibble()&lt;/code&gt; command will coerce the edges, which will then allows us to finish the calculation.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest %&amp;gt;%
  activate(edges) %&amp;gt;%
  filter(selected_edge == 2) %&amp;gt;%
  as_tibble() %&amp;gt;%
  summarise(
    total_stops = n() - 1,
    total_time = round(sum(journey_time) / 60)
    )&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 1 x 2
##   total_stops total_time
##         &amp;lt;dbl&amp;gt;      &amp;lt;dbl&amp;gt;
## 1           8         23&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;re-using-the-code&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Re-using the code&lt;/h2&gt;
&lt;p&gt;To compile most of the code in a single chunk, here is an example of how to re-run the shortest path for a different set of stations: the Laval and Montpellier stations.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;from &amp;lt;- which(stations == &amp;quot;Montpellier&amp;quot;)
to &amp;lt;-  which(stations == &amp;quot;Laval&amp;quot;)

shortest &amp;lt;- graph_routes %&amp;gt;%
  morph(to_shortest_path, from, to, weights = journey_time) %&amp;gt;%
  mutate(selected_node = TRUE) %&amp;gt;%
  activate(edges) %&amp;gt;%
  mutate(selected_edge = TRUE) %&amp;gt;%
  unmorph() %&amp;gt;%
  activate(nodes) %&amp;gt;%
  mutate(selected_node = ifelse(is.na(selected_node), 1, 2)) %&amp;gt;%
  activate(edges) %&amp;gt;%
  mutate(selected_edge = ifelse(is.na(selected_edge), 1, 2)) %&amp;gt;%
  arrange(selected_edge)

shortest %&amp;gt;%
  ggraph(layout = &amp;quot;kk&amp;quot;) +
    geom_edge_diagonal(aes(alpha = selected_edge), color = &amp;quot;gray&amp;quot;) +
    geom_node_text(aes(label = label, color =name, alpha = selected_node ), size = 3)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2019-02-28-intro-to-graph-analysis_files/figure-html/unnamed-chunk-17-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Additional, the same code can be recycled to obtain the trip summarized data.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;shortest %&amp;gt;%
  activate(edges) %&amp;gt;%
  filter(selected_edge == 2) %&amp;gt;%
  as_tibble() %&amp;gt;%
  summarise(
    total_stops = n() - 1,
    total_time = round(sum(journey_time) / 60)
    )&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## # A tibble: 1 x 2
##   total_stops total_time
##         &amp;lt;dbl&amp;gt;      &amp;lt;dbl&amp;gt;
## 1           3         10&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;shiny-app&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Shiny app&lt;/h2&gt;
&lt;p&gt;To see how to use this kind of analysis inside Shiny, please refer to &lt;a href=&#34;https://beta.rstudioconnect.com/content/4606/&#34;&gt;this application&lt;/a&gt;. It lets the user select two stations, and it returns the route, plus the summarized data. The source code is embedded in the app.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2019/03/06/intro-to-graph-analysis/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>End-to-end visualization using ggplot2</title>
      <link>https://rviews.rstudio.com/2017/08/14/end-to-end-visualization-using-ggplot2/</link>
      <pubDate>Mon, 14 Aug 2017 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2017/08/14/end-to-end-visualization-using-ggplot2/</guid>
      <description>
        


&lt;p&gt;&lt;code&gt;ggplot2&lt;/code&gt; is kind of a household word for R users. I’ve ended up using it for complex data munging and wrangling work, where I needed to get clarity on different aspects of the data, especially being able to get different views, slices and dices of it, but in a &lt;em&gt;nice&lt;/em&gt; visualization. At some point along the line, I slowly stopped using more traditional plotting functions like &lt;code&gt;plot()&lt;/code&gt;, &lt;code&gt;matplot()&lt;/code&gt;, &lt;code&gt;barplot()&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;This article is an end-to-end data visualization exercise, using only &lt;code&gt;ggplot2()&lt;/code&gt;. It has been helpful for me to see such pieces online on the endless possibilities of &lt;code&gt;ggplot2()&lt;/code&gt;, so I wanted to give back to the community by doing one of my own.&lt;/p&gt;
&lt;div id=&#34;pima-indian-diabetes-data&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;1. Pima Indian Diabetes data&lt;/h2&gt;
&lt;p&gt;Consider the Pima Indian Diabetes dataset available in &lt;code&gt;R&lt;/code&gt;. It looks at the population of women who were at least 21 years of age, of Pima Indian heritage and living near Phoenix, Arizona, and were tested for diabetes according to WHO criteria. In this exercise, I will use the 332 test data subjects. There are no missing values in this data. It is a very simple dataset, but my goal is to use it to demonstrate the tools available in &lt;code&gt;ggplot2&lt;/code&gt; to visually investigate a dataset we know very little about. This is part of the important data exploration phase of a data science project, to help prepare for the modeling phase.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(MASS)
d &amp;lt;- Pima.te
summary(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##      npreg             glu              bp              skin      
##  Min.   : 0.000   Min.   : 65.0   Min.   : 24.00   Min.   : 7.00  
##  1st Qu.: 1.000   1st Qu.: 96.0   1st Qu.: 64.00   1st Qu.:22.00  
##  Median : 2.000   Median :112.0   Median : 72.00   Median :29.00  
##  Mean   : 3.485   Mean   :119.3   Mean   : 71.65   Mean   :29.16  
##  3rd Qu.: 5.000   3rd Qu.:136.2   3rd Qu.: 80.00   3rd Qu.:36.00  
##  Max.   :17.000   Max.   :197.0   Max.   :110.00   Max.   :63.00  
##       bmi             ped              age         type    
##  Min.   :19.40   Min.   :0.0850   Min.   :21.00   No :223  
##  1st Qu.:28.18   1st Qu.:0.2660   1st Qu.:23.00   Yes:109  
##  Median :32.90   Median :0.4400   Median :27.00            
##  Mean   :33.24   Mean   :0.5284   Mean   :31.32            
##  3rd Qu.:37.20   3rd Qu.:0.6793   3rd Qu.:37.00            
##  Max.   :67.10   Max.   :2.4200   Max.   :81.00&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;head(d)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##   npreg glu bp skin  bmi   ped age type
## 1     6 148 72   35 33.6 0.627  50  Yes
## 2     1  85 66   29 26.6 0.351  31   No
## 3     1  89 66   23 28.1 0.167  21   No
## 4     3  78 50   32 31.0 0.248  26  Yes
## 5     2 197 70   45 30.5 0.158  53  Yes
## 6     5 166 72   19 25.8 0.587  51  Yes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The target variable, &lt;em&gt;type&lt;/em&gt;, tells us whether a patient is diabetic or not.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;distributions-across-categories&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;2. Distributions across categories&lt;/h2&gt;
&lt;p&gt;When the target is categorical, as in this case, &lt;em&gt;type&lt;/em&gt;, I like to start by examining distributions for the continuous input columns. This gives us an overall sense of which input is likely to be useful. To do this, I like to do both boxplots and a density plot, since each has a different goal.&lt;/p&gt;
&lt;div id=&#34;boxplots&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;2.1. Boxplots&lt;/h3&gt;
&lt;p&gt;First, I’ll use boxplots, &lt;em&gt;but&lt;/em&gt; &lt;code&gt;ggplot2&lt;/code&gt;-style. I really like the look of a &lt;code&gt;ggplot2()&lt;/code&gt; boxplot. It also allows me to seamlessly have multiple plots in a grid, as well as tinker around with the plotting parameters more flexibly than in a classical &lt;code&gt;boxplot()&lt;/code&gt; approach, and end up with a nice-looking plot. We can see below how some inputs clearly vary across the 2 target categories, and others don’t.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df &amp;lt;- subset(d, select=c(glu, bp, skin, bmi, ped, age, type))  

library(gridExtra)
library(ggplot2)
p &amp;lt;- list()

for (j in colnames(df)[1:6]) {
  p[[j]] &amp;lt;- ggplot(data=df, aes_string(x=&amp;quot;type&amp;quot;, y=j)) + # Specify dataset, input or grouping col name and Y
            geom_boxplot(aes(fill=factor(type))) + guides(fill=FALSE) + # Boxplot by which factor + color guide
            theme(axis.title.y = element_text(face=&amp;quot;bold&amp;quot;, size=14))  # Make the Y-axis labels bigger/bolder
}

do.call(grid.arrange, c(p, ncol=3))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/boxplot-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;density-plots&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;2.2. Density plots&lt;/h3&gt;
&lt;p&gt;I have used various overlay-density packages in the past, &lt;code&gt;sm.density.compare()&lt;/code&gt; for example. I find the overlay-density rendering in &lt;code&gt;ggplot2()&lt;/code&gt; to be more visually pleasing, with little plotting parameter tuning. E.g., it’s clear in the plot below that diabetic patients are associated with more number of pregnancies. I really like the &lt;code&gt;alpha&lt;/code&gt; parameter.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df$npreg &amp;lt;- d$npreg
g &amp;lt;- ggplot(df, aes(npreg))
g + geom_density(aes(fill=factor(type)), alpha=0.8) + 
    labs(title=&amp;quot;Density plot&amp;quot;, 
         subtitle=&amp;quot;# Pregnancies Grouped by Diabetes Type&amp;quot;,
         x=&amp;quot;# Pregnancies&amp;quot;,
         fill=&amp;quot;Diabetes Type&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/densityplot-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;grid-views&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;3. Grid views&lt;/h2&gt;
&lt;p&gt;Next, I want to mix things up a little, so that I can have multi-dimensional views. By this, I mean that I want to know how the target is distributed across a few important inputs, but I want to link those inputs up as well. Sort of like a 3-way table, but visualized nicely instead of numbers. I came across this problem recently in one of the projects, and while it seems like a basic must-have output to dig deeper, I really needed something like &lt;code&gt;ggplot2&lt;/code&gt; to implement it. Using &lt;code&gt;facet_grid()&lt;/code&gt; was amazing, even more so on account of the smooth control one has on the plotting parameters within a &lt;code&gt;ggplot2&lt;/code&gt; setup.&lt;/p&gt;
&lt;div id=&#34;data-preparation&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;3.1. Data preparation&lt;/h3&gt;
&lt;p&gt;Facet-wrapping and gridding is a must-have tool for deeper data views, but the process is a multi-step one. Not too complicated though - very intuitive under &lt;code&gt;ggplot2&lt;/code&gt;. We start with creating some new categorical columns using the continuous ones. Note that this can be done in different ways: appending new columns directly to the data frame, or using the more sleeker &lt;code&gt;dplyr()&lt;/code&gt; in combination with &lt;code&gt;magrittr()&lt;/code&gt;, which I absolutely love. This integrates a number of operations into a single chunk, making it quite seamless. I am also loading up &lt;code&gt;plyr()&lt;/code&gt;, since I will be using it later.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(magrittr)
library(plyr)
library(dplyr)
df_grid &amp;lt;- d %&amp;gt;% 
          mutate(Skin = ifelse(d$skin &amp;lt;= 29, &amp;quot;low skin fold&amp;quot;, &amp;quot;high skin fold&amp;quot;),
                  BMI = ifelse(d$bmi &amp;lt;= 33, &amp;quot;low BMI&amp;quot;, &amp;quot;high BMI&amp;quot;),
                  Ped = ifelse(d$ped &amp;lt;= 0.31, &amp;quot;low pedigree&amp;quot;,
                ifelse(d$ped &amp;gt; 0.3134 &amp;amp; d$ped &amp;lt;= 0.5844, &amp;quot;medium pedigree&amp;quot;, &amp;quot;high pedigree&amp;quot;))) %&amp;gt;% 
  
            mutate(Ped = factor(Ped, levels = c(&amp;quot;low pedigree&amp;quot;, &amp;quot;medium pedigree&amp;quot;, &amp;quot;high pedigree&amp;quot;)))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;reshaping-the-data&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;3.2. Reshaping the data&lt;/h3&gt;
&lt;p&gt;Next, we need to prepare the data a little more before throwing it into the &lt;code&gt;facet_grid()&lt;/code&gt; mix. Most importantly, we need to “reshape” it, i.e., while our data is a “wide”-form data frame, we need to convert this to a “long”-form to enable &lt;code&gt;facet_grid()&lt;/code&gt; to easily pick up what it needs to “facet” the plot by. We will also add a “size” column - this will allow us to make more granular adjustments in our plot. I will also rename columns in order to enable easier axis labeling when plotting. Again, notice that instead of using &lt;code&gt;reshape2()&lt;/code&gt;, which I have used for many years, we’re using &lt;code&gt;gather()&lt;/code&gt; from &lt;code&gt;tidyr()&lt;/code&gt;, all sewn together with the pipe in &lt;code&gt;magrittr()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tidyr)
DF &amp;lt;- df_grid %&amp;gt;% 
    subset(select=c(type, Skin, BMI, Ped)) %&amp;gt;% 
    gather(variable, value, -c(Skin, Ped, BMI))

colnames(DF)[5] &amp;lt;- &amp;quot;Diabetes_Value&amp;quot;
DF$size &amp;lt;- rep(1.5, nrow(DF))
s &amp;lt;- 1.5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;facet-grid&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;3.3. Facet Grid&lt;/h3&gt;
&lt;p&gt;We’ll try the basic &lt;code&gt;facet_grid()&lt;/code&gt; plot, after which we’ll go in and make some adjustments. For now, our goal is the following: to see a “matrix” or “grid” of the BMI distribution across diabetes type, as a 2x2 table of pedigree/skin fold combinations. In other words, for low pedigree/low skin fold, how does BMI distribute across diabetes type? You can see the amount of information you can pack into just one plot. I have found this to be useful when presenting to an end-user or customer. It becomes all the more useful since its a very clear representation of this slice/dice, with little room for ambiguity.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Simple
library(ggplot2)
ggplot(data=DF, aes(x=Diabetes_Value, fill=BMI)) + geom_bar() +  # Barplot
  facet_grid(Skin ~ Ped)   # wrap up everything to showcase by multiple cols&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/facet-plot-1-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;This looks nice, but I would like to add more of a “pop”. I am going to outline each box, and bolden the fonts. Note that you can also color the “grid strips”, but I won’t do that right now.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# More color
p &amp;lt;- ggplot(data=DF, aes(x=Diabetes_Value, fill=BMI)) + geom_bar() +  # Barplot
  geom_rect(aes(fill=NA, size=size),xmin =-Inf,xmax=Inf,ymin=-Inf,ymax=Inf,alpha = 0.0002, colour=&amp;quot;black&amp;quot;,show.legend = F) +   # use box drawn around each location to cleanly separate facets + suppress guide
  scale_size(range=c(s,s), guide=FALSE) + # use line width/size feature for cleaner plotting
  facet_grid(Skin ~ Ped) +   # wrap up everything to showcase by multiple cols
  theme(strip.text.x = element_text(face=&amp;quot;bold&amp;quot;, size=12)) +
  theme(strip.text.y = element_text(face=&amp;quot;bold&amp;quot;, size=12)) 
  # optional changes in strip
#+ theme(strip.text.x = element_text(face=&amp;quot;bold&amp;quot;, size=12, colour=&amp;quot;white&amp;quot;)) +
#  theme(strip.text.y = element_text(face=&amp;quot;bold&amp;quot;, size=12, color=&amp;quot;white&amp;quot;)) +
#  theme(strip.background = element_rect(fill=&amp;quot;black&amp;quot;))
plot(p)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/facet-plot-2-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Much better. Look how nicely this granular plot adjustment in &lt;code&gt;ggplot2&lt;/code&gt; allows each “block” in the matrix to pop out. Its very clear how BMI is distributed across diabetes type, and how that in turn is distributed across both pedigree function and skin fold. We see that (as expected): 1. A higher triceps skin fold thickness is associated with a higher BMI, as well as a higher count of diabetic people. 2. The above is more true for a higher diabetes pedigree function.&lt;/p&gt;
&lt;p&gt;This kind of a grid plot presents a very powerful tool for such multi-dimensional data views.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;heatmaps&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;4. Heatmaps&lt;/h2&gt;
&lt;p&gt;I like heatmaps - there’s a sense of drama in the way you can see where “something is happening”. I’ve used &lt;code&gt;heatmap.2()&lt;/code&gt; to implement hierarchical clustering and translating that to a heatmap. But I wanted to use &lt;code&gt;ggplot2()&lt;/code&gt; to simply &lt;em&gt;look&lt;/em&gt; at a dataset as a heatmap, without any underlying analysis, to detect patterns before any analysis begins.&lt;/p&gt;
&lt;p&gt;In this case, I want &lt;code&gt;ggplot2()&lt;/code&gt; to show me patterns across different input columns, for the two diabetes types, i.e., what inputs seem to differ across diabetic/non-diabetic patients. This will be clear once we render our dataset into a nice &lt;code&gt;ggplot2()&lt;/code&gt; heatmap.&lt;/p&gt;
&lt;div id=&#34;data-preparation-1&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;4.1. Data preparation&lt;/h3&gt;
&lt;p&gt;As usual, we need to prep our data before pushing it into the &lt;code&gt;ggplot2()&lt;/code&gt; function. We’ll reshape and scale the data first, all within the &lt;code&gt;plyr()&lt;/code&gt;, &lt;code&gt;dplyr()&lt;/code&gt;, and &lt;code&gt;magrittr()&lt;/code&gt; framework. I’ll also specify some plotting parameters that I will call into my &lt;code&gt;ggplot2()&lt;/code&gt; function. I’m going to rely on &lt;code&gt;RColorBrewer()&lt;/code&gt; for these.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;df_heat &amp;lt;- d[order(d$type),1:8]
DF_Heat &amp;lt;- df_heat %&amp;gt;%
          mutate(id = 1:nrow(df_heat)) %&amp;gt;%
          select(c(npreg:age, id))  %&amp;gt;%
          gather(variable, value, -id)  %&amp;gt;%
          ddply(.(variable), transform,
                    rescale = scale(value))  # Notice that this reorders by &amp;quot;variables&amp;quot;
          
# Color scale for heatmap
library(RColorBrewer)
colors &amp;lt;- brewer.pal(9, &amp;#39;Reds&amp;#39;)

# Lines to split patients into diabetic/non-diabetic
my.lines &amp;lt;- data.frame(x1 = 0.5, x2 = 7.5, y1 = 223.5, y2 = 223.5)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;rendering-the-heatmap&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;4.2. Rendering the heatmap&lt;/h3&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Basic plot
p &amp;lt;- ggplot(DF_Heat, aes(as.factor(variable), as.factor(id), group=id)) + 
  geom_tile(aes(fill = rescale),colour = &amp;quot;white&amp;quot;) +
  scale_fill_gradient(low=&amp;quot;green&amp;quot;, high=&amp;quot;red&amp;quot;)

# Make adjustments
base_size &amp;lt;- 9
p_adj &amp;lt;- p + theme_grey(base_size = base_size) + labs(x = &amp;quot;&amp;quot;,y = &amp;quot;&amp;quot;) + scale_x_discrete(expand = c(0, 0)) +
  scale_y_discrete(expand = c(0, 0)) +
  geom_segment(data=my.lines, aes(x = x1, y = y1, xend=x2, yend=y2), size=1, inherit.aes=F) +
  theme(axis.text.y = element_blank(), axis.ticks.y = element_blank()) 
plot(p_adj)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/heatmap-2-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Note that I have suppressed the ticks on the Y-axis. We can clearly see regions of interest on the heatmap. It would be better for these to easily pop out at the viewer, to enable which, I am going to invoke &lt;code&gt;geom_rect()&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Borders of rectangles to indicate areas of interest on heatmap
my.lines.rect.1 &amp;lt;- data.frame(xmin = 1.5, xmax = 2.5, ymin = 223.5, ymax = 255.5)
my.lines.rect.2 &amp;lt;- data.frame(xmin = 3.5, xmax = 4.5, ymin = 223.5, ymax = 332)
my.lines.rect.3 &amp;lt;- data.frame(xmin = 5.5, xmax = 6.5, ymin = 223.5, ymax = 280.5)

p_adj + geom_rect(data=my.lines.rect.1, aes(xmin = xmin, xmax = xmax, 
            ymin = ymin, ymax = ymax), fill = NA, col = &amp;quot;black&amp;quot;, lty=2, inherit.aes = F) +
  geom_rect(data=my.lines.rect.2, aes(xmin = xmin, xmax = xmax, 
            ymin = ymin, ymax = ymax), fill = NA, col = &amp;quot;black&amp;quot;, lty=5, inherit.aes = F) +
  geom_rect(data=my.lines.rect.3, aes(xmin = xmin, xmax = xmax, 
            ymin = ymin, ymax = ymax), fill = NA, col = &amp;quot;black&amp;quot;, lty=4, inherit.aes = F)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/heatmap-3-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Much better.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;segmentation-in-a-scatterplot&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;5. Segmentation in a scatterplot&lt;/h2&gt;
&lt;p&gt;Finally, I want to try to implement some “basic-level clustering”. This is not model-based clustering; rather, it is simply using a scatterplot and a few nice plotting parameters in &lt;code&gt;ggplot2()&lt;/code&gt; to make some things pop right out at the viewer - again, with little room for ambiguity. What I like most here is the boxes that we can draw nicely to showcase the “clusters” a little better, along-with the multi-layered information, e.g., age, BMI, glucose, etc.&lt;/p&gt;
&lt;p&gt;The conclusions are logical and obvious from the following plot, but quite nicely illustrate the use of &lt;code&gt;ggplot2()&lt;/code&gt; for such a specific purpose.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;d$Age &amp;lt;- ifelse(d$age &amp;lt; 30, &amp;quot;&amp;lt;30 yrs&amp;quot;, &amp;quot;&amp;gt;= 30 yrs&amp;quot;)

ggplot(d, aes(x = glu, y = bmi)) +
  geom_rect(aes(linetype = &amp;quot;High BMI - Diabetic&amp;quot;), xmin = 160, ymax = 40, fill = NA, xmax = 200, 
            ymin = 25, col = &amp;quot;black&amp;quot;) + 
  geom_rect(aes(linetype = &amp;quot;Low BMI - Not Diabetic&amp;quot;), xmin = 0, ymax = 25, fill = NA, xmax = 120, 
            ymin = 10, col = &amp;quot;black&amp;quot;) + 
  geom_point(aes(col = factor(type), shape = factor(Age)), size = 3) +
  scale_color_brewer(name = &amp;quot;Type&amp;quot;, palette = &amp;quot;Set1&amp;quot;) +
  scale_shape(name = &amp;quot;Age&amp;quot;) +
  scale_linetype_manual(values = c(&amp;quot;High BMI - Diabetic&amp;quot; = &amp;quot;dotted&amp;quot;, &amp;quot;Low BMI - Not Diabetic&amp;quot; = &amp;quot;dashed&amp;quot;),
                        name = &amp;quot;Segment&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;/post/2017-08-14-end-to-end-visualization-using-ggplot2_files/figure-html/scatter-cluster-1.png&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Hopefully, this little exercise will be helpful for someone wanting to use &lt;code&gt;ggplot2()&lt;/code&gt; for an innovative slice/dice of a complex dataset, and to visualize it nicely.&lt;/p&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2017/08/14/end-to-end-visualization-using-ggplot2/&#39;;&lt;/script&gt;
      </description>
    </item>
    
    <item>
      <title>What is the tidyverse?</title>
      <link>https://rviews.rstudio.com/2017/06/08/what-is-the-tidyverse/</link>
      <pubDate>Thu, 08 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2017/06/08/what-is-the-tidyverse/</guid>
      <description>
        
&lt;!-- BLOGDOWN-HEAD --&gt;
&lt;!-- /BLOGDOWN-HEAD --&gt;

&lt;!-- BLOGDOWN-BODY-BEFORE --&gt;
&lt;!-- /BLOGDOWN-BODY-BEFORE --&gt;
&lt;p&gt;Last week, I had the opportunity to talk to a group of Master’s level &lt;a href=&#34;http://www.csueastbay.edu/about/institutional-effectiveness/educ-effectiveness/program-portfolios/cos/msstat/&#34;&gt;Statistics&lt;/a&gt; and &lt;a href=&#34;http://catalog.csueastbay.edu/preview_program.php?catoid=4&amp;amp;poid=1590&#34;&gt;Business Analytics&lt;/a&gt; students at Cal State East Bay about R and Data Science. Many in my audience were adult students coming back to school with job experience writing code in Java, Python and SAS. It was a pretty sophisticated crowd, but not surprisingly, their R skills were stitched together in a way that left some big gaps. Many for example, didn’t fully understand the importance of CRAN Task Views as curated source for the best packages to support their work in machine learning, time series and the other areas of Statistics they were studying. So, it made sense that even though &lt;code&gt;ggplot2&lt;/code&gt; and &lt;code&gt;dplyr&lt;/code&gt; were mentioned in some of the student’s questions, a faculty member present asked: “What is the tidyverse?” in an attempt to cover an area that he knew was one of those gaps.&lt;/p&gt;
&lt;p&gt;There is an incredible amount of good material available online about the tidyverse, and I will point to some of that below. But here, I’ll elaborate on the answer I gave during the Q&amp;amp;A.&lt;/p&gt;
&lt;div id=&#34;the-basics&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;The Basics&lt;/h2&gt;
&lt;p&gt;The tidyverse is a coherent system of packages for data manipulation, exploration and visualization that share a common design philosophy. These were mostly developed by Hadley Wickham himself, but they are now being expanded by several contributors. Tidyverse packages are intended to make statisticians and data scientists more productive by guiding them through workflows that facilitate communication, and result in reproducible work products. Fundamentally, the tidyverse is about the connections between the tools that make the workflow possible.&lt;/p&gt;
&lt;p&gt;It is also the case that the tidyverse is work in progress. You can find the current state of development at &lt;a href=&#34;http://tidyverse.org/&#34;&gt;tidyverse.org&lt;/a&gt;. Clicking on the icon for each package on this website will bring you to detailed documentation for each package. The following figure illustrates a canonical data science workflow, and shows how the individual packages fit in.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-06-09-What-is-the-tidyverse_files/tidyverse1.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;If you have some experience with R, you ought to be able to jump right into the online documentation and find your way around. If you are new to R, and maybe new to data science as well, you can’t do any better than work through the book &lt;a href=&#34;http://r4ds.had.co.nz/&#34;&gt;R for Data Science&lt;/a&gt; by Hadley Wickham and Garrett Grolemund.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;advantages&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Advantages&lt;/h2&gt;
&lt;p&gt;The advantages of the tidyverse include consistent functions, workflow coverage, a path to data science education, a parsimonious approach to the development of data science tools, and the possibility of greater productivity.&lt;/p&gt;
&lt;div id=&#34;consistency&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Consistency&lt;/h3&gt;
&lt;p&gt;The tidyverse aspires to consistency on multiple levels. Examples of “micro”-level consistency include the convention of having variable names glide along in &lt;code&gt;snake_case&lt;/code&gt;, and the signatures of tidyverse functions follow a regular pattern. (The first formal argument is always a data frame that provides the function’s input.) Higher-level consistency includes the idea of tidy data - a data frame where each row is an observation and each column contains the value of a single variable - and the way in which the pipe operator, &lt;code&gt;%&amp;gt;%&lt;/code&gt;, channels the flow of tidy operations. Under the covers, there are even more levels of structure that aid the pursuit of consistency, including uniform standards for package organization, testing procedures, coding style, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;coverage&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Coverage&lt;/h3&gt;
&lt;p&gt;The workflow shown above, with tidyverse packages associated with the various steps, or more usually rendered with the following iconic tidyverse diagram, preceded and motivated the development of the tidyverse.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2017-06-09-What-is-the-tidyverse_files/tidyverse2.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;It is an abstraction of the canonical data analysis workflow that has always guided statisticians, but now informs data science as a map to organize, streamline, automate and optimize the various processes involved. The fact that tidyverse packages are associate with all of the processes indicates that it comprises enough fundamental building blocks to support the entire end-to-end workflow for a variety of data sources and analysis goals. Moreover, the relatively recent addition of the &lt;code&gt;purrr&lt;/code&gt; package extends the reach of the tidyverse to support the creation of new data science tools.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;critical-mass&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Critical Mass&lt;/h3&gt;
&lt;p&gt;A great strength of the R language is that with over ten thousand user contributed packages on CRAN alone, it has a lot to offer. This kind of organic growth makes it inevitable that packages will offer overlapping features. Users have to make decisions about which package, or suite of packages, they will make the effort to learn. For many users, the decision hinges on whether a collection of packages visibly supports important work. Does it have a large community of users and is it backed by committed developers and maintainers? All of the signals indicate that (at least, among R-using data scientists) the tidyverse has reached critical mass. For example, the tidyverse package has been downloaded 50,000 times in the last month. Moreover, it appears that tidyverse principles are propagating into other application areas. The &lt;a href=&#34;http://www.business-science.io/code-tools/2017/01/01/tidyquant-introduction.html&#34;&gt;tidyquant package&lt;/a&gt;, for example, is a serious attempt to bring tidy principles to Finance.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;education&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Education&lt;/h3&gt;
&lt;p&gt;A typical R user gets involved with R in the first place through a desire to compute in some quantitative field. The path to R competency frequently begins with mastering a small number of relevant functions. Statisticians, for example, may learn to read in data from a &lt;code&gt;.csv&lt;/code&gt; file and build a linear regression model with &lt;code&gt;lm()&lt;/code&gt;. Financial analysts may be introduced to R through a package like &lt;code&gt;quantmod&lt;/code&gt;, which enables a new user to do quite a bit of real work. The tidyverse provides the path of least resistance, or “pit of success”, for data scientists interested in R. For example, the small number of compatible building blocks provided by dplyr enable even a relatively inexperienced user to tidy up a messy data set quickly and easily.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;parsimony&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Parsimony&lt;/h3&gt;
&lt;p&gt;The packages and functions of the tidyverse are the result of trial-and-error experimentation carried out over several years, to find a minimum set of functions that are sufficient to enable the canonical data science workflow. Those of you who have been following Hadley’s work will remember &lt;code&gt;cast()&lt;/code&gt; and &lt;code&gt;melt()&lt;/code&gt; from the &lt;code&gt;reshape&lt;/code&gt; and &lt;code&gt;reshape2&lt;/code&gt; packages, and &lt;code&gt;ddply()&lt;/code&gt; from the &lt;code&gt;plyr&lt;/code&gt; package, which were early attempts to find a vocabulary for wrangling data frames. After several attempts to identify and construct the most advantages set of primitive building blocks, the tidyverse has matured into its present form.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;productivity&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Productivity&lt;/h3&gt;
&lt;p&gt;Hadley has always been clear that a major goal for the tidyverse - and indeed much of his work over the years - has been to help anyone who needs to analyze data work productively, and he is fond of quoting &lt;a href=&#34;https://en.wikipedia.org/wiki/Hal_Abelson&#34;&gt;Hal Abelson&lt;/a&gt;: “Programs must be written for people to read and only incidentally for machines to execute”. My take is that a major reason for the popularity of tidyverse packages is that they help people achieve and maintain &lt;a href=&#34;https://en.wikipedia.org/wiki/Flow_(psychology)&#34;&gt;flow&lt;/a&gt; in their daily data analysis work.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;some-limitations&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Some Limitations&lt;/h2&gt;
&lt;p&gt;The tidyverse, of course, is not without limitations. Some of these are due to factors that are beyond the designer’s control, and others may be by design. Limitations of the first kind may arise from a lack of agreement as to whether some data can be, or should be, forced into a “rectangular” data structure. For example, although there are scientists and data scientists working in genomics that are fans of &lt;code&gt;dplyr&lt;/code&gt; and &lt;code&gt;ggplot2&lt;/code&gt;, much of the work done in the &lt;a href=&#34;https://www.bioconductor.org/&#34;&gt;Bioconductor Project&lt;/a&gt; remains outside of the tidyverse workflow.&lt;/p&gt;
&lt;p&gt;The need for the close coordination of tidyverse packages produces some limitations of the second sort. There are many high-quality R packages that are of great use to data scientists, but based on design goals that differ from those of the tidyverse. There will always be more than the tidyverse.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;a-bigger-picture&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;A Bigger Picture&lt;/h2&gt;
&lt;p&gt;A powerful, but perhaps under-appreciated, capability of the R language is its ability to support the design and programming of Domain Specific Languages. Joe Cheng highlighted this feature in an &lt;a href=&#34;https://rviews.rstudio.com/2017/01/04/interview-with-joe-cheng/&#34;&gt;interview&lt;/a&gt; he gave to R Views last year. He described R as being “shockingly close to LISP”, of which Joe says: “it’s almost like you change the language itself to be a DSL for whatever problem you’re trying to solve … the elegant, terse syntax of dplyr and the pipe operator are possible because of how malleable a language R is, and how great it is for writing DSLs in it.”&lt;/p&gt;
&lt;p&gt;So, from a wider perspective, the tidyverse can be seen as sub-dialect of the R language that is evolving to express ideas and tasks inherent in Data Science workflows and software development. This dialect may not be for everyone, but it does seem to be helping many R fluent data scientists frame their conversations.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;some-resources&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Some Resources&lt;/h2&gt;
&lt;p&gt;The following are some resources that you may find helpful in learning and mastering the tidyverse.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href=&#34;https://www.rstudio.com/resources/videos/data-science-in-the-tidyverse/&#34;&gt;video&lt;/a&gt; of Hadley Wickham’s Keynote address at rstudio::conf 2017&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href=&#34;https://github.com/rstudio/rstudio-conf/blob/master/2017/The_Tidyverse-Hadley_Wickham/tidyverse.pdf&#34;&gt;slides&lt;/a&gt; corresponding to the above video&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://r4ds.had.co.nz/&#34;&gt;R for Data Science&lt;/a&gt; by Hadley Wickham and Garrett Grolemund&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://tidytextmining.com/&#34;&gt;Text Mining with R&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.storybench.org/getting-started-with-tidyverse-in-r/&#34;&gt;Getting Started with the Tidyverse in R&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2017/06/08/what-is-the-tidyverse/&#39;;&lt;/script&gt;
      </description>
    </item>
    
  </channel>
</rss>
