2 Build graph object


Basic workflow of ggNetView

  1. Build a graph object
  2. Understand and manipulate the graph object
  3. Visualize the network using layout algorithms
  4. Retrieve topology of network

Load R Package


2.1 Build graph from matrix

Example data

# Access built-in example datasets in ggNetView

# Raw ASV/OTU abundance table (rows = ASVs/OTUs, cols = samples)
data("otu_tab")
dim(otu_tab)
## [1] 2859   18
otu_tab[1:5, 1:5]
##        KO1  KO2  KO3  KO4  KO5
## ASV_1 1113 1968  816 1372 1062
## ASV_2 1922 1227 2355 2218 2885
## ASV_3  568  460  899  902 1226
## ASV_4 1433  400  535  759 1287
## ASV_6  882  673  819  888 1475
# Rarefied ASV/OTU table (sequencing depth normalised by rarefaction)
data("otu_rare")
dim(otu_rare)
## [1] 2859   18
otu_rare[1:5, 1:5]
##        KO1  KO2  KO3  KO4  KO5
## ASV_1  992 1636  604 1084  806
## ASV_2 1725 1018 1814 1743 2196
## ASV_3  520  389  687  701  932
## ASV_4 1280  328  425  580 1004
## ASV_6  794  557  633  706 1142
# Rarefied + converted to relative abundance — most common downstream input
data("otu_rare_relative")
dim(otu_rare_relative)
## [1] 2859   18
otu_rare_relative[1:5, 1:5]
##              KO1        KO2        KO3        KO4        KO5
## ASV_1 0.03306667 0.05453333 0.02013333 0.03613333 0.02686667
## ASV_2 0.05750000 0.03393333 0.06046667 0.05810000 0.07320000
## ASV_3 0.01733333 0.01296667 0.02290000 0.02336667 0.03106667
## ASV_4 0.04266667 0.01093333 0.01416667 0.01933333 0.03346667
## ASV_6 0.02646667 0.01856667 0.02110000 0.02353333 0.03806667
# Taxonomic annotation for the ASVs/OTUs above.
# First column must be the ASV/OTU ID (matching rownames of the abundance tables).
data("tax_tab")
dim(tax_tab)
## [1] 2859    8
tax_tab[1:5, 1:5]
## # A tibble: 5 × 5
##   OTUID  Kingdom  Phylum          Class          Order            
##   <chr>  <chr>    <chr>           <chr>          <chr>            
## 1 ASV_2  Archaea  Thaumarchaeota  Unassigned     Nitrososphaerales
## 2 ASV_3  Bacteria Verrucomicrobia Spartobacteria Unassigned       
## 3 ASV_31 Bacteria Actinobacteria  Actinobacteria Actinomycetales  
## 4 ASV_27 Archaea  Thaumarchaeota  Unassigned     Nitrososphaerales
## 5 ASV_9  Bacteria Unassigned      Unassigned     Unassigned

Build graph object

# Build a co-occurrence network directly from an abundance matrix.
# Internally: (1) optional transform -> (2) correlation -> (3) p-value adjustment
# -> (4) edge filtering -> (5) community detection -> (6) attach taxonomy.
graph_obj <- build_graph_from_mat(
  mat              = otu_rare_relative,  # variables x samples numeric matrix
  transfrom.method = "none",             # input is already relative abundance
  r.threshold      = 0.7,                # |r| cutoff (subjective; consider ggNetView_RMT)
  p.threshold      = 0.05,               # adjusted p-value cutoff
  method           = "WGCNA",            # correlation backend: WGCNA::corAndPvalue
  cor.method       = "pearson",          # Pearson correlation
  proc             = "bonferroni",       # multiple-testing correction
  module.method    = "Fast_greedy",      # community detection algorithm
  node_annotation  = tax_tab,            # taxonomy joined onto each node by name
  top_modules      = 15,                 # keep top-15 modules; rest -> "Others"
  seed             = 1115                # reproducibility
)

