This package allows R users to easily create a hierarchical edge bundle plot. The underlying D3 code was adapted from Mike Bostock’s examples (see here or here) and the package is based on the htmlwidgets framework.
Many thanks to timelyportfolio for some major improvements.
You can install edgebundleR
from Github using the
devtools
package as follows:
# install.packages("devtools")
devtools::install_github("garthtarr/edgebundleR")
Or you can get it on CRAN:
("edgebundleR") install.packages
(edgebundleR) require
The main function in the edgebundleR package is
edgebundle()
. It takes in a variety of inputs: - an igraph
object - a symmetric matrix, e.g. a correlation matrix or (regularised)
precision matrix - a JSON file structured with name
and
imports
as the keys
The result of the edgebundle()
function is a webpage
that is rendered in the RStudio Viewer pane by default, but also may be
exported to a self contained webpage, embedded in an Rmarkdown document
or used in a Shiny web application.
Given an igraph object as the input, the function will extract the linkages and plot them. For example,
(igraph)
require<- watts.strogatz.game(1, 50, 4, 0.05)
ws_graph (ws_graph,tension = 0.1,fontsize = 18,padding=40) edgebundle
Here’s a more complicated example adapted from this stackoverflow question and answer.
(igraph)
library(data.table)
library<- structure(list(ID = c("KP1009", "GP3040", "KP1757", "GP2243",
d "KP682", "KP1789", "KP1933", "KP1662", "KP1718", "GP3339", "GP4007",
"GP3398", "GP6720", "KP808", "KP1154", "KP748", "GP4263", "GP1132",
"GP5881", "GP6291", "KP1004", "KP1998", "GP4123", "GP5930", "KP1070",
"KP905", "KP579", "KP1100", "KP587", "GP913", "GP4864", "KP1513",
"GP5979", "KP730", "KP1412", "KP615", "KP1315", "KP993", "GP1521",
"KP1034", "KP651", "GP2876", "GP4715", "GP5056", "GP555", "GP408",
"GP4217", "GP641"),
= c("B", "A", "B", "A", "B", "B", "B",
Type "B", "B", "A", "A", "A", "A", "B", "B", "B", "A", "A", "A", "A",
"B", "B", "A", "A", "B", "B", "B", "B", "B", "A", "A", "B", "A",
"B", "B", "B", "B", "B", "A", "B", "B", "A", "A", "A", "A", "A",
"A", "A"),
= c(15L, 1L, 10L, 21L, 5L, 9L, 12L, 15L, 16L,
Set , 22L, 3L, 12L, 22L, 15L, 25L, 10L, 25L, 12L, 3L, 10L, 8L,
19L, 20L, 20L, 19L, 25L, 15L, 6L, 21L, 9L, 5L, 24L, 9L, 20L, 5L,
8L, 2L, 11L, 9L, 16L, 10L, 21L, 4L, 1L, 8L, 5L, 11L),
2L= c(3L, 2L, 3L, 1L, 3L, 3L, 3L, 1L, 2L,
Loc , 3L, 1L, 1L, 2L, 2L, 1L, 3L,
1L, 2L, 2L, 3L, 2L, 3L, 2L, 1L, 3L, 3L, 3L, 2L, 3L, 1L, 3L, 3L,
2L, 3L, 2L, 3L, 1L, 1L, 1L, 2L, 3L, 3L, 3L, 2L, 2L, 3L, 3L)),
1L= c("ID", "Type", "Set", "Loc"), class = "data.frame",
.Names = c(NA, -48L))
row.names # let's add Loc to our ID
<- d$ID
d$key <- paste0(d$Loc,".",d$ID)
d$ID # Get vertex relationships
sets <- unique(d$Set[duplicated(d$Set)])
<- vector("list", length(sets))
rel (i in 1:length(sets)) {
for [[i]] <- as.data.frame(t(combn(subset(d, d$Set ==sets[i])$ID, 2)))
rel}
<- rbindlist(rel)
rel # Get the graph
<- graph.data.frame(rel, directed=F, vertices=d)
g <- as.factor(V(g)$Loc)
clr (clr) <- c("salmon", "wheat", "lightskyblue")
levels(g)$color <- as.character(clr)
V(g)$size = degree(g)*5
V# igraph static plot
# plot(g, layout = layout.circle, vertex.label=NA)
( g ) edgebundle
(MASS)
require= kronecker(diag(3),matrix(2,5,5)) + 3*diag(15)
sig = MASS::mvrnorm(n=100,mu=rep(0,15),Sigma = sig)
X (X) = paste(rep(c("A.A","B.B","C.C"),each=5),1:5,sep="")
colnames(cor(X),cutoff=0.2,tension=0.8,fontsize = 14) edgebundle
Alternatively, you could do some regularisation and plot the results of that:
(huge)
require("stockdata")
data# generate returns sequences
= log(stockdata$data[2:1258,]/stockdata$data[1:1257,])
X # perform some regularisation
= huge(cor(X),method = "glasso",lambda=0.56,verbose = FALSE)
out.huge # identify the linkages
= as.matrix(out.huge$path[[1]])
adj.mat # format the colnames
= paste(gsub("","",stockdata$info[,2]),stockdata$info[,1],sep=".")
nodenames (cbind(stockdata$info[,2],stockdata$info[,1],nodenames))
head(adj.mat) = rownames(adj.mat) = nodenames
colnames# restrict attention to the connected stocks:
= adj.mat[rowSums(adj.mat)>0,colSums(adj.mat)>0]
adj.mat # plot the result
(adj.mat,tension=0.8,fontsize = 10) edgebundle
If you already have an appropriately formatted JSON file with
name
and imports
as the keys linking various
nodes, you can load it directly as follows:
= system.file("sampleData", "flare-imports.json", package = "edgebundleR")
filepath (filepath,width=800,fontsize=8,tension=0.95) edgebundle
In this example, the first few lines of the file are:
(paste("head -4",filepath)) system
[
{"name":"flare.analytics.cluster.AgglomerativeCluster","size":3938,"imports":["flare.animate.Transitioner","flare.vis.data.DataList","flare.util.math.IMatrix","flare.analytics.cluster.MergeEdge","flare.analytics.cluster.HierarchicalCluster","flare.vis.data.Data"]},
{"name":"flare.analytics.cluster.CommunityStructure","size":3812,"imports":["flare.analytics.cluster.HierarchicalCluster","flare.animate.Transitioner","flare.vis.data.DataList","flare.analytics.cluster.MergeEdge","flare.util.math.IMatrix"]},
{"name":"flare.analytics.cluster.HierarchicalCluster","size":6714,"imports":["flare.vis.data.EdgeSprite","flare.vis.data.NodeSprite","flare.vis.data.DataList","flare.vis.data.Tree","flare.util.Arrays","flare.analytics.cluster.MergeEdge","flare.util.Sort","flare.vis.operator.Operator","flare.util.Property","flare.vis.data.Data"]},
The important elements are the name
and
imports
keys. In the current implementation,
size
is ignored. Note the dots in the node names, these are
used to do the clustering. For example these first three nodes would all
appear grouped together in the graph as they all start with
flare.analytics.cluster
. You can have multiple levels of
clustering (hierarchical clustering) using different depths in the
naming convention. Any text after the final dot will be rendered as the
node label in the graph.
When running (recent versions of) RStudio, the default behaviour is for the plot to render in the Viewer pane. You should not specify the width and height parameters, as these will override the dynamic resizing behaviour.
For example, the following code would generate a plot that dynamically resizes to fit in the Viewer pane:
= watts.strogatz.game(1, 50, 4, 0.05)
ws_graph (ws_graph,tension = 0.1,fontsize = 20) edgebundle
You can open the graph in a web browser from RStudio using the “Show
in new window” icon. If you would like to save the webpage to share with
others, the best option is to use the saveEdgebundle
function:
= edgebundle(ws_graph,tension = 0.1,fontsize = 20,width=600,height=600)
g (g,file = "ws_graph.html") saveEdgebundle
This will create a fully self contained html file that renders reliably in most browsers.
Simply set the code chunk argument results='asis'
.
Using the shinyedge
function, you can interactively
adjust the font size, height/width and tension then export the graph to
a self contained html file. The input to the shinyedge
function is a JSON file, igraph object or symmetric matrix (the same as
the edgebundle
function).
= watts.strogatz.game(1, 100, 4, 0.05)
g1 (g1) shinyedge
If you are building your own Shiny app, you can use the standard
output and render functions: edgebundleOutput
and
renderEdgebundle
.
If you would like to save an image (png, jpeg or tiff) you can use the export drop down menu from the RStudio viewer pane. To save as a pdf, the easiest option is to view the graph in a web browser then print to pdf.