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

Skip to content

[Bug]: plt.subplots() cannot take the sharez or shareview keyword for 3D plots #25822

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
scottshambaugh opened this issue May 5, 2023 · 4 comments

Comments

@scottshambaugh
Copy link
Contributor

scottshambaugh commented May 5, 2023

Bug summary

When initializing 3D plots using the plt.subplots interface, the sharez keyword is not implemented. This also applies to the shareview keyword introduced in #25821.

Would like to get some other opinions on if 3d-specific keywords should go into the Figure / subplots method.

Code for reproduction

import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}, sharex=True)  # works
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}, sharey=True)  # works
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}, sharez=True)  # fails
fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}, shareview=True)  # fails

Actual outcome

Exception has occurred: AttributeError
Figure.set() got an unexpected keyword argument 'sharez'
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/artist.py", line 1192, in _update_props
    raise AttributeError(
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/artist.py", line 1218, in _internal_update
    return self._update_props(
           ^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/artist.py", line 1226, in set
    return self._internal_update(cbook.normalize_kwargs(kwargs, self))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/artist.py", line 147, in <lambda>
    cls.set = lambda self, **kwargs: Artist.set(self, **kwargs)
                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/figure.py", line 201, in __init__
    self.set(**kwargs)
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/figure.py", line 2459, in __init__
    super().__init__(**kwargs)
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/backend_bases.py", line 3387, in new_figure_manager
    fig = fig_cls(*args, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/pyplot.py", line 429, in new_figure_manager
    return _get_backend_mod().new_figure_manager(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/pyplot.py", line 898, in figure
    manager = new_figure_manager(
              ^^^^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/lib/matplotlib/pyplot.py", line 1562, in subplots
    fig = figure(**fig_kw)
          ^^^^^^^^^^^^^^^^
  File "/mnt/c/Users/Scott/Documents/Documents/Coding/matplotlib/test_3d_plot.py", line 18, in <module>
    fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}, sharez=True)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: Figure.set() got an unexpected keyword argument 'sharez'

Expected outcome

Plot should generate and share z axes.

Matplotlib Version

latest main

Installation

None

@tacaswell
Copy link
Member

The issue is in plt.subplots we take in keyword arguements that need to be routed to two places: to figure(**kwargs) and to fig.subplots(..., **kwargs). The way that this is currently handled is that the one that should go to subplots are explicitly in the signature and anything else extra is routed to figure.

There is no good solution here (but I can think of a bunch of bad ones!):

  • add the axes3D kwargs to the signature (bad because they only do anything sometimes!)
  • add kwargs_for_fig:dict and kwargs_for_subplots:dict keywords that let you force where things go (bad because it is awkward to use)
  • add logic inside of subplots to pull out the axes3D keywords and just make it work (bad because it is a bit magical, cuts against the ability to make things statically typed)
  • add plt.subplots3D with the special cases (bad because it expands the pyplot API)

@scottshambaugh
Copy link
Contributor Author

scottshambaugh commented May 5, 2023

I tend to think your first option is the least bad - you can check and ignore those kwargs if your axes isn't 3d - but yeah would love to hear others' preferences!

That option would also be an argument for bringing other keywords such as projection='3d' into the top-level call, though unlike projection, sharez/shareview cannot be broadcast as a boolean.

@greglucas
Copy link
Contributor

greglucas commented May 5, 2023

There is already a subplot_kw which we use in Cartopy to set up projection=GeoProjection.
https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots.html

So I'm confused why those couldn't be added to that list within add_subplot instead of separately.

@anntzer
Copy link
Contributor

anntzer commented May 5, 2023

subplot_kw won't work here as subplots(..., sharex=...) takes different inputs (True/False/"all"/"row"/"col") than add_subplot(..., sharex=...), so here it's not really a subplot for add_subplot() (*). So the sharex/y/z kwarg to subplots is really a different kwarg than the kwarg to add_subplot.

(*) You could extend the semantics of add_subplot(..., sharex=...) to support True/False/"all"/"row"/"col" by saying that when one of these values is encountered, check whether there's a preceding axes on the figure that shares the same gridspec (and if necessary the same row/column), and if so, share with that axes and call label_outer() on that shared axes... This way everything is self-contained in the single-subplot constructor, but it does feel like API leakage.

@scottshambaugh scottshambaugh changed the title [Bug]: plt.subplots() cannot take the sharez keyword for 3D plots [Bug]: plt.subplots() cannot take the sharez or shareview keyword for 3D plots Jul 3, 2023
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

4 participants