# Inspect node/edge counts and the columns now available on nodes:
#   modularity, modularity2, modularity3, Modularity, Degree, Strength + taxonomy
graph_obj
## # A tbl_graph: 213 nodes and 844 edges
## #
## # An undirected simple graph with 29 components
## #
## # Node Data: 213 × 14 (active)
##    name    modularity modularity2 modularity3 Modularity Degree Strength Kingdom
##    <chr>   <fct>      <ord>       <chr>       <ord>       <dbl>    <dbl> <chr>  
##  1 ASV_649 5          5           5           5              27     26.5 Bacter…
##  2 ASV_705 5          5           5           5              27     26.5 Bacter…
##  3 ASV_12… 5          5           5           5              27     26.5 Bacter…
##  4 ASV_13… 5          5           5           5              27     26.5 Bacter…
##  5 ASV_14… 5          5           5           5              27     26.5 Bacter…
##  6 ASV_14… 5          5           5           5              27     26.5 Bacter…
##  7 ASV_24… 5          5           5           5              27     26.5 Bacter…
##  8 ASV_25… 5          5           5           5              27     26.4 Bacter…
##  9 ASV_28… 5          5           5           5              27     26.5 Bacter…
## 10 ASV_28… 5          5           5           5              27     26.5 Bacter…
## # ℹ 203 more rows
## # ℹ 6 more variables: Phylum <chr>, Class <chr>, Order <chr>, Family <chr>,
## #   Genus <chr>, Species <chr>
## #
## # Edge Data: 844 × 5
##    from    to weight correlation corr_direction
##   <int> <int>  <dbl>       <dbl> <chr>         
## 1   194   195  0.959       0.959 Positive      
## 2   185   208  0.954       0.954 Positive      
## 3   185   213  0.957       0.957 Positive      
## # ℹ 841 more rows

2.2 Build graph from data frame

Example data

# Edge-list style example data (protein-protein interactions).
data("ppi_example")

# `df`: edge list — typically 3 columns: node1 | node2 | weight (optional)
df = ppi_example$ppi
head(df)
##   from  to    weight
## 1   A1 D40  9.306533
## 2   A2 D39 11.783920
## 3   A3 D38 23.005025
## 4   A4 D37  7.412060
## 5   A5 D36 18.778894
## 6   A6 D35 16.592965
# `node_annotation`: per-node metadata; first column = node ID
node_annotation = ppi_example$annotation
head(node_annotation)
##   node group
## 1   A1     A
## 2   A2     A
## 3   A3     A
## 4   A4     A
## 5   A5     A
## 6   A6     A

Build graph object

# Build a tbl_graph from an edge-list data.frame (no correlation step needed —
# edges are taken as-is from `df`). Community detection still runs on the result.
graph_obj_from_df <- build_graph_from_df(
  df              = df,                # edge list
  node_annotation = node_annotation,   # per-node metadata (joined by name)
  directed        = F,                 # undirected network
  module.method   = "Fast_greedy",     # community detection
  top_modules     = 15,                # keep top-15 modules; rest -> "Others"
  seed            = 1115
)

graph_obj_from_df
## # A tbl_graph: 100 nodes and 50 edges
## #
## # An unrooted forest with 50 trees
## #
## # Node Data: 100 × 9 (active)
##    name  group modularity modularity2 modularity3 Modularity Degree Segree
##    <chr> <chr> <fct>      <fct>       <chr>       <fct>       <dbl>  <dbl>
##  1 C13   C     1          1           1           1               1      1
##  2 C28   C     1          1           1           1               1      1
##  3 C2    C     10         10          10          10              1      1
##  4 D9    D     10         10          10          10              1      1
##  5 A3    A     11         11          11          11              1      1
##  6 D38   D     11         11          11          11              1      1
##  7 B12   B     12         12          12          12              1      1
##  8 D19   D     12         12          12          12              1      1
##  9 A1    A     13         13          13          13              1      1
## 10 D40   D     13         13          13          13              1      1
## # ℹ 90 more rows
## # ℹ 1 more variable: Strength <dbl>
## #
## # Edge Data: 50 × 4
##    from    to weight correlation
##   <int> <int>  <dbl>       <dbl>
## 1     9    10   45.2        45.2
## 2    15    16   50.6        50.6
## 3     5     6   37.8        37.8
## # ℹ 47 more rows
# Same as above, but without any node annotation table.
# Useful when you only have an edge list and no extra metadata to attach.
graph_obj_from_df2 <- build_graph_from_df(
  df              = df,
  node_annotation = NULL,              # skip the annotation join entirely
  directed        = F,
  module.method   = "Fast_greedy",
  top_modules     = 15,
  seed            = 1115
)

