1 Introduction

Bioconductor has a rich ecosystem of metadata around packages, usage, and build status. This package is a simple collection of functions to access that metadata from R in a tidy data format. The goal is to expose metadata for data mining and value-added functionality such as package searching, text mining, and analytics on packages.

Functionality includes access to :

2 Build reports

The Bioconductor build reports are available online as HTML pages. However, they are not very computable. The biocBuildReport function does some heroic parsing of the HTML to produce a tidy data.frame for further processing in R.

library(BiocPkgTools)
head(biocBuildReport())
## # A tibble: 6 x 9
##   pkg   author      version last_commit last_changed_date   node   stage  result
##   <chr> <chr>       <chr>   <chr>       <dttm>              <chr>  <chr>  <chr> 
## 1 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 malbe… insta… OK    
## 2 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 malbe… build… OK    
## 3 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 malbe… check… OK    
## 4 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 tokay1 insta… OK    
## 5 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 tokay1 build… OK    
## 6 a4    Laure Coug… 1.38.0  5b7a908     2020-10-27 10:41:25 tokay1 check… OK    
## # … with 1 more variable: bioc_version <chr>

2.1 Personal build report

Because developers may be interested in a quick view of their own packages, there is a simple function, problemPage, to produce an HTML report of the build status of packages matching a given author regex. The default is to report only “problem” build statuses (ERROR, WARNING).

problemPage()

When run in an interactive environment, the problemPage function will open a browser window for user interaction. Note that if you want to include all your package results, not just the broken ones, simply specify includeOK = TRUE.

3 Download statistics

Bioconductor supplies download stats for all packages. The biocDownloadStats function grabs all available download stats for all packages in all Experiment Data, Annotation Data, and Software packages. The results are returned as a tidy data.frame for further analysis.

head(biocDownloadStats())
## # A tibble: 6 x 7
##   Package  Year Month Nb_of_distinct_IPs Nb_of_downloads repo     Date      
##   <chr>   <int> <chr>              <int>           <int> <chr>    <date>    
## 1 ABarray  2021 Jan                   60             127 Software 2021-01-01
## 2 ABarray  2021 Feb                   51             139 Software 2021-02-01
## 3 ABarray  2021 Mar                   77             146 Software 2021-03-01
## 4 ABarray  2021 Apr                   24              42 Software 2021-04-01
## 5 ABarray  2021 May                    0               0 Software 2021-05-01
## 6 ABarray  2021 Jun                    0               0 Software 2021-06-01

The download statistics reported are for all available versions of a package. There are no separate, publicly available statistics broken down by version.

4 Package details

The R DESCRIPTION file contains a plethora of information regarding package authors, dependencies, versions, etc. In a repository such as Bioconductor, these details are available in bulk for all inclucded packages. The biocPkgList returns a data.frame with a row for each package. Tons of information are avaiable, as evidenced by the column names of the results.

bpi = biocPkgList()
colnames(bpi)
##  [1] "Package"               "Version"               "Depends"              
##  [4] "Suggests"              "License"               "MD5sum"               
##  [7] "NeedsCompilation"      "Title"                 "Description"          
## [10] "biocViews"             "Author"                "Maintainer"           
## [13] "git_url"               "git_branch"            "git_last_commit"      
## [16] "git_last_commit_date"  "Date/Publication"      "source.ver"           
## [19] "win.binary.ver"        "mac.binary.ver"        "vignettes"            
## [22] "vignetteTitles"        "hasREADME"             "hasNEWS"              
## [25] "hasINSTALL"            "hasLICENSE"            "Rfiles"               
## [28] "dependencyCount"       "Imports"               "Enhances"             
## [31] "dependsOnMe"           "VignetteBuilder"       "suggestsMe"           
## [34] "LinkingTo"             "Archs"                 "URL"                  
## [37] "SystemRequirements"    "BugReports"            "importsMe"            
## [40] "Video"                 "linksToMe"             "OS_type"              
## [43] "PackageStatus"         "License_restricts_use" "License_is_FOSS"      
## [46] "organism"

Some of the variables are parsed to produce list columns.

