Package: PathwaySpace 1.0.3.1
This tutorial introduces the core PathwaySpace methods using simple toy examples. We will walk through setting up basic input data and running graph projections. These examples are designed to familiarize users with the core workflow before they work with larger, real-world datasets.
# Check required packages for this vignette
if (!require("remotes", quietly = TRUE)){
install.packages("remotes")
}
if (!require("RGraphSpace", quietly = TRUE)){
remotes::install_github("sysbiolab/RGraphSpace")
}
if (!require("PathwaySpace", quietly = TRUE)){
remotes::install_github("sysbiolab/PathwaySpace")
}
# Check versions
if (packageVersion("RGraphSpace") < "1.1.0"){
message("Need to update 'RGraphSpace' for this vignette")
remotes::install_github("sysbiolab/RGraphSpace")
}
if (packageVersion("PathwaySpace") < "1.0.3.1"){
message("Need to update 'PathwaySpace' for this vignette")
remotes::install_github("sysbiolab/PathwaySpace")
}
# Load packages
library(igraph)
library(ggplot2)
library(RGraphSpace)
library(PathwaySpace)
This section will create an igraph object containing a
binary signal associated to each vertex. The graph layout is configured
manually to ensure that users can easily view all the relevant arguments
needed to prepare the input data for the PathwaySpace package.
The igraph’s make_star() function creates a
star-like graph and the V() function is used to set
attributes for the vertices. The PathwaySpace package will
require that all vertices have x, y, and
name attributes.
# Make a 'toy' igraph object, either a directed or undirected graph
gtoy1 <- make_star(5, mode="undirected")
# Assign 'x' and 'y' coordinates to each vertex
# ..this can be an arbitrary unit in (-Inf, +Inf)
V(gtoy1)$x <- c(0, 2, -2, -4, -8)
V(gtoy1)$y <- c(0, 0, 2, -4, 0)
# Assign a 'name' to each vertex (here, from n1 to n5)
V(gtoy1)$name <- paste0("n", 1:5)
Next, we will create a GraphSpace-class object using the
GraphSpace() constructor. This function will check the
validity of the igraph object. For this example
mar = 0.2, which sets the outer margins of the graph.
# Check graph validity
g_space1 <- GraphSpace(gtoy1, mar = 0.2)
Our graph is now ready for the PathwaySpace package. We can
check its layout using the plotGraphSpace() function.
# Check the graph layout
plotGraphSpace(g_space1, add.labels = TRUE)

Next, we will create a PathwaySpace-class object using the
buildPathwaySpace() constructor. This will calculate
pairwise distances between vertices, subsequently required by the signal
projection methods.
# Run the PathwaySpace constructor
p_space1 <- buildPathwaySpace(g_space1)
As a default behavior, the buildPathwaySpace()
constructor initializes the signal of each vertex as 0. We
can use the vertexSignal() accessor to get and set vertex
signals in a PathwaySpace object; for example, in order to get
vertex names and signal values:
# Check the number of vertices in a PathwaySpace object
gs_vcount(p_space1)
## [1] 5
# Check vertex names
names(p_space1)
## [1] "n1" "n2" "n3" "n4" "n5"
# Check signal (initialized with '0')
vertexSignal(p_space1)
## n1 n2 n3 n4 n5
## 0 0 0 0 0
…and for setting new signal values in the PathwaySpace object:
# Set new signal to all vertices
vertexSignal(p_space1) <- c(1, 4, 2, 4, 3)
# Set a new signal to the 1st vertex
vertexSignal(p_space1)[1] <- 2
# Set a new signal to vertex "n1"
vertexSignal(p_space1)["n1"] <- 6
# Check updated signal values
vertexSignal(p_space1)
## n1 n2 n3 n4 n5
## 6 4 2 4 3
Following that, we will use the circularProjection()
function to project the network signals by the
weibullDecay() function with pdist = 0.4,
which is passed by the decay.fun argument. This term
determines a distance unit for the signal convolution, affecting the
extent over which the convolution operation projects the signal. For
example, when pdist = 1, it will represent the diameter of
the inscribed circle within the coordinate space. We also set
k = 1, which defines the contributing vertices for signal
convolution.
# Run signal projection
p_space1 <- circularProjection(p_space1, k = 1,
decay.fun = weibullDecay(pdist = 0.4))
# Plot a PathwaySpace image
plotPathwaySpace(p_space1, add.marks = TRUE)

