spatial_graph_algorithms.reconstruct
Recover 2-D or 3-D node coordinates from graph topology alone.
Available methods
| Method | Algorithm | When to use |
|---|---|---|
mds |
All-pairs shortest-path distances → sklearn metric MDS | Fast baseline; no extra dependencies |
landmark_mds |
Landmark shortest-path distances → MDS + triangulation | Faster approximation when all-pairs MDS is too expensive |
strnd |
Node2Vec (pecanpy PreComp) → UMAP | State-of-the-art quality; included in base install |
How to choose
- Use MDS for quick checks or small graphs (< 500 nodes).
- Use landmark MDS when you want a seeded MDS-style approximation and can choose an explicit landmark count.
- Use STRND for production-quality reconstructions. It consistently achieves CPD > 0.95 on well-connected circle/square graphs.
Quality evaluation
After reconstruction, use spatial_graph_algorithms.metrics.evaluate() to score the result.
See the metrics reference for the interpretation guide.
API Reference
spatial_graph_algorithms.reconstruct.reconstruct(sn, method='mds', dim=2, seed=None, **kwargs)
Reconstruct node coordinates from graph topology.
Returns a copy of sn with
:attr:~spatial_graph_algorithms.network.SpatialGraph.reconstructed_positions
set. The original sn is never modified.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sn
|
SpatialGraph
|
Input graph. Only the adjacency matrix is used; positions are not required (they are used only for quality evaluation afterwards). |
required |
method
|
str
|
Reconstruction algorithm. One of:
|
'mds'
|
dim
|
int
|
Target number of output dimensions (2 or 3). |
2
|
seed
|
int
|
Random seed for reproducibility. |
None
|
Returns:
| Type | Description |
|---|---|
SpatialGraph
|
Deep copy of sn with reconstructed_positions of shape
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If method is not one of the supported values. |
Examples:
>>> from spatial_graph_algorithms.simulate import generate
>>> from spatial_graph_algorithms.reconstruct import reconstruct
>>> sn = generate(n=300, seed=42)
>>> sn_rec = reconstruct(sn, method="mds", dim=2, seed=42)
>>> sn_rec.reconstructed_positions.shape
(300, 2)
Source code in src/spatial_graph_algorithms/reconstruct/__init__.py
spatial_graph_algorithms.reconstruct.mds.run_mds(adjacency, dim=2, random_state=None)
Reconstruct node coordinates using metric MDS on shortest-path distances.
Computes all-pairs shortest-path distances from adjacency and passes the
resulting dissimilarity matrix to sklearn's MDS with
dissimilarity='precomputed'. Disconnected pairs receive twice the
maximum finite distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
adjacency
|
scipy.sparse matrix
|
Symmetric, unweighted adjacency matrix of shape |
required |
dim
|
int
|
Number of output dimensions. Default is 2. |
2
|
random_state
|
int
|
Seed for sklearn's MDS initialisation. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Float array of shape |
Examples:
>>> from spatial_graph_algorithms.simulate import generate
>>> from spatial_graph_algorithms.reconstruct.mds import run_mds
>>> sn = generate(n=100, seed=0)
>>> coords = run_mds(sn.adjacency_matrix, dim=2, random_state=0)
>>> coords.shape
(100, 2)
Source code in src/spatial_graph_algorithms/reconstruct/mds.py
spatial_graph_algorithms.reconstruct.landmark_mds.run_landmark_mds(adjacency, dim=2, random_state=None, *, n_landmarks=None, weighted=False)
Reconstruct coordinates using landmark MDS.
Selects n_landmarks random nodes, computes shortest-path distances from
those landmarks to every node, embeds the landmarks with metric MDS, and
triangulates every node from its distances to the landmark set.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
adjacency
|
scipy.sparse matrix
|
Symmetric adjacency matrix of shape |
required |
dim
|
int
|
Number of output dimensions. Default is 2. |
2
|
random_state
|
int
|
Seed for landmark selection and sklearn's MDS initialisation. |
None
|
n_landmarks
|
int
|
Number of landmark nodes. Must satisfy |
None
|
weighted
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Float array of shape |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
>>> from spatial_graph_algorithms.simulate import generate
>>> from spatial_graph_algorithms.reconstruct.landmark_mds import run_landmark_mds
>>> sg = generate(n=100, seed=0)
>>> coords = run_landmark_mds(sg.adjacency_matrix, dim=2, random_state=0, n_landmarks=16)
>>> coords.shape
(100, 2)
Source code in src/spatial_graph_algorithms/reconstruct/landmark_mds.py
spatial_graph_algorithms.reconstruct.strnd.run_strnd(adjacency, dim=2, random_state=None, embedding_dim=64, p=1.0, q=1.0, workers=4, umap_n_neighbors=15, umap_min_dist=1.0, verbose=False)
Reconstruct coordinates using STRND: Node2Vec embeddings → UMAP.
Exact port of the NSC compute_pecanpy_embeddings_from_df + UMAP pipeline.
Node2Vec biased random walks (pecanpy PreComp) produce a 64-D embedding which
UMAP reduces to dim spatial coordinates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
adjacency
|
scipy.sparse matrix
|
Symmetric, unweighted adjacency matrix. |
required |
dim
|
int
|
Number of output dimensions. Default is 2. |
2
|
random_state
|
int
|
Seed for UMAP reproducibility. |
None
|
embedding_dim
|
int
|
Dimensionality of the Node2Vec embedding before UMAP reduction. Default is 64 (matches NSC defaults). |
64
|
p
|
float
|
Node2Vec return parameter. |
1.0
|
q
|
float
|
Node2Vec in-out parameter. |
1.0
|
workers
|
int
|
Number of worker threads for pecanpy. Default is 4. |
4
|
umap_n_neighbors
|
int
|
UMAP |
15
|
umap_min_dist
|
float
|
UMAP |
1.0
|
verbose
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Float array of shape |
Examples:
>>> from spatial_graph_algorithms.simulate import generate
>>> from spatial_graph_algorithms.reconstruct.strnd import run_strnd
>>> sn = generate(n=200, seed=0)
>>> coords = run_strnd(sn.adjacency_matrix, dim=2, random_state=0)
>>> coords.shape
(200, 2)
Source code in src/spatial_graph_algorithms/reconstruct/strnd.py
spatial_graph_algorithms.reconstruct.quality
Reconstruction quality metrics comparing original and reconstructed positions.
All three metrics are rotation-, reflection-, and translation-invariant.
Functions
cpd(true_positions, recon_positions)
Compute the Correlation of Pairwise Distances (CPD).
R² of the pairwise distance matrices of the original and reconstructed coordinates. CPD = 1.0 means all inter-node distances are perfectly preserved.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
true_positions
|
ndarray
|
Ground-truth node coordinates, shape |
required |
recon_positions
|
ndarray
|
Reconstructed node coordinates, shape |
required |
Returns:
| Type | Description |
|---|---|
float
|
R² in |
Examples:
>>> import numpy as np
>>> from spatial_graph_algorithms.reconstruct.quality import cpd
>>> pts = np.random.default_rng(0).random((50, 2))
>>> cpd(pts, pts + 0.001) > 0.99
True
Source code in src/spatial_graph_algorithms/reconstruct/quality.py
knn(true_positions, recon_positions, k=10)
Compute k-nearest-neighbour overlap.
For each node, the fraction of its k true nearest neighbours that also appear among its k reconstructed nearest neighbours, averaged over all nodes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
true_positions
|
ndarray
|
Ground-truth coordinates, shape |
required |
recon_positions
|
ndarray
|
Reconstructed coordinates, shape |
required |
k
|
int
|
Number of neighbours to compare. Clamped to |
10
|
Returns:
| Type | Description |
|---|---|
float
|
Mean neighbourhood overlap in |
Examples:
>>> import numpy as np
>>> from spatial_graph_algorithms.reconstruct.quality import knn
>>> pts = np.random.default_rng(0).random((50, 2))
>>> knn(pts, pts)
1.0
Source code in src/spatial_graph_algorithms/reconstruct/quality.py
distortion(true_positions, recon_positions)
Compute normalised pairwise-distance distortion.
Scale-aligns the reconstructed distances to the ground-truth mean scale,
then returns median(|d_true − d_recon_scaled|) / max(d_true).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
true_positions
|
ndarray
|
Ground-truth coordinates, shape |
required |
recon_positions
|
ndarray
|
Reconstructed coordinates, shape |
required |
Returns:
| Type | Description |
|---|---|
float
|
Normalised distortion in |
Examples:
>>> import numpy as np
>>> from spatial_graph_algorithms.reconstruct.quality import distortion
>>> pts = np.random.default_rng(0).random((50, 2))
>>> distortion(pts, pts)
0.0