graph_obj_from_df2
## # A tbl_graph: 100 nodes and 50 edges
## #
## # An unrooted forest with 50 trees
## #
## # Node Data: 100 × 8 (active)
##    name  modularity modularity2 modularity3 Modularity Degree Segree Strength
##    <chr> <fct>      <fct>       <chr>       <fct>       <dbl>  <dbl>    <dbl>
##  1 C13   1          1           1           1               1      1     26.7
##  2 C28   1          1           1           1               1      1     26.7
##  3 C2    10         10          10          10              1      1     37.4
##  4 D9    10         10          10          10              1      1     37.4
##  5 A3    11         11          11          11              1      1     37.8
##  6 D38   11         11          11          11              1      1     37.8
##  7 B12   12         12          12          12              1      1     41.3
##  8 D19   12         12          12          12              1      1     41.3
##  9 A1    13         13          13          13              1      1     45.2
## 10 D40   13         13          13          13              1      1     45.2
## # ℹ 90 more rows
## #
## # Edge Data: 50 × 4
##    from    to weight correlation
##   <int> <int>  <dbl>       <dbl>
## 1     9    10   45.2        45.2
## 2    15    16   50.6        50.6
## 3     5     6   37.8        37.8
## # ℹ 47 more rows

2.3 Build graph from data frame with module

Example data

# Like ppi_example, but `annotation` already contains a `Modularity` column
# (i.e. module assignments computed elsewhere — we will NOT recompute them).
data("ppi_module")

df = ppi_module$ppi
head(df)
##   from  to    weight
## 1   A1 D40  9.306533
## 2   A2 D39 11.783920
## 3   A3 D38 23.005025
## 4   A4 D37  7.412060
## 5   A5 D36 18.778894
## 6   A6 D35 16.592965
node_annotation = ppi_module$annotation
head(node_annotation)   # note: must contain a `Modularity` column
##   node Modularity
## 1   A1          A
## 2   A2          A
## 3   A3          A
## 4   A4          A
## 5   A5          A
## 6   A6          A

Build graph object

# When you already have pre-computed module assignments and want to keep them
# (e.g. from a previous WGCNA run, expert curation, biological prior),
# use the `_module` variant — it skips internal community detection and uses
# the Modularity column from `node_annotation` directly.
graph_obj_from_module <- build_graph_from_module(
  df              = df,
  node_annotation = node_annotation,   # MUST contain `Modularity` column
  directed        = F,
  top_modules     = 15,
  seed            = 1115
)

graph_obj_from_module
## # A tbl_graph: 100 nodes and 50 edges
## #
## # An unrooted forest with 50 trees
## #
## # Node Data: 100 × 7 (active)
##    name  Modularity modularity2 modularity3 Degree Segree Strength
##    <chr> <ord>      <ord>       <chr>        <dbl>  <dbl>    <dbl>
##  1 D1    D          D           D                1      1     37.1
##  2 D2    D          D           D                1      1     63.9
##  3 D3    D          D           D                1      1     54.6
##  4 D4    D          D           D                1      1     61.7
##  5 D5    D          D           D                1      1     36.1
##  6 D6    D          D           D                1      1     71.0
##  7 D7    D          D           D                1      1     27.9
##  8 D8    D          D           D                1      1     34.6
##  9 D9    D          D           D                1      1     37.4
## 10 D10   D          D           D                1      1     63.2
## # ℹ 90 more rows
## #
## # Edge Data: 50 × 4
##    from    to weight correlation
##   <int> <int>  <dbl>       <dbl>
## 1    40    91   45.2        45.2
## 2    39    92   50.6        50.6
## 3    38    93   37.8        37.8
## # ℹ 47 more rows

