# Introduction to cograph

    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.

    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.

    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`.

    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

    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()`.

    strong <- filter_edges(mat, weight > 0.3)
    get_edges(strong)
    #>    from to weight
    #> 1     8  3   0.33
    #> 2    10  3   0.49
    #> 3     8  4   0.43
    #> 4    10  4   0.39
    #> 5     1  5   0.35
    #> 6     6  5   0.35
    #> 7     7  5   0.42
    #> 8     2  6   0.40
    #> 9     4  6   0.34
    #> 10    2  8   0.49
    #> 11    9  8   0.39
    #> 12    3  9   0.37
    #> 13    2 10   0.36

    top3 <- select_nodes(mat, top = 3, by = "betweenness")
    get_labels(top3)
    #> [1] "Plan"    "Monitor" "Adapt"

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 node centrality measures and returns one tidy data frame. The built-in `student_interactions` edge list works directly: no igraph object, no matrix conversion, no setup code.

    data(student_interactions)
    centrality(student_interactions)
    #>    node degree_all strength_all closeness_all betweenness  eigenvector
    #> 1    Ac         33          129    0.01754386   26.342857 1.000000e+00
    #> 2    Ad         20           36    0.01754386   42.541520 1.096110e-01
    #> 3    Fi         24           51    0.01666667   35.721634 1.789565e-01
    #> 4    Ik         14           24    0.01666667   25.844874 1.551369e-02
    #> 5    Vx         26           43    0.01960784   90.717124 7.238902e-02
    #> 6    Rt         20           37    0.01785714   63.135739 1.159931e-01
    #> 7    Km         11           16    0.01639344   18.175108 2.804725e-02
    #> 8    Gj         19           31    0.01818182  114.599049 3.265786e-02
    #> 9    Bd         12           18    0.01612903   21.769264 9.607736e-03
    #> 10   Ce         10           13    0.01612903   16.648629 4.473504e-03
    #> 11   Oq         14           20    0.01754386   34.151726 2.293068e-02
    #> 12   Ya         13           19    0.01612903   18.216122 1.758656e-02
    #> 13   Mo         12           17    0.01587302   38.264502 1.003629e-01
    #> 14   Hj         12           19    0.01754386   85.816522 2.013125e-02
    #> 15   Tv         10           13    0.01666667   25.916306 1.320877e-02
    #> 16   Eg         10           12    0.01639344   22.335171 5.783916e-03
    #> 17   Pr         11           18    0.01666667   23.974060 7.602231e-02
    #> 18   Qs         15           19    0.01785714   76.910851 1.511764e-02
    #> 19   Xz         14           18    0.01639344   22.280159 8.533484e-03
    #> 20   Np          8            8    0.01666667   12.044048 1.549052e-02
    #> 21   Dg         13           13    0.01886792   29.240901 6.260099e-03
    #> 22   Hk         16           25    0.01818182   72.176441 1.201845e-01
    #> 23   Wy         11           16    0.01639344   34.014358 1.054705e-03
    #> 24   Jl         15           18    0.01818182   67.359085 5.009801e-02
    #> 25   Fh         21           55    0.01818182   78.588877 2.817489e-01
    #> 26   Zb          7            8    0.01538462    9.583333 5.429715e-05
    #> 27   Eh          7           13    0.01428571   34.325000 1.163185e-03
    #> 28   Be         14           16    0.01851852  105.250898 2.203252e-03
    #> 29   Df          8           10    0.01562500   11.026190 4.800876e-06
    #> 30   Cf         12           15    0.01724138  119.109163 1.243207e-02
    #> 31   Su          6            9    0.01369863   33.154401 1.028472e-04
    #> 32   Ln          7            8    0.01408451    5.749708 1.376854e-02
    #> 33   Gi          3            4    0.01351351    0.000000 1.280388e-17
    #> 34   Uw          4            7    0.01250000    0.000000 6.480230e-20
    #>       pagerank
    #> 1  0.285861728
    #> 2  0.052985644
    #> 3  0.077591140
    #> 4  0.024836857
    #> 5  0.057364714
    #> 6  0.042552472
    #> 7  0.016655998
    #> 8  0.025444498
    #> 9  0.014321668
    #> 10 0.010679742
    #> 11 0.016087378
    #> 12 0.016588876
    #> 13 0.031180263
    #> 14 0.019051413
    #> 15 0.012644206
    #> 16 0.010425091
    #> 17 0.022794289
    #> 18 0.019784870
    #> 19 0.013229134
    #> 20 0.008466679
    #> 21 0.010345027
    #> 22 0.040383192
    #> 23 0.009067435
    #> 24 0.020529375
    #> 25 0.070538086
    #> 26 0.005635780
    #> 27 0.010080122
    #> 28 0.009378924
    #> 29 0.004957518
    #> 30 0.017877547
    #> 31 0.005136500
    #> 32 0.007628879
    #> 33 0.005483193
    #> 34 0.004411765

That one call returns the default centrality table: degree, strength, closeness, betweenness, eigenvector centrality, and PageRank. Individual functions return named vectors when you want one measure only:

    centrality_degree(student_interactions)
    #> Ac Ad Fi Ik Vx Rt Km Gj Bd Ce Oq Ya Mo Hj Tv Eg Pr Qs Xz Np Dg Hk Wy Jl Fh Zb
    #> 33 20 24 14 26 20 11 19 12 10 14 13 12 12 10 10 11 15 14  8 13 16 11 15 21  7
    #> Eh Be Df Cf Su Ln Gi Uw
    #>  7 14  8 12  6  7  3  4
    centrality_pagerank(student_interactions)
    #>          Ac          Ad          Fi          Ik          Vx          Rt
    #> 0.285861728 0.052985644 0.077591140 0.024836857 0.057364714 0.042552472
    #>          Km          Gj          Bd          Ce          Oq          Ya
    #> 0.016655998 0.025444498 0.014321668 0.010679742 0.016087378 0.016588876
    #>          Mo          Hj          Tv          Eg          Pr          Qs
    #> 0.031180263 0.019051413 0.012644206 0.010425091 0.022794289 0.019784870
    #>          Xz          Np          Dg          Hk          Wy          Jl
    #> 0.013229134 0.008466679 0.010345027 0.040383192 0.009067435 0.020529375
    #>          Fh          Zb          Eh          Be          Df          Cf
    #> 0.070538086 0.005635780 0.010080122 0.009378924 0.004957518 0.017877547
    #>          Su          Ln          Gi          Uw
    #> 0.005136500 0.007628879 0.005483193 0.004411765

Selected 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.

    network_summary(mat)
    #>   node_count edge_count density component_count diameter mean_distance min_cut
    #> 1         10         30   0.333               1     0.97         0.435       1
    #>   centralization_degree centralization_in_degree centralization_out_degree
    #> 1                 0.123                    0.333                     0.222
    #>   centralization_betweenness centralization_closeness centralization_eigen
    #> 1                      0.149                    0.238                0.479
    #>   transitivity reciprocity assortativity_degree hub_score authority_score
    #> 1        0.423       0.111               -0.116        NA              NA

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.

    comms <- communities(mat, method = "walktrap")
    comms
    #> Community structure (walktrap)
    #>   Nodes: 10  | Communities: 2  | Modularity: 0.1976
    #>   Sizes: 5, 5
    #>
    #>        node community
    #>     Explore         1
    #>        Plan         2
    #>     Monitor         2
    #>       Adapt         1
    #>     Reflect         1
    #>     Discuss         1
    #>  Synthesize         1
    #>    Evaluate         2
    #>      Create         2
    #>       Share         2
    community_sizes(comms)
    #> [1] 5 5

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).

    mot <- motifs(mat, significance = FALSE)
    mot
    #> Motif Census
    #> Level: aggregate | States: 10 | Pattern: triangle
    #>
    #> Type distribution:
    #> 030T 120C 030C 120D 120U
    #>   11    3    2    2    1
    #>
    #> Top 5 results:
    #>  type count
    #>  030T    11
    #>  120C     3
    #>  030C     2
    #>  120D     2
    #>  120U     1

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.

    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).

    disparity_filter(mat)
    splot.tna_disparity(disparity_filter(mat))

## Multi-cluster visualization

    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
`csum()` / `summarize_clusters()` | Pre-compute cluster aggregation
`as_tna()` / `as_mcml()` | Convert cluster summaries to tna objects
`summarize_network()` / `cnet()` | Extract cluster-level network (matrix aggregation)

## 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.

    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 — complete list of all functions with examples
- cograph pkgdown site — full documentation and articles

Blog posts:

- cograph: Complex Network Analysis and Visualization — overview of the package design and capabilities
- Human–AI Interaction: A TNA with 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