I'm trying to create a pcolormesh plot with a discrete colorbar. The output should fulfil these criteria:
I am almost there but the 'extend' keyword does not behave the way I would expect it to (the colour in the "max-arrow" is the same as for the last level - see example). How do I set values above 'vmax' to a separate colour (i.e., the last colour of whatever colormap I use)
import numpy as np
import xarray as xr
import matplotlib as mpl
import matplotlib.pyplot as plt
ds = xr.Dataset(
coords={'lon': np.arange(-180, 180, 10),
'lat': np.arange(-85, 90, 10)},
data_vars={'data': (('lat', 'lon'), np.random.rand(18, 36))})
cmap = plt.cm.get_cmap('Reds')
cmap.set_under('w')
# cmap.set_over() # do something here?
levels = np.arange(0, .7, .1)
ds.data.plot.pcolormesh(
cmap=cmap,
vmin=levels[1],
# vmax=levels[-1],
extend='max',
norm = mpl.colors.BoundaryNorm(levels, ncolors=cmap.N, clip=False)
)
I'm using xarray but the behaviour is the same for plt.pcolormesh:
p = plt.pcolormesh(
np.arange(-180, 180, 10),
np.arange(-85, 90, 10),
np.random.rand(18, 36),
cmap=cmap,
vmin=levels[1],
# vmax=levels[-1],
norm = mpl.colors.BoundaryNorm(levels, ncolors=cmap.N, clip=False)
)
plt.colorbar(p, extend='max')
norm = normi; #mpl. colors. Normalize(vmin=-80, vmax=20); plt. axis([1, 1000, -400, 400]);
A colorbar needs a "mappable" ( matplotlib. cm. ScalarMappable ) object (typically, an image) which indicates the colormap and the norm to be used. In order to create a colorbar without an attached image, one can instead use a ScalarMappable with no associated data.
The colorbar() function in pyplot module of matplotlib adds a colorbar to a plot indicating the color scale. Syntax:matplotlib.pyplot.colorbar(mappable=None, cax=None, ax=None, **kwarg) Parameters: ax: This parameter is an optional parameter and it contains Axes or list of Axes.
Indeed, if you set cmap.set_over("blue")
you would see blue as the color of the values exceeding the maximum value.
However, if you want to use the last color of the colormap as that color for set_over
you need to make a colormap, which stops at the second last color. To that end, the following rationale may be used. If we aim at 6 different colors from a colormap plus the color for overshooting values, we take 7 colors from that colormap, replace the first with white color and use the first 6 colors as the colors for the boundary interval. The last colors is then used as the color for overshooting values.
import numpy as np; np.random.seed(1)
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.colors
lon,lat = np.meshgrid(np.arange(-180, 180, 10), np.arange(-85, 90, 10))
data = np.sort(np.random.rand(18, 36),axis=1)
# create 7 boundaries between 0 and 0.6, to have 6 intervals
boundaries = np.arange(0, .7, .1)
# create list of 7(!) colors from colormap
cmap_reds = plt.cm.get_cmap('Reds',len(boundaries))
colors = list(cmap_reds(np.arange(len(boundaries))))
#replace first color with white
colors[0] = "white"
cmap = matplotlib.colors.ListedColormap(colors[:-1], "")
# set over-color to last color of list
cmap.set_over(colors[-1])
cm = plt.pcolormesh(lon,lat,data,
cmap=cmap,
norm = mpl.colors.BoundaryNorm(boundaries, ncolors=len(boundaries)-1, clip=False)
)
plt.colorbar(cm, extend="max")
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With