Add Egocentric layout - #104
Merged
Merged
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #104 +/- ##
==========================================
- Coverage 97.41% 97.28% -0.14%
==========================================
Files 10 11 +1
Lines 580 736 +156
==========================================
+ Hits 565 716 +151
- Misses 15 20 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
emfeltham
force-pushed
the
egocentric-layout
branch
from
September 21, 2026 16:16
3548d7a to
bac228b
Compare
Collaborator
|
thanks for the contribution! Can you rebase on master and get rid of the double ejecting of final layout? That was an actual bug i fixed in #105 |
Adds `Egocentric`, a stress-majorization layout centred on a single focal vertex, following Brandes and Pich, "More Flexible Radial Layout", Journal of Graph Algorithms and Applications 15(1):157-173 (2011, doi 10.7155/jgaa.00221). The layout interpolates between the plain stress objective (`Stress`) and a "focus" objective that only weights the pairs involving the focal vertex. Minimising the latter alone puts every vertex at a radius equal to its graph distance from the focus, so the layout reads as concentric rings of constant geodesic distance while the angles still come from the unconstrained stress solution. Optimisation walks a schedule `tseq` of mixing parameters from 0 to 1, majorising each stage to convergence. Details worth noting for review: - Implemented as an `IterativeLayout`, so `LayoutIterator` animates the schedule. The last item is emitted twice because `layout` returns the second to last item of the iterator. - The majorisation sweep updates positions in place (Gauss-Seidel). The simultaneous (Jacobi) variant of the same update oscillates rather than converging: on a two-vertex graph it alternates around the ideal distance indefinitely. - The focal vertex is never moved and stays at the origin. Stress is translation invariant, so this only fixes the gauge, and it means `initialpos`, `pin` and the returned positions all live in the same focus-centred frame. - Initial positions come from classical (Torgerson) MDS of the graph distances plus a small jitter, computed inline so no new dependency is needed. This makes the result largely independent of the seed. - Unconnected vertices reuse the existing `uncon_dist` treatment from `Stress` rather than being dropped, so the result always has one position per vertex. - `maxdist` optionally compresses vertices beyond a given ring onto a narrow outer band, keeping their angles. Without it a few remote vertices can dominate the frame, since radius equals graph distance. `compress` controls the falloff and accepts a function, a number, or `nothing`. Supports `dim`/`Ptype`, `initialpos`, `pin`, `seed`/`rng`, weighted adjacency matrices, and composes with `Align`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
emfeltham
force-pushed
the
egocentric-layout
branch
from
September 28, 2026 14:29
bac228b to
f9d58d4
Compare
`layout` used to return the second to last item of the iterator, so the `Egocentric` iterator emitted the converged layout twice to make sure the final one was the one returned. JuliaGraphs#105 fixed that bug, so the workaround can go: `iterate` now simply terminates once the `tseq` schedule is exhausted. The workaround was the only writer of `EgocentricState.finished`, so that field is removed too. The returned layout is unchanged; the iterator just yields one item fewer. Verified by comparing positions before and after across the plain, `maxdist`, `compress=<number>`, `compress=nothing`, 3d/Float32 and karate cases -- all bit-identical. Also adapts the iterator tests to the new `iterations` semantics from JuliaGraphs#105: a single-stage `tseq` with `iterations=l` and zero tolerances now yields exactly `l + 1` layouts, with `last(vec) == algo(adj_matrix)`. No `>=` to `>` change was needed in the layout itself, because the per-stage counter is incremented after each sweep and so already counted actual iterations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
emfeltham
force-pushed
the
egocentric-layout
branch
from
September 28, 2026 14:49
f9d58d4 to
9dc6b56
Compare
`layout` used to return the second to last item of the iterator, so the `Egocentric` iterator emitted the converged layout twice to make sure the final one was the one returned. JuliaGraphs#105 fixed that bug, so the workaround can go: `iterate` now simply terminates once the `tseq` schedule is exhausted. The workaround was the only writer of `EgocentricState.finished`, so that field is removed too. The returned layout is unchanged; the iterator now yields one item fewer. Verified by comparing positions before and after across the plain, `maxdist`, `compress=<number>`, `compress=nothing`, 3d/Float32 and karate cases -- all bit-identical. Also adapts the iterator tests to the new `iterations` semantics from single-stage `tseq` with `iterations=l` and zero tolerances now yields exactly `l + 1` layouts, with `last(vec) == algo(adj_matrix)`.
…orkLayout.jl into egocentric-layout
Contributor
Author
|
Okay, great. Take a look and let me know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
Egocentric, a stress-majorization layout centred on a single focal vertex, following Brandes and Pich (2011).Brandes, Ulrik, and Christian Pich. "More flexible radial layout." Journal of Graph Algorithms and Applications 15.1 (2011): 157-173.
Layout
The layout interpolates between two objectives:
Stress), andMinimizing the focus objective alone places every vertex at a radius equal to its graph distance from the focus. The result reads as concentric rings of constant geodesic distance, while the angles still come from the unconstrained stress solution, so vertices that are close in the network stay close on their ring. Optimization walks a schedule
tseqof mixing parameters from0to1, majorizing each stage to convergence: pure stress picks sensible angles first, then the radii are gradually enforced.Notes
IterativeLayout, soLayoutIteratoranimates the schedule. The final layout is emitted twice, becauselayoutreturns the second to last item of the iterator.initialpos,pinand the returned positions all live in the same focus-centred frame, which is what makespinusable here.LinearAlgebraso there is no new dependency. This makes the result largely independent ofseed.uncon_disttreatment fromStressrather than being dropped, so the layout keeps theadjacency matrix -> one position per vertexcontract.maxdistoptionally compresses vertices beyond a given ring onto a narrow outer band, keeping their angles. Without it a handful of remote vertices can dominate the frame, since radius equals graph distance.compresscontrols the falloff and accepts a function (defaultlog1p), a number (collapse onto a single outer ring), ornothing(clamp onto themaxdistring).Supports
dim/Ptype,initialpos,pin,seed/rng, weighted adjacency matrices, and composes withAlign.Specific changes
src/egocentric.jl(new), included fromsrc/NetworkLayout.jltest/runtests.jl: aTesting Egocentric Layouttestset covering construction and argument validation, the focus sitting at the origin, radii matching graph distances (2d and 3d), weighted adjacency matrices, themaxdist/compressvariants and that compression leaves angles untouched, unconnected vertices, determinism,initialpos/pin, the iterator, and monotone stress decrease along a stagedocs/src/index.md: anEgocentric Layoutsection with examples and an iterator animation, plusEgocentricadded to the list of layouts that supportpin