2.4 Build graph from adjacency matrix

Example data

# Square adjacency matrix (already-filtered weights for every node pair).
# Useful when the network was built externally (NetCoMi, FlashWeave, ...).
data("adjacency_matrix_example")
dim(adjacency_matrix_example)
## [1] 2859 2859
adjacency_matrix_example[1:5, 1:5]
##       ASV_1     ASV_2 ASV_3 ASV_4     ASV_6
## ASV_1     0 0.0000000     0     0 0.0000000
## ASV_2     0 0.0000000     0     0 0.8947427
## ASV_3     0 0.0000000     0     0 0.0000000
## ASV_4     0 0.0000000     0     0 0.0000000
## ASV_6     0 0.8947427     0     0 0.0000000
# Reuse the same taxonomy table as node annotation.
data("tax_tab")
dim(tax_tab)
## [1] 2859    8
tax_tab[1:5, 1:5]
## # A tibble: 5 × 5
##   OTUID  Kingdom  Phylum          Class          Order            
##   <chr>  <chr>    <chr>           <chr>          <chr>            
## 1 ASV_2  Archaea  Thaumarchaeota  Unassigned     Nitrososphaerales
## 2 ASV_3  Bacteria Verrucomicrobia Spartobacteria Unassigned       
## 3 ASV_31 Bacteria Actinobacteria  Actinobacteria Actinomycetales  
## 4 ASV_27 Archaea  Thaumarchaeota  Unassigned     Nitrososphaerales
## 5 ASV_9  Bacteria Unassigned      Unassigned     Unassigned

Build graph object

# Build a tbl_graph from a precomputed adjacency matrix.
# Community detection is run internally (Fast_greedy here) because we have
# weights but no module assignments yet.
graph_obj_adj <- build_graph_from_adj_mat(
  adjacency_matrix = adjacency_matrix_example,
  module.method    = "Fast_greedy",
  node_annotation  = tax_tab,
  top_modules      = 15,
  seed             = 1115
)

graph_obj_adj
## # A tbl_graph: 2049 nodes and 9602 edges
## #
## # An undirected simple graph with 100 components
## #
## # Node Data: 2,049 × 14 (active)
##    name    modularity modularity2 modularity3 Modularity Degree Strength Kingdom
##    <chr>   <fct>      <ord>       <chr>       <ord>       <dbl>    <dbl> <chr>  
##  1 ASV_916 1          1           1           1              58     50.5 Bacter…
##  2 ASV_777 1          1           1           1              58     48.7 Bacter…
##  3 ASV_606 1          1           1           1              55     45.8 Bacter…
##  4 ASV_740 1          1           1           1              54     47.2 Bacter…
##  5 ASV_14… 1          1           1           1              54     44.5 Bacter…
##  6 ASV_23… 1          1           1           1              54     47.4 Bacter…
##  7 ASV_15… 1          1           1           1              52     45.3 Bacter…
##  8 ASV_24… 1          1           1           1              52     43.0 Bacter…
##  9 ASV_19… 1          1           1           1              52     43.0 Bacter…
## 10 ASV_568 1          1           1           1              51     45.1 Bacter…
## # ℹ 2,039 more rows
## # ℹ 6 more variables: Phylum <chr>, Class <chr>, Order <chr>, Family <chr>,
## #   Genus <chr>, Species <chr>
## #
## # Edge Data: 9,602 × 5
##    from    to weight correlation corr_direction
##   <int> <int>  <dbl>       <dbl> <chr>         
## 1  1771  1825  0.793       0.793 Positive      
## 2   594   597  0.895       0.895 Positive      
## 3   588   597  0.864       0.864 Positive      
## # ℹ 9,599 more rows

