Skip to content

Implement Figure-level overlay architecture with two-pass drawing - #32199

Open
Vikash-Kumar-23 wants to merge 4 commits into
matplotlib:mainfrom
Vikash-Kumar-23:container-managed-overlays
Open

Implement Figure-level overlay architecture with two-pass drawing#32199
Vikash-Kumar-23 wants to merge 4 commits into
matplotlib:mainfrom
Vikash-Kumar-23:container-managed-overlays

Conversation

@Vikash-Kumar-23

@Vikash-Kumar-23 Vikash-Kumar-23 commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

PR summary

This PR introduces a foundational Figure-level overlay architecture to figure.py. It implements a two-pass drawing system, allowing developers to cleanly segregate base plot artists from overlay artists.

Key Changes:

  • Layered Artist Storage: _children_by_layer dictionary in FigureBase. Artists are now routed to distinct lists based on their layer (e.g., "base", "overlay"), and self.patch has been isolated into its own dedicated "patch" layer.
  • Multi-Pass Drawing: Modified Figure.draw() and SubFigure.draw() to execute in multiple passes using a new, generic _draw_layer(renderer, layer_name) method. The strict sequence is now:
    • "patch" layer: Renders the figure background first.
    • "base" layer: Renders all standard artists.
    • "overlay" layer: Renders all overlay artists last.
  • Public API Routing: Added a layer=None keyword-only argument add_artist and get_children

Addresses #30515

AI Disclosure

AI tools were used to assist in drafting text and suggesting validation scenarios.
All code changes, final implementation decisions, and verification were done manually.

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • New and changed code is tested
  • Plotting related features are demonstrated in an example
  • New features and API changes have release notes
  • Documentation complies with general and docstring guidelines

fig._draw_base_layer = lambda renderer: None
fig.patch.set_alpha(0.0)
ax.patch.set_alpha(0.0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think you need three tests here:

  • base
  • overlay
  • composite

b/c if you have to knock out the patch on the overlay, that seems to indicate you're not getting clean independence.

@ksunden ksunden left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The main idea for this review is to push towards making the layering system more generic. Instead of just one overlay, it is possible to extend into more, which has the added benefit of enabling us to clean up the code and reduce duplicated code.

I've laid out a series of specific changes that I think will add up to making this more useful and cleaner, outlined below.

Comment thread lib/matplotlib/figure.py
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py Outdated
@Vikash-Kumar-23

Copy link
Copy Markdown
Contributor Author

@ksunden @story645 Thanks for the feedback! I've updated the architecture based on your suggestion to make self.patch its own layer instead of special-casing it.

Here are the updates pushed in the latest commit:

  1. Layer Dictionary: Replaced the hardcoded _overlay_children list and _overlay boolean flags with a more scalable _children_by_layer dictionary and a string layer argument.
  2. Dedicated Patch Layer: self.patch is now fully integrated into the layer system inside its own "patch" layer.
  3. Generic Draw Method: Replaced the hardcoded _draw_base_layer and _draw_overlay_layer methods with a single generic _draw_layer(renderer, layer) method. The draw() sequence for both Figure and SubFigure is now explicitly: "patch" -> "base" -> "overlay".
  4. get_children: Updated get_children(layer=None) so it returns artists specific to the requested layer.
    When layer=None is passed, it safely returns the background patch followed by all the base and overlay artists

Comment thread lib/matplotlib/tests/test_figure.py Outdated
Comment thread lib/matplotlib/figure.py
Comment thread lib/matplotlib/figure.py
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py Outdated
Comment thread lib/matplotlib/figure.py
Comment on lines +1128 to +1131
self._children_by_layer = {
"patch": [self.patch],
"base": self._children,
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

does this overwrite line 112?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants