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 { radialDagre } from 'ego-graph';
const positions = radialDagre(graph, { isStructural: (edge) => edge.type !== 'same-ip', isSatellite: (node) => node.type === 'shared-attribute', getWeight: (node) => node.data.memberCount ?? 1,});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.