Next, we reassess the same PathwaySpace object, using
pdist = 0.2, k = 2 and adjusting the
shape of the decay function (for further details, see the
modeling signal
decay tutorial).
# Re-run signal projection, adjusting Weibull's shape
p_space1 <- circularProjection(p_space1, k = 2,
decay.fun = weibullDecay(shape = 2, pdist = 0.2))
# Plot PathwaySpace
plotPathwaySpace(p_space1, marks = "n1", theme = "th2")

The shape parameter allows a projection to take a
variety of shapes. When shape = 1 the projection follows an
exponential decay, and when shape > 1 the projection is
first convex, then concave with an inflection point along the decay
path. For additional examples see modeling signal
decay tutorial.
In this section we will project network signals using a polar
coordinate system. This representation may be useful for certain types
of data, for example, to highlight patterns of signal propagation on
directed graphs, especially to explore the orientation aspect of signal
flow. To demonstrate this feature we will used the gtoy2
directed graph, available in the RGraphSpace package.
# Load a pre-processed directed igraph object
data("gtoy2", package = "RGraphSpace")
# Check graph validity
g_space2 <- GraphSpace(gtoy2, mar = 0.2)
# Check the graph layout
plotGraphSpace(g_space2, add.labels = TRUE)

# Build a PathwaySpace for the 'g_space2'
p_space2 <- buildPathwaySpace(g_space2)
# Set '1s' as vertex signal
vertexSignal(p_space2) <- 1
For fine-grained modeling of signal decay, the
vertexDecay() accessor allows assigning decay functions at
the level of individual vertices. For example, adjusting Weibull’s
shape argument for node n6:
# Modify decay function
# ..for all vertices
vertexDecay(p_space2) <- weibullDecay(shape=2, pdist = 1)
# ..for individual vertices
vertexDecay(p_space2)[["n6"]] <- weibullDecay(shape=3, pdist = 1)
In polar projections, the pdist term defines a reference
distance related to edge length, aiming to constrain signal projections
within edge bounds. Here we set pdist = 1 to reach full
edge lengths. Next, we run the signal projection using polar
coordinates. The beta exponent will control the angular
span; for values greater than zero, beta will progressively
narrow the projection along the edge axis.
# Run signal projection using polar coordinates
p_space2 <- polarProjection(p_space2, beta = 10)
# Plot PathwaySpace
plotPathwaySpace(p_space2, theme = "th2", add.marks = TRUE)

Note that this projection distributes signals on the edges regardless
of direction. To incorporate edge orientation, we set
directional = TRUE, which channels the projection along the
paths:
# Re-run signal projection using 'directional = TRUE'
p_space2 <- polarProjection(p_space2, beta = 10, directional = TRUE)
# Plot PathwaySpace
plotPathwaySpace(p_space2, theme = "th2", marks = c("n1","n3","n4","n5"))

This PathwaySpace polar projection emphasizes the signal flow along the directional pattern of a directed graph (see the igraph plot above). When interpreting, users should note that this approach introduces simplifications; for example, depending on the network topology, the polar projection may fail to capture complex features of directed graphs, such as cyclic dependencies, feedforward and feedback loops, or other intricate interactions.
The PathwaySpace accepts binary, integer, and numeric signal
types, including NAs. If a vertex signal is assigned with
NA, it will be ignored by the convolution algorithm.
Logical values are also allowed, but it will be treated as binary. Next,
we show the projection of a signal that includes negative values, using
the p_space1 object created previously.
# Set a negative signal to vertices "n3" and "n4"
vertexSignal(p_space1)[c("n3","n4")] <- c(-2, -4)
# Check updated signal vector
vertexSignal(p_space1)
# n1 n2 n3 n4 n5
# 6 4 -2 -4 3
# Re-run signal projection
p_space1 <- circularProjection(p_space1, decay.fun = weibullDecay(shape = 2))
# Plot PathwaySpace
plotPathwaySpace(p_space1, bg.color = "white", font.color = "grey20", add.marks = TRUE, mark.color = "magenta", theme = "th2")