2.5 Build graph from adjacency matrix with module information

# Add a pre-existing module assignment to the annotation table.
# Here we just (for demonstration) treat the Kingdom column as the module label;
# in real use, this should be your actual module assignments.
tax_tab_module <- tax_tab %>%
  dplyr::mutate(Modularity = Kingdom)
# `_module` variant for adjacency input: REQUIRES `node_annotation` to contain
# a `Modularity` column. Skips community detection and uses your provided
# module assignments directly.
graph_obj_adj_module <- build_graph_from_adj_mat_module(
  adjacency_matrix = adjacency_matrix_example,
  node_annotation  = tax_tab_module,   # MUST contain `Modularity` column
  top_modules      = 15,
  seed             = 1115
)
## The max module in network is 3 we use the 3  modules for next analysis
graph_obj_adj_module
## # A tbl_graph: 2049 nodes and 9602 edges
## #
## # An undirected simple graph with 100 components
## #
## # Node Data: 2,049 × 14 (active)
##    name   Kingdom Phylum Class Order Family Genus Species Modularity modularity2
##    <chr>  <chr>   <chr>  <chr> <chr> <chr>  <chr> <chr>   <ord>      <ord>      
##  1 ASV_9… Bacter… Prote… Gamm… Unas… Unass… Unas… Unassi… Bacteria   Bacteria   
##  2 ASV_7… Bacter… Acido… Acid… Unas… Unass… Gp6   Unassi… Bacteria   Bacteria   
##  3 ASV_6… Bacter… Actin… Acti… Acti… Nocar… Marm… Unassi… Bacteria   Bacteria   
##  4 ASV_3… Bacter… Prote… Beta… Unas… Unass… Unas… Unassi… Bacteria   Bacteria   
##  5 ASV_7… Bacter… Acido… Acid… Unas… Unass… Gp16  Unassi… Bacteria   Bacteria   
##  6 ASV_1… Bacter… Actin… Acti… Unas… Unass… Unas… Unassi… Bacteria   Bacteria   
##  7 ASV_2… Bacter… Prote… Alph… Rhiz… Hypho… Rhod… Unassi… Bacteria   Bacteria   
##  8 ASV_25 Bacter… Verru… Spar… Unas… Unass… Spar… Unassi… Bacteria   Bacteria   
##  9 ASV_7… Bacter… Actin… Acti… Acti… Cellu… Cell… Cellul… Bacteria   Bacteria   
## 10 ASV_1… Bacter… Acido… Acid… Unas… Unass… Gp3   Unassi… Bacteria   Bacteria   
## # ℹ 2,039 more rows
## # ℹ 4 more variables: modularity3 <chr>, Degree <dbl>, Segree <dbl>,
## #   Strength <dbl>
## #
## # Edge Data: 9,602 × 5
##    from    to weight correlation corr_direction
##   <int> <int>  <dbl>       <dbl> <chr>         
## 1  1211  1492  0.793       0.793 Positive      
## 2   323  2013  0.895       0.895 Positive      
## 3   267  2013  0.864       0.864 Positive      
## # ℹ 9,599 more rows

2.6 Build graph from double matrix

Example data

# Two abundance matrices on the SAME samples but DIFFERENT feature sets,
# typically used for cross-kingdom networks (e.g. bacteria <-> fungi).

