Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting colorbar to show values outside of data range in matplotlib

I am trying to create a figure in which the colorbar will extend beyond the data range (go higher than the max value of data). The ultimate purpose is that I need to plot a series of images (as time progresses) of model output, and each hour is stored in a separate file. I would like the colorbar for all the figures to be the same, so that they can be joined into an animation.

Here is a sample script:

import matplotlib.pyplot as plt
import numpy as np

x = np.arange(0, 360, 1.5)
y = np.arange(-90, 90, 1.5)
lon, lat = np.meshgrid(x, y)
noise = np.random.random(lon.shape) # values in range [0, 1)

fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise)
plt.colorbar()

This produces the following figure:

enter image description here

I've been trying to set the limits of the colorbar to values outside the data range (for example, from -1. to 2.) using two methods that I've found online:

Setting vmin=-1 and vmax=2 inside the plotting line:

fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise, vmin=-1., vmax=2.)
plt.colorbar()

This seems to only change the colors displayed, so that the first color in the colormap would correspond to -1 and the last one to 2, but it does not extend the colorbar to show those values (left figure in link below).

The other one was to try and enforce ticks in the colorbar to extend to that range:

fig = plt.figure()
ax = fig.add_subplot(111)
plt.hold(True)
plt.contourf(lon, lat, noise)
plt.colorbar(ticks=np.arange(-1,2.1, .2))

This results in tick position as defined, but only for the range in which there's data, i.e., the colorbar still doesn't extend from -1 to 2 (middle figure in link below).

Does anyone know how I would get it to do what I want? Something like the right figure at this link: http://orca.rsmas.miami.edu/~ajdas1/SOF/n.html

like image 768
asav Avatar asked Jun 02 '15 22:06

asav


People also ask

How do you normalize a Colorbar in Python?

will map the data in Z linearly from -1 to +1, so Z=0 will give a color at the center of the colormap RdBu_r (white in this case). Matplotlib does this mapping in two steps, with a normalization from the input data to [0, 1] occurring first, and then mapping onto the indices in the colormap.

How do I change the color bar in Matplotlib?

You can change the color of bars in a barplot using color argument. RGB is a way of making colors. You have to to provide an amount of red, green, blue, and the transparency value to the color argument and it returns a color.


2 Answers

For most 2D plotting function (such as imshow, pcolor, etc.) setting vmin and vmax does the job. However, contourf (and also contour) take the levels at which you ask it to draw the contours into account when mapping the colors:

If you don't specify the levels argument, then the function automatically generates 10 equally spaced levels from the minimal to maximal value of your data. So to achieve what you want (consistency over varying input data) you have to specify the levels explicitly:

import matplotlib.pyplot as plt
import numpy as np

# generate data
x = np.arange(0, 360, 1.5)
y = np.arange(-90, 90, 1.5)
lon, lat = np.meshgrid(x, y)
noise = np.random.random(lon.shape) 

# specify levels from vmim to vmax
levels = np.arange(-1, 2.1, 0.2)

# plot
fig = plt.figure()
ax = fig.add_subplot(111)
plt.contourf(lon, lat, noise, levels=levels)
plt.colorbar(ticks=levels)
plt.show()

Result:

enter image description here

like image 90
hitzg Avatar answered Oct 22 '22 11:10

hitzg


Colorbar limits are not respecting set vmin/vmax in plt.contourf. How can I more explicitly set the colorbar limits? gives a good example to solve this problem.

These can be done if the colorbars of a series of images share a same ScalarMappable instance, but not the corresponding ContourSet instance which is created by each plt.contourf(). More details in https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.colorbar

We can solve the problem like this:

import matplotlib.pyplot as plt
import matplotlib.cm as cm

fig = plt.figure()
ax = fig.add_subplot(111)
m0=ax.contourf(lon, lat, noise, vmin=-1., vmax=2.)
m = plt.cm.ScalarMappable(cmap=cm.coolwarm)
m.set_clim(-1, 2)
fig.colorbar(m,ax=ax)

Instead of using m0 (QuadContourSet instance created by contourf), we use m (ScalarMappable instance) in fig.colorbar(), because colorbar is used to describe the mappable parameter. https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.figure.Figure.html#matplotlib.figure.Figure.colorbar

clim in m.set_clim should be matched to vmin/vmax in contourf.

like image 33
Lin Avatar answered Oct 22 '22 11:10

Lin