Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix the misplacement of rasterized object in DrawingArea in the vectorized backends #30171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions lib/matplotlib/offsetbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@
DEBUG = False


def _is_vector_renderer(renderer):
# 1. Check the renderer name
vector_bases = {'RendererPdf', 'RendererSVG', 'RendererPS'}

Check warning on line 47 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L47

Added line #L47 was not covered by tests
# If it's MixedModeRenderer, get the actual renderer recursively
actual_renderer = renderer

Check warning on line 49 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L49

Added line #L49 was not covered by tests
while type(actual_renderer).__name__ == 'MixedModeRenderer':
actual_renderer = getattr(actual_renderer, '_renderer', actual_renderer)
renderer_name = type(actual_renderer).__name__

Check warning on line 52 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L51-L52

Added lines #L51 - L52 were not covered by tests
Comment on lines +50 to +52
Copy link
Member

@timhoffm timhoffm Jun 18, 2025

Choose a reason for hiding this comment

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

This approach feels quite hacky. The functionality should live in a method MxedModeRenderer.is_vector_renderer(). Possibly that function should be made a core feature Renderer so that the whole _is_vector_renderer can go away. Though I'm not sure whether there are implications for third party renders. @anntzer what do you as a backend implementer think?

if renderer_name in vector_bases:
return True

Check warning on line 54 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L54

Added line #L54 was not covered by tests
# 3. For unknown renderers, assume they are not vector
return False

Check warning on line 56 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L56

Added line #L56 was not covered by tests


def _compat_get_offset(meth):
"""
Decorator for the get_offset method of OffsetBox and subclasses, that
Expand Down Expand Up @@ -689,18 +703,33 @@
self.dpi_transform.clear()
self.dpi_transform.scale(dpi_cor)

# At this point the DrawingArea has a transform
# to the display space so the path created is
# good for clipping children
tpath = mtransforms.TransformedPath(
mpath.Path([[0, 0], [0, self.height],
[self.width, self.height],
[self.width, 0]]),
self.get_transform())
for c in self._children:
if self._clip_children and not (c.clipbox or c._clippath):
c.set_clip_path(tpath)
c.draw(renderer)
is_rasterized = getattr(c, 'get_rasterized', lambda: False)()
if is_rasterized and _is_vector_renderer(renderer):
# PDF/SVG backend uses 72 dpi in display units,
# so we need to scale the rasterized content accordingly
target_dpi = getattr(renderer, 'dpi', 72) or 72
dpi_correction = target_dpi / 72

Check warning on line 717 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L716-L717

Added lines #L716 - L717 were not covered by tests
# New transform to apply the dpi correction
corrected_transform = self.get_transform() \

Check warning on line 719 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L719

Added line #L719 was not covered by tests
+ mtransforms.Affine2D().scale(dpi_correction)
orig_transform = c.get_transform() \

Check warning on line 721 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L721

Added line #L721 was not covered by tests
if hasattr(c, 'get_transform') else None
c.set_transform(corrected_transform)

Check warning on line 723 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L723

Added line #L723 was not covered by tests
if self._clip_children and not (c.clipbox or c._clippath):
c.set_clip_path(tpath)
c.draw(renderer)

Check warning on line 726 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L725-L726

Added lines #L725 - L726 were not covered by tests
if orig_transform is not None:
c.set_transform(orig_transform)

Check warning on line 728 in lib/matplotlib/offsetbox.py

View check run for this annotation

Codecov / codecov/patch

lib/matplotlib/offsetbox.py#L728

Added line #L728 was not covered by tests
else:
if self._clip_children and not (c.clipbox or c._clippath):
c.set_clip_path(tpath)
c.draw(renderer)

_bbox_artist(self, renderer, fill=False, props=dict(pad=0.))
self.stale = False
Expand Down
Loading