# RedeR: bridging network analysis and visualization

Sysbiolab - Bioinformatics and Systems Biology Laboratory.

#### 2024-10-30

#### Abstract

RedeR is an R-based package combined with a stand-alone Java application for interactive visualization and manipulation of nested networks. Graph, node, and edge attributes are set either using graphical or command-line methods following igraph syntax rules. The RedeR/R package sets all details to initialize the R-to-Java interface, which uses an interactive force-directed layout algorithm, adjusting the graph layout to the hierarchical levels of a nested network. Supporting information is available from Castro et al. (2016).

#### Package

RedeR 3.2.0

# 1 Overview

RedeR is an R-based package combined with a Java application for network analysis and visualization. RedeR is designed to deal with three key challenges in network analysis. Firstly, biological networks are modular and hierarchical, so network visualization needs to take advantage of such structural features. Secondly, network analysis relies on statistical methods, many of which are already available in resources like CRAN or Bioconductor. Thirdly, in larger networks user input is needed to focus the view of the network on the biologically relevant parts, rather than relying on an automatic layout function. The graphical user interface is depicted in Figure 1.

Figure 1: RedeR's graphical user interface
The startRedeR() function initiates the R-to-Java interface. RedeR (\(\geq\) 3) will need the Java Runtime Environment (JRE) version 11 (Java \(\geq\) 11). To verify the Java version on your system, please refer to the system requirements section.

# 2 Quick start

    #--- Load required packages
    library("RedeR")
    library("igraph")

## 2.1 Initializing the interface

The RedeR/R package sets all details to initialize the R-to-Java interface. Next, the `startRedeR()` function will launch the RedeR application (Figure 1), initializing the R-to-Java interface:

    #--- Initialize the R-to-Java interface
    startRedeR()

Note that RedeR >=2.0.0 is designed to run on Java>=11 (see system requirements).

## 2.2 Displaying graphs

The `addGraphToRedeR()` function displays igraph objects in the RedeR application. The following snippet will display the `gtoy1` graph in RedeR, using the `layout_with_kk()` function to set the network layout (Figure 2):

    #--- Add a graph
    gtoy1 <- graph.lattice(c(3,3,3))

    ## Warning: `graph.lattice()` was deprecated in igraph 2.1.0.
    ## ℹ Please use `make_lattice()` instead.
    ## This warning is displayed once every 8 hours.
    ## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    ## generated.

    addGraphToRedeR(g=gtoy1, layout=layout_with_kk(gtoy1))

Figure 2: A toy example generated by the addGraphToRedeR() function

In the reverse process, graphs are transferred from the application to R using the `getGraphFromRedeR()` function:

    #--- Get a graph
    gtoy2 <- getGraphFromRedeR()
    summary(gtoy2)

    ## IGRAPH cc396a0 U--- 0 0 --

    # IGRAPH fc08ebf UN-- 27 54 --
    # + attr: zoom (g/n), name (v/c), x (v/n), y (v/n)
    #...

    #--- Reset the application:
    resetRedeR()

## 2.3 Working with containers

The `addGraphToRedeR()` method is also used to nest graphs into containers when setting `isNested = TRUE`. Next, the graphs `g1` and `g2` are nested into containers and then displayed in the RedeR application.

    #--- Generate two scale-free graphs
    g1 <- sample_pa(7)
    g2 <- sample_pa(5)

    #--- Set names to graph vertices
    V(g1)$name <- paste("m",1:7,sep="")
    V(g2)$name <- paste("n",1:5,sep="")

    #--- Nest graphs into containers
    addGraphToRedeR(g=g1, isNested=TRUE, gcoord=c(30,30), gscale=50)
    addGraphToRedeR(g=g2, isNested=TRUE, gcoord=c(70,70), gscale=40)

Figure 3: Nested graphs in RedeR using the addGraphToRedeR() function

In this case, `g1` and `g2` are nested into containers N1 and N2, respectively (Figure 3). Each subgraph will retain the network structure, allowing access to individual nodes and edges in subsequent jobs. For example, the following snippet selects all nodes in container N2 and then retrieves the corresponding subgraph.

    #--- Select nodes within a container
    selectNodes(nodes="N2")

    #--- Get nodes from 'N2'
    getGraphFromRedeR(status="selected")

    ## IGRAPH d2a337b U--- 0 0 --
    ## + edges from d2a337b:

    #--- Reset the application:
    resetRedeR()

## 2.4 Interactive layout

