Add chord-diagram (circular) graph-layout mode, make it the default - #371
Merged
Conversation
… the default (#367) Adds a second algorithm for MAE's native KB graph view alongside the existing force-directed (Fruchterman-Reingold) layout: nodes evenly spaced around a circle's circumference, relationships drawn as curved chords through the interior (Circos/D3-chord style). Chord is now the default. - New GraphLayoutAlgorithm enum (Force/Chord), orthogonal to the existing GraphLayoutMode (which is a scheduling concept -- one-shot vs animated tick -- for whichever algorithm runs, not an algorithm choice itself). - New kb_graph_layout_algorithm option, following the exact 3-part OptionRegistry pattern daemon_mode already established (a real Rust enum with parse/as_str, validated in the setter). - build_kb_graph_chord_positions (crates/canvas/src/kb_graph.rs) places nodes on a ring whose circumference grows linearly with node count (unlike the sunflower disk's deliberately sub-linear growth -- correct for a 1-D ring, not merely acceptable). Shares all edge-building logic with build_kb_graph_positions_only via a new positions_to_scene helper (only the position-computation differs between the two). - populate_graph_buffer branches on the algorithm: Chord's layout is immediately final, so it never queues a background force-refinement pass (also forces GraphView.animating false regardless of kb_graph_animate, since nothing will ever arrive to settle it). - Curved-edge rendering already existed (kb_graph_edge_curvature -> VisualElement::Curve -> a real Skia quadratic Bezier); only the control-point formula needed a Chord-specific branch: pulled toward the viewport-transformed scene origin instead of Force's perpendicular offset from the edge midpoint.
…branch main's #369 changeset added KbNodeInfo::is_seed after this branch's chord test fixtures were authored; backfill the field on the 3 affected literals. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ce mode's scale Constant-arc-spacing (radius growing linearly with node count) blew the chord ring up to tens of thousands of scene units on a real ~1300-node subgraph -- far past what the shared [0.1, 10.0] zoom range can zoom out to fit, leaving the diagram permanently too large to view. Reuse the sunflower disk's sqrt(n) growth rate instead, extracted to a shared sqrt_area_radius() helper, so both algorithms stay visually comparable. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sion bump 0.14.52)
…fault color, radial labels, quieter boundary badges Smoke-testing the chord-diagram layout (#367) surfaced four related issues: - No opacity control on edges, so dense chords near the circle's center blended into a solid gray mass. New kb_graph_edge_alpha option (default 0.5, per chord-diagram design research); the boundary self-loop stub stays fully opaque regardless (sparse correctness signal, not part of the density problem). - default.toml's ui.graph.edge was a stray literal hex instead of aliasing "comment" like every other shipped theme already does -- one-line fix, no Rust changes needed (theme_hex_fg already resolves it). - Node labels were always drawn flat-horizontal, so nodes near the top/ bottom of the ring collided. Added radial label rotation with the standard D3/Circos 180-flip-and-right-align technique for the far half of the circle (chord_label_placement), gated on layout_algorithm == Chord with zero effect on Force mode. label_bbox (used by the existing label-declutter pass) now shares the same placement so declutter and the real draw can never disagree. - The boundary stub's "... (+N)" count badge is now hidden by default, shown only when its source node is hovered/selected (progressive disclosure) -- new kb_graph_boundary_stub_label_always_shown option restores the original always-on behavior. Grounded in chord/Circos-diagram design research (D3, Circos docs, the CHORDination VINCI-2024 study, Tufte chartjunk/data-ink-ratio framing). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Summary
Closes #367. Adds a second layout algorithm for MAE's native KB graph view alongside the existing
force-directed (Fruchterman-Reingold) layout: a chord diagram — nodes evenly spaced around a
circle's circumference, relationships drawn as curved chords through the interior (Circos/D3-chord
style). Per explicit request, chord is now the default layout mode.
GraphLayoutAlgorithmenum (Force/Chord) — orthogonal to the existingGraphLayoutMode(a scheduling concept, one-shot vs. animated tick, for whichever algorithm runs).
kb_graph_layout_algorithmoption, following the exact 3-part OptionRegistry patterndaemon_modealready established.build_kb_graph_chord_positionsshares all edge-building logic with the existingbuild_kb_graph_positions_onlyvia a newpositions_to_scenehelper — only the positioncomputation differs.
populate_graph_bufferskips queuing a background force-refinement pass entirely for Chord mode(the layout is immediately final).
branch (pulled toward the viewport-transformed scene origin instead of Force's perpendicular
midpoint offset).
Switch back to the old behavior any time with
:set kb_graph_layout_algorithm force.Test plan
cargo build --workspace+cd daemon && cargo build— cleancargo test --workspace+ daemon — all green (2745 mae-core tests, full canvas/daemon suites)cargo clippy --workspace --all-targets -- -D warnings(both workspaces) — cleancargo fmt --check— cleanmake code-map-check— up to datescales with node count, edge-building parity with the sunflower layout),
populate_graph_buffernever queues a background pass for Chord (and still does for Force — regression guard),
option roundtrip/reject, and edge-curve control-point direction (Chord pulls toward center,
including under a panned viewport; Force keeps its existing perpendicular-offset behavior
byte-for-byte unchanged)
🤖 Generated with Claude Code