A useful layout reveals graph structure while keeping distance distortion and sensitivity to initialization in view. This guide compares a small set of settings on 494_bus, a 494-vertex power network supplied with grip. Its source electrical values are not layout distances: we use the bundled unit-length connectivity graph.
Start with metric.mds(backend="sgd") for a
graph-distance embedding. When full pairwise distances and fitting
exceed the available resources, use
metric.mds(backend="sgd", approximation="sparse"); sparse
mode approximates the fitting objective and still needs independent
distance-fidelity checks. Do not append edge-KK automatically: improving
adjacent-edge lengths can worsen longer-range distance fidelity. This
starting recommendation is not a claim that one optimizer wins on every
graph.
| Question | Starting point |
|---|---|
| Explore graph connectivity | grip(metric='hop') |
| Respect positive traversal lengths | grip(metric='edge_length') |
| Fit all shortest-path distances directly | metric.mds(); SGD is the default backend |
| Reduce the cost of full MDS | metric.mds(approximation='sparse') |
| Adjust edge lengths of an existing drawing | edge.kk(coords=...), followed by independent
scoring |
The function overview explains input conventions and provides the complete categorized catalog. Metric MDS compares its two optimizers; weighted layouts explains distance-valued edges.
g <- suitesparse.graph('494_bus')
cmp <- compare.layouts(edges=g$edges,n=g$n,dim=3,
candidates=c('default','tree','mesh'),seeds=1:3,
sample.size.stress=2000L,sample.size.nonedge=3000L,
edge.crossings='never',return.layouts=TRUE)
knitr::kable(cmp$summary[,c('candidate','sampled.stress.mean',
'edge.length.cv.mean','sampled.nonedge.sep.ratio.mean',
'stability.procrustes.mean')],digits=3)| candidate | sampled.stress.mean | edge.length.cv.mean | sampled.nonedge.sep.ratio.mean | stability.procrustes.mean |
|---|---|---|---|---|
| mesh | 0.277 | 0.192 | 0.322 | 0.370 |
| default | 0.291 | 0.282 | 0.411 | 0.389 |
| tree | 0.353 | 0.648 | 0.053 | 0.198 |
This section demonstrates an alternative algorithm, not the default SGD workflow. These are three GRIP presets with three seeds each. They are a teaching comparison, not tuned recommendations for power networks. Sampled stress is smaller when drawn distances better match graph shortest paths. Stability summarizes how much layouts vary after alignment. Use the same scoring samples and definitions across candidates.
494_bus: three GRIP presets, seed 1 in every view. Rigid alignment; no resizing.
The figure always shows seed 1; the table summarizes all three seeds. Rotate and switch presets to inspect branches and crowded regions. Neither the matrix nor these layouts provide a known geographical reference.
cmp$runs retains the individual runs. A good average
should be considered alongside variation among seeds and any
unsuccessful attempts.
knitr::kable(cmp$runs[,intersect(c('candidate','seed','status','sampled.stress'),
names(cmp$runs))],digits=3)| candidate | seed | status | sampled.stress |
|---|---|---|---|
| default | 1 | ok | 0.262 |
| default | 2 | ok | 0.294 |
| default | 3 | ok | 0.317 |
| tree | 1 | ok | 0.349 |
| tree | 2 | ok | 0.402 |
| tree | 3 | ok | 0.309 |
| mesh | 1 | ok | 0.287 |
| mesh | 2 | ok | 0.242 |
| mesh | 3 | ok | 0.301 |
Use params.from.summary() to recover a candidate’s
settings. If further improvement matters, try a small neighborhood of
those settings and retain the initial comparison as a separate result. A
composite score ranks candidates within its chosen criteria and weights;
it is not a universal quality grade.
| What matters? | Function | What the score means |
|---|---|---|
| Overall graph-distance agreement | score.layout() |
Sampled drawn distances versus graph shortest paths, with fitted scale |
| Edge, route, and endpoint errors separately | score.gmds() |
Distinct residuals with an explicit scale policy |
| Locations of corresponding vertices | score.coordinates() |
Vertex displacement after the requested alignment |
| Shape of an already aligned triangular surface | score.surface() |
Area-weighted surface distance; does not align the surfaces |
Score the original 3D coordinates, not their 2D projection. An improvement in edge lengths can accompany worse distances between distant vertices. Likewise, a close surface overlay does not establish recovery of corresponding vertices. See the score definitions for units, alignment choices, and the differences between these quantities.
For graphs with meaningful labels, examine those labels alongside the geometry. The HMP/U01 case study illustrates this with biological community labels. Label separation alone does not establish accurate geometry.
Full MDS requires dense distances. Use
estimate.preparation() before a large preparation; its
matrix-size estimate is a lower bound, not peak memory. Start with a few
seeds and candidates. Use traces to investigate a fold
or collapse before increasing a search indiscriminately.
The layout-engine comparison illustrates common diagnostics for multiscale GRIP, igraph and graphlayouts on unweighted graphs. Those results do not benchmark the current metric-MDS backend.