Layout: port the actual LaNet-vi placement (nested components, neighbour-based rho, central-core cliques)
- Dominant language
- Python
- Stars
- 8
- Forks
- 0
- Avg merge
- 6h 10m
- Merged PRs (30d)
- 16
Description
Found by the September 2026 comparison against the C++ sources (see docs/migration-from-cpp.md on branch docs/legacy-heritage (PR #17)).
The reachable layout path (`visualization/layout.py`, `compute_hierarchical_layout` with `all_nodes_by_shell`) is a flat "one ring per shell" placement, not the NIPS 2005 / NJP 2008 algorithm implemented in `kcores_component.cpp` / `graph_kcores_components.cpp`:
- Ring radius is a hard-coded `(max_shell - shell + 1) * 80`; `delta`, `gamma`, `unit_length`, `ratio_constant` never enter.
- Radial position (formula (1)): the C++ average over higher-shell neighbours was replaced by `rng.uniform(0, 1)` (`layout.py` ~625). Only the `(1-eps)+eps*average` envelope survived.
- Angular position: the circular-average port uses a vector mean instead of the C++ arc interpolation (`circular_average.h`), adds an order-dependent jitter, and measures angles from the origin instead of the component centre. The second pass of the loop is a no-op.
- The nested component hierarchy (components of each k-core, recursively, with their own centre/radius/u; formulas (3)-(5)) is not modelled. Python `Component`s are the C++ "clusters".
- `distribute_components` is ported but unreachable; it lacks the alpha growth loop and multiplies radii by 1.10 on failure where the C++ divides. `coord_distribution`, `alpha`, `beta`, `use_spatial_hashing` are therefore inert. `alpha` default changed 0.3 -> 1.0, `epsilon` 0.18 -> 0.40.
- Central-core clique decomposition (`clique.cpp`, `computeCliqueHostCoordinates`) is missing; `place_in_circular_sector` is a faithful port with no caller. `--no-cliques` is ignored for the top shell and wrong (uniform instead of sector formula (2)) elsewhere.
- The k-dense layout variant (`kdenses_component.cpp`) is not ported; kdenses/dcores reuse the k-core layout.
- `draw_circles` draws circles at synthetic positions (`layout.py` ~650), unrelated to node placement.
- `layout.py` ~600: `graph.is_weighted()` does not exist on `nx.Graph`; the `hasattr` guard silently forces `False`.
Suggested approach: port `KCores_Component::computeComponents` + `findCoordinatesClassic` faithfully first (classic mode), then `pow`/`log` with `distribute_components`, then the clique placement. Keep the karate-club example as a regression image.
Contributor guide
Research direction
Start in visualization/layout.py at compute_hierarchical_layout and compare its component and coordinate flow with kcores_component.cpp, graph_kcores_components.cpp, and circular_average.h. Run the karate-club example as the baseline regression image. Done means the classic placement matches the C++ algorithm, followed by working pow/log distribution, clique placement, and correct circle rendering and weighted-graph handling.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- data-visualization
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100