It looks like I am able to answer my own question... But it's not easy to find!
It appears
pcolormesh accepts a
BoundaryNorm keyword that generates "...a colormap index based on discrete intervals." In my original question I had 7 classes + 1 class for values that are larger than 100, so I can create a block plot like this:
import matplotlib.colors as colorsplot_reldif = iplt.pcolormesh(reldif_field,cmap=brewer_cmap,norm = colors.BoundaryNorm(mylevels,ncolors=8,clip=False))Like this the color scheme of my plot will only use the first 8 colours of my selected colour map, though, while I had selected a
Brewer palette (brewer_RdYlBu_11) that nicely goes from dark red to light colours in the middle to dark blue at the end. How can I make sure that my middle class (from -10 to 10) is plotted with the light colour in the middle of my palette? The Brewer palette has 11 colours, and setting
ncolors=10 or
ncolors=11 sort of works, but means the 11 colours of the palette are distributed over the 7+1 classes, giving not quite the result you would expect (when setting
ncolors=11 the class >100 also has the same colour has the last "normal" class, 50-100).
So can we subset the Brewer palette and use only those colours that we want? Turns out you can:
brewer_cmap = mpl_cm.get_cmap('brewer_RdYlBu_11')# subset the color map for the levels (classes) defined abovemy_cmap = brewer_cmap([1,2,3,5,7,8,9,10]) # indices of colors in brewer_cmap to usenew_cmap = colors.ListedColormap(my_cmap,"my_colormap") # creates a new color map with 8 coloursNow we need to call
BoundaryNorm with
ncolors=7 to use the first 7 colours in my new colour map for my 7 classes; the 8th colour is then used for values that are larger than the maximum class limit (>100). I think that values smaller than the minimum value (< -100 in my case) would always be plotted with the same colour as the first "proper" class (-100 to -50), which might be a limitation, but this does not happen in my specific case.
plot_reldif = iplt.pcolormesh(reldif_field,cmap=new_cmap,norm = colors.BoundaryNorm(mylevels,ncolors=len(mylevels)-1,clip=False))Finally we can plot the colour bar so that it extends beyond the maximum value:
colorbar = plt.colorbar(plot_reldif, colorbar_axes, orientation='horizontal',extend='max')... and we get something that looks like what I wanted.
If you think this looks relatively straightforward, a necessary condition is that you first spend hours (if not days) trawling through pages and pages and
pages of highly technical, but not very practical matplotlib and pylab documentation before you get any hints of how this kind of (what seems to me) fairly standard operations can be done.
HTH
Rutger