Visualizing R Function Dependencies
Asked Answered
D

4

24

There are a lot of resources for people who want to visualize package dependencies, but I'm interested specifically in visualizing functions within a package and their dependencies on one another. There are tools like miniCRAN for graphing package dependencies, but is there anything available to graph function dependencies within a package?

For example, suppose I only have two functions in my package.

func1 <- function(n) return(LETTERS[n])
func2 <- function(n) return(func1(n%%26+1))

Then I would just want a graph with two labeled nodes and an edge connecting them, depicting the dependency of func2 on func1.

I would think there are a lot of packages out there that have really hairy functional dependencies that such a utility could help in understanding/organizing/refactoring/etc.

Thanks.

Dialectical answered 23/5, 2017 at 19:5 Comment(0)
D
29

I think a better option (built on top of the mvbutil package's foodweb functions) is the DependenciesGraph package built by datastorm-open on Github on top of their more general visNetwork package.

  • DependenciesGraph : an R package for dependencies visualization between packages and functions

In my example, I have been visualizing my own package for maintenance and development and have been very pleased with the results.

library(DependenciesGraph)
library(QualtricsTools) # A package I'm developing
deps <- funDependencies("package:QualtricsTools", "generate_split_coded_comments")
plot(deps)

Dependency Graph generated by DependenciesGraph

The output is a web server (either viewed in RStudio's viewer or in a separate browser) that allows you to choose specific functions through a drop down or by clicking on them, to zoom in and out, to drag them around, and so forth. To me, this is much nicer than using base R to plot the output of the foodweb function because often it is difficult to get the text to look nice displayed on top of each node, all the edges are jarringly colored differently in a foodweb plot, and it doesn't appear to me that the base R plot functions are doing very much to ensure that the layout of the plot is readable or clear.

A comparison against mvbutil's foodweb:

library(mvbutils)
library(QualtricsTools) 
deps <- foodweb(where="package:QualtricsTools", prune='make_split_coded_comments')
plot(deps)

A foodweb dependency graph of make_split_coded_comments

(Sorry there's a discrepancy in the names, they really are the same function, I just happened to have renamed the function between making these two plots).

Dialectical answered 10/7, 2017 at 15:36 Comment(0)
N
9

I suggest using the foodweb function from mvbutils package.

e <- new.env()
e$func1 <- function(n) return(LETTERS[n])
e$func2 <- function(n) return(func1(n%%26+1))

library(mvbutils)
foodweb(where = e)

See examples under ?mvbutils for more.

Novelette answered 23/5, 2017 at 19:31 Comment(2)
Thank you! This is helpful. Do you know if there is a way to make the text smaller, or increase the zoom without adjusting the window size? When I run it on the package I'm working on, it's way too crammed together to read: i.imgur.com/yiL9NIU.pngDialectical
I found the answer to my above comment in the documentation for foodweb. They say if it's unreadable (like mine) to run foodweb( .Last.value, cex=<<something below 1>>, charlim=<<something probably less than 100>>)Dialectical
O
6

For the sake of completeness, and as a shameless plug, I'm developing another package to address this: foodwebr. The DependenciesGraphs package does not appear to have been updated for several years and I find the output of mvbutils::foodweb() hard to parse. All three packages use the same dependency detection algorithm under the hood.

Using the original example:

e <- new.env()
e$func1 <- function(n) return(LETTERS[n])
e$func2 <- function(n) return(func1(n%%26+1))

fw <- foodwebr::foodweb(env = e)

fw
#> # A `foodweb`: 2 vertices and 1 edge 
#> digraph 'foodweb' {
#>   func1()
#>   func2() -> { func1() }
#> }

Calling plot() shows the graph (can't upload images as this is my first post):

plot(fw)

You can also use tidygraph::as_tbl_graph() to create a tidygraph object, which gives you more plotting and analysis options.

tidy_fw <- tidygraph::as_tbl_graph(fw)

tidy_fw
#> # A tbl_graph: 2 nodes and 1 edges
#> #
#> # A rooted tree
#> #
#> # Node Data: 2 x 1 (active)
#>   name 
#>   <chr>
#> 1 func1
#> 2 func2
#> #
#> # Edge Data: 1 x 2
#>    from    to
#>   <int> <int>
#> 1     2     1

The package is still in development but you can use devtools::install_github("lewinfox/foodwebr") to give it a go.

Orthoclase answered 31/5, 2021 at 23:1 Comment(2)
This looks interesting, @Lewin! However I'm having issues installing your package, getting error: Error: Failed to install 'unknown package' from GitHub: Line starting '<U+FEFF><!DOCTYPE HT ...' is malformed!"?Altricial
Hi @AlexanderKielland - I checked on my laptop and was able to install OK using install_github(). That error looks like the beginning of a HTML file, are you trying this from inside a corporate or university network? You may be hitting a firewall block page of some kind. I've created a release on GitHub here: github.com/lewinfox/foodwebr/releases/tag/v0.1.1 - you could try downloading that and installing from the zip file. Feel free to email me at <lewin dot a dot f at gmail dot com> if you like. Would love to get some feedback on the package!Orthoclase
E
2

The more recent pkgdepR R package does just that! And it can also create the same network with a vector of packages.

pkgdepR is on CRAN so you can install it with install.packages("pkgdepR"). To use it on, e.g., pkgdepR itself, you can run:

library(pkgdepR)
v <- deps(pkg = "pkgdepR")
plot(v)

pkgdepR output of itself: a network visualisation of how the different functions relate to one another in this package

Edelmiraedelson answered 4/12, 2023 at 15:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.