DiagrammeR with VivaGraphJS
Kent Russell
2015-05-22
Way back in my first real post on this blog Week 01 | Easy Flowcharts and Diagrams ~ DiagrammeR, we announced DiagrammeR
. Since then, DiagrammeR
’s author Rich Iannone has amazed me with his efforts to improve, grow, and document (truly something special) the package. DiagrammeR
began with mermaid
(mermaid.js
) and then quickly added grViz
(viz.js
/graphviz
) as two methods to both layout and render diagrams specified as text.
Even with all the dedicated efforts by Rich Iannone, there are still many ways DiagrammeR
can improve, but much of the improvement depends on some determination of the strategic direction for DiagrammeR
. What I think Rich would like is a cohesive set of functionality that allows users easy access to multiple layout engines and interactive renderers while also leveraging strengths of existing R functionality. With this in mind, areas of improvement can be grouped in three ways:
- interoperability within
DiagrammeR
-mermaid
is completely separate and isolated fromgrViz
with their own unique specification. - interoperability with
R
-R
is loaded with packages that could benefitDiagrammeR
. One example is networks. Diagrams arent always networks, but very often networks become diagrams.DiagrammeR
’s support of networks in non-text form, such asigraph
, does not exist. - interactivity - Technically, a user can achieve interactivity in
DiagrammeR
, but only if the user has a thorough understanding of JavaScript. Incorporating ideas and features like those in the newhtmlwidget
package visNetwork would provide a very robust and interactive aesthetic result.
Does VivaGraphJS fit in?
Does the very nice JavaScript library VivaGraphJS
/ngraph
from Andrei Kashcha fit in DiagrammeR
? Adding VivaGraphJS
gives DiagrammeR
a interactive rendering engine focused on networks. If possible, combining VivaGraphJS
and grViz
could prove very powerful and synergystic. Similarly, VivaGraphJS
could offer nice functionality to igraph
and other R
network packages.
I should note that Keeghan Hines already started an htmlwidget
implementation vivagRaph
that encouraged me to explore this further. Thanks so much to Keeghan for his work here.
Seed for Iteration
Since learning often occurs best by doing, we’ll start with a new function vivagraph
as our seed for iteration. Hopefully, it will give us some insight into new features, better coordination, additional interactivity, more network support, leveraging of existing R layouts, and additional unforeseen use cases. Let’s see some examples with the first rough draft of vivagraph
.
Installation
We are not entirely sure how this will be incorporated, so currently vivagraph
exists in its own Github branch. To test out vivagraph
, please install as shown below. Note, existing functionality in DiagrammeR
will be unaffected, so nothing should break.
devtools::install_github( "timelyportfolio/DiagrammeR@feature/vivagraphjs" )
With create_graph
from DiagrammeR
Rich Iannone has put quite a bit of effort into graph building functions that don’t require knowledge of the specialized field of networks. Here is an example using create_graph
to build our nodes and edges but rendering with vivagraph
.
## please see install step above
library( DiagrammeR )
## use example create_graph from DiagrammeR documentation
## http://rich-iannone.github.io/DiagrammeR/graphs.html
###
# Create a graph
###
nodes <-
create_nodes(nodes = LETTERS,
type = "letter",
shape = sample(c("circle", "rectangle"),
length(LETTERS),
replace = TRUE),
fillcolor = sample(c("aqua", "gray80",
"pink", "lightgreen",
"azure", "yellow"),
length(LETTERS),
replace = TRUE))
edges <-
create_edges(edge_from = sample(LETTERS, replace = TRUE),
edge_to = sample(LETTERS, replace = TRUE),
relationship = "letter_to_letter")
graph <-
create_graph(nodes_df = nodes,
edges_df = edges,
graph_attrs = "layout = neato",
node_attrs = c("fontname = Helvetica",
"style = filled"),
edge_attrs = c("color = gray20",
"arrowsize = 0.5"))
vivagraph( nodes, edges )
You might notice some interactivity that we don’t get with grViz
. However, you will also probably notice that vivagraph
is not aware of the styling, etc. that we applied on our nodes and edges. This is definitely on the roadmap for future development.
With igraph
network
DiagrammeR
does not have any built-in handlers for igraph
and other powerful R
network packages. vivagraph
does try to smartly handle igraph
network graphs.
library( DiagrammeR )
library( igraph )
# plot one of the graph.famous from igraph
vivagraph( graph.famous( "Franklin" ) )
You might notice as above that any styling, etc. is not currently supported, but as above, this is definitely on the roadmap.
If you love igraph
layouts though, you should definitely like this. In the examples above we used the default forceDirected
layout from VivaGraphJS
, but vivagraph
can also use positions defined by layout.*
.
vivagraph( graph.famous( "Franklin" ), layout = layout.circle )
And here is an igraph
plot for reference using layout.circle
, so vivagraph
leverages the layout engine while also adding interactivity and in the future various node types and styling.
plot( graph.famous( "Franklin" ), layout = layout.circle )
Let’s see a couple more to illustrate.
vivagraph( graph.famous( "Dodecahedron" ), layout = layout.grid )
vivagraph( graph.famous( "Herschel" ), layout = layout.fruchterman.reingold )
grViz with igraph layout
As an example how we learn by doing, I discovered that grViz
could also use igraph
for layouts. Even though there is no vivagraph
in here, let’s look at how we could eventually realize interoperability within DiagrammeR
. Our diagram will get some additional help from graphviz splines
and overlap
. You can see this at work by closely comparing the bottom of our grViz
diagram with the reference igraph
plot below.
library(DiagrammeR)
library(igraph)
library(pipeR)
#### use igraph example from documentation
actors <- data.frame(
name=c("Alice", "Bob", "Cecil", "David", "Esmeralda")
, age=c(48,33,45,34,21)
, gender=c("F","M","F","M","F")
)
relations <- data.frame(
from=c("Bob", "Cecil", "Cecil", "David", "David", "Esmeralda")
, to=c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice")
, same.dept=c(FALSE,FALSE,TRUE,FALSE,FALSE,TRUE)
, friendship=c(4,5,5,2,1,1), advice=c(4,5,5,4,2,3)
)
g <- graph.data.frame(relations, directed=TRUE, vertices=actors)
## use igraph layout for positions
g_layout <- layout.grid(g)
## now plot with DiagrammeR using igraph layout positions
## but use graphviz splines and overlap handling
g %>>%
get.data.frame( what = "both" ) %>>%
(
# DiagrammeR create_graph helper function
create_graph(
data.frame(
nodes = rownames(.$vertices)
,.$vertices
,x = g_layout[,1] # define our x from the igraph layout
,y = g_layout[,2] # define our y from the igraph layout
)
,.$edges
,graph_attrs = 'splines="true" overlap = "scale" label = "igraph + grViz"'
)
) %>>%
(
grViz( .$dot_code, engine="neato" )
)
Let’s compare to the default igraph
plot.
plot( g, layout = g_layout)
Thoughts and Conclusion
Even if VivaGraphJS
does not fit in DiagrammeR
, DiagrammeR
can improve by learning from a VivaGraphJS
experimental implementation. Please give us thoughts, feedback, use cases to help us determine the future direction of DiagrammeR
.
Thanks
Thanks so much
VivaGraphJS
from Andrei Kashcha- Keeghan Hines for his initial implementation vivagRaph
- Rich Iannone for his dedicated and admirable work on
DiagrammeR
- Ramnath Vaidyanathan and RStudio for
htmlwidgets
- all the contributors to
R
andJavaScript