-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Surface plots #5101
Surface plots #5101
Conversation
Use broadcast_like if either `x` or `y` inputs are 2d to ensure that both have dimensions in the same order as the DataArray being plotted. Convert to numpy arrays after possibly using broadcast_like. Simplifies code, and fixes pydata#5097 (bug when dimensions have the same size).
Wraps mpl_toolkits.mplot3d.axes3d.plot_surface
Does not work because the datetime.timedelta does not work with surface's 'shading'.
Seems like the way I've implemented surface plots requires a slightly newer version than the oldest supported matplotlib to use the |
Hello @johnomotani! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found: There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻 Comment last updated at 2021-05-03 12:06:43 UTC |
Too complicated to check matplotlib version is high enough just for surface plots.
Tests pass! Think this is ready for review now @pydata/xarray |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, thanks for your patience! I left some comments but I think the implementation looks good overall. I suggest we merge #5099 first and then get this one under way. I would prefer to have the fix and the new feature in two different PRs.
xarray/plot/plot.py
Outdated
del LooseVersion | ||
del mpl |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
del LooseVersion | |
del mpl |
Not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these were necessary, because of this a bit later
Lines 672 to 673 in 648e13b
if row or col: | |
allargs = locals().copy() |
If
LooseVersion
and mpl
are not deleted, they are in the local environment, and end up in allargs
, but are not valid keyword arguments. Moving the LooseVersion
import to the top of the file fixes that, but I guess we don't want to do the same with mpl
?
xarray/tests/test_plot.py
Outdated
pass | ||
|
||
def test_seaborn_palette_as_cmap(self): | ||
# seaborn does not work with mpl_toolkits.mplot3d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? I would not expect an interaction here? Or is it because you don't actually call the code determining the cmap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the error. If I don't modify the test, I get
================================================================================================================== FAILURES ==================================================================================================================
__________________________________________________________________________________________________ TestSurface.test_seaborn_palette_as_cmap __________________________________________________________________________________________________
self = <xarray.tests.test_plot.TestSurface object at 0x7f5043826220>
@requires_seaborn
def test_seaborn_palette_as_cmap(self):
> cmap_name = self.plotmethod(levels=2, cmap="husl").get_cmap().name
.../xarray/xarray/tests/test_plot.py:1232:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.../xarray/xarray/plot/plot.py:873: in plotmethod
return newplotfunc(**allargs)
.../xarray/xarray/plot/plot.py:775: in newplotfunc
primitive = plotfunc(
.../xarray/xarray/plot/plot.py:1035: in surface
primitive = ax.plot_surface(x, y, z, **kwargs)
.../python3.8/site-packages/matplotlib/_api/deprecation.py:431: in wrapper
return func(*inner_args, **inner_kwargs)
.../python3.8/site-packages/mpl_toolkits/mplot3d/axes3d.py:1742: in plot_surface
polyc = art3d.Poly3DCollection(polys, *args, **kwargs)
.../python3.8/site-packages/mpl_toolkits/mplot3d/art3d.py:715: in __init__
super().__init__(verts, *args, **kwargs)
.../python3.8/site-packages/matplotlib/collections.py:1206: in __init__
super().__init__(**kwargs)
.../python3.8/site-packages/matplotlib/_api/deprecation.py:431: in wrapper
return func(*inner_args, **inner_kwargs)
.../python3.8/site-packages/matplotlib/collections.py:164: in __init__
cm.ScalarMappable.__init__(self, norm, cmap)
.../python3.8/site-packages/matplotlib/cm.py:263: in __init__
self.set_cmap(cmap) # The Colormap instance of this ScalarMappable.
.../python3.8/site-packages/matplotlib/cm.py:432: in set_cmap
cmap = get_cmap(cmap)
.../python3.8/site-packages/matplotlib/cm.py:190: in get_cmap
_api.check_in_list(sorted(_cmap_registry), name=name)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_values = ['Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG', 'BrBG_r', ...], _print_supported_values = True, kwargs = {'name': 'husl'}, values = ['Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG', 'BrBG_r', ...], key = 'name', val = 'husl'
def check_in_list(_values, *, _print_supported_values=True, **kwargs):
"""
For each *key, value* pair in *kwargs*, check that *value* is in *_values*.
Parameters
----------
_values : iterable
Sequence of values to check on.
_print_supported_values : bool, default: True
Whether to print *_values* when raising ValueError.
**kwargs : dict
*key, value* pairs as keyword arguments to find in *_values*.
Raises
------
ValueError
If any *value* in *kwargs* is not found in *_values*.
Examples
--------
>>> _api.check_in_list(["foo", "bar"], arg=arg, other_arg=other_arg)
"""
values = _values
for key, val in kwargs.items():
if val not in values:
if _print_supported_values:
> raise ValueError(
f"{val!r} is not a valid value for {key}; "
f"supported values are {', '.join(map(repr, values))}")
E ValueError: 'husl' is not a valid value for name; supported values are 'Accent', 'Accent_r', 'Blues', 'Blues_r', 'BrBG', 'BrBG_r', 'BuGn', 'BuGn_r', 'BuPu', 'BuPu_r', 'CMRmap', 'CMRmap_r', 'Dark2', 'Dark2_r', 'GnBu', 'GnBu_r', 'Greens', 'Greens_r', 'Greys', 'Greys_r', 'OrRd', 'OrRd_r', 'Oranges', 'Oranges_r', 'PRGn', 'PRGn_r', 'Paired', 'Paired_r', 'Pastel1', 'Pastel1_r', 'Pastel2', 'Pastel2_r', 'PiYG', 'PiYG_r', 'PuBu', 'PuBuGn', 'PuBuGn_r', 'PuBu_r', 'PuOr', 'PuOr_r', 'PuRd', 'PuRd_r', 'Purples', 'Purples_r', 'RdBu', 'RdBu_r', 'RdGy', 'RdGy_r', 'RdPu', 'RdPu_r', 'RdYlBu', 'RdYlBu_r', 'RdYlGn', 'RdYlGn_r', 'Reds', 'Reds_r', 'Set1', 'Set1_r', 'Set2', 'Set2_r', 'Set3', 'Set3_r', 'Spectral', 'Spectral_r', 'Wistia', 'Wistia_r', 'YlGn', 'YlGnBu', 'YlGnBu_r', 'YlGn_r', 'YlOrBr', 'YlOrBr_r', 'YlOrRd', 'YlOrRd_r', 'afmhot', 'afmhot_r', 'autumn', 'autumn_r', 'binary', 'binary_r', 'bone', 'bone_r', 'brg', 'brg_r', 'bwr', 'bwr_r', 'cividis', 'cividis_r', 'cool', 'cool_r', 'coolwarm', 'coolwarm_r', 'copper', 'copper_r', 'crest', 'crest_r', 'cubehelix', 'cubehelix_r', 'flag', 'flag_r', 'flare', 'flare_r', 'gist_earth', 'gist_earth_r', 'gist_gray', 'gist_gray_r', 'gist_heat', 'gist_heat_r', 'gist_ncar', 'gist_ncar_r', 'gist_rainbow', 'gist_rainbow_r', 'gist_stern', 'gist_stern_r', 'gist_yarg', 'gist_yarg_r', 'gnuplot', 'gnuplot2', 'gnuplot2_r', 'gnuplot_r', 'gray', 'gray_r', 'hot', 'hot_r', 'hsv', 'hsv_r', 'icefire', 'icefire_r', 'inferno', 'inferno_r', 'jet', 'jet_r', 'magma', 'magma_r', 'mako', 'mako_r', 'nipy_spectral', 'nipy_spectral_r', 'ocean', 'ocean_r', 'pink', 'pink_r', 'plasma', 'plasma_r', 'prism', 'prism_r', 'rainbow', 'rainbow_r', 'rocket', 'rocket_r', 'seismic', 'seismic_r', 'spring', 'spring_r', 'summer', 'summer_r', 'tab10', 'tab10_r', 'tab20', 'tab20_r', 'tab20b', 'tab20b_r', 'tab20c', 'tab20c_r', 'terrain', 'terrain_r', 'turbo', 'turbo_r', 'twilight', 'twilight_r', 'twilight_shifted', 'twilight_shifted_r', 'viridis', 'viridis_r', 'vlag', 'vlag_r', 'winter', 'winter_r'
.../python3.8/site-packages/matplotlib/_api/__init__.py:126: ValueError
Co-authored-by: Mathias Hauser <mathause@users.noreply.github.com>
I think you can remove all those matplotlib checks if you do something like this: subplot_kws = dict()
if ax is None:
# TODO: Importing Axes3D is not necessary in matplotlib >= 3.2.
# Remove when minimum requirement of matplotlib is 3.2:
from mpl_toolkits.mplot3d import Axes3D # type: ignore # noqa
subplot_kws.update(projection="3d") I got stuck with the same thing in #4909. Importing Axes3D was the the standard way of turning on the 3d plotting functionalities. Now with newer releases it's not necessary anymore, but it's a backwards friendly way of doing it for a while longer. |
Following suggestion from Illviljan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you merge master so we don't get the changes from #5099. I can then have another look.
Co-authored-by: Mathias Hauser <mathause@users.noreply.github.com>
Thanks @mathause - |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more minor comments. It's good to go from my side afterwards. Maybe @dcherian wants to have a look?
Co-authored-by: Mathias Hauser <mathause@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! I can merge in a few days unless someone else has comments. One thing that could be nice is an example in http://xarray.pydata.org/en/stable/plotting.html - up to you.
It seemed odd to add a |
Once again, thanks a lot for your contribution @johnomotani! (the test failure is unrelated) |
.plot.surface()
method that wrapsmatplotlib
'splot_surface()
method from the 3d toolkit.plot_surface()
's kwargs.I'm not sure if there's somewhere good to note the new
surface()
method in the docs to make it more discoverable? Maybe in one of the examples?pre-commit run --all-files
whats-new.rst
api.rst