CRAN Dependency Graph
This article covers the technicalities behind the CRAN dependency graph visualisation.
Visualisation
The complete source code is available on Github, and is surprisingly simple. Below is the script used to to generate the visualisation. We'll break it down.
library(grapher)
library(tidygraph)
# get cran network data
deps <- cran_deps_graph(
Inf,
format = "igraph",
include_base_r = FALSE
)
# compute graph metrics
graph <- as_tbl_graph(deps) %>%
activate(nodes) %>%
mutate(
in_degree = centrality_degree(mode = "in")
)
# build and save graph
graph(graph) %>%
graph_offline_layout(steps = 75) %>%
hide_long_links(100) %>%
scale_node_size(in_degree, c(6, 50)) %>%
scale_link_color_coords(red = c(.1, 1)) %>%
save_graph_json("./assets/data/graph.json")
The first function called (cran_deps_graph
) generates the network of dependencies as igraph
object. Note that I purposely do not include base R packages (the likes of methods
or tools
) as 1) this visualisation is intended for the R community of open source developers, 2) R base packages are obviously used a lot and make the graph even more of a hairball than it already is, 3) finally they do not really bring new information to the graph and are thus best left out.
By default cran_deps_graph
includes three forms of dependencies: Depends, Imports, and LinkingTo. It purposely (perhaps wrongly—feedback welcome) Suggests as these, to my mind, indicate some kind of weaker dependency.
I then use tidygraph by Thomas Lin Pedersen (which I highly recommend) to compute in degree or in this case the number of packages that depend on each other packages.
Finally I build the graph using grapher. Note the use save_graph_json
to store the visualisation as JSON, we will read that file in the Shiny app (explained below). This is somewhat unconventional but helps immensely improve the performances in Shiny, you can read more about it in the Shiny guide.
App
I won't cover all the details of application, it's rather straight forward. I will only give a few tips in the event you want to produce something similar.
First, make the grapher visualisation take the entire screen with height = 100vh
in graphOutput
.
Make the directory containing graph.json
available to Shiny with addResourcePath
. and pass that path to grapher. This is explained in more details in the Shiny guide.
library(shiny)
library(grapher)
addResourcePath("prefix", "./assets")
ui <- fluidPage(
graphOutput("g", height = "100vh")
)
server <- function(input, output){
output$g <- render_graph({
graph("./prefix/data/graph.json")
})
}
shinyApp(ui, server)