From 8a51fd92f65fec226733d911ab1633a8eb3e8e0d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 12 Apr 2025 23:40:30 -0400 Subject: [PATCH 1/3] DOC: add warnings about get_window_extent and BboxImage Closes #2831 --- lib/matplotlib/artist.py | 26 +++++++++++++------ lib/matplotlib/image.py | 56 +++++++++++++++++++++++++++++++++------- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index c87c789048c4..f4782f0d942d 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -329,19 +329,29 @@ def get_window_extent(self, renderer=None): """ Get the artist's bounding box in display space. - The bounding box' width and height are nonnegative. + The bounding box's width and height are non-negative. Subclasses should override for inclusion in the bounding box "tight" calculation. Default is to return an empty bounding box at 0, 0. - Be careful when using this function, the results will not update - if the artist window extent of the artist changes. The extent - can change due to any changes in the transform stack, such as - changing the Axes limits, the figure size, or the canvas used - (as is done when saving a figure). This can lead to unexpected - behavior where interactive figures will look fine on the screen, - but will save incorrectly. + .. warning :: + + Be careful when using this function, the results will not update if + the artist window extent of the artist changes. + + The extent can change due to any changes in the transform stack, such + as changing the Axes limits, the figure size, the canvas used (as is + done when saving a figure), or the DPI. + + This can lead to unexpected behavior where interactive figures will + look fine on the screen, but will save incorrectly. + + To get accurate results you may need to manually call + `matplotlib.figure.Figure.savefig` or + `matplotlib.figure.Figure.draw_without_rendering` to have Matplotlib + compute the rendered size. + """ return Bbox([[0, 0], [0, 0]]) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index bd1254c27fe1..8aa48f30d947 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1374,8 +1374,52 @@ def set_data(self, A): class BboxImage(_ImageBase): - """The Image class whose size is determined by the given bbox.""" + """ + The Image class whose size is determined by the given bbox. + + Parameters + ---------- + bbox : BboxBase or Callable[RendererBase, BboxBase] + The bbox or a function to generate the bbox + + .. warning :: + + If using `matplotlib.artist.Artist.get_window_extent` as the + callable ensure that the other artist is drawn first (lower zorder) + or you may need to renderer the figure twice to ensure that the + computed bbox is accurate. + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar + data to colors. + norm : str or `~matplotlib.colors.Normalize` + Maps luminance to 0-1. + interpolation : str, default: :rc:`image.interpolation` + Supported values are 'none', 'auto', 'nearest', 'bilinear', + 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', + 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', + 'sinc', 'lanczos', 'blackman'. + origin : {'upper', 'lower'}, default: :rc:`image.origin` + Place the [0, 0] index of the array in the upper left or lower left + corner of the Axes. The convention 'upper' is typically used for + matrices and images. + filternorm : bool, default: True + A parameter for the antigrain image resize filter + (see the antigrain documentation). + If filternorm is set, the filter normalizes integer values and corrects + the rounding errors. It doesn't do anything with the source floating + point values, it corrects only integers according to the rule of 1.0 + which means that any sum of pixel weights must be equal to 1.0. So, + the filter function must produce a graph of the proper shape. + filterrad : float > 0, default: 4 + The filter radius for filters that have a radius parameter, i.e. when + interpolation is one of: 'sinc', 'lanczos' or 'blackman'. + resample : bool, default: False + When True, use a full resampling method. When False, only resample when + the output image is larger than the input image. + **kwargs : `~matplotlib.artist.Artist` properties + + """ def __init__(self, bbox, *, cmap=None, @@ -1388,12 +1432,7 @@ def __init__(self, bbox, resample=False, **kwargs ): - """ - cmap is a colors.Colormap instance - norm is a colors.Normalize instance to map luminance to 0-1 - kwargs are an optional list of Artist keyword args - """ super().__init__( None, cmap=cmap, @@ -1409,12 +1448,11 @@ def __init__(self, bbox, self.bbox = bbox def get_window_extent(self, renderer=None): - if renderer is None: - renderer = self.get_figure()._get_renderer() - if isinstance(self.bbox, BboxBase): return self.bbox elif callable(self.bbox): + if renderer is None: + renderer = self.get_figure()._get_renderer() return self.bbox(renderer) else: raise ValueError("Unknown type of bbox") From 8865ece2cb72b46e23309f59d14f15c0aead1dfa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 14 Apr 2025 09:08:49 -0400 Subject: [PATCH 2/3] DOC: fix rst markup Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/artist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index f4782f0d942d..fa468e7ffe4f 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -335,7 +335,7 @@ def get_window_extent(self, renderer=None): "tight" calculation. Default is to return an empty bounding box at 0, 0. - .. warning :: + .. warning:: Be careful when using this function, the results will not update if the artist window extent of the artist changes. From d494c318707db65110783ae629e6f498afe7bcb1 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 14 Apr 2025 09:17:57 -0400 Subject: [PATCH 3/3] DOC: clarify wording Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> --- lib/matplotlib/artist.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index fa468e7ffe4f..39fed23d1d7c 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -337,15 +337,14 @@ def get_window_extent(self, renderer=None): .. warning:: - Be careful when using this function, the results will not update if - the artist window extent of the artist changes. - The extent can change due to any changes in the transform stack, such as changing the Axes limits, the figure size, the canvas used (as is done when saving a figure), or the DPI. - This can lead to unexpected behavior where interactive figures will - look fine on the screen, but will save incorrectly. + Relying on a once-retrieved window extent can lead to unexpected + behavior in various cases such as interactive figures being resized or + moved to a screen with different dpi, or figures that look fine on + screen render incorrectly when saved to file. To get accurate results you may need to manually call `matplotlib.figure.Figure.savefig` or