The following snippet generates a scale-free graph using igraph's `sample_pa()` function and then displays the network in RedeR.

    #--- Generate a larger scale-free graph
    g1 <- sample_pa(100, directed=FALSE)

    #--- Set names to igraph vertices
    V(g1)$name <- paste0("V",1:vcount(g1))

    #--- Check attributes in the 'g1' graph
    summary(g1)

    ## IGRAPH d3e9e0d UN-- 100 99 -- Barabasi graph
    ## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
    ## | (g/c), name (v/c)

    #--- Send the 'g1' graph to RedeR
    addGraphToRedeR(g=g1, zoom=50)

Next, the `relaxRedeR()` function starts RedeR's interactive force-directed layout algorithm, which will arrange the network as in Figure 4A. The layout algorithm has 9 parameters (`p1` to `p9`), set either in the `relaxRedeR()` function or in the interactive application. These parameters control the layout algorithm by adjusting the relaxing process to the hierarchical levels of the network.

    #--- Run RedeR's interactive layout
    relaxRedeR(p1=20, p2=150, p3=20, p4=100, p5=10)

Figure 4: Graph layouts set by RedeR's interactive force-directed algorithm
A) Section of a scale-free graph generated by igraph's sample_pa() function. B) Section a demo network available in the RedeR application.

    #--- Reset the application:
    resetRedeR()

# 3 Command-line attributes

RedeR attributes can be set either using the graphical user interface or the command-line interface. When using command-line attributes, these must follow igraph syntax rules and valid RedeR's attribute names. Graph attributes are set directly on a graph using igraph shortcuts, while node and edge attributes are set using igraph's `V()` and `E()` functions, respectivelly. For example:

    #--- Set a new graph attribute in 'g1'
    g1$bgcolor <- "white"

    #--- Set new node attributes in 'g1'
    V(g1)$nodeLineColor <- "skyblue"
    V(g1)$nodeSize <- 50

    #--- Set new edge attributes in 'g1'
    E(g1)$edgeLineColor <- "skyblue"
    E(g1)$edgeLineWidth <- 10

    #--- Check the new attributes in 'g1'
    summary(g1)

    ## IGRAPH d3e9e0d UN-- 100 99 -- Barabasi graph
    ## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
    ## | (g/c), bgcolor (g/c), name (v/c), nodeLineColor (v/c), nodeSize
    ## | (v/n), edgeLineColor (e/c), edgeLineWidth (e/n)

Tables 1, 2, and 3 list all command-line attributes available for the current version (RedeR 3.2.0), including usage examples.

Table 1: Graph attributes. Examples of how to set RedeR's graph attributes using igraph shortcuts.
RedeR attribute | Description | Value | Usage example
--- | --- | --- | ---
bgcolor | Background color of the app panel | Single color, hexadecimal or name | g$bgcolor <- 'white'
gscale | Graph expansion factor in the app panel | Single number in [0, 100] | g$gscale <- 75
zoom | Zoom scale applied to the app panel | Single number in [0, 100] | g$zoom <- 100
nestShape | Container shapes | 'ELLIPSE', 'RECTANGLE', 'ROUNDED_RECTANGLE', 'TRIANGLE', 'DIAMOND' | g$nestShape <- 'ELLIPSE'
nestSize | Container size | Single number >=0 | g$nestSize <- 500
nestColor | Container color | Single color, hexadecimal or name | g$nestColor <- 'grey'
nestLineType | Container line types | 'SOLID', 'DOTTED', 'DASHED', 'LONG_DASH' | g$nestLineType <- 'SOLID'
nestLineWidth | Container line width | Single number >=0 | g$nestLineWidth <- 2
nestLineColor | Container line color | Single color, hexadecimal or name | g$nestLineColor <- 'grey'
nestLabel | Label of the container | Single string | g$nestLabel <- 'a_name'
nestLabelSize | Label size | Single number >=0 | g$nestLabelSize <- 24
nestLabelColor | Label color | Single color, hexadecimal or name | g$nestLabelColor <- 'grey20'
nestLabelCoords | Label xy-coord, relative to container | Numeric vector with two numbers | g$nestLabelCoords <- c(x=0, y=0)

