---
title: "Introduction to cograph"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Introduction to cograph}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

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

## Why cograph

R has several network packages — igraph for graph algorithms, qgraph for psychometric networks, tidygraph for dplyr-style manipulation. Each does one thing well but forces you into its own data format and API. Going from a raw matrix to a filtered, annotated, publication-ready figure typically means loading three packages, converting between formats, and writing boilerplate code to stitch the results together.

cograph was designed to eliminate that friction. Every function — plotting, centrality, community detection, filtering — accepts any major network format directly: matrices, edge lists, igraph, statnet, qgraph, and tna objects. No manual conversion. Centrality returns a tidy data frame, not a list of separate calls. Community detection is one function with 11 algorithms behind it. Statistical annotations (confidence intervals, p-values, significance stars) render directly on the figure. And when you need igraph or statnet for something cograph does not do, `to_igraph()` and `to_network()` convert back without data loss.

Beyond standard network analysis, cograph visualizes higher-order sequential pathways as simplicial blob diagrams, renders bootstrap stability results with forest plots (linear, circular, and grouped layouts), and performs motif analysis that identifies specific named node triples — not just abstract type counts.

The result is a single package that covers the full workflow from data import to publication-ready output, while remaining interoperable with the rest of the R network ecosystem.

```{r}
set.seed(42)
n <- 10
states <- c("Explore", "Plan", "Monitor", "Adapt", "Reflect",
            "Discuss", "Synthesize", "Evaluate", "Create", "Share")
mat <- matrix(0, n, n, dimnames = list(states, states))
# Sparse: ~30% of edges populated
edges <- sample(which(row(mat) != col(mat)), 30)
mat[edges] <- round(runif(30, 0.05, 0.5), 2)
```

## Plotting

`splot()` is the main plotting function. One call, publication-ready output.

```{r fig.height=6}
splot(mat, tna_styling = TRUE, minimum = 0.1,
  title = "Learning Regulation Network")
```

Key parameters: `layout`, `minimum`, `node_fill`, `node_size`, `edge_labels`, `curvature`, `scale_nodes_by`, `theme`, `tna_styling`.

```{r eval=FALSE}
splot(mat, layout = "spring")
splot(mat, minimum = 0.1, edge_labels = TRUE)
splot(mat, scale_nodes_by = "betweenness")
splot(mat, theme = "dark")
splot(mat, tna_styling = TRUE)
```

Layouts: `"oval"`, `"spring"`, `"circle"`, `"grid"`, `"mds"`, `"star"`, `"bipartite"`, `"groups"`, or a custom coordinate matrix.

Themes: `"default"`, `"dark"`, `"minimal"`, `"gray"`, `"nature"`, `"colorblind"`, `"viridis"`.

Node shapes: `"circle"`, `"square"`, `"triangle"`, `"diamond"`, `"pentagon"`, `"hexagon"`, `"star"`, `"heart"`, `"ellipse"`, `"cross"`, `"rectangle"`, `"pie"`, `"donut"`, or custom SVG via `register_svg_shape()`.

## Specialized plots

| Function | Purpose |
|----------|---------|
| `splot()` | Network graph (base R) |
| `soplot()` | Grid/ggplot2 network |
| `plot_tna()` / `tplot()` | TNA-style wrappers with qgraph-compatible parameters |
| `plot_chord()` | Chord diagram (directed/undirected ribbons) |
| `plot_heatmap()` | Adjacency heatmap with clustering |
| `plot_ml_heatmap()` | Multi-layer comparison heatmap |
| `plot_transitions()` / `plot_alluvial()` | Alluvial / Sankey flow diagrams |
| `plot_trajectories()` | Individual trajectory tracking |
| `plot_compare()` | Difference network between two matrices |
| `plot_comparison_heatmap()` | Side-by-side heatmap comparison |
| `plot_mixed_network()` | Directed + undirected edges combined |
| `plot_bootstrap_forest()` | Bootstrap CI forest plots (linear, circular, grouped) |
| `plot_edge_diff_forest()` | Edge difference plots (linear, circular, chord, tile) |
| `plot_simplicial()` | Higher-order pathway blob overlays |
| `overlay_communities()` | Community blob overlays on network |
| `plot_mcml()` | Two-layer hierarchical cluster visualization |
| `plot_mtna()` | Flat multi-cluster layout |
| `plot_mlna()` | Stacked multilayer 3D perspective |
| `plot_htna()` | Multi-group heterogeneous TNA layout |
| `plot_robustness()` | Robustness degradation curves |
| `plot_permutation()` / `plot_group_permutation()` | Permutation test results |

