Skip to content

Support moving axes to the opposite side of the panel#1085

Merged
has2k1 merged 19 commits into
mainfrom
axis-position
Jun 23, 2026
Merged

Support moving axes to the opposite side of the panel#1085
has2k1 merged 19 commits into
mainfrom
axis-position

Conversation

@has2k1

@has2k1 has2k1 commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Adds the ability to place a position scale's axis on the opposite side of the panel — the x axis on top, the y axis on the right — together with per-side theming so each axis side can be styled independently.

  from plotnine import *
  from plotnine.data import mtcars

  (
      ggplot(mtcars, aes("wt", "mpg"))
      + geom_point()
      + scale_x_continuous(position="top")
      + scale_y_continuous(position="right")
  )

iangow and others added 18 commits May 27, 2026 13:49
(cherry picked from commit 7a65e28)
Add a scale_position mixin that validates and carries the axis position
("left"/"right" for y, "top"/"bottom" for x), and a scale_position_view
that propagates the resolved position through coord_cartesian to the coord.
Add per-side axis theme hierarchy (axis_text/ticks/line/title
each gain _x_top/_x_bottom, _y_left/_y_right children under the existing
parent). Each child styles its own side's artist; coord.setup_ax makes
the active side's ticks/spine visible per scale.position. coord_flip
rotates the position with the swap. Delete the dead mpl<3.10 tick-param
shim.
… axes

Side-scoped extent accessors on the layout items (label1/label2,
tick1line/tick2line via side_artists); top_space/right_space gain axis
attrs and the side-spaces read the scoped accessors + side-scoped
margins;
per-side axis-title placement; tick text justified into the band past
the
panel's far edge. Anchor top/right titles at the band's panel edge
(y1/x1,
not y2/x2, which cropped them) and align them across compositions via
axis_title_alignment, matching bottom/left. Default plots are
byte-identical.
The axis text/title gap is the single margin between the text and the
panel. Each side reads the margin edge that actually faces the panel: top
for a bottom axis, bottom for a top axis, right for a left axis, left for a
right axis. The value is read from the side-scoped themeable
(axis_text_x_top, axis_title_y_right, ...), which cascades to the parent by
default, so a user can override one side's margin without touching the
others. The themes (gray, matplotlib, seaborn) set both edges of the axis
text/title margins so every position has a gap. Docstrings updated to match.
Default plots unchanged.
New baselines for the axis-position feature: x_axis_top_continuous,
y_axis_right_continuous, x_axis_top_discrete, coord_flip_x_top,
facet_wrap_y_right. theme_seaborn is refreshed for the per-side axis
text/title margins.
Remove the temporal coupling where Layout.setup pre-assigned
self.facet.plot = plot so axis_positions() could reach
self.plot.scales before facet.setup(plot) ran at draw time.

axis_positions() now takes `scales` explicitly and uses an
explicit `is None` check (replacing getattr) so a present scale
missing `position` becomes a type error rather than a silent
default. compute_layout gains `axis_positions: tuple[str, str]`
in the base class and both subclasses (facet_grid, facet_wrap,
facet_null). Layout.setup resolves the positions from
plot.scales and passes them in, dropping the early assignment.
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.58140% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.25%. Comparing base (17eeeb6) to head (f2acb48).
⚠️ Report is 20 commits behind head on main.

Files with missing lines Patch % Lines
plotnine/themes/themeable.py 92.52% 9 Missing and 4 partials ⚠️
plotnine/facets/facet_grid.py 50.00% 2 Missing and 2 partials ⚠️
plotnine/facets/facet_wrap.py 71.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1085      +/-   ##
==========================================
+ Coverage   87.16%   87.25%   +0.09%     
==========================================
  Files         208      208              
  Lines       14375    14557     +182     
  Branches     1796     1812      +16     
==========================================
+ Hits        12530    12702     +172     
- Misses       1272     1281       +9     
- Partials      573      574       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@has2k1 has2k1 merged commit f2acb48 into main Jun 23, 2026
13 checks passed
@has2k1 has2k1 deleted the axis-position branch June 23, 2026 09:29
@TyberiusPrime

Copy link
Copy Markdown
Contributor

Will this eventually lead to dual axis plots?

@has2k1

has2k1 commented Jun 23, 2026

Copy link
Copy Markdown
Owner Author

Will this eventually lead to dual axis plots?

A big yes. And not eventually, rather immediately!

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.

3 participants