Layouts: what does distance in the drawing mean?

A layout changes node coordinates, not the Mapper graph, cover memberships, or node summaries. Two nodes drawn close together are not necessarily close in the original metric. Select a layout according to what you want the drawing to explain.

Choose a family

FamilyFunctionsWhat supplies positions
Graph topologylayout_spring, layout_stress, layout_spectral_graph, layout_sfdp, layout_shellGraph connectivity
Original coordinateslayout_landmarksFirst two/three coordinates of member centroids
Global centroid geometrylayout_mds, layout_pca, layout_kpca, layout_ppca, layout_fa, layout_icaA matrix with one centroid per node
Manifold embeddinglayout_isomap, layout_lle, layout_hlle, layout_lem, layout_ltsa, layout_diffmap, layout_tsne, layout_umapCentroid neighbourhoods or embedding objectives
Customlayout_genericYour function applied to the centroid matrix

Graph layouts are useful for inspecting branches, loops and connected components. Their lengths, rotations and spacing are drawing choices. Centroid layouts retain information about where subsets lie in the cloud, but averaging can move a centroid away from the observed manifold. Manifold embeddings can emphasize local structure while distorting global distances.

Despite its name, layout_landmarks computes member centroids. For Ball Mapper they need not coincide with the sampled landmark points. No dimension reduction is fitted: it takes the first min(dim, ambient_dimension) centroid coordinates, requiring an effective dimension of two or three.

Use an explicit layout

The following small overlapping cover lets us compare layout APIs without depending on a clustering choice:

using CairoMakie, TDAplots
using Graphs: path_graph

X = EuclideanSpace([[Float64(i), sin(i), cos(i)] for i in 1:12])
C = [collect(1:4), collect(3:7), collect(6:10), collect(9:12)]
M = Mapper(X=X, C=C, g=path_graph(4))
ctd = centroid(M)
@assert size(ctd) == (3, 4)

mapper_plot(M; node_positions=layout_landmarks(M; dim=3), show_node_ids=true)
Example block output

centroid returns an ambient_dimension × number_of_nodes matrix; columns are nodes. Each layout_* wrapper returns one Makie point per node. Pass that vector as node_positions:

mds_positions = layout_mds(M; dim=2)
@assert length(mds_positions) == length(M.C)
mapper_plot(M; node_positions=mds_positions, show_node_ids=true)
Example block output

The MDS wrapper uses the centroid coordinate matrix, rather than shortest-path distances in M.g. Graph spectral embedding (layout_spectral_graph) and centroid Laplacian Eigenmaps (layout_lem) therefore answer different questions even though both are spectral methods.

Graph algorithm objects and Mapper wrappers

mapper_plot has two routes:

mapper_plot(M; node_positions=layout_shell(M))
Example block output

or supply an algorithm called on the graph:

mapper_plot(M; layout_function=NaiveLayouts.Spring(dim=3))
Example block output

layout_function receives M.g, whereas layout_spring(M) and the other package wrappers receive a Mapper. To use a Mapper wrapper through that keyword, capture M: layout_function=g -> layout_pca(M). When node_positions is supplied, it takes precedence over layout_function.

The explorer accepts layout_function, but currently has no node_positions keyword. Use layout_function=g -> precomputed_positions to retain a chosen layout there.

Bring your own embedding

layout_generic calls your function on the centroid matrix. It expects a 2 × number_of_nodes or 3 × number_of_nodes matrix in return, with columns in the same node order.

custom_positions = layout_generic(M, c -> c[[1, 3], :])
mapper_plot(M; node_positions=custom_positions, show_node_ids=true)
Example block output

This projects to original coordinates 1 and 3. A learned embedding can be substituted, provided it follows the same orientation. A transposed matrix silently changes which columns correspond to nodes or leads to inconsistent plot inputs, so check dimensions explicitly.

Constraints and reproducibility

Most wrappers accept dim=2 or dim=3 and forward further keyword arguments to their underlying package. layout_shell is always two-dimensional. Embedding methods differ in rank requirements, accepted keywords, neighbourhood sizes and random initialization; the wrappers do not make those requirements interchangeable.

On a tiny graph, start with a graph layout or centroid projection. Neighbourhood methods need fewer requested neighbours than available nodes, and Isomap-style methods need an appropriate connected neighbourhood graph. Rank-deficient centroids may not support the requested statistical dimension. For stochastic methods, configure the underlying method's random seed/RNG where supported, record parameters and save final coordinates when comparisons require the same drawing.

Do not interpret a new visual loop or an apparent split in an embedding as a change in Mapper connectivity: check M.g and the overlapping member sets directly.