Table 2: Node attributes. Examples of how to set RedeR's node attributes using igraph shortcuts.
RedeR attribute | Description | Value | Usage example
--- | --- | --- | ---
name | Node name | Character vector (unique IDs) | V(g)$name <- paste0('Node',1:vcount(g))
x | Node x-coordinate | Numeric vector in (-Inf, Inf) | V(g)$x <- runif(vcount(g))
y | Node y-coordinate | Numeric vector in (-Inf, Inf) | V(g)$y <- runif(vcount(g))
nodeShape | Node shapes | 'ELLIPSE', 'RECTANGLE', 'ROUNDED_RECTANGLE', 'TRIANGLE', 'DIAMOND' | V(g)$nodeShape <- 'ELLIPSE'
nodeSize | Node size | Numeric vector >=0 | V(g)$nodeSize <- 20
nodeColor | Node color | Hexadecimal or color name | V(g)$nodeColor <- 'white'
nodeLineWidth | Line width | Numeric vector >=0 | V(g)$nodeLineWidth <- 1
nodeLineColor | Line color | Hexadecimal or color name | V(g)$nodeLineColor <- 'grey'
nodeLabel | Node label | Character vector | V(g)$nodeLabel <- V(g)$name
nodeLabelSize | Label size | Numeric vector >=0 | V(g)$nodeLabelSize <- 12
nodeLabelColor | Label color | Hexadecimal or color name | V(g)$nodeLabelColor <- 'black'
nodeBend | Node bend | Numeric vector in [0,100] | V(g)$nodeBend <- 50
nodeWeight | Node weight (not implemented) | Numeric vector >=0 | V(g)$nodeWeight <- 0

Table 3: Edge attributes. Examples of how to set RedeR's edge attributes using igraph shortcuts.
RedeR attribute | Description | Value | Usage example
--- | --- | --- | ---
edgeLineType | Line types | 'SOLID', 'DOTTED', 'DASHED', 'LONG_DASH' | E(g)$edgeLineType <- 'SOLID'
edgeLineWidth | Line width | Numeric vector >=0 | E(g)$edgeLineWidth <- 1
edgeLineColor | Line color | Hexadecimal or color name | E(g)$edgeLineColor <- 'grey'
arrowType | Arrows in directed graphs | Integer vector: -1, 0, 1 | E(g)$arrowType <- 1
arrowType | Arrows in undirected graphs | Integer vector: 0 (A-B), 1 (A-> B), -1 (A-| B), 2 (A <-B), -2 (A |-B), 3 (A <-> B), -3 (A |-| B), 4 (A |-> B), -4 (A <-| B) | E(g)$arrowType <- 0
arrowLength | Arrow length | Numeric vector >=0 | E(g)$arrowLength <- 15
arrowAngle | Arrowhead angle in degrees | Numeric vector in [10, 90] | E(g)$arrowAngle <- 20
edgeWeight | Edge weight | Numeric vector >=0 | E(g)$edgeWeight <- 0

RedeR provides two wrapper functions to add fixed values to igraph graphs. The `att.addv()` function adds a new attribute with a fixed value to all nodes or selected nodes, while `att.adde()` function adds a new attribute with a fixed value to all edges. These functions will require that the vertices are named.

    #--- Make sure vertices are named!
    V(g1)$name[1:5]

    ## [1] "V1" "V2" "V3" "V4" "V5"

    #--- Add 'nodeLabelSize' attribute from a fixed value
    g1 <- att.addv(g1, to = "nodeLabelSize", value = 20)

    #--- Same as above, but applied only to three nodes
    g1 <- att.addv(g1, to = "nodeLabelSize", value = 70,
      filter = list("name" = V(g1)$name[1:3]))

    #--- Add 'edgeLineType' attribute from a fixed value
    g1 <- att.adde(g1, to = "edgeLineType", value = "DOTTED")

    #--- Check the new attributes added to 'g1'
    summary(g1)

    ## IGRAPH d3e9e0d UN-- 100 99 -- Barabasi graph
    ## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
    ## | (g/c), bgcolor (g/c), name (v/c), nodeLineColor (v/c), nodeSize
    ## | (v/n), nodeLabelSize (v/n), edgeLineColor (e/c), edgeLineWidth (e/n),
    ## | edgeLineType (e/c)

