Take this piece of code which generates a random integer within a range, assigns it an RGBA colour, and then plots it as a patch.
import numpy
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as mcolors
import matplotlib.colorbar as cbar
from matplotlib import cm
import random
class MidpointNormalize(mpl.colors.Normalize):
def __init__(self,vmin=None,vmax=None,midpoint=None,clip=False):
self.midpoint=midpoint
mpl.colors.Normalize.__init__(self,vmin,vmax,clip)
def __call__(self,value,clip=None):
x,y=[self.vmin,self.midpoint,self.vmax],[0,0.5,1]
return numpy.ma.masked_array(numpy.interp(value,x,y),numpy.isnan(value))
colors=plt.cm.RdBu(numpy.linspace(0,1,256))
colormap=mcolors.LinearSegmentedColormap.from_list('colormap',colors)
normalisecolors=MidpointNormalize(vmin=-50,midpoint=0,vmax=100)
scalecolors=cm.ScalarMappable(norm=normalisecolors,cmap=colormap)
fig,ax=plt.subplots(figsize=(8,8))
ax.set_xlim(0,100)
ax.set_ylim(0,100)
for x in range(0,100):
for y in range(0,100):
val=random.randint(-50,100)
rgbacolor=scalecolors.to_rgba(val)
ax.add_patch(patches.Polygon([(x,y),(x,y+1),(x+1,y+1),(x+1,y)],fill=True,facecolor=rgbacolor))
cax,_=cbar.make_axes(ax,orientation='horizontal',aspect=50,pad=0.12)
cb=cbar.ColorbarBase(cax,cmap=colormap,norm=normalisecolors,orientation='horizontal')
I want to modify the colour bar so that the colour white is represented by the value 0 (which is what I thought I'd done on line 20), but this hasn't worked:
I'd be grateful if anyone could suggest where I've gone wrong.
I'd kindly ask contributors to refrain from suggesting alternative ways of plotting this data; the actual data I am plotting requires hundreds of lines of code to read and process output files from a numerical model. I've stripped away all of this code and replaced it with a random number generator to enable users to run the code themselves to help me.
I have resolved this by using TwoSlopeNorm instead:
normalisecolors=TwoSlopeNorm(vmin=-50,vcenter=0,vmax=100)
and by adding a key line of code:
cb.ax.set_xscale('linear')
The MidpointNormalize elements of the code are therefore redundant and have been removed.
The new code generates a plot and colour bar identical to previous versions of matplotlib.
import numpy
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.colors as mcolors
from matplotlib.colors import TwoSlopeNorm
import matplotlib.colorbar as cbar
from matplotlib import cm
import random
colors=plt.cm.RdBu(numpy.linspace(0,1,256))
colormap=mcolors.LinearSegmentedColormap.from_list('colormap',colors)
normalisecolors=TwoSlopeNorm(vmin=-50,vcenter=0,vmax=100)
scalecolors=cm.ScalarMappable(norm=normalisecolors,cmap=colormap)
fig,ax=plt.subplots(figsize=(8,8))
ax.set_xlim(0,100)
ax.set_ylim(0,100)
for x in range(0,100):
for y in range(0,100):
val=random.randint(-50,100)
rgbacolor=scalecolors.to_rgba(val) # Calculate RGBA color code for value
ax.add_patch(patches.Polygon([(x,y),(x,y+1),(x+1,y+1),(x+1,y)],fill=True,facecolor=rgbacolor))
cax,_=cbar.make_axes(ax,orientation='horizontal',aspect=50,pad=0.12)
cb=cbar.ColorbarBase(cax,cmap=colormap,norm=normalisecolors,orientation='horizontal')
cb.ax.set_xscale('linear')