Skip to content
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

Add a Figure._get_cachedRenderer() method #21319

Closed
wants to merge 1 commit into from

Conversation

dstansby
Copy link
Member

@dstansby dstansby commented Oct 8, 2021

PR Summary

Adds Figure._get_cachedRenderer() which can be used to get the cached renderer, but error if it's not present. This can be used in one existing place, and is also now used in a legend method, which probably fixes #21285

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

@jklymak
Copy link
Member

jklymak commented Oct 8, 2021

Yes I was wondering if it should try and get the rendere from the current figure if there is one in pyplot.

@@ -2378,6 +2378,13 @@ def axes(self):

get_axes = axes.fget

def _get_cachedRenderer(self, error_if_none=True):
# Get the cached renderer, raising an error if it doesn't exist yet
Copy link
Member

Choose a reason for hiding this comment

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

I guess if self._cachedRenderer is None, I'd do self.draw_without_rendering() here and force a renderer (I think).

Copy link
Member Author

Choose a reason for hiding this comment

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

This is probably a behaviour change and outside the scope of this (bugfix) PR? Perhaps not though, I'm not very well acquainted with renderers etc.

Copy link
Member

Choose a reason for hiding this comment

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

We already have a public method https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.get_renderer_cache.html ax.get_render_cache, do we want to prompt this to be public on the Figure too (or deprecate the one on Axes? We do not use it internally, it only shows up where it is defined, in an example, and in the source rst).

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question, and I'm not entirely sure what the answer is as I'm not too sure why/if a user would want to get the cached renderer.

Copy link
Member

Choose a reason for hiding this comment

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

I think for exactly the reason we are getting it here!

I can see an argument than all of the renderer cache stuff should be private. It is a cache and there is no good reason for the user to be poking around the cache, we want to be able to replace/clear it/etc at will. On the other hand, we expose a couple of public functions that take a renderer as an "optional" (but only because fill it in with the cache) argument. Making renderers is a bit finicky (and if you make it your self no guarantee that it is consistent with anything you care about!).

@tacaswell

This comment has been minimized.

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

I guess this needs an API change note as the Error has changed in both cases?

@tacaswell tacaswell modified the milestones: v3.5.1, v3.6.0 Dec 1, 2021
@@ -2829,10 +2836,7 @@ def draw_artist(self, a):
This method can only be used after an initial draw of the figure,
because that creates and caches the renderer needed here.
"""
if self._cachedRenderer is None:
raise AttributeError("draw_artist can only be used after an "
Copy link
Member

Choose a reason for hiding this comment

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

I suspect that this is raising AttributeError to maintain exact API compatibility with older versions of the code where _cachedRenderer was not an attribute until it was stashed 😱 .

@tacaswell
Copy link
Member

I pushed this to 3.6 because I think this is a slightly bigger change than we want to put in a patch release, this is a very old bug, and there is multiple reasonable workarounds.

@tacaswell
Copy link
Member

I think this needs an API change note because the Exception type is changed. We may also want to do

class NoRenderer(RuntimeError, AttributeError):
    ...

and raise that instead (back-compatible and a more informative name).

@jklymak
Copy link
Member

jklymak commented Feb 1, 2022

@dstansby popped this to draft until the rebase and API change note are done. I imagine it is mergeable at that point?

@dstansby
Copy link
Member Author

dstansby commented Feb 8, 2022

I don't have time to pick this up in the short term - if someone else wants to feel free

@timhoffm timhoffm modified the milestones: v3.6.0, unassigned Apr 30, 2022
@QuLogic
Copy link
Member

QuLogic commented Jul 5, 2022

@jklymak #22745 added Figure._get_renderer, so can this be closed?

@jklymak
Copy link
Member

jklymak commented Jul 6, 2022

I think so....

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.

legend.get_window_extent() fails
5 participants