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 at Castro et al. (2016).
RedeR 2.0.1
RedeR is an R-based package combined with a Java application for network analysis and visualization. The design of the software is depicted in Figure 1. 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 RedeR/R package sets all details to initialize the R-to-Java interface. Next, the RedPort()
constructor will create the rdp
object, which will be used in all methods calling the RedeR/Java application.
Note that RedeR >=2.0.0 is designed to run on Java>=11 (see system requirements). Next, the calld()
function will use the rdp
object to launch the RedeR application (Figure 2), initializing the R-to-Java interface:
The addGraph()
method displays igraph graphs in the RedeR application. The following snippet will display the g1
graph in RedeR, using the layout_with_kk()
function to set the network layout (Figure 3):
In the reverse process, graphs are transferred from the application to R using the getGraph()
method:
The addGraph()
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
addGraph(rdp, g=g1, isNested=TRUE, gcoord=c(30,30), gscale=50)
addGraph(rdp, g=g2, isNested=TRUE, gcoord=c(70,70), gscale=50)
In this case, g1
and g2
are nested into containers N1 and N2, respectively (Figure 4). 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.
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(300, directed=FALSE)
#--- Set names to igraph vertices
V(g1)$name <- paste0("V",1:vcount(g1))
#--- Check attributes in the 'g1' graph
summary(g1)
## IGRAPH 79f6c63 UN-- 300 299 -- Barabasi graph
## + attr: name (g/c), power (g/n), m (g/n), zero.appeal (g/n), algorithm
## | (g/c), name (v/c)
Next, the relax()
function starts RedeR’s interactive force-directed layout algorithm, which will arrange the network as in Figure 5A. The layout algorithm has 9 parameters (p1
to p9
), set either in the relax()
function or in the interactive application. These parameters control the layout algorithm by adjusting the relaxing process to the hierarchical levels of the network.
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 <- 'grey90'
#--- Set new node attributes in 'g1'
V(g1)$nodeColor <- "skyblue"
V(g1)$nodeSize <- 50
#--- Set new edge attributes in 'g1'
E(g1)$edgeColor <- "skyblue"
E(g1)$edgeWidth <- 10
## IGRAPH 79f6c63 UN-- 300 299 -- 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), nodeColor (v/c), nodeSize (v/n),
## | edgeColor (e/c), edgeWidth (e/n)
Tables 1, 2, and 3 list all command-line attributes available for the current version (RedeR 2.0.1), including usage examples.
RedeR attribute | Description | Value | Usage example |
---|---|---|---|
bgColor | Background color of the app panel | Hexadecimal or color name | g$bgColor <- ‘white’ |
zoom | Zoom scale applyed to graph objects and area | Numeric, 0-100 | g$zoom <- 100 |
gzoom | Zoom scale applyed to graph objects | Numeric, 0-100 | g$gzoom <- NULL |
gscale | Expansion factor applyed to the graph area | Numeric, 0-100 | g$gscale <- 100 |
isNested | Whether to nest nodes into a container | Logical | g$isNested <- FALSE |
isAnchored | Whether to anchor the container | Logical | g$isAnchored <- FALSE |
isAssigned | Whether to assign container name to nodes | Logical | g$isAssigned <- FALSE |
nestAlias | Label of the node nesting container | Logical | g$nestAlias <- ‘a name’ |
nestSize | Size of the node nesting container | Numeric, >=0 | g$nestSize <- 500 |
nestShape | Shape of the node nesting container | String: ELLIPSE, RECTANGLE, ROUNDED_RECTANGLE, TRIANGLE, DIAMOND | g$nestShape <- ‘ELLIPSE’ |
nestColor | Color of the node nesting container | Hexadecimal or color name | g$nestColor <- ‘grey’ |
nestFontSize | Container label font size | Numeric, >=0 | g$nestFontSize <- 18 |
nestLineWidth | Container line width | Numeric, >=0 | g$nestLineWidth <- 2 |
nestLineColor | Container line color | Hexadecimal or color name | g$nestLineColor <- ‘grey’ |
nestLineType | Container line type | String: SOLID, DOTTED, DASHED, LONG_DASH | g$nestLineType <- ‘SOLID’ |
nestImage | Status of the container on the screen | String: plain, transparent, or hide | g$nestImage <- ‘plain’ |
RedeR attribute | Description | Value | Usage example |
---|---|---|---|
name | Node name | String, a unique ID | V(g)$name <- paste0(‘Node’,1:vcount(g)) |
nodeAlias | Node alias | String, a label | V(g)$nodeAlias <- V(g)$name |
coordX | X-coordinate of a point in a plane | Numeric, (-Inf,Inf) | V(g)$coordX <- runif(vcount(g)) |
coordY | Y-coordinate of a point in a plane | Numeric, (-Inf,Inf) | V(g)$coordY <- runif(vcount(g)) |
nodeSize | Node size | Numeric, >=0 | V(g)$nodeSize <- 20 |
nodeShape | Node shape | String: ELLIPSE, RECTANGLE, ROUNDED_RECTANGLE, TRIANGLE, DIAMOND | V(g)$nodeShape <- ‘ELLIPSE’ |
nodeColor | Node color | Hexadecimal or color name | V(g)$nodeColor <- ‘white’ |
nodeLineWidth | Line width | Numeric, >=0 | V(g)$nodeLineWidth <- 1 |
nodeLineColor | Line color | Hexadecimal or color name | V(g)$nodeLineColor <- ‘grey’ |
nodeFontSize | Font size | Numeric, >=0 | V(g)$nodeFontSize <- 12 |
nodeFontColor | Font color | Hexadecimal or color name | V(g)$nodeFontColor <- ‘black’ |
nodeBend | Node bend | Numeric, 0-100 | V(g)$nodeBend <- 50 |
nodeWeight | Node weight (not implemented) | Numeric, >=0 | V(g)$nodeWeight <- 0 |
RedeR attribute | Description | Value | Usage example |
---|---|---|---|
edgeWeight | Edge weight | Numeric, >=0 | E(g)$edgeWeight <- 0 |
edgeWidth | Edge width | Numeric, >=0 | E(g)$edgeWidth <- 1 |
edgeColor | Edge color | Hexadecimal or color name | E(g)$edgeColor <- ‘grey’ |
edgeType | Edge type | String: SOLID, DOTTED, DASHED, LONG_DASH | E(g)$edgeType <- ‘SOLID’ |
arrowLength | Arrow length | Numeric, >=0 | E(g)$arrowLength <- 15 |
arrowAngle | Arrowhead angle in degrees | Numeric, 10-75 | E(g)$arrowAngle <- 20 |
arrowType | Associations in directed graphs | Integer: -1, 0, 1 | E(g)$arrowType <- 1 |
arrowDirection | Associations in undirected graphs | Integer: 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)$arrowDirection <- 0 |
linkType | Assignment type between nodes and containers | String: nested, notnested | E(g)$linkType <- ‘nested’ |
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.
## [1] "V1" "V2" "V3" "V4" "V5"
#--- Add 'nodeFontSize' attribute from a fixed value
g1 <- att.addv(g1, to = "nodeFontSize", value = 20)
#--- Same as above, but applied only to three nodes
g1 <- att.addv(g1, to = "nodeFontSize", value = 70,
filter = list("name" = V(g1)$name[1:3]))
#--- Add 'edgeType' attribute from a fixed value
g1 <- att.adde(g1, to = "edgeType", value = "DOTTED")
## IGRAPH 79f6c63 UN-- 300 299 -- 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), nodeColor (v/c), nodeSize (v/n),
## | nodeFontSize (v/n), edgeColor (e/c), edgeWidth (e/n), edgeType (e/c)
Alternatively, RedeR’s attributes can be set using the att.mapv()
, att.mape()
,att.setv()
, and att.sete()
wrapper functions. The att.mapv()
and att.mape()
will map variables from a data frame to igraph vertices and edges, respectively, while the att.setv()
and att.sete()
will transform these variables into valid attribute types. Next, to demonstrate these functions, load an igraph graph and a data.frame
object with compatible identifiers.
#--- Load an igraph graph and a data frame with compatible identifiers
data(ER.deg)
g2 <- ER.deg$ceg # an igraph graph with named nodes
df <- ER.deg$dat # a data frame
#--- Check attributes already available in the 'g2' graph
summary(g2)
## IGRAPH fd53520 UNW- 174 1016 --
## + attr: name (v/c), weight (e/n)
## [1] "ENTREZ" "Symbol" "logFC.t3" "logFC.t6" "logFC.t12"
## [6] "p.value.t3" "p.value.t6" "p.value.t12" "degenes.t3" "degenes.t6"
## [11] "degenes.t12" "ERbdist"
#--- Map 'df' to 'g2' using the att.mapv() function
#Note: 'refcol = 0' indicates that 'df' rownames will be used as mapping IDs
g2 <- att.mapv(g=g2, dat=df, refcol=0)
#--- Check the new attributes mapped to 'g2'
summary(g2)
## IGRAPH fd53520 UNW- 174 1016 --
## + attr: name (v/c), ENTREZ (v/c), Symbol (v/c), logFC.t3 (v/n),
## | logFC.t6 (v/n), logFC.t12 (v/n), p.value.t3 (v/n), p.value.t6 (v/n),
## | p.value.t12 (v/n), degenes.t3 (v/n), degenes.t6 (v/n), degenes.t12
## | (v/n), ERbdist (v/n), weight (e/n)
Note that new names were included in the g2
graph, but these names are not valid RedeR’s attributes yet. Next, the att.setv()
amd att.sete()
functions are used to transform different data types into valid attributes.
# Set 'nodeAlias' from 'Symbol'
g2 <- att.setv(g2, from="Symbol", to="nodeAlias")
# Set 'nodeColor' from 'logFC.t3'
g2 <- att.setv(g2, from="logFC.t3", to="nodeColor", breaks=seq(-2,2,0.4), pal=2)
# Set 'nodeSize' from 'ERbdist'
g2 <- att.setv(g2, from="ERbdist", to="nodeSize", nquant=10, xlim=c(20,100,1))
# Set 'nodeFontSize' from 'ERbdist'
g2 <- att.setv(g2, from="ERbdist", to="nodeFontSize", nquant=10, xlim=c(1,50,1))
# Set 'edgeWidth' from 'weight'
g2 <- att.sete(g2, from="weight", to="edgeWidth", nquant=5, xlim=c(1,10,1))
#--- Check the new attributes set in 'g2'
summary(g2)
## IGRAPH fd53520 UNW- 174 1016 --
## + attr: legNodeColor (g/x), legNodeSize (g/x), legNodeFontSize (g/x),
## | legEdgeWidth (g/x), name (v/c), ENTREZ (v/c), Symbol (v/c), logFC.t3
## | (v/n), logFC.t6 (v/n), logFC.t12 (v/n), p.value.t3 (v/n), p.value.t6
## | (v/n), p.value.t12 (v/n), degenes.t3 (v/n), degenes.t6 (v/n),
## | degenes.t12 (v/n), ERbdist (v/n), nodeAlias (v/c), nodeColor (v/c),
## | nodeSize (v/n), nodeFontSize (v/n), weight (e/n), edgeWidth (e/n)
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.
Start the RedeR application (i.e. run the calld()
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; https://www.hprd.org/). The next snippets will show a step-by-step preparation of three nested subgraphs to display in the RedeR application.
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
gt3 <- subg(g=hs.inter, dat=ER.limma[ER.limma$degenes.t3!=0,], refcol=1)
## ...note: not all genes found in the network!
#-- Set attributes
gt3 <- att.setv(g=gt3, from="Symbol", to="nodeAlias")
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
gt6 <- subg(g=hs.inter, dat=ER.limma[ER.limma$degenes.t6!=0,], refcol=1)
## ...note: not all genes found in the network!
#--- Set attributes
gt6 <- att.setv(g=gt6, from="Symbol", to="nodeAlias")
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
gt12 <- subg(g=hs.inter, dat=ER.limma[ER.limma$degenes.t12!=0,], refcol=1)
## ...note: not all genes found in the network!
#--- Set attributes
gt12 <- att.setv(g=gt12, from="Symbol", to="nodeAlias")
gt12 <- att.setv(g=gt12, from="logFC.t12", to="nodeColor", breaks=seq(-2,2,0.4), pal=2)
Now use the addGraph()
function to send the subgraphs to the RedeR application, nesting into containers. This should start building the nested network depicted in Figure 6. The addGraph()
function will return the container IDs, N1
to N5
, which will be used to identify graph parents.
#--- Send nested subgraphs to the RedeR application
N1 <- addGraph(rdp, gt3, gcoord=c(10,25), gscale=20, isNested=TRUE, theme='tm1', gzoom=30)
N2 <- addGraph(rdp, gt6, gcoord=c(20,70), gscale=50, isNested=TRUE, theme='tm1', gzoom=30)
N3 <- addGraph(rdp, gt12, gcoord=c(70,55), gscale=80, isNested=TRUE, theme='tm1', gzoom=30)
… and use the nestNodes()
function to indicate overlapping genes in the time series:
#--- Nest sub-subgraphs
N4 <- nestNodes(rdp, nodes=V(gt3)$name, parent=N2, theme='tm2')
N5 <- nestNodes(rdp, nodes=V(gt6)$name, parent=N3, theme='tm2')
nestNodes(rdp, nodes=V(gt3)$name, parent=N5, theme='tm3')
To simplify the graph, the mergeOutEdges()
function can be used to assign edges to containers:
…then telax the network:
…and add a color legend:
scl <- gt3$legNodeColor$scale
leg <- gt3$legNodeColor$legend
addLegend.color(rdp, colvec=scl, labvec=leg, title="Node color (logFC)")
Next, the selectNodes()
function will zoom-in on the RET gene at different time points:
This example will show a step-by-step preparation of a hierarchical network to display in the RedeR application. Please, load the ER.deg
dataset and then get the dat
and ceg
objects. The dat
object is a data frame listing DE genes with log2 fold change statistics (logFC), while the ceg
object is an igraph graph with a co-expression gene network.
Next, the att.mapv()
function is used to map the dat
data frame to the ceg
co-expression network:
The att.setv()
function is then used to set valid RedeR attributes in the ceg
graph: Symbol
will be mapped to nodeAlias
, logFC.t3
will be mapped to nodeColor
, and ERbdist
will be mapped to nodeSize
.
#--- Set RedeR attributes
ceg <- att.setv(ceg, from="Symbol", to="nodeAlias")
ceg <- att.setv(ceg, from="logFC.t3", to="nodeColor", breaks=seq(-2,2,0.4), pal=2)
ceg <- att.setv(ceg, from="ERbdist", to="nodeSize", nquant=10, isrev=TRUE, xlim=c(5,40,1))
Then the ceg
graph is displayed in the RedeR application:
Next, the hclust()
function is used for an unsupervised hierarchical cluster analysis on the ceg
adjacency matrix:
#--- Hierarchical clustering on the adjacency matrix
hc <- hclust(dist(get.adjacency(ceg, attr="weight")))
…and the nesthc()
function is used to superimpose the corresponding dendrogram onto the network:
#--- Map the hclust object onto the network
nesthc(rdp, hc, cutlevel=3, nmemb=5, cex=0.3, labels=V(ceg)$nodeAlias)
At this point nested subgraphs should appear in the RedeR application mapped to the dendrogram depicted in Figure 7. Next, the mergeOutEdges()
function is used to assign edges to containers, simplifying the graph presented in Figure 8.
…then relax the network:
…and add the legends:
scl <- ceg$legNodeColor$scale
leg <- ceg$legNodeColor$legend
addLegend.color(rdp, colvec=scl, labvec=leg, title="Diff. Gene Expression (logFC)")
scl <- ceg$legNodeSize$scale
leg <- ceg$legNodeSize$legend
addLegend.size(rdp, sizevec=scl, labvec=leg, title="TFBS Distance (kb)")
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 9 in the RedeR application. Please refer to the TreeAndLeaf package’s documentation for additional details and examples.
#-- 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)$nodeAlias <- ""
E(tal)$edgeColor <- "grey70"
#--- Send the tree-and-leaf graph to RedeR
addGraph(rdp, tal, gzoom=50)
#--- Suggestion: anchor inner nodes to adjust the final layout
# selectNodes(rdp, V(tal)$name[!V(tal)$isLeaf], anchor=TRUE)
#--- Call 'relax' to fine-tune the leaf nodes
relax(rdp, p1=10, p2=100, p3=2, p4=120, p5=1)
#--- Add legends
addLegend.color(rdp, tal, title="Species")
addLegend.size(rdp, tal, title="PetalWidth", position="bottomright")
If you use RedeR, please cite:
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
RedeR 2.0.1 will need the Java Runtime Environment (JRE) version 11 or higher (Java >=11). The package will also run on earlier Java versions (Java >=8), but with reduced functionality. 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.
## R version 4.2.1 (2022-06-23)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 20.04.4 LTS
##
## Matrix products: default
## BLAS: /home/biocbuild/bbs-3.15-bioc/R/lib/libRblas.so
## LAPACK: /home/biocbuild/bbs-3.15-bioc/R/lib/libRlapack.so
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_GB 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] igraph_1.3.4 RedeR_2.0.1 BiocStyle_2.24.0
##
## loaded via a namespace (and not attached):
## [1] knitr_1.40 magrittr_2.0.3 lattice_0.20-45
## [4] R6_2.5.1 rlang_1.0.4 fastmap_1.1.0
## [7] stringr_1.4.1 highr_0.9 tools_4.2.1
## [10] grid_4.2.1 xfun_0.32 cli_3.3.0
## [13] jquerylib_0.1.4 htmltools_0.5.3 yaml_2.3.5
## [16] digest_0.6.29 bookdown_0.28 Matrix_1.4-1
## [19] BiocManager_1.30.18 sass_0.4.2 cachem_1.0.6
## [22] evaluate_0.16 rmarkdown_2.16 stringi_1.7.8
## [25] compiler_4.2.1 bslib_0.4.0 jsonlite_1.8.0
## [28] pkgconfig_2.0.3