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

Skip to content

It is painful as a new user, to figure out what AxesSubplot is #18222

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

Closed
aathan opened this issue Aug 11, 2020 · 19 comments
Closed

It is painful as a new user, to figure out what AxesSubplot is #18222

aathan opened this issue Aug 11, 2020 · 19 comments
Milestone

Comments

@aathan
Copy link

aathan commented Aug 11, 2020

Bug report

Try googling "AxesSubplot" which is the type you get back from a plt.gca() call. Try finding this class in the docs. Try searching for this class in the source code.

Poor new users trying to figure out what they're dealing with...

(It's a dynamic class created in _subplot.py that is a subclass of Axes, but ... boy was that a pain to detangle. Asked it's class for it's module, etc... Have mercy on new users and make it easier to find documentation for dynamic classes.)

(and no, it's not good enough that google does show Axes in its result, because it's not AxesSubplot, and if you're chasing down an AttributeError, or have a typo in a function call that you believe it "should" respond to, you're in a mindset of thinking "this must not be an Axes")

@timhoffm
Copy link
Member

timhoffm commented Aug 11, 2020

As a remark, gca() will return an Axes or a subclass thereof. For example plt.axes([0, 0, 1, 1]) will result in the current axes being an Axes instance directly.

Would have a more descriptive docstring of AxesSubplot already have helped?

@aathan
Copy link
Author

aathan commented Aug 11, 2020

I'm pretty sure plt.gca() was returning an AxesSubplot. See #18220 for the code. Anything that fixes the online docs and/or increases the probability that a user will quickly understand that AxesSubplot is an Axes, would be an improvement. I'm not sure the current docstring but if it's the one from _picklable_subplot_class_constructor I'd consider improving it so that new users understand what they can do with it, not why it is a necessary hack.

@tacaswell
Copy link
Member

Can you be a bit more specific about what changes to the documentation would have helped?

As a side note, my go-to tools when exploring new classes (looking at the mro and isinstance checks)

In [13]: isinstance(plt.gca(), matplotlib.axes.Axes)                                                                                                                                                                                                                                                   
Out[13]: True

In [14]: type(plt.gca()).mro()                                                                                                                                                                                                                                                                         
Out[14]: 
[matplotlib.axes._subplots.AxesSubplot,
 matplotlib.axes._subplots.SubplotBase,
 matplotlib.axes._axes.Axes,
 matplotlib.axes._base._AxesBase,
 matplotlib.artist.Artist,
 object]

both seem pretty clear.

@aathan
Copy link
Author

aathan commented Aug 12, 2020

Thomas, I agree. Those things are clear. If it wasn't clear above, the specific fixes I recommend are:

  1. Ensuring that a [ insert favorite search engine ] search of AxesSubplot leads to a useful documentation page that appears to be about AxesSubplot (and points you to Axes for more info)
  2. Ensuring that the docstring for AxesSubplot includes words like "AxesSubplot is the Axes instance for certain plots, returned by calls such as gca(), and does not have any special plotting related behaviors related to subplots per-se. It is a dynamically generated class for persistence (pickling) purposes."
  3. Ensuring that at the matplotlib.org site, the search box returns non-empty results for "AxesSubplot" -- preferably a link to Axes documentation per # 1 & # 4. Currently it returns one result and it's not helpful documentation, titled "origin and extent in imshow"
  4. Mentioning AxesSubplot (and any other Subplot dynamic classes) in their parent class' documentation (i.e., # 1)
  5. Including the names of likely frequently encountered autogenerated subclasses in the .py that generates them

As things currently stand, AxesSubplot is frequently encountered when using matplotlib but isn't even mentioned in the docs. This leads to many questions about what it might be, whether it is a true Axes or (per its name) doing some special forwarding or modified behaviors for contained Axes of subplots, etc ... and when one goes to find the source code to make sure it's the Axes you want to be talking to ... you end up not finding it easily because it's name appears nowhere in the source code either.

I hope that helps :)

Matplotlib is awesome.

@jklymak
Copy link
Member

jklymak commented Aug 12, 2020

I agree this is painful. Its made worse by the fact that we use a factory to create the subclass, so its really hard as a beginner interested in the internals to trace how the class is even defined. It would be nice to figure out a reasonable place to explain this.

@tacaswell tacaswell added this to the v3.4.0 milestone Aug 12, 2020
@timhoffm
Copy link
Member

In principle, it should be possible to document dynamically created classes in Sphinx because AFAIK it uses introspection and no static code analysis.

@DingXuefeng
Copy link

I think adding the sentence "AxesSubplot" is a dynamically created class inheriting SubplotBase" in the docstring of SubplotBase (https://matplotlib.org/3.3.0/api/_as_gen/matplotlib.axes.SubplotBase.html) would be enough.

@anntzer
Copy link
Contributor

anntzer commented Sep 10, 2020

Actually, looking at it again, I think it may be reasonable to just push all the SubplotBase functionality either to the base Axes class (with ax.get_subplotspec returning None if the axes is not gridspec-positioned) or, for lower level stuff (is_first_row, etc.) to the SubplotSpec. This means that one would have to change all the isinstance(ax, SubplotBase) checks to ax.get_subplotspec() is not None which seems fine (you even save an import ;-)), but gets rid of the main dynamically generated subclass, which is a big simplification...
The Axes and Subplot constructor signatures are different (one takes a rectangle and the other something convertible to a SubplotSpec) but we can easily support both at least during the transition period (and possibly forever); in any case direct instantiations of Axes/Subplots are rare as one usually relies on add_subplot/add_axes/subplots.

@anntzer
Copy link
Contributor

anntzer commented Nov 12, 2020

AxesSubplot is going away; this started in #18564. While this will still take a couple of releases to finish (because of backcompat-imposed waits), I think this issue can be closed as it will basically fix itself once the deprecations in #18564 expire. Feel free to reopen if you disagree.

@anntzer anntzer closed this as completed Nov 12, 2020
@raamana
Copy link
Contributor

raamana commented Mar 21, 2022

just wanted to say I agree with the sentiment of pain with AxesSubplot expressed here, and wanted to bring a relevant question of mine over at MPL discord to your attention: https://discourse.matplotlib.org/t/comparing-axessubplot-with-axes/22676?u=raamana

@anntzer
Copy link
Contributor

anntzer commented Mar 21, 2022

AxesSubplot is going away; the deprecation machinery is already in (cf mpl.axes._subplots), now someone (mostly) just needs to pull the thread and remove everything...

@raamana
Copy link
Contributor

raamana commented Mar 21, 2022

thanks @anntzer, I noticed that. I guess you are suggesting not to deal with it all, which would mean me not using plt.subplots() (or any derivatives of pyplot really to be future-proof) that would return an AxesSubplot. What do you recommend as a clear and robust alternative to

fig, axes = plt.subplots(n_rows, n_cols, figsize)

that doesn't depend on any subplot mechanism, and returns the "unadulterated" native Axes?

I am assuming GridSpec only deals with geometry (and not create axes), and the new mosaic compositional mechanism still returns AxesSubplots:

from matplotlib import pyplot as plt
fig = plt.figure(constrained_layout=True)
ax_dict = fig.subplot_mosaic(
    [
        ["bar", "plot"],
        ["hist", "image"],
    ],
)

ax_dict
Out[22]: 
{'bar': <AxesSubplot:label='bar'>,
 'plot': <AxesSubplot:label='plot'>,
 'hist': <AxesSubplot:label='hist'>,
 'image': <AxesSubplot:label='image'>}

i have created grids of axes before e.g. in the mrivis library that does not depend on any subplot mechanism purely using fig.add_axes() one by one, but I am hoping MPL team may have a more native or better solution, that'll likely to remain the codebase for a longtime to come (so I dont have to worry about deprecations and future changes)

Thanks you for help.

@anntzer
Copy link
Contributor

anntzer commented Mar 21, 2022

@kate-jeffreys
Copy link

FWIW: TIL what AxesSubplot is by reading this issue. Thank you @aathan!

@davidgilbertson
Copy link
Contributor

For anyone who found this and is not yet on v3.7, know that AxesSubplot is now gone (although true to form, isn't actually mentioned anywhere in release notes!)

@jklymak
Copy link
Member

jklymak commented Feb 24, 2023

true to form

Ouch - PRs gratefully accepted, even for post-facto improvements to the release notes - sometimes things get overlooked with the finite developer time at our disposal https://github.com/matplotlib/matplotlib/blob/main/doc/users/prev_whats_new/whats_new_3.7.0.rst

@tacaswell
Copy link
Member

Please see discussion at #25228 (comment) as to why we did not consider this an API change.

@davidgilbertson
Copy link
Contributor

Sorry @jklymak I didn't mean it in an ouchy way at all, I actually thought it was quite funny that the elusive AxesSubplot would leave the API without a trace. Certainly not meant as a criticism of anyone.

@tacaswell
Copy link
Member

This is a good example of why text-only communication is hard!

Reading your message with a joking tone of voice is funny (that class is a ghost and disappeared like one) vs and angry one (the good for nothing devs once again changed things) induce very different responses.

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

No branches or pull requests

9 participants