Classify your graph
Two predicates describe independent things:
isStructuraldecides whether an edge contributes to the spanning tree. Non-structural edges remain drawable; they just do not decide position.isSatellitekeeps a node out of the tree and parks it in an outer pocket, even if it has edges.
import { customLayout } from 'ego-graph';
const positions = customLayout(graph, { firstLayer: { mode: 'radial' }, nextLayers: { mode: 'bubble' }, isStructural: (edge) => edge.type !== 'same-ip', isSatellite: (node) => node.type === 'shared-attribute', getWeight: (node) => node.data.memberCount ?? 1,});The same callbacks work on every customLayout import.
This distinction matters for shared attributes. If a phone number connects several unrelated customers, letting it join the hierarchy can pull all of them into one branch. Treat it as a satellite instead: it stays visible without distorting the ego view.
getWeight is useful after folding: return the number of represented members so a collapsed branch still receives enough space on the ring.