Alternatively, RedeR's attributes can be set using the `att.mapv()`, `att.setv()`, and `att.sete()` wrapper functions. The `att.mapv()` will map variables from a data frame to igraph vertices, while the `att.setv()` and `att.sete()` will transform vertex and edge variables into valid attribute types. Next, to demonstrate these functions, we will create a `data.frame` object with compatible identifiers.

    #--- Create data frame with IDs compatible to 'g1'
    df <- data.frame(ID=sample(V(g1)$name))

    #--- Add two random variables for demonstration
    df$newAttr1 <- rnorm(nrow(df))
    df$newAttr2 <- rnorm(nrow(df))

    #--- Map 'df' to 'g1' using the att.mapv() function
    #Note: 'refcol' indicates a 'df' column for mapping IDs
    g1 <- att.mapv(g=g1, dat=df, refcol=1)

    #--- Check the new attributes mapped to 'g2'
    summary(g1)

    ## IGRAPH d3e9e0d UN-- 100 99 -- Barabasi graph
    ## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
    ## | (g/c), bgcolor (g/c), name (v/c), nodeLineColor (v/c), nodeSize
    ## | (v/n), nodeLabelSize (v/n), newAttr1 (v/n), newAttr2 (v/n),
    ## | edgeLineColor (e/c), edgeLineWidth (e/n), edgeLineType (e/c)

Note that new names were included in the `g2` graph, but these names are not valid RedeR's attributes yet. Next, the `att.setv()` and `att.sete()` functions are used to transform different data types into valid attributes.

    # Set 'nodeColor' from 'newAttr1'
    g1 <- att.setv(g1, from="newAttr1", to="nodeColor",
      breaks=seq(-2,2,0.4), pal=2)

    # Set 'nodeSize' from 'newAttr1'
    g1 <- att.setv(g1, from="newAttr2", to="nodeSize",
      nquant=10, xlim=c(20,50,1))

    #--- Check the new attributes set in 'g1'
    summary(g1)

    ## IGRAPH d3e9e0d UN-- 100 99 -- Barabasi graph
    ## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
    ## | (g/c), bgcolor (g/c), legNodeColor (g/x), legNodeSize (g/x), name
    ## | (v/c), nodeLineColor (v/c), nodeSize (v/n), nodeLabelSize (v/n),
    ## | newAttr1 (v/n), newAttr2 (v/n), nodeColor (v/c), edgeLineColor (e/c),
    ## | edgeLineWidth (e/n), edgeLineType (e/c)

# 4 Workflow examples

This section provides some practical examples of how users might integrate its own pre-processed data into a graph visualization workflow. Please refer to Castro et al. (2016) and Cardoso et al. (2021) for more details about the biological background and experimental design of each example.

## 4.1 Nested subgraphs

Start the RedeR application (i.e. run the `startRedeR()` function), and then load the `ER.limma` and `hs.inter` datasets. The `ER.limma` is a data frame with results from a time-course differential expression analysis, listing differentially expressed (DE) genes from estrogen-treated MCF-7 cells for 0, 3, 6, and 12 hours (contrasts: t3-t0, t6-t0, and t12-t0). The `hs.inter` is an igraph graph derived from the Human Protein Reference Database (HPRD, release 9). The next snippets list a step-by-step preparation of three nested subgraphs to display in the RedeR application.

    #--- Load required packages
    library("RedeR")
    library("igraph")

    #--- If not running, initialize the ReadeR application
    # startRedeR()
    resetRedeR()

    #--- Load a dataframe and an interactome
    data(ER.limma)
    data(hs.inter)

Extract a subgraph from the `hs.inter` graph and set its attributes using the `att.setv()` function. This subgraph will include DE genes called in the t3-t0 contrast. Note that some genes are not listed in the `hs.inter`, and that's okay.

    #-- Extract a subgraph from the hs.inter graph
    deg.t3 <- ER.limma[ER.limma$degenes.t3!=0,]
    gt3 <- subg(g=hs.inter, dat=deg.t3, refcol=1)

    ## ...not all genes found in the network!

    #-- Set attributes
    gt3 <- att.setv(g=gt3, from="Symbol", to="nodeLabel")
    gt3 <- att.setv(g=gt3, from="logFC.t3", to="nodeColor",
      breaks=seq(-2,2,0.4), pal=2)

Extract another subgraph from the `hs.inter` graph, for DE genes in the t6-t0 contrast:

    #--- Extract another subgraph from the hs.inter graph
    deg.t6 <- ER.limma[ER.limma$degenes.t6!=0,]
    gt6 <- subg(g=hs.inter, dat=deg.t6, refcol=1)

    ## ...not all genes found in the network!

    #--- Set attributes
    gt6 <- att.setv(g=gt6, from="Symbol", to="nodeLabel")
    gt6 <- att.setv(g=gt6, from="logFC.t6", to="nodeColor",
      breaks=seq(-2,2,0.4), pal=2)

