Skip to content

ENH: Add pre_draw_event callback#31887

Open
Vikash-Kumar-23 wants to merge 8 commits into
matplotlib:mainfrom
Vikash-Kumar-23:pre-draw-event-implementation
Open

ENH: Add pre_draw_event callback#31887
Vikash-Kumar-23 wants to merge 8 commits into
matplotlib:mainfrom
Vikash-Kumar-23:pre-draw-event-implementation

Conversation

@Vikash-Kumar-23

Copy link
Copy Markdown
Contributor

Closes #17168.

This PR adds a new pre_draw_event callback that is emitted during Figure.draw() after layout and geometry have been finalized but before any rendering occurs.

Currently, draw_event is emitted only after rendering has completed, which makes it difficult for callbacks to inspect or modify artists based on their final geometry before pixels are written to the renderer.

The new event is emitted after _get_draw_artists(renderer) so that:

  • layout engines have already executed,
  • axes positions have been finalized,
  • locator-based axes (such as inset axes) have resolved their geometry,
  • artist extents can be queried reliably,

while still allowing callbacks to run before rendering begins.

One motivating use case is overlay systems that need access to final axes geometry before rendering occurs without requiring an additional draw pass.

Minimum self-contained example

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

def on_pre(event):
    print("pre_draw_event")

def on_draw(event):
    print("draw_event")

fig.canvas.mpl_connect("pre_draw_event", on_pre)
fig.canvas.mpl_connect("draw_event", on_draw)

fig.canvas.draw()

Output:

pre_draw_event
draw_event

pre_draw_event is emitted before rendering begins, while
draw_event is emitted after rendering completes.

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 checklist

Comment thread lib/matplotlib/figure.py Outdated
# ValueError can occur when resizing a window.

artists = self._get_draw_artists(renderer)
DrawEvent("pre_draw_event", self.canvas, renderer)._process()

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.

This seems wrong to me. I think we need a new class for PreDrawEvent as while the code maybe identical, the semantics are quite different (e.g. you can't do any blitting related work)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks.
What I am planning to do is introduce a dedicated event type (PreRenderEvent) rather than reusing DrawEvent. The callback would still fire at its current location in the pipeline, after layout/geometry calculations but before rendering begins.

Does that sound reasonable?

@tacaswell

Copy link
Copy Markdown
Member

It is not clear to me that "pre draw" is the right name for this. Maybe "pre render" on "LayoutEvent" would be clearer. My confusion is that "pre draw" sounds like it should filre at the very top of Figure.draw before anything has been done rather than someplace in the middle of draw.

@github-actions github-actions Bot added the Documentation: API files in lib/ and doc/api label Jun 15, 2026
@timhoffm

Copy link
Copy Markdown
Member

Can we keep the callback private for now? As long as we're only needing this for the overlay system, there is no need to expose this to users.

Naming and timing have some issues, which we don't have to fully resolve if it stays private:

  • As of now "pre_render_event" would also fire in Figure.draw_without_rendering which is a bit awkward.
  • This is the only "pre" event so far.
  • The logic and terminology around draw is somewhat muddied: draw is maybe layout + "internal draw", where "internal draw" is patch.draw + _draw_list_compositing_images. This may called render or not (not arguments would be that render is a lower level concept of rendering something though the renderer, and alternatively and contradicting, render could be bounded by Renderer.open_group/close_group("figure"))

@github-actions github-actions Bot removed topic: pyplot API Documentation: API files in lib/ and doc/api labels Jun 16, 2026
@Vikash-Kumar-23

Copy link
Copy Markdown
Contributor Author

Thanks! I updated the implementation to keep the callback private.

Changes made:

Renamed pre_render_event to _pre_render_event
Removed the public API exposure (RenderEventType, pyplot overloads, docs, etc.)
Kept the hook available only through the internal callback registry used by the overlay system

Updated tests accordingly.

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.

Add a pre_draw_event event

3 participants