Skip to content

Instantly share code, notes, and snippets.

@Rekyt
Last active March 11, 2020 16:16
Show Gist options
  • Save Rekyt/261c2c3040715dcd8c211d7f5d18c9c8 to your computer and use it in GitHub Desktop.
Save Rekyt/261c2c3040715dcd8c211d7f5d18c9c8 to your computer and use it in GitHub Desktop.
Plot dependency network copy-pasted from https://gist.github.com/crsh/c906e93c260488e7363ea606243057c2 but considered all dependencies
#' Plot network of package dependencies
#'
#' @param pkg package description, can be path or package name.
#' See \code{\link[devtools]{as.package}} for more information.
#' @param type which packages should be included in the network
#'
#' @details The resulting plot visualizes the network of package dependencies.
#' If you are trying to cut down on package dependencies look for big red
#' dots that represent a lot of upstream but few downstream dependencies.
#' @import ggplot2
#' @export
#'
#' @examples
plot_dependencies <- function(pkg = ".", type = c("imports", "suggests",
"full")) {
library("devtools")
library("miniCRAN")
library("igraph")
library("ggplot2")
library("ggnetwork")
type = match.arg(type)
pkg <- devtools::as.package(pkg)
if (type != "full") {
dependencies <- unlist(strsplit(pkg[[type]], split = "\n"))
} else {
dependencies <- unlist(strsplit(c(pkg$imports, pkg$suggests),
split = "\n"))
}
dependencies <- gsub("\\n| \\(.+\\)|,", "", dependencies)
dependency_graph <- miniCRAN::makeDepGraph(dependencies, suggests = FALSE,
enhances = FALSE)
class(dependency_graph) <- "igraph"
dependency_graph <- dependency_graph + igraph::vertices(pkg$package) +
igraph::edges(as.vector(rbind(dependencies, pkg$package)))
dependency_graph <- igraph::simplify(dependency_graph)
edge_list <- igraph::get.edgelist(dependency_graph)
dependency_graph <- igraph::graph(rbind(edge_list[, 2], edge_list[, 1]))
dependency_graph_df <- ggnetwork::ggnetwork(
dependency_graph,
arrow.gap = 0.025
)
dependency_graph_df$package <- dependency_graph_df$name
dependency_graph_df$face <- ifelse(dependency_graph_df$package == pkg$package,
"bold", "plain")
dependency_graph_df$n_dependencies <- as.vector(
table(gsub("\\|.+", "",
attr(igraph::E(dependency_graph),
"vnames")))[as.character(dependency_graph_df$package)])
dependency_graph_df$n_dependencies[
is.na(dependency_graph_df$n_dependencies)] <- 0
dependency_graph_df$importance <- as.vector(
table(gsub(".+\\|", "",
attr(E(dependency_graph),
"vnames")))[as.character(dependency_graph_df$package)])
dependency_graph_df$importance[is.na(dependency_graph_df$importance)] <- 0
max_downstream_deps <- max(dependency_graph_df$importance)
dependency_graph_df$importance <- dependency_graph_df$importance /
max_downstream_deps
dependency_graph_df$importance <- abs(1 - dependency_graph_df$importance)
dependency_graph_df <- as.data.frame(lapply(dependency_graph_df, as.vector))
ggplot(dependency_graph_df, aes(x = x, y = y, xend = xend, yend = yend)) +
geom_nodes(aes(color = n_dependencies), size = 6.5, alpha = 0.4) +
geom_edges(arrow = arrow(length = unit(4, "pt"), type = "closed"),
color = grey(0.4)) +
geom_nodelabel_repel(
aes(label = package, fontface = face, color = n_dependencies)
, box.padding = unit(8, "pt")
) +
geom_nodes(aes(color = n_dependencies, size = 7 * importance)) +
scale_color_viridis_c(option = "inferno", end = 0.9) +
scale_size(labels = function(x) {
abs(max_downstream_deps - ceiling(x / 7 * max_downstream_deps))
}) +
theme_blank(legend.position = "top") +
guides(
size = guide_legend(title = "Downstream dependencies",
title.position = "top", title.hjust = 0.5,
label.position = "bottom", label.hjust = 0.5),
color = guide_colorbar(title = "Upstream dependencies",
title.position = "top", title.hjust = 0.5,
barwidth = unit(130, "pt"),
barheight = unit(4, "pt"))
)
}
@Rekyt
Copy link
Author

Rekyt commented Feb 11, 2019

I did not author this code! @crsh did https://gist.github.com/crsh/c906e93c260488e7363ea606243057c2 but there was a problem with the gist that did not consider all dependencies. Thus I changed a small bit of the function.

@Rekyt
Copy link
Author

Rekyt commented Feb 14, 2019

In the second revision I added a type argument to plot_dependencies() that can be:

  • imports to only show the network with packages listed as Imports in the DESCRIPTION file,
  • suggests to only show the network with packages listed as Suggests in the DESCRIPTION file,
  • full to show the network of dependencies with packages listed both as Imports and Suggests in the DESCRIPTION file.

@Rekyt
Copy link
Author

Rekyt commented Feb 14, 2019

in the third revision:

  • I changed the color scale to use viridis plasma scale in order to better see the network,
  • I wrap the lines to be less than 80 characters long for easier reading.

@Rekyt
Copy link
Author

Rekyt commented Feb 14, 2019

In the fourth revision:

  • I changed the color scale to viridis inferno and set a maximum relative scale of 0.9 to avoid the pale yellow/white colors that are difficult to distinguish on white background.

@Rekyt
Copy link
Author

Rekyt commented Mar 11, 2020

In the fifth revision:

  • change layout to be clearer

@Rekyt
Copy link
Author

Rekyt commented Mar 11, 2020

In the sixth revision:

  • change argument name to cope with ggnetwork::fortify.igraph()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment