proplot-dev / proplot

🎨 A succinct matplotlib wrapper for making beautiful, publication-quality graphics
https://proplot.readthedocs.io
MIT License
1.1k stars 100 forks source link

Compability with DataArray.plot() #314

Closed zxdawn closed 2 years ago

zxdawn commented 2 years ago

Description

The colorbar location can be changed in DataArray.plot().

Steps to reproduce

import xarray as xr
import proplot as pplt

airtemps = xr.tutorial.open_dataset('air_temperature')

air = airtemps.air - 273.15
air2d = air.isel(time=500)

fig, axs = pplt.subplots()
air2d.plot(ax=axs, cbar_kwargs=dict(orientation='horizontal', label='Temperature ($^{\circ}$C)'))

Error:

~/miniconda3/lib/python3.9/site-packages/matplotlib/axis.py in set_label_position(self, position)
   2065         position : {'top', 'bottom'}
   2066         """
-> 2067         self.label.set_verticalalignment(_api.check_getitem({
   2068             'top': 'baseline', 'bottom': 'top',
   2069         }, position=position))

~/miniconda3/lib/python3.9/site-packages/matplotlib/_api/__init__.py in check_getitem(_mapping, **kwargs)
    186         return mapping[v]
    187     except KeyError:
--> 188         raise ValueError(
    189             "{!r} is not a valid value for {}; supported values are {}"
    190             .format(v, k, ', '.join(map(repr, mapping)))) from None

ValueError: 'right' is not a valid value for position; supported values are 'top', 'bottom'

If I set the loc in .plot():

air2d.plot(ax=axs, cbar_kwargs=dict(loc='bottom', label='Temperature ($^{\circ}$C)'))

It doesn't work. image

Expected behavior: [What you expected to happen]

Control the colorbar using orientation or 'loc'

Equivalent steps in matplotlib

import xarray as xr

airtemps = xr.tutorial.open_dataset('air_temperature')

air = airtemps.air - 273.15
air2d = air.isel(time=500)
air2d.plot(cbar_kwargs=dict(orientation='horizontal',
           pad=0.15, shrink=1, label='Temperature ($^{\circ}$C)'))

image

Proplot version

Paste the results of import matplotlib; print(matplotlib.__version__); import proplot; print(proplot.version)here.

3.5.0
0.9.5.post105
zxdawn commented 2 years ago

BTW, extend='max' also doesn't work.

lukelbd commented 2 years ago

The orientation issue was very simple -- looks like matplotlib/xarray manually manually select an appropriate "side" if the orientation is passed but not the loc. Previously, proplot did not do this, but now it does.

The extend issue was very subtle. Here's the rundown (mainly for future me):

I've fixed this by permitting overwriting those "hidden" parameters by passing arguments to colorbar. This is important anyway -- passing ax.colorbar(..., locator=locs_new) after ax.pcolor(..., colorbar_kw={'locator': locs_old}) before this fix would fail to apply locs_new, which is kind of weird behavior.

Here's an example (before this fix, there were no triangle extensions). Note there's a caveat: because xarray internally strips extend from the ax.pcolormesh() call, proplot is unable to apply the correct DiscreteNorm that assigns unique colors to out-of-bounds data. But I don't think there is any way around this.

import xarray as xr
import proplot as pplt
airtemps = xr.tutorial.open_dataset('air_temperature')
air = airtemps.air - 273.15
air2d = air.isel(time=500)
fig, axs = pplt.subplots()
air2d.plot(ax=axs, extend='both', cbar_kwargs=dict(orientation='horizontal', label='Temperature ($^{\circ}$C)'))

fix