Note that the original signal vector was rescale to
[-1, +1]. If the signal vector is >=0, then
it will be rescaled to [0, 1]; if the signal vector is
<=0, it will be rescaled to [-1, 0]; and if
the signal vector is in (-Inf, +Inf), then it will be
rescaled to [-1, +1]. To override this signal processing,
simply set rescale = FALSE in the projection function.
If you use PathwaySpace, please cite:
Tercan & Apolonio et al. Protocol for assessing distances in pathway space for classifier feature sets from machine learning methods. STAR Protocols 6(2):103681, 2025. https://doi.org/10.1016/j.xpro.2025.103681
Ellrott et al. Classification of non-TCGA cancer samples to TCGA molecular subtypes using compact feature sets. Cancer Cell 43(2):195-212.e11, 2025. https://doi.org/10.1016/j.ccell.2024.12.002
## R version 4.5.1 (2025-06-13)
## Platform: x86_64-pc-linux-gnu
## Running under: Ubuntu 24.04.3 LTS
##
## Matrix products: default
## BLAS: /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
## LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so; LAPACK version 3.12.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
## [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
##
## time zone: America/Sao_Paulo
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] patchwork_1.3.2 igraph_2.2.0 SpotSpace_0.0.2
## [4] PathwaySpace_1.0.3.1 RGraphSpace_1.1.0 ggplot2_4.0.0.9000
## [7] remotes_2.5.0 bs4cards_0.1.1
##
## loaded via a namespace (and not attached):
## [1] deldir_2.0-4 pbapply_1.7-4 gridExtra_2.3
## [4] rlang_1.1.6 magrittr_2.0.4 RcppAnnoy_0.0.22
## [7] spatstat.geom_3.6-0 matrixStats_1.5.0 ggridges_0.5.7
## [10] compiler_4.5.1 png_0.1-8 vctrs_0.6.5
## [13] reshape2_1.4.4 stringr_1.5.2 pkgconfig_2.0.3
## [16] fastmap_1.2.0 fontawesome_0.5.3 promises_1.3.3
## [19] rmarkdown_2.30 purrr_1.1.0 xfun_0.53
## [22] cachem_1.1.0 jsonlite_2.0.0 goftest_1.2-3
## [25] later_1.4.4 spatstat.utils_3.2-0 irlba_2.3.5.1
## [28] parallel_4.5.1 cluster_2.1.8.1 R6_2.6.1
## [31] ica_1.0-3 spatstat.data_3.1-8 stringi_1.8.7
## [34] bslib_0.9.0 RColorBrewer_1.1-3 reticulate_1.43.0
## [37] spatstat.univar_3.1-4 parallelly_1.45.1 lmtest_0.9-40
## [40] jquerylib_0.1.4 scattermore_1.2 Rcpp_1.1.0
## [43] knitr_1.50 tensor_1.5.1 future.apply_1.20.0
## [46] zoo_1.8-14 sctransform_0.4.2 httpuv_1.6.16
## [49] Matrix_1.7-4 splines_4.5.1 tidyselect_1.2.1
## [52] abind_1.4-8 rstudioapi_0.17.1 yaml_2.3.10
## [55] spatstat.random_3.4-2 spatstat.explore_3.5-3 codetools_0.2-20
## [58] miniUI_0.1.2 listenv_0.9.1 lattice_0.22-5
## [61] tibble_3.3.0 plyr_1.8.9 shiny_1.11.1
## [64] withr_3.0.2 S7_0.2.0 ROCR_1.0-11
## [67] evaluate_1.0.5 Rtsne_0.17 future_1.67.0
## [70] fastDummies_1.7.5 survival_3.8-3 polyclip_1.10-7
## [73] fitdistrplus_1.2-4 pillar_1.11.1 Seurat_5.3.1.9999
## [76] KernSmooth_2.23-26 plotly_4.11.0 generics_0.1.4
## [79] RcppHNSW_0.6.0 sp_2.2-0 scales_1.4.0
## [82] globals_0.18.0 xtable_1.8-4 glue_1.8.0
## [85] lazyeval_0.2.2 tools_4.5.1 data.table_1.17.8
## [88] RSpectra_0.16-2 RANN_2.6.2 fs_1.6.6
## [91] dotCall64_1.2 cowplot_1.2.0 grid_4.5.1
## [94] tidyr_1.3.1 nlme_3.1-168 cli_3.6.5
## [97] spatstat.sparse_3.1-0 spam_2.11-1 viridisLite_0.4.2
## [100] dplyr_1.1.4 uwot_0.2.3 gtable_0.3.6
## [103] sass_0.4.10 digest_0.6.37 progressr_0.17.0
## [106] ggrepel_0.9.6 htmlwidgets_1.6.4 SeuratObject_5.2.0
## [109] farver_2.1.2 htmltools_0.5.8.1 lifecycle_1.0.4
## [112] httr_1.4.7 mime_0.13 MASS_7.3-65