0

I have a function whose image goes from 0 to infinity, for example $f(x,y)=x^2 + y^2$. I would like to use a diverging colormap to highlight the region where the function equals 1 with a flexible colorbar. The colorbar should go from 0 to whatever vmax, white ("center") at 1, and the interval between colors should be proportional to numbers.

When plotting it with no constrains, the white region placement depends on the vmin-vmax range. I would like to have it fixed at 1, vmin cannot be less than 0. I partially solve the problem using Matplotloib's TwtoSlopeNorm setting the center to 1, whatever the vmin-vmax range is. But this causes the lower part of the colorbar to take as much space as the upper part, which is not correct. The colorbar is stretched. Trying spacing="proportional" does nothing. How can I have the colorbar use as much space for the 0-1 range as it does for the other unit intervals, while fixing the white to 1?

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cbook as cbook
from matplotlib import cm

delta = 0.01
x = np.arange(0, 2.001, delta)
y = np.arange(0.0, 2.001, delta)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2

cmap = cm.seismic

fig = plt.figure(figsize=(16,5))

ax = fig.add_subplot(131)
plt.pcolormesh(Z, cmap=cmap, vmin=0, vmax=9)
plt.title('White position depends on vmin-vmax range')
plt.colorbar(extend='max')

ax = fig.add_subplot(132)
plt.pcolormesh(Z, cmap=cmap, norm=colors.TwoSlopeNorm(vmin=0, vmax=9, vcenter=1))
plt.title('White position is fixed, but colorbar is streched')
plt.colorbar(extend='max')

ax = fig.add_subplot(133)
plt.pcolormesh(Z, cmap=cmap, norm=colors.TwoSlopeNorm(vmin=0, vmax=9, vcenter=1))
plt.title('spacing="proportional" does not work')
plt.colorbar(extend='max', spacing='proportional')

plt.show()

enter image description here

ouranos
  • 301
  • 4
  • 17
  • 1
    See comments in [TwoSlopeNorm in Matplotlib not working as expected](https://stackoverflow.com/questions/74595690/twoslopenorm-in-matplotlib-not-working-as-expected). This is a [closed github issue](https://github.com/matplotlib/matplotlib/issues/22197). `cb.ax.set_yscale('linear')` is suggested as a workaround. – JohanC Nov 29 '22 at 16:22
  • Thank you! It does the trick! Confusing that `spacing='proportional'` also sounds logical. – ouranos Nov 29 '22 at 16:32

1 Answers1

0

Full answer is here

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

delta = 0.01
x = np.arange(0, 4.001, delta)
y = np.arange(0.0, 4.001, delta)
X, Y = np.meshgrid(x, y)
Z = X**2 + Y**2

fig = plt.figure(figsize=(6,3))
ax = fig.add_subplot(121)
m1 = plt.contourf(Z, cmap=cm.seismic, levels=np.arange(0,33,1), norm=colors.TwoSlopeNorm(vmin=0, vmax=32, vcenter=1), extend='max')
plt.colorbar(m1)

ax = fig.add_subplot(122)
m1 = plt.pcolormesh(Z, cmap=cm.seismic, norm=colors.TwoSlopeNorm(vmin=0, vmax=32, vcenter=1))
cb = plt.colorbar(m1, extend='max', spacing='proportional')
cb.ax.set_yscale('linear')

plt.tight_layout()
plt.show()

enter image description here

ouranos
  • 301
  • 4
  • 17