Description
What happened?
If cmap.set_over
is specified, the array color mapping and the colorbar behave badly if the array does not contain values above the norm.vmax
.
Let's take an array and apply a colormap and norm (see code below)
Now, if in the array I change the array values larger than the norm.vmax
(the 2 bottom right pixels) with other values inside the norm:
What did you expect to happen?
The colorbar should not "shift" and the array should be colormapped correctly
This is possibily related also to #4061
Minimal Complete Verifiable Example
import matplotlib.colors
import numpy as np
import xarray as xr
import matplotlib as mpl
import matplotlib.pyplot as plt
# Define DataArray
arr = np.array([[0, 10, 15, 20],
[ np.nan, 40, 50, 100],
[150, 158, 160, 161],
])
lon = np.arange(arr.shape[1])
lat = np.arange(arr.shape[0])[::-1]
lons, lats = np.meshgrid(lon, lat)
da = xr.DataArray(arr,
dims=["y", "x"],
coords={"lon": (("y","x"), lons),
"lat": (("y","x"), lats),
}
)
da
# Define colormap
color_list = ["#9c7e94", "#640064", "#009696", "#C8FF00", "#FF7D00"]
levels = [0.05, 1, 10, 20, 150, 160]
cmap = mpl.colors.LinearSegmentedColormap.from_list("cmap", color_list, len(levels) - 1)
norm = mpl.colors.BoundaryNorm(levels, cmap.N)
cmap.set_over("darkred") # color for above 160
cmap.set_under("none") # color for below 0.05
cmap.set_bad("gray", 0.2) # color for nan
# Define colorbar settings
ticks = levels
cbar_kwargs = {
'extend': "max",
}
# Correct plot
p = da.plot.pcolormesh(x="lon", y="lat", cmap=cmap, norm=norm, cbar_kwargs=cbar_kwargs)
plt.show()
# Remove values larger than the norm.vmax level
da1 = da.copy()
da1.data[da1.data>=norm.vmax] = norm.vmax - 1 # could be replaced with any value inside the norm
# With matplotlib.pcolormesh [OK]
p = plt.pcolormesh(da1["lon"].data,
da1["lat"],
da1.data,
cmap=cmap, norm=norm)
plt.colorbar(p, **cbar_kwargs)
plt.show()
# With matplotlib.imshow [OK]
p = plt.imshow(da1.data,
cmap=cmap, norm=norm)
plt.colorbar(p, **cbar_kwargs)
plt.show()
# With xarray.pcolormesh [BUG]
# --> The colorbar shift !!!
da1.plot.pcolormesh(x="lon", y="lat", cmap=cmap, norm=norm, cbar_kwargs=cbar_kwargs)
plt.show()
# With xarray.imshow [BUG]
# --> The colorbar shift !!!
da1.plot.imshow(cmap=cmap, norm=norm, cbar_kwargs=cbar_kwargs, origin="upper")
MVCE confirmation
- Minimal example — the example is as focused as reasonably possible to demonstrate the underlying issue in xarray.
- Complete example — the example is self-contained, including all data and the text of any traceback.
- Verifiable example — the example copy & pastes into an IPython prompt or Binder notebook, returning the result.
- New issue — a search of GitHub Issues suggests this is not a duplicate.
Relevant log output
No response
Anything else we need to know?
No response
Environment
INSTALLED VERSIONS
commit: None
python: 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:56:21)
[GCC 10.3.0]
python-bits: 64
OS: Linux
OS-release: 5.4.0-124-generic
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: ('en_US', 'UTF-8')
libhdf5: 1.12.1
libnetcdf: 4.8.1
xarray: 2022.6.0
pandas: 1.4.3
numpy: 1.22.4
scipy: 1.9.0
netCDF4: 1.6.0
pydap: None
h5netcdf: 1.0.2
h5py: 3.7.0
Nio: None
zarr: 2.12.0
cftime: 1.6.1
nc_time_axis: None
PseudoNetCDF: None
rasterio: 1.3.0
cfgrib: None
iris: None
bottleneck: 1.3.5
dask: 2022.7.1
distributed: 2022.7.1
matplotlib: 3.5.2
cartopy: 0.20.3
seaborn: 0.11.2
numbagg: None
fsspec: 2022.7.1
cupy: None
pint: 0.19.2
sparse: None
flox: None
numpy_groupies: None
setuptools: 63.3.0
pip: 22.2.2
conda: None
pytest: None
IPython: 7.33.0
sphinx: 5.1.1
/home/ghiggi/anaconda3/envs/gpm_geo/lib/python3.9/site-packages/_distutils_hack/init.py:33: UserWarning: Setuptools is replacing distutils.
warnings.warn("Setuptools is replacing distutils.")