Use of extend in a pcolormesh plot with discrete c

2019-05-15 16:00发布

I'm trying to create a pcolormesh plot with a discrete colorbar. The output should fulfil these criteria:

  1. The first level should be white
  2. The data should be cut off at some level
  3. Data above the cut off should have a separate colour (namely the last colour of the colormap)

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)
)

enter image description here

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') 

1条回答
欢心
2楼-- · 2019-05-15 16:48

Indeed, if you set cmap.set_over("blue") you would see blue as the color of the values exceeding the maximum value.

enter image description here

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()

enter image description here

查看更多
登录 后发表回答