# Bacterial ASV table
data("BASV_tab")
dim(BASV_tab)
## [1] 50 10
BASV_tab[1:5, 1:5]
##         Sample1   Sample2   Sample3   Sample4   Sample5
## BASV1  7.769249 14.676091  6.822246 11.806957 12.086254
## BASV2 10.771846  7.749385 14.966987  7.486507 12.645461
## BASV3 11.746937 10.023547 10.025906 11.967562  8.748440
## BASV4  8.210859  4.408296 10.070862  8.954202 14.639298
## BASV5  9.833271  9.776280 10.465463  8.380012  8.905738
# Fungal ASV table
data("FASV_tab")
dim(FASV_tab)
## [1] 50 10
FASV_tab[1:5, 1:5]
##         Sample1   Sample2   Sample3   Sample4   Sample5
## FASV1  8.195641  7.715472 13.247401 10.419618 11.961410
## FASV2 10.032701 12.427388  7.693471 10.711077 12.157527
## FASV3 10.109549 11.891917  9.607849  8.256637  9.989264
## FASV4  9.817056  8.038730  5.519155  7.601228 12.688531
## FASV5 13.370263  9.795554 13.639041 11.071635  8.176218
# Combined node annotation table covering BOTH feature sets above.
data("double_mat_node_df")
dim(double_mat_node_df)
## [1] 100   2
head(double_mat_node_df)
##    name      type
## 1 BASV1 Bacterial
## 2 BASV2 Bacterial
## 3 BASV3 Bacterial
## 4 BASV4 Bacterial
## 5 BASV5 Bacterial
## 6 BASV6 Bacterial

Build graph object

# Cross-domain bipartite-style network:
# correlations are computed BETWEEN features in mat1 and features in mat2
# (no within-mat1 / within-mat2 edges), then thresholded, modularised, joined
# with node annotation.
graph_obj_double_mat <- build_graph_from_double_mat(
  mat1            = BASV_tab,          # set A (e.g. bacteria)
  mat2            = FASV_tab,          # set B (e.g. fungi)
  module.method   = "Fast_greedy",
  node_annotation = double_mat_node_df,
  top_modules     = 15,
  seed            = 1115
)
## The max module in network is 4 we use the 4  modules for next analysis
graph_obj_double_mat
## # A tbl_graph: 100 nodes and 2500 edges
## #
## # A bipartite simple graph with 1 component
## #
## # Node Data: 100 × 9 (active)
##    name   type      modularity modularity2 modularity3 Modularity Degree Segree
##    <chr>  <chr>     <fct>      <fct>       <chr>       <fct>       <dbl>  <dbl>
##  1 BASV3  Bacterial 1          1           1           1              50     50
##  2 BASV6  Bacterial 1          1           1           1              50     50
##  3 BASV8  Bacterial 1          1           1           1              50     50
##  4 BASV13 Bacterial 1          1           1           1              50     50
##  5 BASV17 Bacterial 1          1           1           1              50     50
##  6 BASV19 Bacterial 1          1           1           1              50     50
##  7 BASV25 Bacterial 1          1           1           1              50     50
##  8 BASV26 Bacterial 1          1           1           1              50     50
##  9 BASV27 Bacterial 1          1           1           1              50     50
## 10 BASV31 Bacterial 1          1           1           1              50     50
## # ℹ 90 more rows
## # ℹ 1 more variable: Strength <dbl>
## #
## # Edge Data: 2,500 × 5
##    from    to weight correlation corr_direction
##   <int> <int>  <dbl>       <dbl> <chr>         
## 1    15    57  0.338      -0.338 Negative      
## 2    57    90  0.648       0.648 Positive      
## 3    16    57  0.162       0.162 Positive      
## # ℹ 2,497 more rows

2.7 Build graph from igraph object

# Load the PPI example dataset (edge list + node annotation).
data("ppi_example")

# First build a native igraph object directly from the edge list.
# This is what users typically already have when they come from an igraph workflow.
igraph_object <- igraph::graph_from_data_frame(
  d        = ppi_example$ppi,          # edge list
  vertices = ppi_example$annotation,   # vertex metadata
  directed = FALSE
)

