Nothing
#' @name get_dependencies
#' @title Get (reverse) dependencies of a set of packages
#' @description
#' Get (reverse) dependencies of a set of packages till a certain
#' depth(`level`) for a set of dependency types (`relation`).
#' @param packages (`chr`) Package names
#' @param level (`count(1)`) Depth of recursive dependency
#' @param relation (`chr`) Types of relations. Must be a subset of
#' c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances")
#' @param strict (`flag[T]`) Whether to consider all packages
#' (alternately only 'relation' specific packages) when computing dependencies
#' for the next level.
#' @param ignore (`chr`) package names to ignore.
#' @param reverse (`flag[F]`) Whether to get reverse dependencies.
#' @return (`dataframe`) with three columns: `pkg_1`, `relation` and `pkg_2`
#' @examples
#' \dontrun{
#' init()
#' get_dependencies("mlr3") |>
#' get_dependencies("mlr3", level = 2)
#' get_dependencies("mlr3", level = 2, reverse = TRUE)
#' get_dependencies("mlr3", level = 2, relation = "Imports")
#' # setting strict to TRUE to only consider 'Imports' of the previous level
#' get_dependencies("mlr3",
#' level = 2,
#' relation = "Imports",
#' strict = TRUE
#' )
#' }
#' @seealso [get_neighborhood]
#' @export
get_dependencies = function(packages,
level = 1L,
relation = c("Depends",
"Imports",
"LinkingTo",
"Suggests",
"Enhances"
),
strict = FALSE,
ignore = c("datasets",
"utils",
"grDevices",
"graphics",
"stats",
"methods"
),
reverse = FALSE
){
# assertions
if (!exists("deptable")){
rlang::abort("Unable to find `deptable`. Did you run `init`?")
}
assert_character(packages, min.len = 1, unique = TRUE)
assert_count(level)
assert_character(relation, min.len = 1)
relation_chr = c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances")
assert_subset(relation, relation_chr)
assert_flag(strict)
assert_character(ignore)
assert_flag(reverse)
relation2 = relation_chr
if (strict) relation2 = relation
# loop over 'level'
ell = length(relation2)
for (it in seq_along(1:level)){
if (reverse){
res = filter(deptable, pkg_2 %in% packages)
} else {
res = filter(deptable, pkg_1 %in% packages)
}
# filter depending on 'strict'
if (strict) res = filter(res, relation %in% relation2)
# handle ignore
if (length(ignore) > 0){
res = filter(res, !(pkg_1 %in% ignore) & !(pkg_2 %in% ignore))
}
packages = base::union(res[["pkg_1"]], res[["pkg_2"]])
}
res =
res |>
# always filter for relation (strict only affects inside the loop)
filter(relation %in% !!relation) |>
arrange(relation, pkg_1, pkg_2)
return(res)
}
#' @name get_neighborhood
#' @title Obtain dependencies and reverse dependencies of a set of packages
#' @description Obtain dependencies and reverse dependencies of packages till a
#' given depth (`level`) for a set of dependency types (`relation`).
#' @param packages (`chr`) Package names
#' @param level (`count[1]`) Depth of recursive dependency
#' @param relation (`chr`) Types of relations. Must be a subset of
#' c("Depends", "Imports", "LinkingTo", "Suggests", "Enhances")
#' @param strict (`flag[T]`) Whether to consider all packages
#' (alternately only 'relation' specific packages) when computing dependencies
#' for the next level
#' @param ignore (`chr`) Package names to ignore.
#' @return (`dataframe`) three columns: `pkg_1`, `relation` and `pkg_2`
#' @examples
#' \dontrun{
#' init()
#' # explore first level dependencies
#' get_neighborhood("mlr3")
#'
#' # explore second level dependencies
#' get_neighborhood("caret", level = 2)
#'
#' # explore first level dependencies of multiple packages
#' # and consider second level dependencies
#' get_neighborhood(c("caret", "mlr"))
#'
#' # get 'imports' specific neighborhood of 'mlr'
#' get_neighborhood("mlr", relation = "Imports")
#' }
#' @seealso [get_dependencies]
#' @export
get_neighborhood = function(packages,
level = 1L,
relation = c("Depends",
"Imports",
"LinkingTo",
"Suggests",
"Enhances"
),
strict = FALSE,
ignore = c("datasets",
"utils",
"grDevices",
"graphics",
"stats",
"methods"
)
){
# get direct dependencies
dep_df = get_dependencies(packages,
level = level,
relation = relation,
strict = strict,
ignore = ignore,
reverse = FALSE
)
# get reverse dependencies
rev_df = get_dependencies(packages,
level = level,
relation = relation,
strict = strict,
ignore = ignore,
reverse = TRUE
)
# get interconnects
pkgs_chr = Reduce(base::union,
list(dep_df[["pkg_1"]],
dep_df[["pkg_2"]],
rev_df[["pkg_1"]],
rev_df[["pkg_2"]]
)
)
# filter with AND
interconnect_df =
deptable |>
filter(pkg_1 %in% pkgs_chr,
pkg_2 %in% pkgs_chr,
relation %in% !!relation
)
res =
bind_rows(dep_df, rev_df, interconnect_df) |>
distinct() |>
arrange(relation, pkg_1, pkg_2)
return(res)
}
#' @name as_graph
#' @title Get igraph object from a dataframe representing package dependencies
#' @description Packages dependencies (typically obtained from
#' [get_dependencies()] or [get_neighborhood()]) is converted into a
#' [igraph](https://cran.r-project.org/package=igraph) object.
#' @param dependency_df (`dataframe`) Representing package dependencies
#' @returns igraph object
#' @examples
#' \dontrun{
#' init()
#' as_graph(get_neighborhood("mlr3"))
#' }
#' @export
as_graph = function(dependency_df){
assert_data_frame(dependency_df)
assert_subset(c("pkg_1", "relation", "pkg_2"), colnames(dependency_df))
# create
ng = igraph::graph_from_data_frame(dependency_df[ , c("pkg_1","pkg_2")],
directed = TRUE
)
# add attr
ng = igraph::set_edge_attr(graph = ng,
name = "relation",
value = as.character(dependency_df[["relation"]])
)
package_title_df =
tibble::tibble(
"Package" = base::union(dependency_df$pkg_1, dependency_df$pkg_2)) |>
left_join(select(packmeta, Package, Title), by = "Package") |>
select(Package, Title)
ng = igraph::set_vertex_attr(graph = ng,
name = "title",
value = package_title_df$Title,
index = package_title_df$Package
)
class(ng) = c("neighborhood_graph", class(ng))
return(ng)
}
#' @name plot.neighborhood_graph
#' @title Static plot of package dependencies
#' @description Plot of packages dependencies or neighborhood with edges colored
#' by `relation` and node sized by 'centrality' from a `neighborhood_graph`
#' obtained from [as_graph].
#' @param x neighborhood_graph
#' @param layout layout is passed to [ggraph::ggraph]
#' @param ... Not used
#' @returns ggraph plot
#' @examples
#' \dontrun{
#' init()
#' get_neighborhood("mboost") |>
#' as_graph() |>
#' plot()
#' }
#' @export
plot.neighborhood_graph = function(x, layout = "sugiyama", ...){
colors = c(
"Imports" = "darkblue",
"Depends" = "darkgreen",
"LinkingTo" = "grey",
"Suggests" = "orange",
"Enhances" = "pink"
)
po =
tidygraph::as_tbl_graph(x) |>
mutate(cen = tidygraph::centrality_eigen()) |>
ggraph(layout = layout) +
geom_edge_link(aes(edge_color = relation),
arrow = arrow(type = "closed", )
) +
geom_node_point(aes(size = cen)) +
geom_node_label(aes(label = name), repel = TRUE) +
scale_edge_color_manual(values = colors)
return(po)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.