--- title: "Introduction to cograph" author: "[Mohammed Saqr](https://saqr.me) and [Sonsoles López-Pernas](https://sonsoles.me)" 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 offers several network packages, each with its own data format and interface, among them igraph for graph algorithms, qgraph for psychometric networks, statnet for statistical network models and tidygraph for data manipulation. An analysis that uses more than one of them begins by converting the network between their formats. cograph is designed as a modern R package that offers a comprehensive set of analysis options for social and complex networks, one that is tidy and simple to work with, and above all feature-rich and beautiful. cograph accepts the formats of all of these packages without conversion and returns its own results as tidy data frames. cograph visualizes networks with specialized styling for transition and psychological networks, and plots the results of bootstrap, permutation and stability analyses directly. cograph offers a family of wrangling verbs for selecting, filtering, thresholding and editing networks, a large collection of node centrality measures across all major families, and a wide array of network-level statistics from density and diameter to efficiency and clique size. For community structure, cograph provides a range of detection algorithms together with consensus, comparison and significance testing of partitions, and for local structure, cograph provides motif analysis that identifies the nodes forming each pattern. cograph also supports robustness and vulnerability analysis, backbone extraction with the disparity filter, hierarchical plots for multi-cluster networks, multilayer networks and higher-order pathways. cograph's figures carry statistical annotations such as confidence intervals, p-values and significance stars. The examples below use `regulation_net`, a synthetic weighted transition network among ten learning states such as Explore, Plan and Reflect, included in the package. ## Plotting cograph offers tools for visualizing networks through `splot()` and a set of specialized plots. `splot()` plots any supported network input with base R graphics and has arguments for controlling the layout, the nodes and their pie and donut decorations, the edges with their curvature, arrows and labels, the legends and the theme. It has specialized styling for transition networks (`tna_styling`) and psychological networks (`psych_styling`), and it plots the result objects of tna and Nestimate directly, including bootstrap, permutation and stability results, multilevel VAR models and group comparisons. Heterogeneous transition networks are plotted with `plot_htna()`. ```{r fig.height=6} splot(regulation_net, tna_styling = TRUE, minimum = 0.1, title = "Learning Regulation Network") ``` ```{r eval=FALSE} splot(regulation_net, layout = "spring") splot(regulation_net, minimum = 0.1, edge_labels = TRUE) splot(regulation_net, scale_nodes_by = "betweenness") splot(regulation_net, theme = "dark") splot(regulation_net, tna_styling = TRUE) ``` ## Specialized plots cograph offers a wide array of network plots across visualization domains. These include transitions, flows and individual trajectories over time, network evolution in temporal small multiples and three-dimensional prisms, weight matrices as heatmaps and chord diagrams, centrality profiles with their distributions, comparisons and stability, edge-weight and degree distributions, motifs, comparisons between networks, bootstrap confidence intervals and permutation tests, mixed directed and undirected networks, multi-cluster, multi-group and multilayer structure, community overlays, higher-order pathways and robustness curves. | Function | Purpose | |----------|---------| | `splot()` | Network graph (base R) | | `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_difference()` | 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_centrality()` / `plot_centrality_distribution()` | Centrality profiles and their distributions | | `plot_centrality_heatmap()` / `plot_centrality_compare()` | Centrality across nodes and groups | | `plot_net_stability()` | Centrality stability results | | `plot_edge_weights()` / `plot_degree_correlation()` | Edge-weight distribution and degree-degree correlation | | `plot_motifs()` | Motif and subgraph results | | `plot_network_evolution()` | Network evolution in small multiples | | `plot_temporal()` | Temporal network as a three-dimensional prism | ```{r fig.height=6, fig.width=10} plot_simplicial(regulation_net, c("Explore Plan -> Monitor", "Monitor Adapt -> Reflect", "Discuss Synthesize -> Evaluate", "Create Share -> Explore"), dismantled = TRUE, ncol = 2, title = "Higher-Order Pathways") ``` ## Input formats cograph accepts adjacency matrices, edge lists, and igraph, statnet, qgraph and tna objects without conversion. Its conversion functions export a network to igraph, statnet, matrix and edge-list formats for exchange with other packages, and `from_qgraph()` imports the styling of a qgraph plot. | Format | Example | |--------|---------| | Matrix | `splot(regulation_net)` | | Edge list | `splot(data.frame(from = "A", to = "B", weight = 1))` | | igraph | `splot(igraph::make_ring(5))` | | statnet | `splot(network::network(regulation_net))` | | qgraph | `from_qgraph(q)` | | tna | `splot(tna::tna(data))` | | 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 | ## Wrangling cograph offers a family of wrangling verbs for selecting and filtering nodes and edges, thresholding and transforming weights, and restructuring and editing a network. Every verb accepts any supported input, takes its options as named arguments and returns a network, so verbs chain with the native pipe. `as.data.frame()` returns the edges as a tidy data frame, and `as.data.frame(what = "nodes")` returns the nodes. ```{r} strong <- filter_edges(regulation_net, weight > 0.3) as.data.frame(strong) ``` `select_nodes()` selects nodes by name or index, the top nodes by any centrality measure, the neighbours of given nodes up to a chosen order, or the nodes of a connected component. `select_edges()` selects the strongest edges, the edges involving or joining given sets of nodes, bridges and mutual ties. Centrality measures named in a selection are computed when the verb runs. ```{r} top3 <- select_nodes(regulation_net, top = 3, by = "betweenness") get_labels(top3) ``` `filter_nodes()` keeps the nodes that satisfy logical expressions over node attributes, any centrality measure, and structural properties such as component membership, k-core, isolation and cut vertices. `filter_edges()` keeps the edges that satisfy expressions over edge columns, such as `weight > mean(weight)`. Filters combine with the other verbs into pipelines that prepare a network for analysis in a single, reproducible expression. The pipeline below keeps the ties with weights of at least 0.3, removes the nodes left without ties, and adds each node's degree and a hub indicator to the node table. ```{r} regulation_net |> threshold_edges(minimum = 0.3) |> remove_isolates() |> mutate_nodes(deg = degree, hub = degree >= 3) |> as.data.frame(what = "nodes") ``` ### Selecting cograph provides functions for extracting ego networks of several orders, connected components, k-cores, bridges and the edges between two sets of nodes. | Function | Purpose | |----------|---------| | `filter_edges(x, ...)` | Filter by weight, endpoints, any edge column | | `filter_nodes(x, ...)` | Filter by degree, centrality, label | | `select_nodes(x, ...)` | Top-N by centrality, by name, neighbors, component | | `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_k_core(x, k)` | The k-core | | `split_components(x)` | One network per component | | `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, ...)` | Aliases of the filters | ### Weights cograph provides functions for thresholding edges by weight, count, proportion or density, binarizing weights, and symmetrizing a directed network by maximum, minimum, mean, sum or mutuality. Further functions normalize weights by row, column, maximum, sum or range, and convert similarities into distances for path-based measures. | Function | Purpose | |----------|---------| | `threshold_edges(x, ...)` | Keep edges by weight, count, proportion, density | | `binarize(x)` | Replace weights with 0/1 | | `symmetrize(x, method)` | Combine opposite arcs into one edge | | `normalize_weights(x, method)` | Rescale by row, column, max, sum, min-max | | `invert_weights(x, method)` | Similarities to distances | ### Structure and editing cograph provides functions for converting between directed and undirected networks, reversing arcs, contracting groups of nodes into single nodes with aggregated weights, extracting minimum or maximum spanning trees and forming the complement of a network. Nodes and edges can be added or removed, their attributes computed, and two networks combined by union, intersection or difference. | Function | Purpose | |----------|---------| | `to_undirected(x)` / `to_directed(x)` | Change directedness | | `reverse_edges(x)` | Reverse every arc | | `remove_isolates(x)` | Drop nodes with no edges | | `contract_nodes(x, groups)` | Collapse groups into single nodes | | `spanning_tree(x)` | Minimum or maximum spanning tree | | `complement_network(x)` | Join the non-adjacent pairs | | `reorder_nodes(x, order)` / `rename_nodes(x, from, to)` | Node order and labels | | `add_nodes()` / `remove_nodes()` / `add_edges()` / `remove_edges()` | Editing | | `mutate_nodes(x, ...)` / `mutate_edges(x, ...)` | Compute and store attributes | | `bind_networks(x, y, method)` | Union, intersection, difference | | `simplify(x)` | Remove multi-edges and self-loops | The node and edge tables, labels, size, direction, group assignments and layout of a network object can be read and set with accessor functions. | Function | Purpose | |----------|---------| | `as.data.frame(x)` | Tidy edge table (`what = "nodes"` for nodes) | | `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 | ## Centrality cograph offers `r nrow(list_centralities())` node centrality measures through `centrality()`, which returns a tidy data frame with a column for each measure, and through individual functions that return a single measure. The measures span degree and strength, distance and closeness, shortest-path brokerage, spectral and walk-based influence, neighbourhood cohesion, directed prestige and community-based roles. Measures that are also implemented elsewhere are tested against igraph, sna, centiserve, brainGraph, influenceR, netrankr and NetworkX. The examples in this section use the built-in `student_interactions` edge list, which `centrality()` accepts directly. ```{r} data(student_interactions) centrality(student_interactions) ``` By default, `centrality()` returns six classical measures: degree, strength, closeness, betweenness, eigenvector centrality and PageRank. Any other measure is chosen by name with `measures`, and `type = "all"` returns every measure of ordinary computational cost. ```{r} centrality_degree(student_interactions) centrality_pagerank(student_interactions) ``` The measures fall into seven families: degree, strength and local connectivity; distance and closeness; shortest-path brokerage and flow; spectral, walk and influence; neighbourhood structure and cohesion; community and group-based roles; and directed prestige and hierarchy. Recent measures from these families include Trust-PageRank, randomized shortest-path betweenness, the Lhc index and the BG-index, and any of them can be requested alongside the classical ones. Community-based measures also require a partition, supplied with `membership`. The centrality catalogue documents every measure with its definition, interpretation and an example. ```{r} centrality(student_interactions, measures = c("collective_influence", "harmonic", "rsp_betweenness", "trust_pagerank", "lhc", "beta_measure"), sort_by = "trust_pagerank", digits = 3) ``` ## Network properties cograph offers network-level statistics through `network_summary()`, which returns density, diameter, mean distance, centralization, reciprocity, transitivity and degree assortativity in a data frame with one row for the network, and up to 35 statistics with `detailed = TRUE` and `extended = TRUE`. Individual functions compute small-worldness, global and local efficiency, the rich-club coefficient, girth, radius, bridges, cut vertices, vertex connectivity and clique size. ```{r} network_summary(regulation_net) ``` | Function | Purpose | |----------|---------| | `network_summary()` | Up to 35 statistics (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 cograph offers tools for studying community structure through detection, consensus, comparison, quality assessment and significance testing of partitions. `communities()` runs eleven community detection algorithms, including Louvain, Leiden, Infomap, walktrap and spinglass, through one call and returns the partition with its modularity, and each algorithm also has its own function with a short alias. `community_consensus()` runs an algorithm repeatedly and returns the consensus partition across runs. `compare_communities()` compares two partitions by variation of information, normalized mutual information, split-join distance or the Rand and adjusted Rand indices, `cluster_quality()` scores a partition, and `cluster_significance()` tests its modularity against random networks that preserve the degree sequence or the number of edges. ```{r} comms <- communities(regulation_net, 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()` | | Function | Purpose | |----------|---------| | `community_consensus()` | Run algorithm N times, keep stable assignments | | `compare_communities()` | Compare partitions (NMI, VI, Rand, adjusted Rand) | | `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 cograph offers motif analysis for directed networks based on the 16 triads of the MAN classification. `motifs()` counts each triad type and tests its frequency with a permutation test, across the whole network, per actor, or within rolling and tumbling windows. `subgraphs()` identifies the nodes behind each motif and reports which node triples form each pattern, in how many sessions or actors they occur, and whether they occur more often than expected. `plot()` visualizes the counts, their significance, the triads and the patterns. ```{r} mot <- motifs(regulation_net, 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 | ## Robustness cograph offers tools for studying network robustness and vulnerability through simulated attacks and node-level efficiency loss. `robustness()` simulates the sequential removal of nodes or edges, ordered by a centrality measure or at random, and returns the size of the largest component at each step. The ranking can be recomputed after every removal or fixed at the start, and random removal is averaged over repeated runs. `robustness_auc()` and `robustness_summary()` summarize each curve, including the area under it, and `plot_robustness()` visualizes several attack strategies together. `vulnerability()` computes, for each node, the relative drop in global efficiency when that node is removed. ```{r eval=FALSE} robustness(regulation_net, type = "vertex", measure = "betweenness", n_iter = 100) plot_robustness(x = regulation_net, 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 | | `vulnerability()` | Relative drop in global efficiency when each node is removed | ## Disparity filter cograph offers backbone extraction for weighted networks through the disparity filter (Serrano et al., 2009), which keeps the edges whose weights are significantly larger than expected if each node's strength were spread uniformly over its ties. `disparity_filter()` applies the test at a chosen significance level. For a matrix it returns a binary matrix of the significant edges, and for a network object it returns a backbone that `splot()` plots directly. ```{r eval=FALSE} backbone <- disparity_filter(as_cograph(regulation_net), level = 0.05) splot(backbone) ``` ## Multi-cluster visualization cograph offers hierarchical plots for multi-cluster multi-level (MCML) networks, whose nodes belong to known clusters. `plot_mcml()` shows the network as a two-layer hierarchy. The lower layer places every node inside its cluster's shell with the within- and between-cluster edges, and the upper layer collapses each cluster into a single node whose pie chart shows its share of the initial state distribution. `plot_mtna()` shows the clusters as shells in one plane, with individual edges within clusters and summary edges between them. `csum()` aggregates an estimated weight matrix into cluster-level transitions, and `summarize_clusters()` estimates the Markov chain over cluster states from the raw transition data. ```{r eval=FALSE} clusters <- list( Cognitive = c("Explore", "Plan", "Monitor", "Adapt", "Reflect"), Social = c("Discuss", "Synthesize", "Share"), Evaluative = c("Evaluate", "Create") ) plot_mcml(regulation_net, clusters, mode = "tna") plot_mtna(regulation_net, clusters) ``` | Function | Architecture | |----------|-------------| | `plot_mcml()` | Two-layer: detail nodes + summary pies | | `plot_mtna()` | Flat cluster layout | | `csum()` | Aggregate an estimated weight matrix to cluster level | | `summarize_clusters()` | Estimate the cluster-level Markov chain from transition data | | `as_tna()` / `as_mcml()` | Convert cluster summaries to tna objects | | `summarize_network()` / `cnet()` | Extract cluster-level network (matrix aggregation) | ## Multilayer networks cograph offers tools for constructing, analysing and visualizing multilayer and multiplex networks. `supra_adjacency()` builds the supra-adjacency matrix, with the layers as its diagonal blocks and the inter-layer coupling, diagonal, full or user-defined and weighted by `omega`, off the diagonal. `supra_layer()` and `supra_interlayer()` extract its blocks. `aggregate_layers()` combines layers by sum, mean, maximum, minimum, union or intersection, and `layer_similarity()` compares two layers by Jaccard, overlap, Hamming, cosine or Pearson similarity. `plot_mlna()` visualizes the layers stacked in a three-dimensional perspective with dashed inter-layer edges, and `plot_ml_heatmap()` shows each layer as a heatmap on a tilted plane. | Function | Purpose | |----------|---------| | `supra_adjacency()` | Build the supra-adjacency matrix | | `supra_layer()` / `supra_interlayer()` | Extract individual layers | | `aggregate_layers()` / `aggregate_weights()` | Combine layers | | `layer_similarity()` | Similarity between two layers | | `plot_mlna()` / `mlna()` | Layers stacked in 3D perspective | | `plot_ml_heatmap()` | Multi-layer heatmap comparison | ## Higher-order networks cograph offers visualization of higher-order network models, which capture sequential dependencies beyond a first-order Markov chain and are estimated with the Nestimate package. `plot_simplicial()` visualizes higher-order pathways as blobs over the network layout, from pathway strings, higher-order network (HON) and HYPA objects, or multi-order model transitions. Given a tna model or a Nestimate network with sequence data, it builds the pathways itself, as a HON, as anomalous paths under a hypergeometric null, or as association rules. | Function | Purpose | |----------|---------| | `Nestimate::build_hon()` | Higher-Order Network construction | | `Nestimate::build_hypa()` | Path anomaly detection (hypergeometric null) | | `Nestimate::build_mogen()` | Multi-order model selection (AIC/BIC) | | `Nestimate::path_counts()` | k-step path frequencies | | `plot_simplicial()` | Visualize pathways as blob overlays | | `Nestimate::build_simplicial()` | Simplicial complex from cliques | | `Nestimate::persistent_homology()` | Topological persistence across thresholds | | `Nestimate::q_analysis()` | Multi-level structural connectivity | | `Nestimate::verify_simplicial()` | Cross-validate via Euler-Poincare theorem | ## TNA integration cograph offers visualization for Transition Network Analysis (TNA) models estimated with the tna package. `splot()` plots tna models with donut rings filled by the initial probabilities, bootstrap results with edges styled by stability, permutation tests as difference networks, and communities and disparity backbones. Group models appear as one panel per group, or as a single group selected with `i`. `plot_tna()` and `tplot()` accept qgraph's argument names, so plotting code written for qgraph carries over, and `plot_htna()` plots heterogeneous TNA models, whose nodes belong to groups of different kinds, in circular, bipartite or polygonal layouts. | 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_communities` | Network coloured by community | | `tna_disparity` | Backbone filter visualization | ## Palettes cograph offers colour palettes for sequential, diverging and categorical encodings. They include viridis, blue and red gradients, a blue-white-red diverging scale with a configurable midpoint, the colour-blind-safe Okabe-Ito colours and a pastel set. Each palette function returns `n` colours. | 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 | ## 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:** - Serrano, M. Á., Boguñá, M., & Vespignani, A. (2009). Extracting the multiscale backbone of complex weighted networks. *Proceedings of the National Academy of Sciences*, 106(16), 6483–6488. - Saqr, M., López-Pernas, S., Conde-González, M. Á., & Hernández-García, Á. (2024). Social Network Analysis: A Primer, a Guide and a Tutorial in R. In *Learning Analytics Methods and Tutorials* (pp. 491–518). 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*, 49(6), 326–328.