igraph_object
## IGRAPH 32738cf UNW- 100 200 -- 
## + attr: name (v/c), group (v/c), weight (e/n)
## + edges from 32738cf (vertex names):
##  [1] A1 --D40 A2 --D39 A3 --D38 A4 --D37 A5 --D36 A6 --D35 A7 --D34 A8 --D33
##  [9] A9 --D32 A10--D31 B1 --D30 B2 --D29 B3 --D28 B4 --D27 B5 --D26 B6 --D25
## [17] B7 --D24 B8 --D23 B9 --D22 B10--D21 B11--D20 B12--D19 B13--D18 B14--D17
## [25] B15--D16 B16--D15 B17--D14 B18--D13 B19--D12 B20--D11 C1 --D10 C2 --D9 
## [33] C3 --D8  C4 --D7  C5 --D6  C6 --D5  C7 --D4  C8 --D3  C9 --D2  C10--D1 
## [41] C11--C30 C12--C29 C13--C28 C14--C27 C15--C26 C16--C25 C17--C24 C18--C23
## [49] C19--C22 C20--C21 C20--C21 C19--C22 C18--C23 C17--C24 C16--C25 C15--C26
## [57] C14--C27 C13--C28 C12--C29 C11--C30 C10--D1  C9 --D2  C8 --D3  C7 --D4 
## + ... omitted several edges
# Convert an existing igraph object into a ggNetView-compatible tbl_graph.
# Adds Modularity / Degree / Strength columns and harmonises the schema so it
# can be plugged straight into ggNetView().
graph_obj_from_igraph <- build_graph_from_igraph(
  igraph        = igraph_object,
  module.method = "Fast_greedy",
  seed          = 1115
)

graph_obj_from_igraph
## # A tbl_graph: 100 nodes and 50 edges
## #
## # An unrooted forest with 50 trees
## #
## # Node Data: 100 × 8 (active)
##    name  group modularity modularity2 modularity3 Modularity Degree Strength
##    <chr> <chr> <fct>      <ord>       <chr>       <ord>       <dbl>    <dbl>
##  1 C13   C     1          1           1           1               1     26.7
##  2 C28   C     1          1           1           1               1     26.7
##  3 C2    C     10         10          10          10              1     37.4
##  4 D9    D     10         10          10          10              1     37.4
##  5 A3    A     11         11          11          11              1     37.8
##  6 D38   D     11         11          11          11              1     37.8
##  7 B12   B     12         12          12          12              1     41.3
##  8 D19   D     12         12          12          12              1     41.3
##  9 A1    A     13         13          13          13              1     45.2
## 10 D40   D     13         13          13          13              1     45.2
## # ℹ 90 more rows
## #
## # Edge Data: 50 × 3
##    from    to weight
##   <int> <int>  <dbl>
## 1     9    10   45.2
## 2    15    16   50.6
## 3     5     6   37.8
## # ℹ 47 more rows

2.8 Build graph from WGCNA

# Workflow for importing an existing WGCNA pipeline output.
# (Not evaluated here because it requires external files saved by WGCNA::blockwiseModules.)

# 1. Load the topological overlap matrix (TOM) saved by WGCNA.
load(file = "WGCNA.tom-block.1.RData")
TOM_mat <- as.matrix(TOM)

# 2. Load the abundance matrix used to build that TOM (for any downstream
#    re-thresholding / sanity checks).
plot.mat = readRDS(file = "plot.mat.Rds")

# 3. Sparsify the TOM: keep only the top_k strongest TOM connections per node.
#    `trans_TOM_in_WGCNA()` is a helper bundled with ggNetView for this step.
trans_TOM <- trans_TOM_in_WGCNA(TOM_mat, plot.mat, top_k = 1)

# 4. Load the WGCNA net object (contains module colour assignments).
net <- readRDS(file = "net.Rds")

# 5. Build the module table — one row per feature, columns: ID + Module.
module <- data.frame(
  ID     = names(net$colors),
  Module = as.character(net$colors)
)

# 6. Optional ordering of node IDs (used as node_annotation here).
id <- data.frame(
  ID = names(sort(net$colors))
)

# 7. Assemble the tbl_graph: uses the sparsified TOM as edge weights and the
#    WGCNA module colours as the Modularity assignment (no recomputation).
obj <- build_graph_from_wgcna(
  wgcna_tom       = trans_TOM,
  module          = module,
  node_annotation = id
)

obj

2.9 Build graph from multi-graph