head(bpi)
## # A tibble: 6 x 46
##   Package  Version Depends  Suggests License MD5sum   NeedsCompilation Title    
##   <chr>    <chr>   <list>   <list>   <chr>   <chr>    <chr>            <chr>    
## 1 a4       1.38.0  <chr [5… <chr [6… GPL-3   2ab2a7b… no               Automate…
## 2 a4Base   1.38.0  <chr [2… <chr [4… GPL-3   0ca9c7e… no               Automate…
## 3 a4Class… 1.38.0  <chr [2… <chr [4… GPL-3   9e4fb68… no               Automate…
## 4 a4Core   1.38.0  <chr [1… <chr [2… GPL-3   138cb05… no               Automate…
## 5 a4Prepr… 1.38.0  <chr [1… <chr [4… GPL-3   6baf7e2… no               Automate…
## 6 a4Repor… 1.38.0  <chr [1… <chr [2… GPL-3   89870e9… no               Automate…
## # … with 38 more variables: Description <chr>, biocViews <list>, Author <list>,
## #   Maintainer <list>, git_url <chr>, git_branch <chr>, git_last_commit <chr>,
## #   git_last_commit_date <chr>, Date/Publication <chr>, source.ver <chr>,
## #   win.binary.ver <chr>, mac.binary.ver <chr>, vignettes <list>,
## #   vignetteTitles <list>, hasREADME <chr>, hasNEWS <chr>, hasINSTALL <chr>,
## #   hasLICENSE <chr>, Rfiles <list>, dependencyCount <chr>, Imports <list>,
## #   Enhances <list>, dependsOnMe <list>, VignetteBuilder <chr>,
## #   suggestsMe <list>, LinkingTo <list>, Archs <list>, URL <chr>,
## #   SystemRequirements <chr>, BugReports <chr>, importsMe <list>, Video <chr>,
## #   linksToMe <list>, OS_type <chr>, PackageStatus <chr>,
## #   License_restricts_use <chr>, License_is_FOSS <chr>, organism <chr>

As a simple example of how these columns can be used, extracting the importsMe column to find the packages that import the GEOquery package.

require(dplyr)
bpi = biocPkgList()
bpi %>% 
    filter(Package=="GEOquery") %>%
    pull(importsMe) %>%
    unlist()
##  [1] "bigmelon"              "ChIPXpress"            "coexnet"              
##  [4] "crossmeta"             "EGAD"                  "GAPGOM"               
##  [7] "MACPET"                "minfi"                 "MoonlightR"           
## [10] "phantasus"             "recount"               "SRAdb"                
## [13] "BeadArrayUseCases"     "geneExpressionFromGEO" "MetaIntegrator"

5 Package Explorer

For the end user of Bioconductor, an analysis often starts with finding a package or set of packages that perform required tasks or are tailored to a specific operation or data type. The biocExplore() function implements an interactive bubble visualization with filtering based on biocViews terms. Bubbles are sized based on download statistics. Tooltip and detail-on-click capabilities are included. To start a local session:

biocExplore()

6 Dependency graphs

The Bioconductor ecosystem is built around the concept of interoperability and dependencies. These interdependencies are available as part of the biocPkgList() output. The BiocPkgTools provides some convenience functions to convert package dependencies to R graphs. A modular approach leads to the following workflow.

  1. Create a data.frame of dependencies using buildPkgDependencyDataFrame.
  2. Create an igraph object from the dependency data frame using buildPkgDependencyIgraph
  3. Use native igraph functionality to perform arbitrary network operations. Convenience functions, inducedSubgraphByPkgs and subgraphByDegree are available.
  4. Visualize with packages such as visNetwork.

6.1 Working with dependency graphs

A dependency graph for all of Bioconductor is a starting place.

library(BiocPkgTools)
dep_df = buildPkgDependencyDataFrame()
g = buildPkgDependencyIgraph(dep_df)
g
## IGRAPH 749a6e9 DN-- 3537 32456 -- 
## + attr: name (v/c), edgetype (e/c)
## + edges from 749a6e9 (vertex names):
##  [1] a4           ->a4Base      a4           ->a4Preproc  
##  [3] a4           ->a4Classif   a4           ->a4Core     
##  [5] a4           ->a4Reporting a4Base       ->a4Preproc  
##  [7] a4Base       ->a4Core      a4Classif    ->a4Core     
##  [9] a4Classif    ->a4Preproc   ABAEnrichment->R          
## [11] abseqR       ->R           ABSSeq       ->R          
## [13] ABSSeq       ->methods     acde         ->R          
## [15] acde         ->boot        ACE          ->R          
## + ... omitted several edges
library(igraph)
head(V(g))
## + 6/3537 vertices, named, from 749a6e9:
## [1] a4            a4Base        a4Classif     ABAEnrichment abseqR       
## [6] ABSSeq
head(E(g))
## + 6/32456 edges from 749a6e9 (vertex names):
## [1] a4    ->a4Base      a4    ->a4Preproc   a4    ->a4Classif  
## [4] a4    ->a4Core      a4    ->a4Reporting a4Base->a4Preproc

See inducedSubgraphByPkgs and subgraphByDegree to produce subgraphs based on a subset of packages.

See the igraph documentation for more detail on graph analytics, setting vertex and edge attributes, and advanced subsetting.

6.2 Graph visualization

