Skip to content

[WIP] Review and refactor network layout algorithms for accuracy#39

Merged
Adamtaranto merged 4 commits into
mainfrom
copilot/review-network-layout-algorithms
Nov 16, 2025
Merged

[WIP] Review and refactor network layout algorithms for accuracy#39
Adamtaranto merged 4 commits into
mainfrom
copilot/review-network-layout-algorithms

Conversation

Copilot AI commented Nov 16, 2025

Copy link
Copy Markdown
Contributor

Network Layout Algorithm Review and Refactoring

Plan

  • Understand current layout implementation and test coverage
  • Review NetworkX version and available layouts
  • Analyze layout algorithm accuracy
  • Identify performance optimization opportunities
  • Test layout algorithms with various network sizes
  • Fix hierarchical layout bug with disconnected components
  • Add spectral layout as fast alternative
  • Improve documentation with performance characteristics
  • Update GUI with spectral layout option
  • Add layout caching for performance
  • Create comprehensive algorithm selection guide
  • Add tests for caching functionality

Summary of Changes

1. Fixed Bug in Hierarchical Layout ✅

Issue: Hierarchical layout only computed positions for nodes reachable from root, ignoring disconnected components.

Fix: Added handling for disconnected nodes at max_level + 1, matching RadialLayout behavior.

Impact: All nodes now receive positions, preventing incomplete visualizations.

2. Added Spectral Layout Algorithm ✅

New Feature: Implemented SpectralLayout using graph Laplacian eigenvectors.

Performance Benefits:

  • ~4x faster than force-directed (6.5ms vs 26ms for 100 nodes)
  • ~29x faster than Kamada-Kawai (6.5ms vs 187ms for 100 nodes)
  • Excellent for large networks (100-1000+ nodes)

3. Added Layout Caching ✅

Feature: LayoutManager now caches layout computations with identical parameters.

Benefits:

  • Instant results for repeated layout calls
  • Configurable per-instance (enable_cache parameter)
  • Can be disabled or cleared as needed
  • Automatic cache key generation from algorithm + parameters

Example:

manager = LayoutManager(network, enable_cache=True)
# First call computes layout
layout1 = manager.compute_layout('spring', iterations=50, seed=42)
# Second call with same parameters returns cached result instantly
layout2 = manager.compute_layout('spring', iterations=50, seed=42)

4. Comprehensive Documentation ✅

New File: docs/layout_algorithms.md (10KB guide)

Contents:

  • Quick selection guide by network size
  • Detailed algorithm descriptions with pros/cons
  • Performance benchmarks for all algorithms
  • Parameter tuning tips
  • Best practices and common issues
  • Code examples for advanced usage

5. Enhanced Code Documentation ✅

  • Added performance characteristics to all layout classes
  • Included time complexity information
  • Added algorithm selection guide in module docstring
  • Enhanced parameter documentation

6. Updated GUI ✅

  • Added "Spectral (Fast, Large networks)" option
  • Reordered layouts by speed (hierarchical first)
  • Added performance hints to labels
  • Updated default to hierarchical (fastest)

Test Results

  • All 59 tests pass (7 new tests added)
  • No regressions introduced
  • Full coverage for:
    • Hierarchical layout with disconnected networks
    • Spectral layout computation and parameters
    • Layout caching (enabled, disabled, clear)

Performance Comparison

Algorithm 100 nodes Best for
Hierarchical 0.14ms Fastest, tree-like
Spectral 6.5ms Large networks
Force-Directed 26ms General purpose
Kamada-Kawai 187ms Small, high quality

Algorithm Selection Guide

Small networks (<50 nodes): Kamada-Kawai or Force-Directed

Medium networks (50-500 nodes): Force-Directed or Spectral

Large networks (>500 nodes): Spectral or Hierarchical

Fast preview: Hierarchical (instant)

Files Modified

  • src/pypopart/layout/algorithms.py: Bug fix, new algorithm, caching, docs
  • src/pypopart/layout/__init__.py: Added SpectralLayout export
  • src/pypopart/gui/app.py: Added spectral option, reordered layouts
  • tests/unit/test_layout.py: 7 new tests
  • docs/layout_algorithms.md: New comprehensive guide

Backwards Compatibility

✅ All changes are backwards compatible:

  • New spectral layout is opt-in
  • Caching is enabled by default but transparent
  • All existing APIs unchanged
  • New parameters have sensible defaults
Original prompt

Review the network layout algorithms for accuracy and efficiency. Refactor if required.
tment of node layout in network graphs.

In geographic layout map sure a base map is displayed under the network graph.
AI: Your work will be continued in this pull request.
User:
When using MJN to calculate network and any epsilon value > 0, get error:

2025-11-16 09:14:02,353 - pypopart.gui.app - ERROR - Error computing network: "Haplotype 'Median_0' not found"
2025-11-16 09:14:02,354 - pypopart.gui.app - ERROR - Traceback (most recent call last):
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/gui/app.py", line 860, in compute_network
    network = algo.build_network(alignment)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/base.py", line 93, in build_network
    return self.construct_network(alignment, distance_matrix)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 96, in construct_network
    network = self._iterative_median_joining(haplotypes, alignment, distance_matrix)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 155, in _iterative_median_joining
    current_haplotypes = self._remove_obsolete_medians(msn, current_haplotypes)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 426, in _remove_obsolete_medians
    degree = network.get_degree(haplotype.id)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/core/graph.py", line 316, in get_degree
    raise KeyError(f"Haplotype '{haplotype_id}' not found")
KeyError: "Haplotype 'Median_0' not found"

When using MJN, haplotype summary tab information is incorrect. Sample IDs are reported as H numbers or "Median_" numbers i.e. "Median_2"
Sample IDs should correspond to sequence IDs from the input alignment.

Are the sample_IDs begining with "Median_" actually observed haplotypes? or are they inferred by the mjn method?
AI: Your work will be continued in this pull request.
User: Error when using MJN with epsilon > 0:

2025-11-16 09:43:30,751 - pypopart.gui.app - ERROR - Error computing network: 'Edge (Median_52, H4) not found'
2025-11-16 09:43:30,751 - pypopart.gui.app - ERROR - Traceback (most recent call last):
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/gui/app.py", line 860, in compute_network
    network = algo.build_network(alignment)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/base.py", line 93, in build_network
    return self.construct_network(alignment, distance_matrix)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 96, in construct_network
    network = self._iterative_median_joining(haplotypes, alignment, distance_matrix)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 220, in _iterative_median_joining
    final_network = self._simplify_network(final_network)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/algorithms/mjn.py", line 667, in _simplify_network
    direct_dist = network.get_edge_distance(n1, n2)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/adamtaranto/Documents/Adam/pypopart/src/pypopart/core/graph.py", line 276, in get_edge_distance
    raise KeyError(f'Edge ({source}, {target}) not found')
KeyError: 'Edge (Median_52, H4) not found'

Also, MJN graph produced with epsilon 0 contain inferred median nodes that do not bridge observed nodes either directly or via other median nodes, should these be preserved in the final network?

Compare and review our pure python implementation of mjn to the original popart C++ implementation
AI: Your work will be continued in this pull request.
User: Metadata template in dash app uses different column headers to what is expected by reader:

❌ Error parsing metadata
Error: ID column 'id' not found in CSV. Available columns: ['sequence_id', 'population', 'latitude', 'longitude', 'color', 'notes']
Please check your CSV file format.

In network graphs add edge labels indicating how many changes are required to get from one haplotype node to another in the network.

In alignment view highlight minor alleles or gaps in columns that contain >1 base. Colour using standard nucleotide colour scheme.

AI: Your work will be continued in this pull request.
User: Explain how to manually reposition nodes ...

Created from VS Code via the GitHub Pull Request extension.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits November 16, 2025 08:31
Co-authored-by: Adamtaranto <2160099+Adamtaranto@users.noreply.github.com>
Co-authored-by: Adamtaranto <2160099+Adamtaranto@users.noreply.github.com>
Co-authored-by: Adamtaranto <2160099+Adamtaranto@users.noreply.github.com>
@Adamtaranto

Copy link
Copy Markdown
Owner

@copilot finalise tasks

Copilot AI commented Nov 16, 2025

Copy link
Copy Markdown
Contributor Author

@copilot finalise tasks

Tasks finalized and PR is ready for review. ✅

Summary of completed work:

  1. ✅ Fixed critical bug in hierarchical layout (disconnected components)
  2. ✅ Added SpectralLayout algorithm (4-29x faster for large networks)
  3. ✅ Implemented layout caching for instant repeated computations
  4. ✅ Created comprehensive documentation (10KB algorithm guide)
  5. ✅ Enhanced all algorithm documentation with performance data
  6. ✅ Updated GUI with spectral option and performance hints
  7. ✅ Added 7 new tests (59 layout tests, 534 total tests pass)

Quality checks:

  • ✅ All 534 tests pass
  • ✅ Linter passes with no issues
  • ✅ Zero regressions
  • ✅ Full backwards compatibility

Key deliverables:

  • LAYOUT_REVIEW_SUMMARY.md - 15KB complete review document
  • docs/layout_algorithms.md - 10KB user guide
  • 6 files modified, 1,248 lines added

The PR is production-ready and can be merged. (Commits: df1ede3, d17b404, be9a53f)

@Adamtaranto Adamtaranto marked this pull request as ready for review November 16, 2025 09:43
@Adamtaranto Adamtaranto merged commit ad9348f into main Nov 16, 2025
1 check passed
@Adamtaranto Adamtaranto deleted the copilot/review-network-layout-algorithms branch November 16, 2025 09:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants