---
title: "Network Structure and Node Groups"
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 6,
  fig.height = 4,
  fig.dpi = 300,
  dpi = 300
)
```

## Overview

This tutorial covers:

1. The `cograph_network` data structure
2. Setting node groups with `set_groups()`
3. Auto-dispatch to specialized plot functions

```{r setup}
library(cograph)
```

## The cograph_network Structure

When you call `as_cograph()`, it creates a lightweight S3 object that stores all network data as accessible list elements.

```{r structure}
# Create a simple network
mat <- matrix(c(
  0.0, 0.5, 0.3, 0.0,
  0.5, 0.0, 0.8, 0.2,
  0.3, 0.8, 0.0, 0.6,
  0.0, 0.2, 0.6, 0.0
), nrow = 4, byrow = TRUE)
rownames(mat) <- colnames(mat) <- c("A", "B", "C", "D")

net <- as_cograph(mat)
```

### Accessing Network Data

All data is accessible via `$`:

```{r access}
# Edge data
net$from      # Source node indices
net$to        # Target node indices
net$weight    # Edge weights

# Network properties
net$n_nodes   # Number of nodes
net$n_edges   # Number of edges
net$directed  # Is directed?
net$labels    # Node labels
```

### Using Getter Functions

For programmatic access, use the getter functions:
```{r getters}
get_nodes(net)    # Full nodes data frame
get_edges(net)    # Edges as data frame
get_labels(net)   # Node labels vector
n_nodes(net)      # Node count
n_edges(net)      # Edge count
is_directed(net)  # Directedness
```

## Setting Node Groups

The `set_groups()` function assigns nodes to groups. The **type of group** determines which specialized plot function `splot()` will use:

| Group Type | Column Name | Plot Function | Visualization |
|------------|-------------|---------------|---------------|
| `"layer"`  | `layer`     | `plot_mlna()` | Stacked 3D layers |
| `"cluster"`| `cluster`   | `plot_mtna()` | Clustered shapes |
| `"group"`  | `group`     | `plot_htna()` | Bipartite/polygon |

### Method 1: Vector Arguments (Recommended)

The clearest way to set groups:

```{r vectors, fig.show='hide'}
# Create a larger network for demonstration
set.seed(42)
mat <- matrix(runif(225, 0, 0.4), 15, 15)
diag(mat) <- 0
rownames(mat) <- colnames(mat) <- paste0("N", 1:15)

net <- as_cograph(mat)

# Set layers using vectors
net_layers <- set_groups(net,
  nodes = paste0("N", 1:15),
  layers = c(rep("Macro", 5), rep("Meso", 5), rep("Micro", 5))
)

# Check the result
get_groups(net_layers)
```

```{r vectors-plot, fig.cap="Multilevel network (layers)"}
splot(net_layers)
```

If `nodes` is omitted, the network's node order is used:

```{r vectors-no-nodes, fig.show='hide'}
# Clusters without specifying nodes
net_clusters <- set_groups(net,
  clusters = c("North", "North", "North", "North",
               "East", "East", "East",
               "South", "South", "South", "South",
               "West", "West", "West", "West")
)
```

```{r clusters-plot, fig.cap="Multi-cluster network"}
splot(net_clusters)
```

### Method 2: Named List

Group nodes by name:

```{r named-list, fig.show='hide'}
net_groups <- set_groups(net, list(
  Input = paste0("N", 1:5),
  Processing = paste0("N", 6:10),
  Output = paste0("N", 11:15)
), type = "group")
```

```{r groups-plot, fig.cap="Heterogeneous network (groups)"}
splot(net_groups)
```

### Method 3: Data Frame

Use a data frame with `nodes` and `layers`/`clusters`/`groups` columns:

```{r dataframe}
# Both singular and plural column names work
df <- data.frame(
  nodes = paste0("N", 1:15),
  layers = c(rep("Top", 5), rep("Middle", 5), rep("Bottom", 5))
)

net_df <- set_groups(net, df)
get_groups(net_df)
```

### Method 4: Community Detection

Automatically detect groups using algorithms:

```{r community, fig.show='hide'}
# Make symmetric for community detection
mat_sym <- (mat + t(mat)) / 2
net_sym <- as_cograph(mat_sym)

# Use Louvain algorithm
net_auto <- set_groups(net_sym, "louvain", type = "group")
get_groups(net_auto)
```

```{r community-plot, fig.cap="Auto-detected communities"}
splot(net_auto)
```

Available algorithms: `"louvain"`, `"walktrap"`, `"fast_greedy"`, `"label_prop"`, `"infomap"`, `"leiden"`

## Validation

`set_groups()` validates your input:

```{r validation, error=TRUE}
# Duplicate nodes
try(set_groups(net, nodes = c("N1", "N1", "N2", "N3", "N4"),
               layers = c("A", "A", "B", "B", "B")))

# Unknown nodes
try(set_groups(net, nodes = c("N1", "N2", "N3", "N4", "UNKNOWN"),
               layers = c("A", "A", "B", "B", "B")))

# Missing nodes (not all network nodes assigned)
try(set_groups(net, nodes = c("N1", "N2", "N3"),
               layers = c("A", "B", "B")))

# Only 1 group (need at least 2)
try(set_groups(net, nodes = paste0("N", 1:15),
               layers = rep("Same", 15)))
```

## Auto-Dispatch in splot()

When you call `splot()` on a network with groups, it automatically dispatches to the appropriate specialized function:

```{r dispatch-summary, eval=FALSE}
# These are equivalent:
splot(net_layers)
plot_mlna(mat, layer_list = list(Macro = ..., Meso = ..., Micro = ...))

# These are equivalent:
splot(net_clusters)
plot_mtna(mat, cluster_list = list(North = ..., East = ..., ...))

# These are equivalent:
splot(net_groups)
plot_htna(mat, node_list = list(Input = ..., Processing = ..., Output = ...))
```

## Complete Example: Pipe Workflow

```{r pipe-workflow, fig.cap="Complete pipe workflow"}
# Create, configure, and plot in one pipeline
matrix(runif(100, 0, 0.5), 10, 10) |>
  {\(m) { diag(m) <- 0; rownames(m) <- colnames(m) <- paste0("X", 1:10); m }}() |>
  as_cograph() |>
  set_groups(
    nodes = paste0("X", 1:10),
    layers = c(rep("Input", 3), rep("Hidden", 4), rep("Output", 3))
  ) |>
  splot()
```

## Summary

| Function | Purpose |
|----------|---------|
| `as_cograph()` | Convert matrix/igraph/etc to cograph_network |
| `set_groups()` | Assign node groupings |
| `get_groups()` | Retrieve current groupings |
| `splot()` | Plot (auto-dispatches based on group type) |

| Group Type | Argument | Plot Style |
|------------|----------|------------|
| Layers | `layers = ...` | Stacked 3D (mlna) |
| Clusters | `clusters = ...` | Shaped clusters (mtna) |
| Groups | `type = "group"` | Bipartite/polygon (htna) |
