Center diverging colors to zero

Viewed 1237

I would like to plot with diverging colors centered at 0 (red for postive values and blue for negative). I tried normalizing the data with 0 as midpoint as suggested here

import matplotlib.colors as colors
import numpy as np

class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))

minzz = -4
maxzz = 1.5 

plt.contourf(x, y, z, cmap='RdBu_r',  norm=MidpointNormalize(midpoint=0), vmin=minzz, vmax=maxzz)
plt.xticks()
plt.colorbar()

and I get this

enter image description here

It does not really follow the -4 to 1.5 range and how do I also increase the intervals especially to highlight more positive values.

1 Answers

The following drawing was done using matplotlib.colors.DivergingNorm and passing explicitly a list of levels to plt.contourf, because otherwise the contouring algorithm chooses intervals of the same length both for negative and positive values (and that is not what one usually wants).

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import DivergingNorm

t = np.linspace(-3.1, 3.1, 63)
x, y = np.meshgrid(t, t)
r = np.sqrt(x**2+y**2)
z = -2*np.cos(2*r)-1 # max = 1, min = -3

fig, ax = plt.subplots()
ax.set_aspect(1)
img = ax.contourf(x, y, z, levels=[-3,-2.5,-2,-1.5,-1,-0.5,0,0.25,0.5, 0.75, 1],
                  cmap='RdBu_r',
                  norm=DivergingNorm(0))
plt.colorbar(img)
plt.show()

center

Related