# Consensus network workflow:
# (1) Build per-method networks on the SAME matrix.
# (2) Convert each tbl_graph back to an adjacency matrix.
# (3) Fuse the per-method adjacencies into ONE consensus tbl_graph.

# Restrict to the 40 most abundant OTUs to keep this chunk responsive.
data(otu_rare_relative)
mat <- as.matrix(otu_rare_relative)
mat <- mat[order(rowSums(mat), decreasing = TRUE)[seq_len(40)], ]

# ---- (1) Three per-method networks on the same data ----
# Spearman correlation through psych::corr.test — baseline.
g_cor   <- build_graph_from_mat(mat, method = "cor",   cor.method = "spearman",
                                proc = "BH", r.threshold = 0.4, p.threshold = 0.05,
                                module.method = "Fast_greedy", seed = 1)
## The max module in network is 5 we use the 5  modules for next analysis
# WGCNA-style correlation (WGCNA::corAndPvalue + the package's thresholding).
g_wgcna <- build_graph_from_mat(mat, method = "WGCNA", cor.method = "spearman",
                                proc = "BH", r.threshold = 0.4, p.threshold = 0.05,
                                module.method = "Fast_greedy", seed = 1)
## The max module in network is 6 we use the 6  modules for next analysis
# Hmisc::rcorr — yet another correlation engine, slightly different tie/NA behaviour.
g_hmisc <- build_graph_from_mat(mat, method = "Hmisc", cor.method = "spearman",
                                r.threshold = 0.4, p.threshold = 0.05,
                                module.method = "Fast_greedy", seed = 1)
## The max module in network is 4 we use the 4  modules for next analysis
# ---- (2) tbl_graph -> adjacency matrix ----
# `get_graph_adjacency()` recovers the weighted adjacency matrix from a tbl_graph,
# which is the format expected by build_graph_from_consensus().
adj_cor   <- get_graph_adjacency(g_cor)
adj_wgcna <- get_graph_adjacency(g_wgcna)
adj_hmisc <- get_graph_adjacency(g_hmisc)

# Bundle the per-method matrices into a named list. The names ("cor", "wgcna",
# "hmisc") are kept as method labels in subsequent reports.
adj_list <- list(cor = adj_cor, wgcna = adj_wgcna, hmisc = adj_hmisc)

# ---- (3) Consensus fusion ----
# Borda rank fusion: ranks every pair by |w| in each method, averages the ranks,
# then min-max rescales to [-1, 1]. Robust to across-method weight-scale differences.
g_borda <- build_graph_from_consensus(
  adj_list              = adj_list,
  method                = "rank_fusion",
  rank_fusion_algorithm = "borda",
  threshold             = 0.5,        # final |w| cutoff applied to the fused matrix
  top_modules           = 5,
  seed                  = 1
)
## The max module in network is 3 we use the 3  modules for next analysis
g_borda
## # A tbl_graph: 8 nodes and 8 edges
## #
## # An undirected simple graph with 3 components
## #
## # Node Data: 8 × 7 (active)
##   name   modularity modularity2 modularity3 Modularity Degree Strength
##   <chr>  <fct>      <ord>       <chr>       <ord>       <dbl>    <dbl>
## 1 ASV_6  1          1           1           1               3     2.33
## 2 ASV_10 1          1           1           1               3     2.33
## 3 ASV_2  1          1           1           1               3     2.33
## 4 ASV_17 1          1           1           1               3     2.33
## 5 ASV_36 2          2           2           2               1     1   
## 6 ASV_38 2          2           2           2               1     1   
## 7 ASV_33 3          3           3           3               1     1   
## 8 ASV_37 3          3           3           3               1     1   
## #
## # Edge Data: 8 × 5
##    from    to weight correlation corr_direction
##   <int> <int>  <dbl>       <dbl> <chr>         
## 1     1     2  0.667       0.667 Positive      
## 2     1     3  0.667       0.667 Positive      
## 3     1     4  1           1     Positive      
## # ℹ 5 more rows