Extract another subgraph from the `hs.inter` graph, for DE genes in the t12-t0 contrast:

    #--- Extract another subgraph from the hs.inter graph
    deg.t12 <- ER.limma[ER.limma$degenes.t12!=0,]
    gt12 <- subg(g=hs.inter, dat=deg.t12, refcol=1)

    ## ...not all genes found in the network!

    #--- Set attributes
    gt12 <- att.setv(g=gt12, from="Symbol", to="nodeLabel")
    gt12 <- att.setv(g=gt12, from="logFC.t12", to="nodeColor",
      breaks=seq(-2,2,0.4), pal=2)

    #--- Customize subgraph names
    gt3$nestLabel <- "3h"
    gt6$nestLabel <- "6h"
    gt12$nestLabel <- "12h"

Now use the `addGraphToRedeR()` function to send the three subgraphs to the RedeR application, nesting them into containers. This should start building the nested network depicted in Figure 5. The `addGraphToRedeR()` function will return the container IDs, from `N1` to `N5`, which will be used to identify the graph parents.

    #--- Send nested subgraphs to the RedeR application
    N1 <- addGraphToRedeR(gt3, gcoord=c(10,25), gscale=20,
      isNested=TRUE, theme='th1', zoom=30)
    N2 <- addGraphToRedeR(gt6, gcoord=c(20,70), gscale=50,
      isNested=TRUE, theme='th1', zoom=30)
    N3 <- addGraphToRedeR(gt12, gcoord=c(70,55), gscale=80,
      isNested=TRUE, theme='th1', zoom=30)

... and use the `nestNodes()` function to nest overlapping genes in the time series:

    #--- Nest nodes into the sub-subgraphs
    N4 <- nestNodes(nodes=V(gt3)$name, parent=N2, theme='th2')
    N5 <- nestNodes(nodes=V(gt3)$name, parent=N3, theme='th2')
    nestNodes(nodes=V(gt3)$name, parent=N5, theme='th2')

To simplify the graph, the `mergeOutEdges()` function can be used to assign edges to containers:

    #--- Assign edges to containers
    mergeOutEdges(nlevels=2)

...then telax the network:

    relaxRedeR(p1=100, p2=100, p3=5, p4=150,
      p5=5, p8=10, p9=20)

...and add a color legend:

    scl <- gt3$legNodeColor$scale
    names(scl) <- gt3$legNodeColor$legend
    addLegendToRedeR(scl, type="nodecolor",
      title="Node color (logFC)", stretch = 0.1)

Next, the `selectNodes()` function will zoom-in on the RET gene at different time points:

    selectNodes("RET")
    # repeat this line to see RET in all graph instances

