--- title: "Constructing and Diagnosing Data-Derived Graphs" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Constructing and Diagnosing Data-Derived Graphs} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 6.5, fig.height = 5, warning = FALSE, message = FALSE ) ``` ## Overview `dgraphs` constructs graphs whose vertices are numerical observations. The package supports mutual and symmetric k-nearest-neighbor graphs, fixed and adaptive radius graphs, continuous-kNN graphs, intersection-kNN graphs, and minimum-spanning-tree completion. Constructors retain graph lifecycle stages so that native, pruned, and connectivity-repaired graphs can be compared. This vignette follows a small example from construction through connectivity repair, parameter inspection, conversion to `igraph`, and geodesic fidelity diagnostics. ```{r data} library(dgraphs) set.seed(20260820) n <- 60L theta <- sort(c( runif(40L, 0, pi), runif(20L, pi, 2 * pi) )) X <- cbind(x = cos(theta), y = sin(theta)) + matrix(rnorm(2L * n, sd = 0.015), ncol = 2) ``` The unequal sample counts on the two semicircles create a simple variable-density point cloud. Its circular ordering also supplies a known reference distance for later diagnostics. ## Construct candidate graph families The following calls use the same local scale, `k = 5`, where that parameter is defined. Connectivity repair is requested so every final graph supports all-pairs geodesic distances. ```{r constructors} graphs <- list( mutual = create.mknn.graph( X, k = 5, connect.components = TRUE ), symmetric = create.sknn.graph( X, k = 5, neighbor.method = "ann", connect.components = TRUE ), continuous = create.cknn.graph( X, k.scale = 5, delta = 1.2, connect.components = TRUE ), adaptive.max = create.rknn.graph( X, type = "adaptive.radius", k.scale = 5, radius.rule = "max", connect.components = TRUE ) ) ``` Each final graph exposes aligned `adj_list` and `weight_list` fields. The weights are Euclidean edge lengths. The raw fields represent the graph before optional pruning and connectivity repair. ```{r candidate-summary} graph.summary <- do.call(rbind, lapply(names(graphs), function(name) { graph <- graphs[[name]] data.frame( graph = name, edges = sum(lengths(graph$adj_list)) / 2, raw.components = length(unique( graph.connected.components(graph$raw_adj_list) )), final.components = length(unique( graph.connected.components(graph$adj_list) )), bridges = graph$n_mst_edges_added ) })) graph.summary ``` The number of edges is a property of the construction rule, not a quality score by itself. The component columns show when the optional repair stage was needed and how many minimum-spanning-tree bridge edges it added. ## Inspect a parameter sequence Plural constructors make parameter sweeps explicit. Here `create.rknn.graphs()` constructs adaptive-radius graphs for four local-scale values. Its statistics table separates native edge and component counts from repair counts. ```{r parameter-sequence} radius.sequence <- create.rknn.graphs( X, k.values = 3:6, radius.search = "ann", connect.components = TRUE ) radius.sequence$k_statistics[, c( "k", "n_edges_before_pruning", "n_components_before", "n_mst_edges_added", "n_components_after" )] ``` For exploratory work, this table can identify the smallest neighborhood scale that produces a connected native graph. Scientific applications should also evaluate whether the resulting geodesics preserve the geometry relevant to the analysis. ## Convert and inspect a selected graph Current graph objects convert directly to `igraph`. Edge lengths become the `weight` edge attribute. ```{r conversion} selected <- graphs$continuous selected.igraph <- as_igraph(selected) c( vertices = igraph::vcount(selected.igraph), edges = igraph::ecount(selected.igraph) ) degree.pmf <- compute.graph.summary.pmf( selected, summary = "degree_distribution" ) degree.pmf$pmf ``` The graph can also be drawn in the original coordinates without running a layout algorithm. ```{r graph-figure, fig.cap="Continuous-kNN graph on the variable-density circular point cloud. Lines are graph edges and points are observations.", fig.alt="A circular point cloud with denser sampling on the upper semicircle. Gray graph edges connect nearby points around the circle."} edge.matrix <- convert.adjacency.to.edge.matrix( selected$adj_list )$edge.matrix plot( X, asp = 1, pch = 19, col = "#1F5A94", xlab = "Coordinate 1", ylab = "Coordinate 2" ) segments( X[edge.matrix[, 1], 1], X[edge.matrix[, 1], 2], X[edge.matrix[, 2], 1], X[edge.matrix[, 2], 2], col = grDevices::adjustcolor("grey35", alpha.f = 0.45) ) points(X, pch = 19, col = "#1F5A94") ``` ## Diagnose geodesic fidelity For this example, the reference geodesic distance is the shorter arc between two sample angles. `graph.geodesic.distances()` computes graph shortest-path distances, and `isometry.geodesic.diagnostics()` summarizes their deviation from the reference after an optional global scale calibration. ```{r geodesic-diagnostics} graph.distance <- graph.geodesic.distances(selected) angle.difference <- abs(outer(theta, theta, "-")) reference.distance <- pmin( angle.difference, 2 * pi - angle.difference ) round(isometry.geodesic.diagnostics( graph.distance, reference.distance ), 3) ``` The relative stress summarizes overall discrepancy. The shortcut fraction is the fraction of calibrated graph distances that are shorter than their reference distances. The short-, middle-, and long-distance bias entries show whether distortion is concentrated at a particular distance scale. ## Practical guidance No graph family is uniformly best. Mutual-kNN graphs are conservative and can disconnect in sparse regions; symmetric-kNN graphs are more connected but can introduce asymmetric-density links; adaptive-radius and continuous-kNN graphs adjust their support using local scales. Connectivity repair guarantees finite final geodesics, but bridge edges are modeling choices that should be inspected rather than hidden. Parameter sequences, lifecycle fields, graph summaries, and geodesic diagnostics are therefore intended to be used together.