Feature/autolayout improvements#412
Conversation
- Replace manual positioning with Reingold-Tilford algorithm - Remove num_rows/num_cols parameters from TreeGrid.__init__() - Remove "position" keys from tree structure, only "children" required - Add automatic parent centering over children - Update RevenueTree to use simplified auto-layout API - Update all TreeGrid tests for new API - Add comprehensive layout verification tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…r preservation - Replace _find_parent() O(n²) helper with O(n) parent_map dictionary - Use more Pythonic patterns (deque initialization, max with default) - Fix bug where Qwen's version sorted leaves alphabetically instead of preserving tree structure order - Add noqa: C901 for acceptable algorithm complexity - Maintain correct two-pass Reingold-Tilford inspired approach 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
…n rendering IMPROVEMENTS: - Extract DRY violation: Created build_node() helper function in revenue_tree.py * Reduced 84 lines of repetitive node definitions to 46 lines (45% reduction) * Eliminates code duplication across 7 node definitions - Fix inconsistent spacing calculations in TreeGrid * horizontal_spacing and vertical_spacing now use consistent logic * Both now calculate as: node_dimension + fixed_gap * Removed asymmetric division by grid_spacing - Extract magic numbers to named constants * Added DEFAULT_VERTICAL_GAP, DEFAULT_HORIZONTAL_GAP, DEFAULT_LR_DEPTH_GAP * Added 10 layout constants to DetailedTreeNode * Improves maintainability and clarity - Consolidate duplicate contour functions * Unified get_left_contour and get_right_contour into single get_contour() * Reduced 28 lines to 16 lines with parameterized behavior * Eliminates near-duplicate code - Fix TB orientation connection rendering * Added threshold check for small horizontal offsets * Uses simple straight lines when offset < 2× curve_radius * Eliminates jagged appearance on nearly-vertical connections * Preserves smooth S-curves for larger offsets PRESERVED: - TB/LR orientation support for future speeddrill feature - All existing functionality and public API - Test coverage maintained at 99% for revenue_tree.py 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
IMPROVEMENTS: - Add shared fixtures for common tree structures * simple_three_node_tree for SimpleTreeNode tests * detailed_three_node_tree for DetailedTreeNode tests - Consolidate redundant BaseRoundedBox vertex tests * Reduced 5 tests to 3 with better coverage * Combined partial radius tests into single test - Parametrize duplicate orientation tests * Combined test_orientation_lr and test_orientation_tb * Now uses @pytest.mark.parametrize for both orientations - Add missing test scenarios (TestMissingScenarios class): * test_tb_orientation_position_mapping - verify Y axis mapping * test_custom_spacing_parameters - custom spacing overrides * test_default_spacing_uses_constants - verify constant usage * test_detailed_node_without_contribution - optional field * test_contour_prevents_overlap_in_complex_tree - overlap prevention * test_tree_with_fixture - fixture usage validation * test_lr_orientation_depth_maps_to_x - LR depth mapping Test count: 57 tests (was 52), all passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix ruff linting issues (magic numbers, unused variables, SIM114) - Add matplotlib Agg backend to avoid tkinter errors in CI - Format code with ruff formatter - All 57 tests now pass with 97% coverage 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @09hanvaik's task —— View job PR Review Complete ✅
SummaryI've completed a comprehensive review of this PR implementing the Reingold-Tilford auto-layout algorithm. The detailed review has been posted as a separate comment. Overall Assessment: High-quality work with excellent implementation ⭐ Key Findings:
Recommendation: Approve with minor suggestions. The spacing inconsistency should be reviewed before merge, but all other items are nice-to-haves. |
Code Review SummaryI've completed a comprehensive review of this PR implementing the Reingold-Tilford auto-layout algorithm. Overall, this is excellent work with high code quality, comprehensive test coverage, and solid adherence to best practices. Below are my findings organized by category. ✅ StrengthsAlgorithm Implementation
Code Quality
Test Coverage
Architecture
🔍 Issues Found1. Code Quality - Consolidation Opportunity (Minor)Location: The PR summary mentions consolidating def get_contour(node_id: str, mod_sum: float, get_leftmost: bool) -> dict[int, float]:
contour: dict[int, float] = {}
node_depth = depths[node_id]
contour[node_depth] = prelim_x[node_id] + mod_sum
children = children_map.get(node_id, [])
if children:
child_contours = [get_contour(child, mod_sum + modifier[node_id], get_leftmost) for child in children]
for child_contour in child_contours:
for depth, x in child_contour.items():
if (
depth not in contour
or (get_leftmost and x < contour[depth])
or (not get_leftmost and x > contour[depth])
):
contour[depth] = x
return contourSuggestion: The conditional logic on lines 493-497 could be simplified. Consider extracting the comparison logic: def should_update_contour(new_x: float, current_x: float, get_leftmost: bool) -> bool:
return get_leftmost and new_x < current_x or not get_leftmost and new_x > current_x
# Then use:
if depth not in contour or should_update_contour(x, contour[depth], get_leftmost):
contour[depth] = xThis is a minor readability improvement - the current code is correct and clear enough. 2. Potential Bug - Spacing Inconsistency (Medium)Location: There's an inconsistency in how spacing is calculated between orientations: # Lines 395-398
default_vertical = node_height + self.DEFAULT_VERTICAL_GAP
default_horizontal = node_width + self.DEFAULT_HORIZONTAL_GAP
self.vertical_spacing = vertical_spacing if vertical_spacing is not None else default_vertical
self.horizontal_spacing = horizontal_spacing if horizontal_spacing is not None else default_horizontal
# Lines 401-407
if self.orientation == "LR":
self.depth_spacing = node_width + self.DEFAULT_LR_DEPTH_GAP # Uses DEFAULT_LR_DEPTH_GAP (1.0)
else:
self.depth_spacing = self.vertical_spacing # Uses vertical_spacing (node_height + 0.8)Issue: In LR orientation, Recommendation: Consider either:
3. Test Quality - Missing Edge Case (Minor)Location: The test suite is comprehensive, but there's one missing edge case: Missing: Test for trees with Suggestion: Add a test like: def test_none_children_treated_as_leaf(self):
"""Test that None children value is treated as empty list."""
tree_structure = {
"root": {
"header": "Root",
"percent": 5.0,
"value1": "00K",
"value2": "5K",
"children": None, # Explicit None instead of [] or missing
},
}
grid = TreeGrid(tree_structure=tree_structure, node_class=SimpleTreeNode)
ax = grid.render()
assert len(ax.patches) == 2 # Should render as leaf node4. Code Quality - Magic Number Still Present (Minor)Location: Line 80 contains a magic number: period_count = 2
if len(df.index) == period_count:Recommendation: While this is named as a constant locally, consider making it a module-level constant if this value is significant to the domain logic, or add a comment explaining why exactly 2 periods requires special handling. 5. Documentation - Algorithm Complexity (Minor)Location: The docstring mentions O(n) complexity, which is excellent! However, it would be helpful to explain why it's O(n): """Compute node positions using Reingold-Tilford algorithm with contour tracking.
Time Complexity: O(n) where n is the number of nodes. Each node is visited exactly
once in the post-order pass and once in the pre-order pass. Contour merging at each
node processes only the depths present in its subtrees.
"""🔒 SecurityNo security concerns identified. The code:
⚡ PerformanceExcellent performance characteristics:
Minor optimization opportunity: Lines 490-498 iterate over child contours. For very wide trees (many children), this could be optimized with a single pass, but this is likely premature optimization for typical use cases. 🧪 Test CoverageOutstanding test coverage (91.6% based on PR description): ✅ Comprehensive coverage includes:
✅ Tests follow best practices:
Suggestions:
📋 Best Practices Compliance✅ Follows CLAUDE.md guidelines:
✅ Clean git history:
🎯 RecommendationsHigh Priority
Medium Priority
Low Priority (Nice-to-have)
✨ ConclusionThis is high-quality work that successfully implements a non-trivial algorithm with excellent code organization, comprehensive testing, and strong adherence to best practices. The issues identified are minor and don't block merging. Recommendation: APPROVE with minor suggestions The spacing inconsistency (Issue #2) is the only item I'd suggest addressing before merge, as it could cause unexpected visual differences between orientations. All other items are nice-to-haves that could be addressed in follow-up PRs. Great job on this implementation! The Reingold-Tilford algorithm is well-executed and the test coverage is exemplary. 🎉 |
Codecov Report❌ Patch coverage is
... and 9 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Summary