Figure 5: Nested subnetworks
This graph shows genes differentially expressed in estrogen-treated MCF-7 cells at 3, 6 and 12 h (relative to 0 h). The insets correspond to the overlap between consecutive time points. Adapted from Castro et al. (2012, https://doi.org/10.1186/gb-2012-13-4-r29).

## 4.2 Tree-and-leaf diagrams

The TreeAndLeaf package combines tree and force-directed layout algorithms for drawing binary trees, aiming to improve the visualization of dendrogram leaves. RedeR is used to display tree-and-leaf diagrams. Next we will transform an `hclust` object into a `tree-and-leaf` object, and then display Figure 6 in the RedeR application. Please refer to the TreeAndLeaf package's documentation for additional details and examples.

    #--- Load required packages
    library("RedeR")
    library("igraph")
    library("TreeAndLeaf")

    #--- If not running, initialize the ReadeR application
    #startRedeR()
    resetRedeR()

    #-- Generate an 'hclust' object from the 'iris' dataset
    hc_iris <- hclust(dist(iris[,-5]))

    #-- Convert the 'hclust' object into a 'tree-and-leaf' object
    tal <- treeAndLeaf(hc_iris)

    #--- Map 'iris' variables to the tree-and-leaf graph
    #Note: 'refcol = 0' indicates that 'iris' rownames will be used as mapping IDs
    tal <- att.mapv(g = tal, dat = iris, refcol = 0)

    #--- Set node attributes using the 'att.setv' wrapper function
    cols <- c("#80b1d3","#fb8072","#8dd3c7")
    tal <- att.setv(tal, from="Species", to="nodeColor", cols=cols)
    tal <- att.setv(tal, from="Species", to="nodeLineColor", cols=cols)
    tal <- att.setv(tal, from="Petal.Width", to="nodeSize", nquant=6, xlim=c(5,50,1))

    #--- Set other attributes using igraph shortcuts
    V(tal)$nodeLabel <- ""
    E(tal)$edgeLineColor <- "grey70"

    #--- Send the tree-and-leaf graph to RedeR
    addGraphToRedeR(tal, zoom=50)

    #--- Suggestion: anchor inner nodes to adjust the final layout
    selectNodes(V(tal)$name[!V(tal)$isLeaf], anchor=TRUE)

    #--- Call 'relax' to fine-tune the leaf nodes
    relaxRedeR(p1=10, p2=100, p3=5, p4=120, p5=1, p6=100)

    #--- Add legends
    addLegendToRedeR(tal, type="nodecolor", title="Species", stretch=0.2)
    addLegendToRedeR(tal, type="nodesize", title="PetalWidth")

Figure 6: A tree-and-leaf diagram
This graph is obtained by transforming an hclust object into a tree-and-leaf object.

# 5 Citation

If you use RedeR, please cite:

- Castro MA, Wang X, Fletcher MN, Meyer KB, Markowetz F (2012). "RedeR: R/Bioconductor package for representing modular structures, nested networks and multiple levels of hierarchical associations." Genome Biology, 13(4), R29. Doi:10.1186/gb-2012-13-4-r29.

# 6 Other useful links

- Cardoso MA, Rizzardi LEA, Kume LW, Groeneveld C, Trefflich S, Morais DAA, Dalmolin RJS, Ponder BAJ, Meyer KB, Castro MAA. "TreeAndLeaf: an R/Bioconductor package for graphs and trees with focus on the leaves." Bioinformatics, 38(5):1463-1464, 2022. https://bioconductor.org/packages/TreeAndLeaf/

- Csardi G and Nepusz T. "The Igraph Software Package for Complex Network Research." InterJournal, ComplexSystems:1695, 2006. https://igraph.org

# 7 System requirements

RedeR 3.2.0 will need the Java Runtime Environment (JRE) version 11 or higher (Java >=11). In order to check the Java on your system, please use the `RedPort()` function with `checkJava=TRUE`, for example:

    RedPort(checkJava=TRUE)
    # RedeR will need Java Runtime Environment (Java >=11)
    # Checking Java version installed on this system...
    # openjdk version "11.0.13" 2021-10-19
    # OpenJDK Runtime Environment (build 11.0.13+8-Ubuntu-0ubuntu1.20.04)
    # OpenJDK 64-Bit Server VM (build 11.0.13+8-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)

The exact output will vary, but you need to make sure the system meets the minimum version requirement.

# 8 Session information

    ## R version 4.4.1 (2024-06-14 ucrt)
    ## Platform: x86_64-w64-mingw32/x64
    ## Running under: Windows Server 2022 x64 (build 20348)
    ##
    ## Matrix products: default
    ##
    ##
    ## locale:
    ## [1] LC_COLLATE=C
    ## [2] LC_CTYPE=English_United States.utf8
    ## [3] LC_MONETARY=English_United States.utf8
    ## [4] LC_NUMERIC=C
    ## [5] LC_TIME=English_United States.utf8
    ##
    ## time zone: America/New_York
    ## tzcode source: internal
    ##
    ## attached base packages:
    ## [1] stats     graphics  grDevices utils     datasets  methods   base
    ##
    ## other attached packages:
    ## [1] TreeAndLeaf_1.18.0 igraph_2.1.1       RedeR_3.2.0        BiocStyle_2.34.0
    ##
    ## loaded via a namespace (and not attached):
    ##  [1] jsonlite_1.8.9      compiler_4.4.1      BiocManager_1.30.25
    ##  [4] highr_0.11          crayon_1.5.3        Rcpp_1.0.13
    ##  [7] parallel_4.4.1      jquerylib_0.1.4     scales_1.3.0
    ## [10] yaml_2.3.10         fastmap_1.2.0       lattice_0.22-6
    ## [13] R6_2.5.1            knitr_1.48          bookdown_0.41
    ## [16] munsell_0.5.1       bslib_0.8.0         pillar_1.9.0
    ## [19] rlang_1.1.4         utf8_1.2.4          cachem_1.1.0
    ## [22] xfun_0.48           sass_0.4.9          cli_3.6.3
    ## [25] magrittr_2.0.3      digest_0.6.37       grid_4.4.1
    ## [28] lifecycle_1.0.4     nlme_3.1-166        vctrs_0.6.5
    ## [31] evaluate_1.0.1      glue_1.8.0          ape_5.8
    ## [34] fansi_1.0.6         colorspace_2.1-1    rmarkdown_2.28
    ## [37] tools_4.4.1         pkgconfig_2.0.3     htmltools_0.5.8.1