```{r fig.height=6, fig.width=10}
plot_simplicial(mat,
  c("Explore Plan -> Monitor",
    "Monitor Adapt -> Reflect",
    "Discuss Synthesize -> Evaluate",
    "Create Share -> Explore"),
  dismantled = TRUE, ncol = 2,
  title = "Higher-Order Pathways")
```

## Input formats

Every function accepts six formats directly.

| Format | Example |
|--------|---------|
| Matrix | `splot(mat)` |
| Edge list | `splot(data.frame(from = "A", to = "B", weight = 1))` |
| igraph | `splot(igraph::make_ring(5))` |
| statnet | `splot(network::network(mat))` |
| qgraph | `from_qgraph(q)` |
| tna | `splot(tna::tna(data))` |

Conversion utilities:

| Function | Output |
|----------|--------|
| `as_cograph(x)` | cograph_network object |
| `to_igraph(x)` | igraph object |
| `to_matrix(x)` | Adjacency matrix |
| `to_data_frame(x)` / `to_df(x)` | Edge list data frame |
| `to_network(x)` | statnet network object |
| `from_qgraph(q)` | Extract qgraph styles into cograph |

## Filtering and selection

Filter edges and nodes with expressions. Centrality measures are lazy-computed inside `filter_nodes()`.

```{r}
strong <- filter_edges(mat, weight > 0.3)
get_edges(strong)
```

```{r}
top3 <- select_nodes(mat, top = 3, by = "betweenness")
get_labels(top3)
```

| Function | Purpose |
|----------|---------|
| `filter_edges(x, ...)` | Filter by weight, from, to |
| `filter_nodes(x, ...)` | Filter by degree, centrality, label |
| `select_nodes(x, ...)` | Top-N by centrality, by name, neighbors |
| `select_edges(x, ...)` | Top-N, involving, between, bridges, mutual |
| `select_neighbors(x, of)` | Ego-network extraction (multi-hop) |
| `select_component(x)` | Largest or named component |
| `select_top(x, n, by)` | Top-N nodes by any centrality |
| `select_bridges(x)` | Bridge edges only |
| `select_top_edges(x, n)` | Top-N edges by weight |
| `select_edges_involving(x, nodes)` | Edges touching specific nodes |
| `select_edges_between(x, s1, s2)` | Edges between two node sets |
| `subset_nodes(x, ...)` / `subset_edges(x, ...)` | Base R-style subsetting |
| `simplify(x)` | Remove multi-edges and self-loops |

Getters and setters:

| Function | Purpose |
|----------|---------|
| `get_nodes(x)` / `set_nodes(x, df)` | Node data frame |
| `get_edges(x)` / `set_edges(x, df)` | Edge data frame |
| `get_labels(x)` | Node label vector |
| `n_nodes(x)` / `n_edges(x)` | Counts |
| `is_directed(x)` | Directedness |
| `set_groups(x)` / `get_groups(x)` | Group assignments |
| `set_layout(x, layout)` | Layout coordinates |
| `summarize_network(x)` | Network summary |

## Centrality

`centrality()` computes up to 25 measures and returns a data frame.

```{r}
centrality(mat, measures = c("degree", "betweenness", "pagerank"))
```

Individual functions return named vectors:

```{r}
centrality_degree(mat)
centrality_pagerank(mat)
```

All 25 measures:

| Category | Functions |
|----------|-----------|
| Degree | `centrality_degree()`, `centrality_strength()`, `centrality_indegree()`, `centrality_outdegree()`, `centrality_instrength()`, `centrality_outstrength()` |
| Path | `centrality_betweenness()`, `centrality_closeness()`, `centrality_harmonic()`, `centrality_eccentricity()` (each with in/out variants) |
| Spectral | `centrality_eigenvector()`, `centrality_pagerank()`, `centrality_authority()`, `centrality_hub()`, `centrality_alpha()`, `centrality_power()`, `centrality_subgraph()` |
| Structural | `centrality_coreness()`, `centrality_constraint()`, `centrality_transitivity()`, `centrality_laplacian()` |
| Flow | `centrality_current_flow_closeness()`, `centrality_current_flow_betweenness()`, `centrality_load()` |
| Spreading | `centrality_diffusion()`, `centrality_leverage()`, `centrality_kreach()`, `centrality_voterank()`, `centrality_percolation()` |

Edge centrality: `edge_centrality()`, `edge_betweenness()`.

## Network properties

`network_summary()` computes up to 37 network-level metrics.

```{r}
network_summary(mat)
```

| Function | Purpose |
|----------|---------|
| `network_summary()` | 37 metrics (density, diameter, clustering, etc.) |
| `network_small_world()` | Small-world coefficient |
| `network_rich_club()` | Rich-club coefficient |
| `network_global_efficiency()` | Global efficiency |
| `network_local_efficiency()` | Local efficiency |
| `degree_distribution()` | Degree histogram |
| `network_girth()` | Shortest cycle |
| `network_radius()` | Minimum eccentricity |
| `network_bridges()` | Bridge edges |
| `network_cut_vertices()` | Articulation points |
| `network_vertex_connectivity()` | Minimum vertices to disconnect |
| `network_clique_size()` | Largest complete subgraph |

## Community detection

11 algorithms with a consistent interface.

```{r}
comms <- communities(mat, method = "walktrap")
comms
community_sizes(comms)
```

| Function | Algorithm | Alias |
|----------|-----------|-------|
| `community_louvain()` | Louvain modularity | `com_lv()` |
| `community_leiden()` | Leiden (improved Louvain) | `com_ld()` |
| `community_fast_greedy()` | Fast greedy | `com_fg()` |
| `community_walktrap()` | Random walk | `com_wt()` |
| `community_infomap()` | Information flow | `com_im()` |
| `community_label_propagation()` | Label propagation | `com_lp()` |
| `community_edge_betweenness()` | Edge betweenness | `com_eb()` |
| `community_leading_eigenvector()` | Leading eigenvector | `com_le()` |
| `community_spinglass()` | Spin glass | `com_sg()` |
| `community_optimal()` | Exact optimization | `com_op()` |
| `community_fluid()` | Fluid communities | `com_fl()` |

Additional community functions:

| Function | Purpose |
|----------|---------|
| `community_consensus()` | Run algorithm N times, keep stable assignments |
| `compare_communities()` | Compare partitions (NMI, VI, Rand, adjusted Rand) |
| `modularity()` | Modularity score |
| `community_sizes()` | Size of each community |
| `color_communities()` | Color vector from community membership |
| `cluster_quality()` | Quality metrics (silhouette, Dunn index) |
| `cluster_significance()` | Permutation-based significance testing |
| `detect_communities()` | Alternative interface (returns data frame) |

## Motifs

Motif analysis identifies recurring 3-node patterns using the MAN classification (16 directed triad types).

```{r}
mot <- motifs(mat, significance = FALSE)
mot
```

| Function | Purpose |
|----------|---------|
| `motifs()` | MAN type census with significance testing |
| `subgraphs()` | Named node triples forming each pattern |
| `motif_census()` | Low-level triad census |
| `extract_motifs()` | Per-individual motif extraction |
| `extract_triads()` | Extract specific triad types |
| `triad_census()` | Raw 16-type triad count |
| `get_edge_list()` | Edge list from tna for motif input |

Plot types: `plot(mot, type = "types")`, `"significance"`, `"triads"`, `"patterns"`.

## Robustness

Simulate network degradation under targeted and random removal.

```{r eval=FALSE}
robustness(mat, type = "vertex", measure = "betweenness", n_iter = 100)
plot_robustness(x = mat, measures = c("betweenness", "degree", "random"))
```

| Function | Purpose |
|----------|---------|
| `robustness()` | Simulate removal attacks (vertex or edge) |
| `plot_robustness()` | Plot robustness curves for multiple strategies |
| `robustness_summary()` | AUC and summary statistics |
| `robustness_auc()` | Area under the robustness curve |

## Disparity filter

Backbone extraction using the disparity filter (Serrano et al. 2009).

```{r eval=FALSE}
disparity_filter(mat)
splot.tna_disparity(disparity_filter(mat))
```

## Multi-cluster visualization

```{r eval=FALSE}
clusters <- list(
  Cognitive  = c("Explore", "Plan", "Monitor", "Adapt", "Reflect"),
  Social     = c("Discuss", "Synthesize", "Share"),
  Evaluative = c("Evaluate", "Create")
)
plot_mcml(mat, clusters, mode = "tna")
plot_mtna(mat, clusters)
```

| Function | Architecture |
|----------|-------------|
| `plot_mcml()` | Two-layer: detail nodes + summary pies |
| `plot_mtna()` | Flat cluster layout |
| `plot_mlna()` | Stacked 3D multilayer |
| `plot_htna()` | Multi-group heterogeneous TNA |
| `cluster_summary()` / `build_mcml()` | Pre-compute cluster aggregation |
| `as_tna()` / `as_mcml()` | Convert cluster summaries to tna objects |
| `cluster_network()` | Extract cluster-level network |

## Multilayer networks

Construct and analyze supra-adjacency matrices for multilayer/multiplex networks.

| Function | Purpose |
|----------|---------|
| `mlna()` / `supra_adjacency()` | Build supra-adjacency matrix |
| `supra_layer()` / `supra_interlayer()` | Extract individual layers |
| `aggregate_layers()` / `aggregate_weights()` | Combine layers |
| `plot_mlna()` | 3D perspective visualization |
| `plot_ml_heatmap()` | Multi-layer heatmap comparison |