The visNetwork package is a nice interactive visualization tool that implements graph plotting in a browser. It can be integrated into shiny applications. Interactive graphs can also be included in Rmarkdown documents (see vignette)

igraph_network = buildPkgDependencyIgraph(buildPkgDependencyDataFrame())

The full dependency graph is really not that informative to look at, though doing so is possible. A common use case is to visualize the graph of dependencies “centered” on a package of interest. In this case, I will focus on the GEOquery package.

igraph_geoquery_network = subgraphByDegree(igraph_network, "GEOquery")

The subgraphByDegree() function returns all nodes and connections within degree of the named package; the default degree is 1.

The visNework package can plot igraph objects directly, but more flexibility is offered by first converting the graph to visNetwork form.

library(visNetwork)
data <- toVisNetworkData(igraph_geoquery_network)

The next few code chunks highlight just a few examples of the visNetwork capabilities, starting with a basic plot.

visNetwork(nodes = data$nodes, edges = data$edges, height = "500px")

For fun, we can watch the graph stabilize during drawing, best viewed interactively.

visNetwork(nodes = data$nodes, edges = data$edges, height = "500px") %>%
    visPhysics(stabilization=FALSE)

Add arrows and colors to better capture dependencies.

data$edges$color='lightblue'
data$edges[data$edges$edgetype=='Imports','color']= 'red'
data$edges[data$edges$edgetype=='Depends','color']= 'green'

visNetwork(nodes = data$nodes, edges = data$edges, height = "500px") %>%
    visEdges(arrows='from') 

Add a legend.

ledges <- data.frame(color = c("green", "lightblue", "red"),
  label = c("Depends", "Suggests", "Imports"), arrows =c("from", "from", "from"))
visNetwork(nodes = data$nodes, edges = data$edges, height = "500px") %>%
  visEdges(arrows='from') %>%
  visLegend(addEdges=ledges)

6.3 Integration with BiocViews

[Work in progress]

The biocViews package is a small ontology of terms describing Bioconductor packages. This is a work-in-progress section, but here is a small example of plotting the biocViews graph.

library(biocViews)
data(biocViewsVocab)
biocViewsVocab
## A graphNEL graph with directed edges
## Number of Nodes = 489 
## Number of Edges = 488
library(igraph)
g = igraph.from.graphNEL(biocViewsVocab)
library(visNetwork)
gv = toVisNetworkData(g)
visNetwork(gv$nodes, gv$edges, width="100%") %>%
    visIgraphLayout(layout = "layout_as_tree", circular=TRUE) %>%
    visNodes(size=20) %>%
    visPhysics(stabilization=FALSE)

7 Dependency burden

The dependency burden of a package, namely the amount of functionality that a given package is importing, is an important parameter to take into account during package development. A package may break because one or more of its dependencies have changed the part of the API our package is importing or this part has even broken. For this reason, it may be useful for package developers to quantify the dependency burden of a given package. To do that we should first gather all dependency information using the function buildPkgDependencyDataFrame() but setting the arguments to work with packages in Bioconductor and CRAN and dependencies categorised as Depends or Imports, which are the ones installed by default for a given package.

library(BiocPkgTools)

depdf <- buildPkgDependencyDataFrame(repo=c("BioCsoft", "CRAN"),
                                     dependencies=c("Depends", "Imports"))
depdf
## # A tibble: 116,360 x 3
##    Package       dependency  edgetype
##    <chr>         <chr>       <chr>   
##  1 a4            a4Base      Depends 
##  2 a4            a4Preproc   Depends 
##  3 a4            a4Classif   Depends 
##  4 a4            a4Core      Depends 
##  5 a4            a4Reporting Depends 
##  6 a4Base        a4Preproc   Depends 
##  7 a4Base        a4Core      Depends 
##  8 a4Classif     a4Core      Depends 
##  9 a4Classif     a4Preproc   Depends 
## 10 ABAEnrichment R           Depends 
## # … with 116,350 more rows

Finally, we call the function pkgDepMetrics() to obtain different metrics on the dependency burden of a package we want to analyze, in the case below, the package BiocPkgTools itself:

pkgDepMetrics("BiocPkgTools", depdf)
##               ImportedAndUsed Exported Usage DepOverlap DepGainIfExcluded
## utils                       1      215  0.47       0.01                 0
## rlang                       4      476  0.84       0.02                 0
## graph                       1      116  0.86       0.08                 0
## readr                       1      110  0.91       0.23                 3
## igraph                      9      782  1.15       0.12                 4
## RBGL                        1       77  1.30       0.10                 0
## htmltools                   1       72  1.39       0.07                 0
## xml2                        1       66  1.52       0.01                 0
## tidyr                       1       62  1.61       0.25                 1
## magrittr                    1       41  2.44       0.01                 0
## dplyr                       7      285  2.46       0.24                 0
## DT                          1       39  2.56       0.21                 4
## httr                        3       91  3.30       0.11                 0
## tidyselect                  1       25  4.00       0.10                 0
## tibble                      2       42  4.76       0.18                 0
## jsonlite                    1       17  5.88       0.01                 0
## htmlwidgets                 1       14  7.14       0.11                 0
## rvest                       3       40  7.50       0.36                 2
## gh                          1       10 10.00       0.18                 3
## stringr                     5       49 10.20       0.08                 0
## rex                         2       16 12.50       0.02                 1
## BiocManager                 1        5 20.00       0.02                 0
## BiocFileCache              NA       27    NA       0.52                12
## biocViews                  NA       31    NA       0.19                 6
## rappdirs                   NA        7    NA       0.01                 0
## tools                      NA      119    NA       0.01                 0

In this resulting table, rows correspond to dependencies and columns provide the following information:

The reported information is ordered by the Usage column to facilitate the identification of dependencies for which the analyzed package is using a small fraction of their functionality and therefore, it could be easier remove them. To aid in that decision, the column DepOverlap reports the overlap of the dependency graph of each dependency with the one of the analyzed package. Here a value above, e.g., 0.5, could, albeit not necessarily, imply that removing that dependency could substantially lighten the dependency burden of the analyzed package.

An NA value in the ImportedAndUsed column indicates that the function pkgDepMetrics() could not identify what functionality calls in the analyzed package are made to the dependency. This may happen because pkgDepMetrics() has failed to identify the corresponding calls, as it happens with imported built-in constants such as DNA_BASES from Biostrings, or that although the given package is importing that dependency, none of its functionality is actually being used. In such a case, this dependency could be safely removed without any further change in the analyzed package.

We can find out what actually functionality calls are we importing as follows:

imp <- pkgDepImports("BiocPkgTools")
imp %>% filter(pkg == "DT")
## # A tibble: 1 x 2
##   pkg   fun      
##   <chr> <chr>    
## 1 DT    datatable

8 Provenance

sessionInfo()
## R version 4.0.5 (2021-03-31)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.5 LTS
## 
## Matrix products: default
## BLAS:   /home/biocbuild/bbs-3.12-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.12-bioc/R/lib/libRlapack.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C              
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] biocViews_1.58.1   visNetwork_2.0.9   igraph_1.2.6       dplyr_1.0.5       
## [5] BiocPkgTools_1.8.2 htmlwidgets_1.5.3  knitr_1.32         BiocStyle_2.18.1  
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.6           tidyr_1.1.3          ps_1.6.0            
##  [4] assertthat_0.2.1     digest_0.6.27        utf8_1.2.1          
##  [7] BiocFileCache_1.14.0 R6_2.5.0             stats4_4.0.5        
## [10] RSQLite_2.2.6        evaluate_0.14        httr_1.4.2          
## [13] pillar_1.6.0         rlang_0.4.10         lazyeval_0.2.2      
## [16] curl_4.3             rstudioapi_0.13      jquerylib_0.1.3     
## [19] blob_1.2.1           DT_0.18              RUnit_0.4.32        
## [22] rmarkdown_2.7        readr_1.4.0          stringr_1.4.0       
## [25] selectr_0.4-2        RCurl_1.98-1.3       bit_4.0.4           
## [28] compiler_4.0.5       xfun_0.22            pkgconfig_2.0.3     
## [31] BiocGenerics_0.36.0  htmltools_0.5.1.1    tidyselect_1.1.0    
## [34] tibble_3.1.0         bookdown_0.21        XML_3.99-0.6        
## [37] fansi_0.4.2          dbplyr_2.1.1         crayon_1.4.1        
## [40] rappdirs_0.3.3       bitops_1.0-6         RBGL_1.66.0         
## [43] jsonlite_1.7.2       lifecycle_1.0.0      DBI_1.1.1           
## [46] magrittr_2.0.1       graph_1.68.0         cli_2.4.0           
## [49] stringi_1.5.3        cachem_1.0.4         rex_1.2.0           
## [52] xml2_1.3.2           bslib_0.2.4          ellipsis_0.3.1      
## [55] generics_0.1.0       vctrs_0.3.7          gh_1.2.1            
## [58] tools_4.0.5          bit64_4.0.5          Biobase_2.50.0      
## [61] glue_1.4.2           purrr_0.3.4          hms_1.0.0           
## [64] fastmap_1.1.0        parallel_4.0.5       yaml_2.2.1          
## [67] BiocManager_1.30.12  rvest_1.0.0          memoise_2.0.0       
## [70] sass_0.3.1