<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/introduction-to-ggraph-edges/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.data-imaginist.com/2017/ggraph-introduction-edges/"> Data Imaginist - R posts</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>This is the third post in my series of <code>ggraph</code> introductions. The<br>
<a target="_blank" rel="nofollow" href="http://www.data-imaginist.com/2017/ggraph-introduction-layouts/">first</a> post introduced<br>
the concept of layouts, which is simply a specification on how nodes should be<br>
placed on a plane. The <a target="_blank" rel="nofollow" href="http://www.data-imaginist.com/2017/ggraph-introduction-nodes/">second</a><br>
explained how to draw nodes using the <code>geom_node_*()</code> family. This post will<br>
connect the dots, so to speak, by introducing the concept of edges.</p>
<h2>Edges</h2>
<p>If the natural <code>ggplot2</code> equivalent to nodes is <code>geom_point()</code>, then surely the<br>
equivalent to edges must be <code>geom_segment()</code>? Well, sort of, but there’s a bit<br>
more to it than that.</p>
<p><img alt="One does not simply draw a line between two nodes" src="https://i2.wp.com/www.data-imaginist.com/assets/images/edge_meme_wide.jpg?w=456" data-recalc-dims="1"></p>
<p>While nodes are the sensible, mature, and predictably geoms, edges are the edgy<br>
(sorry), younger cousins that pushes the boundaries. To put it bluntly:</p>
<blockquote>
<p>On the ggraph savannah you definetly want to be an edge!</p>
</blockquote>
<h3>Meet the <code>geom_edge_*()</code> family</h3>
<p>While the introduction might feel a bit over-the-top it is entirely true. An<br>
edge is an abstract concept denoting a relationship between two enteties. A<br>
straight line is simply just one of many ways this relationship can be<br>
visualised. As we saw when <a target="_blank" rel="nofollow" href="http://www.data-imaginist.com/2017/ggraph-introduction-nodes/">discussing nodes</a><br>
sometimes it is not drawn at all but impied using containment or position<br>
(treemap, circle packing, and partition layouts), but more often it is shown<br>
using a line of some sort. This use-case is handled by the large family of edge<br>
geoms provided in <code>ggraph</code>. Some of the edges are general while others are<br>
dedicated to specific layouts. Lets creates some graphs for illustrary purpose<br>
first:</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>ggraph</span><span>)</span><span>
</span><span>library</span><span>(</span><span>igraph</span><span>)</span><span>
</span><span>hierarchy</span><span> </span><span>&lt;-</span><span> </span><span>as.dendrogram</span><span>(</span><span>hclust</span><span>(</span><span>dist</span><span>(</span><span>iris</span><span>[,</span><span> </span><span>1</span><span>:</span><span>4</span><span>])))</span><span>
</span><span># Classify nodes based on agreement between children
</span><span>hierarchy</span><span> </span><span>&lt;-</span><span> </span><span>tree_apply</span><span>(</span><span>hierarchy</span><span>,</span><span> </span><span>function</span><span>(</span><span>node</span><span>,</span><span> </span><span>children</span><span>,</span><span> </span><span>...</span><span>)</span><span> </span><span>{</span><span>
</span><span>if</span><span> </span><span>(</span><span>is.leaf</span><span>(</span><span>node</span><span>))</span><span> </span><span>{</span><span>
</span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'Class'</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>as.character</span><span>(</span><span>iris</span><span>[</span><span>as.integer</span><span>(</span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'label'</span><span>)),</span><span>5</span><span>])</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span>
</span><span>classes</span><span> </span><span>&lt;-</span><span> </span><span>unique</span><span>(</span><span>sapply</span><span>(</span><span>children</span><span>,</span><span> </span><span>attr</span><span>,</span><span> </span><span>which</span><span> </span><span>=</span><span> </span><span>'Class'</span><span>))</span><span>
</span><span>if</span><span> </span><span>(</span><span>length</span><span>(</span><span>classes</span><span>)</span><span> </span><span>==</span><span> </span><span>1</span><span> </span><span>&amp;&amp;</span><span> </span><span>!</span><span>anyNA</span><span>(</span><span>classes</span><span>))</span><span> </span><span>{</span><span>
</span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'Class'</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>classes</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span>
</span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'Class'</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>NA</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'nodePar'</span><span>)</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>attr</span><span>(</span><span>node</span><span>,</span><span> </span><span>'Class'</span><span>))</span><span>
</span><span>node</span><span>
</span><span>},</span><span> </span><span>direction</span><span> </span><span>=</span><span> </span><span>'up'</span><span>)</span><span>
</span><span>hairball</span><span> </span><span>&lt;-</span><span> </span><span>graph_from_data_frame</span><span>(</span><span>highschool</span><span>)</span><span>
</span><span># Classify nodes based on popularity gain
</span><span>pop1957</span><span> </span><span>&lt;-</span><span> </span><span>degree</span><span>(</span><span>delete_edges</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>which</span><span>(</span><span>E</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>year</span><span> </span><span>==</span><span> </span><span>1957</span><span>)),</span><span> </span><span>mode</span><span> </span><span>=</span><span> </span><span>'in'</span><span>)</span><span>
</span><span>pop1958</span><span> </span><span>&lt;-</span><span> </span><span>degree</span><span>(</span><span>delete_edges</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>which</span><span>(</span><span>E</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>year</span><span> </span><span>==</span><span> </span><span>1958</span><span>)),</span><span> </span><span>mode</span><span> </span><span>=</span><span> </span><span>'in'</span><span>)</span><span>
</span><span>V</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>pop_devel</span><span> </span><span>&lt;-</span><span> </span><span>ifelse</span><span>(</span><span>pop1957</span><span> </span><span>&lt;</span><span> </span><span>pop1958</span><span>,</span><span> </span><span>'increased'</span><span>,</span><span>
</span><span>ifelse</span><span>(</span><span>pop1957</span><span> </span><span>></span><span> </span><span>pop1958</span><span>,</span><span> </span><span>'decreased'</span><span>,</span><span> </span><span>'unchanged'</span><span>))</span><span>
</span><span>V</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>popularity</span><span> </span><span>&lt;-</span><span> </span><span>pmax</span><span>(</span><span>pop1957</span><span>,</span><span> </span><span>pop1958</span><span>)</span><span>
</span><span>E</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>year</span><span> </span><span>&lt;-</span><span> </span><span>as.character</span><span>(</span><span>E</span><span>(</span><span>hairball</span><span>)</span><span>$</span><span>year</span><span>)</span></code></pre>
</figure>
<h4>Link</h4>
<p>While you don’t have to use a straight line for edges it is certainly possible<br>
and <code>geom_edge_link()</code> is here to serve your needs:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'kk'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-3-1.png?w=456" data-recalc-dims="1"></p>
<p>There’s really not much more to it — every edge is simply a straight line<br>
between the terminal nodes. Moving on…</p>
<h4>Fan</h4>
<p>Sometimes the graph is not simple, i.e. it has multiple edges between the same<br>
nodes. Using links is a bad choice here because edges will overlap and the<br>
viewer will be unable to discover parallel edges. <code>geom_edge_fan()</code> got you<br>
covered here. If there are no parallel edges it behaves like <code>geom_edge_link()</code><br>
and draws a straight line, but if parallel edges exists it will spread them out<br>
as arcs with different curvature. Parallel edges will be sorted by<br>
directionality prior to plotting so edges flowing in the same direction will be<br>
plottet together:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'kk'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_fan</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i1.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-4-1.png?w=456" data-recalc-dims="1"></p>
<h4>Loops</h4>
<p>Loops cannot be shown with regular edges as they have no length. A dedicated<br>
<code>geom_edge_loop()</code> exists for these cases:</p>
<figure>
<pre><code data-lang="r"><span># let's make some of the student love themselves
</span><span>loopy_hairball</span><span> </span><span>&lt;-</span><span> </span><span>add_edges</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>rep</span><span>(</span><span>1</span><span>:</span><span>5</span><span>,</span><span> </span><span>each</span><span>=</span><span>2</span><span>),</span><span> </span><span>year</span><span> </span><span>=</span><span> </span><span>rep</span><span>(</span><span>'1957'</span><span>,</span><span> </span><span>5</span><span>))</span><span>
</span><span>ggraph</span><span>(</span><span>loopy_hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'kk'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>),</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.25</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_loop</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-5-1.png?w=456" data-recalc-dims="1"></p>
<p>The direction, span, and strength of the loop can all be controlled, but in<br>
general loops will add a lot of visual clutter to your plot unless the graph is<br>
very simple.</p>
<h4>Density</h4>
<p>This one is definetly strange, and I’m unsure of it’s usefulness, but it is here<br>
and it deserves an introduction. Consider the case where it is of interest to<br>
see which types of edges dominates certain areas of the graph. You can colour<br>
the edges, but edges can tend to get overplotted, thus reducing readability.<br>
<code>geom_edge_density()</code> lets you add a shading to your plot based on the density<br>
of edges in a certain area:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'kk'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_density</span><span>(</span><span>aes</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.25</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-6-1.png?w=456" data-recalc-dims="1"></p>
<h4>Arcs</h4>
<p>While some insists that curved edges should be used in standard <em>“hairball”</em><br>
graph visualisations it really is a poor choice, as it increases overplotting<br>
and interpretability for virtually no gain (unless complexiness is your thing).<br>
That doesn’t mean arcs have no use in graph visualizations. Linear and circular<br>
layouts can benefit greatly from them and <code>geom_edge_arc()</code> is provided<br>
precisely for this scenario:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'linear'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_arc</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-7-1.png?w=456" data-recalc-dims="1"></p>
<p>Arcs behave differently in circular layouts as they will always bend towards<br>
the center no matter the direction of the edge (the same thing can be achieved<br>
in a linear layout by setting <code>fold = TRUE</code>).</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'linear'</span><span>,</span><span> </span><span>circular</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_arc</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span><span> </span><span>+</span><span> </span><span>coord_fixed</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-8-1.png?w=456" data-recalc-dims="1"></p>
<h4>Elbow</h4>
<p>Aah… The classic dendrogram with its right angle bends. Of course such<br>
visualizations are also supported with the <code>geom_edge_elbow()</code>. It goes without<br>
saying that this type of edge requires a layout that flows in a defined<br>
direction, such as a dendrogram:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hierarchy</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'dendrogram'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_elbow</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-9-1.png?w=456" data-recalc-dims="1"></p>
<h4>Diagonals</h4>
<p>If right angles aren’t really your thing <code>ggraph</code> provides a smoother version in<br>
the form of <code>geom_edge_diagonal()</code>. This edge is a quadratic bezier with control<br>
points positioned at the same x-value as the terminal nodes and halfway<br>
in-between the nodes on the y-axis. The result is more organic than the elbows:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hierarchy</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'dendrogram'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_diagonal</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i1.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-10-1.png?w=456" data-recalc-dims="1"></p>
<p>It tend to look a bit weird with hugely unbalanced trees so use with care…</p>
<h4>Hive</h4>
<p>This is certainly a very specific type of edge, intended only for use with hive<br>
plots. It draws edges as quadratic beziers with control point positioned<br>
perpendicular to the axes of the hive layout:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'hive'</span><span>,</span><span> </span><span>axis</span><span> </span><span>=</span><span> </span><span>'pop_devel'</span><span>,</span><span> </span><span>sort.by</span><span> </span><span>=</span><span> </span><span>'popularity'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_hive</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_axis_hive</span><span>()</span><span> </span><span>+</span><span> </span><span>coord_fixed</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-11-1.png?w=456" data-recalc-dims="1"></p>
<h2>The three types of edge geoms</h2>
<p>Almost all edge geoms comes in three variants. The basic variant (no suffix) as<br>
well as the variant suffixed with 2 (e.g. <code>geom_edge_link2()</code>) calculates a<br>
number (<code>n</code>) of points along the edge and draws it as a path. The variant<br>
suffixed with 0 (e.g. <code>geom_edge_diagonal0()</code>) uses the build in grid grobs to<br>
draw the edges directly (in case of a diagonal it uses <code>bezierGrob()</code>). It might<br>
seem strange to have so many different implementations of the same geoms but<br>
there’s a reason to the insanity…</p>
<h3>Base variant</h3>
<p>The basic edge geom is drawn by calculating a number of points along the edge<br>
path and draw a line between these. This means that you’re in control of the<br>
detail level of curved edges and that all complex calculations happens up front.<br>
Generally you will see better performance using the base variant rather than the<br>
0-variant that uses grid grobs, unless you set the number of points to calculate<br>
to something huge (50–100 is usually sufficient for a smooth look). Apart from<br>
better performance you also get a nice bonus (you actually get several, but only<br>
one is discussed here): The possibility of drawing a gradient along the edge.<br>
Each calculated point gets an index value between 0 and 1 that specifies how<br>
far along the edge it is positioned and this value can be used to e.g. map to<br>
an alpha level to show the direction of the edge:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hairball</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'linear'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_arc</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>year</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>..index..</span><span>))</span><span> </span><span>+</span><span> </span><span>scale_edge_alpha</span><span>(</span><span>'Edge direction'</span><span>,</span><span> </span><span>guide</span><span> </span><span>=</span><span> </span><span>'edge_direction'</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-12-1.png?w=456" data-recalc-dims="1"></p>
<h3>2-variant</h3>
<p>Like the base variant the 2-variant calculates points along the edge and draws<br>
a path along them. The difference here is that in this variant you can map node<br>
attributes to the edge and the aesthetics are then interpolated along the edge.<br>
This is easier to show than to explain:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>hierarchy</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'dendrogram'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_elbow2</span><span>(</span><span>aes</span><span>(</span><span>colour</span><span> </span><span>=</span><span> </span><span>node.class</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-13-1.png?w=456" data-recalc-dims="1"></p>
<p>There are considerably more computation going on than in the base variant so<br>
unless you need to interpolate values between the terminal nodes you should go<br>
with the base variant.</p>
<h3>0-variant</h3>
<p>This is, sadly, the boring one at the end. You don’t get the luxury of smooth<br>
gradients over the edge and often you have a considerably worse performance.<br>
What you gain though is tack sharp resolution in the curves so if this is of<br>
utmost importance you are covered by this variant.</p>
<h2>Decorating edges</h2>
<p>An edge is so much more than a line… Well at least it is also potentially an<br>
arrow and a label. This section will go into how these can be added. To clearly<br>
see the effect here we will use a slightly simpler graph</p>
<figure>
<pre><code data-lang="r"><span>simple</span><span> </span><span>&lt;-</span><span> </span><span>make_graph</span><span>(</span><span>'bull'</span><span>)</span><span>
</span><span># Random names - I swear
</span><span>V</span><span>(</span><span>simple</span><span>)</span><span>$</span><span>name</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>'Thomas'</span><span>,</span><span> </span><span>'Bob'</span><span>,</span><span> </span><span>'Hadley'</span><span>,</span><span> </span><span>'Winston'</span><span>,</span><span> </span><span>'Baptiste'</span><span>)</span><span>
</span><span>E</span><span>(</span><span>simple</span><span>)</span><span>$</span><span>type</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>c</span><span>(</span><span>'friend'</span><span>,</span><span> </span><span>'foe'</span><span>),</span><span> </span><span>5</span><span>,</span><span> </span><span>TRUE</span><span>)</span></code></pre>
</figure>
<h3>Arrows</h3>
<p>While we saw above that direction can be encoded as a gradient, the good old<br>
arrow is still available. As with the standard <code>ggplot2</code> geoms an arrow can be<br>
added using the arrow argument:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'graphopt'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)))</span><span> </span><span>+</span><span> </span><span>geom_node_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i1.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-15-1.png?w=456" data-recalc-dims="1"></p>
<p>I hope you think <em>Ugh</em> at the sight of this. The edges naturally extend to the<br>
node center and nodes are thus drawn on top of the arrow heads. There’s a<br>
solution to this in the form of the <code>start_cap</code> and <code>end_cap</code> aesthetics in the<br>
base and 2-variant edge geoms (sorry 0-variant). This can be used to start and<br>
stop the edge drawing at an absolut distance from the terminal nodes. Wath this:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'graphopt'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)),</span><span> </span><span>end_cap</span><span> </span><span>=</span><span> </span><span>circle</span><span>(</span><span>3</span><span>,</span><span> </span><span>'mm'</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_node_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i1.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-16-1.png?w=456" data-recalc-dims="1"></p>
<p>Using the <code>circle()</code>, <code>square()</code>, <code>ellipsis()</code>, and <code>rectangel()</code> helpers it is<br>
possible to get a lot of control over how edges are capped at either end. This<br>
works for any edge, curved or not:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'linear'</span><span>,</span><span> </span><span>circular</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_arc</span><span>(</span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)),</span><span> </span><span>start_cap</span><span> </span><span>=</span><span> </span><span>circle</span><span>(</span><span>3</span><span>,</span><span> </span><span>'mm'</span><span>),</span><span>
</span><span>end_cap</span><span> </span><span>=</span><span> </span><span>circle</span><span>(</span><span>3</span><span>,</span><span> </span><span>'mm'</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_node_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>)</span><span> </span><span>+</span><span> </span><span>coord_fixed</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-17-1.png?w=456" data-recalc-dims="1"></p>
<p>When plotting node labels you often want to avoid that incoming and outgoing<br>
edges overlaps with the labels. <code>ggraph</code> provides a helper that calculates the<br>
bounding rectangle of the labels and cap edges based on that:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'graphopt'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>aes</span><span>(</span><span>start_cap</span><span> </span><span>=</span><span> </span><span>label_rect</span><span>(</span><span>node1.name</span><span>),</span><span>
</span><span>end_cap</span><span> </span><span>=</span><span> </span><span>label_rect</span><span>(</span><span>node2.name</span><span>)),</span><span> </span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)))</span><span> </span><span>+</span><span> </span><span>geom_node_text</span><span>(</span><span>aes</span><span>(</span><span>label</span><span> </span><span>=</span><span> </span><span>name</span><span>))</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-18-1.png?w=456" data-recalc-dims="1"></p>
<p>The capping of edges is dynamic and responds to resizing of the plot so the<br>
absolute size of the cap areas are maintained at all time.</p>
<h4>A quick note on directionality</h4>
<p>In <code>ggraph</code> there is no such thing as an undirected graph. Every edge has a<br>
start and an end node. For undirected graphs the start and end of edges is<br>
arbitrary but still exists and it is thus possible to add arrowheads to<br>
undirected graphs as well. This should not be done of course, but this is the<br>
responsibility of the user as <code>ggraph</code> does not make any checks during<br>
rendering.</p>
<h3>Labels</h3>
<p>You would expect that edge labels would be their own geom(s), but <code>ggraph</code><br>
departs from the stringent grammar interpretation here. This is because the<br>
label placement is dependent on the choice of edge. Because of this edge<br>
labeling is bundled with each edge geom (but not the 0-variant) through the<br>
label aesthetic</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'graphopt'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>aes</span><span>(</span><span>label</span><span> </span><span>=</span><span> </span><span>type</span><span>),</span><span> </span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)),</span><span> </span><span>end_cap</span><span> </span><span>=</span><span> </span><span>circle</span><span>(</span><span>3</span><span>,</span><span> </span><span>'mm'</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_node_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i2.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-19-1.png?w=456" data-recalc-dims="1"></p>
<p>Usually you would like the labels to run along the edges, but providing a<br>
fixed angle will only work at a very specific aspect ratio. Instead <code>ggraph</code><br>
offers to calculate the correct angle dynamically so the labels always runs<br>
along the edge. Furthermore it can offset the label by an absolute length:</p>
<figure>
<pre><code data-lang="r"><span>ggraph</span><span>(</span><span>simple</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'graphopt'</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_edge_link</span><span>(</span><span>aes</span><span>(</span><span>label</span><span> </span><span>=</span><span> </span><span>type</span><span>),</span><span> </span><span>angle_calc</span><span> </span><span>=</span><span> </span><span>'along'</span><span>,</span><span>
</span><span>label_dodge</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>2.5</span><span>,</span><span> </span><span>'mm'</span><span>),</span><span>
</span><span>arrow</span><span> </span><span>=</span><span> </span><span>arrow</span><span>(</span><span>length</span><span> </span><span>=</span><span> </span><span>unit</span><span>(</span><span>4</span><span>,</span><span> </span><span>'mm'</span><span>)),</span><span> </span><span>end_cap</span><span> </span><span>=</span><span> </span><span>circle</span><span>(</span><span>3</span><span>,</span><span> </span><span>'mm'</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_node_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>)</span></code></pre>
</figure>
<p><img alt="center" src="https://i1.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-20-1.png?w=456" data-recalc-dims="1"></p>
<p><code>ggraph</code> offers a lot of additional customization of the edge labels but this<br>
shows the main features. As with arrowheads labels can severely clutter your<br>
visualization so it is only advisable on very simple graphs.</p>
<h2>Connections</h2>
<p>The estranged cousin of edges are connections. While edges show the relational<br>
nature of the nodes in the graph structure, connections connect nodes that are<br>
not connected in the graph. This is done by finding the shortest path between<br>
the two nodes. Currently the only connection geom available is<br>
<code>geom_conn_bundle()</code> that implements the hierarchical edge bundling techinque:</p>
<figure>
<pre><code data-lang="r"><span>flaregraph</span><span> </span><span>&lt;-</span><span> </span><span>graph_from_data_frame</span><span>(</span><span>flare</span><span>$</span><span>edges</span><span>,</span><span> </span><span>vertices</span><span> </span><span>=</span><span> </span><span>flare</span><span>$</span><span>vertices</span><span>)</span><span>
</span><span>from</span><span> </span><span>&lt;-</span><span> </span><span>match</span><span>(</span><span>flare</span><span>$</span><span>imports</span><span>$</span><span>from</span><span>,</span><span> </span><span>flare</span><span>$</span><span>vertices</span><span>$</span><span>name</span><span>)</span><span>
</span><span>to</span><span> </span><span>&lt;-</span><span> </span><span>match</span><span>(</span><span>flare</span><span>$</span><span>imports</span><span>$</span><span>to</span><span>,</span><span> </span><span>flare</span><span>$</span><span>vertices</span><span>$</span><span>name</span><span>)</span><span>
</span><span>ggraph</span><span>(</span><span>flaregraph</span><span>,</span><span> </span><span>layout</span><span> </span><span>=</span><span> </span><span>'dendrogram'</span><span>,</span><span> </span><span>circular</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_conn_bundle</span><span>(</span><span>data</span><span> </span><span>=</span><span> </span><span>get_con</span><span>(</span><span>from</span><span> </span><span>=</span><span> </span><span>from</span><span>,</span><span> </span><span>to</span><span> </span><span>=</span><span> </span><span>to</span><span>),</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.1</span><span>)</span><span> </span><span>+</span><span> </span><span>coord_fixed</span><span>()</span></code></pre>
</figure>
<p><img alt="center" src="https://i0.wp.com/www.data-imaginist.com/assets/images/2017-02-16-ggraph-introduction-edges/unnamed-chunk-21-1.png?w=456" data-recalc-dims="1"></p>
<p>The connection concept is underutilized at the moment but I expect to add more<br>
support for this in comming releases.</p>
<h2>The end</h2>
<p>This concludes my tour of the main features of <code>ggraph</code> — I hope you are all<br>
well prepared to take your network visualizations to the next level!</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://www.data-imaginist.com/2017/ggraph-introduction-edges/"> Data Imaginist - R posts</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 title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/8I0QLzJFrMI"></a></div>