Skip to content

feat(pl): add angle_range parameter for polar pie-slice trees#51

Merged
colganwi merged 1 commit intomainfrom
feat/polar-angle-range
Mar 21, 2026
Merged

feat(pl): add angle_range parameter for polar pie-slice trees#51
colganwi merged 1 commit intomainfrom
feat/polar-angle-range

Conversation

@colganwi
Copy link
Copy Markdown
Collaborator

Summary

  • Add angle_range: tuple[float, float] = (0, 360) parameter to pl.branches() and pl.tree() for polar plots
  • Users can now generate "pie slice" shaped trees by specifying a (start, end) arc in degrees (e.g. (0, 180) for a semicircle)
  • annotation() automatically aligns annotation rings with the partial arc by reading stored angles from ax._attrs
  • Fully backward-compatible: default (0, 360) preserves existing behavior

Usage

# Semicircle
py.pl.branches(tdata, polar=True, angle_range=(0, 180), depth_key="time")

# Quarter circle
py.pl.branches(tdata, polar=True, angle_range=(0, 90), depth_key="time")

# Offset arc
py.pl.branches(tdata, polar=True, angle_range=(45, 315), depth_key="time")

# Combined with annotation via tree()
py.pl.tree(tdata, polar=True, angle_range=(0, 180), keys="clade", depth_key="time")

Test plan

  • New test_polar_angle_range test covers semicircle, quarter-circle, offset arc, and default (360°) cases
  • Verifies ax._attrs stores correct radian values
  • Verifies annotation layer renders without error on partial-arc trees
  • All 8 tests pass

🤖 Generated with Claude Code

…r pie-slice trees

Add an `angle_range=(start, end)` tuple parameter (in degrees) to
`pl.branches()` and `pl.tree()` so users can plot polar trees that span
a subset of the circle (e.g. a semicircle or quarter-circle) rather than
always using the full 360 degrees.

- `layout_trees()` now accepts `start_angle`/`end_angle` (radians) and
  distributes leaves across that arc instead of always [0, 2π]
- `branches()` converts the degree tuple to radians, passes it through,
  and stores the angles in `ax._attrs` for downstream consumers
- `annotation()` reads `start_angle`/`end_angle` from `ax._attrs` so
  annotation rings align with partial-arc trees
- `tree()` accepts and forwards `angle_range` to `branches()`

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.91%. Comparing base (a35566a) to head (5ba3de3).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #51      +/-   ##
==========================================
+ Coverage   92.89%   92.91%   +0.01%     
==========================================
  Files          34       34              
  Lines        2549     2554       +5     
==========================================
+ Hits         2368     2373       +5     
  Misses        181      181              
Files with missing lines Coverage Δ
src/pycea/pl/_utils.py 89.69% <100.00%> (ø)
src/pycea/pl/plot_tree.py 93.28% <100.00%> (+0.11%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@colganwi colganwi merged commit 5725107 into main Mar 21, 2026
8 checks passed
@colganwi colganwi deleted the feat/polar-angle-range branch March 21, 2026 13:29
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ba3de39a2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +139 to +140
start_angle_rad = np.deg2rad(angle_range[0])
end_angle_rad = np.deg2rad(angle_range[1])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Constrain polar axes to the requested angle span

When polar=True and angle_range is smaller than 360°, this change only remaps the branch coordinates; branches() never applies set_thetamin/set_thetamax (or equivalent) to the polar axes. In Matplotlib that still renders a full 360° polar frame, so the new semicircle/quarter-circle modes produce mostly empty circular plots instead of the advertised pie-slice trees.

Useful? React with 👍 / 👎.

Comment on lines +144 to +148
polar=polar,
extend_branches=extend_branches,
angled_branches=angled_branches,
start_angle=start_angle_rad,
end_angle=end_angle_rad,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip angle_range when rendering Cartesian trees

These angles are passed into layout_trees() unconditionally, even though the new parameter is documented as 'Only used when polar=True'. If a caller reuses a config like tree(..., angle_range=(0, 180)) with polar=False, the Cartesian branch layout and any later annotation() call are compressed into that half-range because ax._attrs['start_angle'/'end_angle'] also gets populated from it.

Useful? React with 👍 / 👎.

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.

1 participant