ENH: Give control whether twinx() or twiny() overlays the main axis by sanrishi · Pull Request #31181 · matplotlib/matplotlib
PR summary
This PR addresses the ergonomics issue where twinned axes default to overlaying the main axis, obscuring the primary data unless users manually manipulate z-orders and patch visibilities.
Key Changes:
-
New delta_zorder Parameter: Exposed delta_zorder as a keyword-only argument in twinx() and twiny() (and updated the type stubs in _base.pyi). This allows users to easily position twins relative to the main axes (e.g., passing delta_zorder=-1 puts the twin behind the main data).
-
Automated Patch Visibility: Added _update_twinned_axes_patch_visibility() which evaluates the whole group of twinned axes. The group is sorted by zorder (using figure insertion order as a tie-breaker), ensuring that only the bottom-most axis has a visible background patch.
-
Reactive Logic: Extended set_zorder and set_frame_on in _AxesBase to trigger the patch visibility update. If a user dynamically changes the z-order or frame state of any axis in a twinned group after creation, the background visibility automatically corrects itself.
-
Respects frameon: The visibility logic explicitly checks ax.get_frame_on() so it does not force a background onto an axis where the user explicitly disabled the frame.
-
Cleanup: Removed the legacy, hardcoded patch.set_visible(False) calls in twinx() and twiny().
Documentation & Testing:
Added a new gallery example (galleries/examples/subplots_axes_and_figures/twin_axes_zorder.py) demonstrating how to plot overlapping data with a background twin.
Added comprehensive tests in lib/matplotlib/tests/test_axes.py covering default behavior, custom delta_zorder stacking, multiple twins, and dynamic visibility updates. Verified locally that regression tests pass.
Here is a quick test using ax2 = ax.twinx(delta_zorder=-1) with a semi-transparent blue line on the main axis and a solid red line on the twin. As requested in the original issue, the main axis data (blue) is correctly layered on top of the twin axis data (red), and the background patches are handling the transparency perfectly!

PR checklist
- "closes [ENH]: Give control whether twinx() or twiny() overlays the main axis #31122" is in the body of the PR description to link the related issue
- new and changed code is tested
- Plotting related features are demonstrated in an example
- New Features and API Changes are noted with a directive and release note
- Documentation complies with general and docstring guidelines