## Higher-order networks

Detect sequential dependencies beyond first-order Markov models. Requires the **Nestimate** package.

| Function | Purpose |
|----------|---------|
| `build_hon()` | Higher-Order Network construction |
| `build_hypa()` | Path anomaly detection (hypergeometric null) |
| `build_mogen()` | Multi-order model selection (AIC/BIC) |
| `path_counts()` | k-step path frequencies |
| `plot_simplicial()` | Visualize pathways as blob overlays |
| `build_simplicial()` | Simplicial complex from cliques |
| `persistent_homology()` | Topological persistence across thresholds |
| `q_analysis()` | Multi-level structural connectivity |
| `verify_simplicial()` | Cross-validate via Euler-Poincare theorem |

## TNA integration

Direct support for all tna package objects:

| Object | What splot() does |
|--------|-------------------|
| `tna` | Network with donut rings, TNA styling |
| `group_tna` | Multi-panel grid per group |
| `tna_bootstrap` | Stability-styled edges |
| `tna_permutation` | Colored difference network |
| `group_tna_permutation` | Multi-panel permutation results |
| `tna_disparity` | Backbone filter visualization |

## Palettes

| Function | Colors |
|----------|--------|
| `palette_viridis(n)` | Viridis scale |
| `palette_pastel(n)` | Soft pastel |
| `palette_blues(n)` | Blue gradient |
| `palette_reds(n)` | Red gradient |
| `palette_diverging(n)` | Blue-white-red |
| `palette_colorblind(n)` | Colorblind-safe |
| `palette_rainbow(n)` | Rainbow |

## Pipe API

The `sn_*` functions provide a chainable builder for the grid/ggplot2 rendering path.

```{r eval=FALSE}
mat |>
  cograph() |>
  sn_layout("spring") |>
  sn_theme("minimal") |>
  sn_nodes(size = 8, fill = "steelblue") |>
  sn_edges(curvature = 0.2) |>
  sn_render(title = "My Network")

mat |> cograph() |> sn_save("network.pdf")
p <- mat |> cograph() |> sn_ggplot()
```

| Function | Purpose |
|----------|---------|
| `cograph()` / `as_cograph()` | Create network object |
| `sn_nodes()` | Node aesthetics |
| `sn_edges()` | Edge aesthetics |
| `sn_layout()` | Layout algorithm |
| `sn_theme()` | Visual theme |
| `sn_palette()` | Color palette |
| `sn_render()` | Render to screen |
| `sn_save()` / `sn_save_ggplot()` | Save to file |
| `sn_ggplot()` | Convert to ggplot2 object |
| `register_theme()` / `register_layout()` / `register_shape()` | Register custom themes, layouts, shapes |

## Further reading

**Package resources:**

- [cograph function reference](https://saqr.me/cograph/) — complete list of all functions with examples
- [cograph pkgdown site](https://sonsoles.me/cograph/) — full documentation and articles

**Blog posts:**

- [cograph: Complex Network Analysis and Visualization](https://saqr.me/blog/2026/cograph-network-visualization/) — overview of the package design and capabilities
- [Human–AI Interaction: A TNA with cograph](https://saqr.me/blog/2026/human-ai-interaction-cograph/) — worked example analyzing 13,002 turns of human–AI coding collaboration

**References:**

- Saqr, M., López-Pernas, S., Conde, M. A., & Hernández-García, A. (2024). Social Network Analysis: A Primer, a Guide and a Tutorial in R. In *Learning Analytics Methods and Tutorials*. Springer. <https://doi.org/10.1007/978-3-031-54464-4_15>

- Hernández-García, Á., Cuenca-Enrique, C., Traxler, A., López-Pernas, S., Conde-González, M. Á., & Saqr, M. (2024). Community detection in learning networks using R. In *Learning Analytics Methods and Tutorials* (pp. 519–540). Springer. <https://doi.org/10.1007/978-3-031-54464-4_16>

- Saqr, M., López-Pernas, S., Törmänen, T., Kaliisa, R., Misiejuk, K., & Tikka, S. (2025). Transition Network Analysis: A Novel Framework for Modeling, Visualizing, and Identifying the Temporal Patterns of Learners and Learning Processes. In *Proceedings of the 15th LAK Conference* (pp. 351–361). ACM.  <https://doi.org/10.1145/3706468.3706513>

- Tikka, S., López-Pernas, S., & Saqr, M. (2025). tna: An R Package for Transition Network Analysis. *Applied Psychological Measurement*. <https://doi.org/10.1177/01466216251348840>
