--- 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. - 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. - 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. - Tikka, S., López-Pernas, S., & Saqr, M. (2025). tna: An R Package for Transition Network Analysis. *Applied Psychological Measurement*.