Search code examples
pythonmatplotlibrangecolorbar

Same color bar range for different plots - Matplotlib


I'm struggling to keep the same color bar range through different plots.

For example, I have these visualizations:

enter image description here

enter image description here

Which are produced with this code:

def plot_contour(x_dim, y_dim, x_steps, y_steps, scalar_field, file_path):
    plt.figure()

    x, y = numpy.mgrid[-x_dim:x_dim/:x_steps*1j, -y_dim:y_dim:y_steps*1j] 
    cs = plt.contourf(x, y, scalar_field, zorder=1, extent=[-x_dim, x_dim, -y_dim, y_dim])
    plt.colorbar(cs)

    plt.savefig(file_path + '.png', dpi=Vc.dpi)
    plt.close()

I want to be able to compare both fields, so, I would like to use the same color mapping for both of them.

My first approach was to use the parameters v_min and v_max, using the min/max values of the data.

cs = plt.contourf(x, y, scalar_field, zorder=1, extent=[-x_dim, x_dim, -y_dim, y_dim], vmin=-1.00, vmax=1.05) # Manual setting to test

Then I got the same color mapping:

enter image description here enter image description here

But I also would like to have the same color bar range displayed in the plot. I tried to use

cb = plt.colorbar(cs)
cb.set_clim(vmin=-1.00, vmax=1.05)

With no success.

This complete example produces the same behavior:

import matplotlib
import numpy as numpy
import matplotlib.cm as cm
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt

matplotlib.rcParams['xtick.direction'] = 'out'
matplotlib.rcParams['ytick.direction'] = 'out'

delta = 0.025
x = numpy.arange(-3.0, 3.0, delta)
y = numpy.arange(-2.0, 2.0, delta)
X, Y = numpy.meshgrid(x, y)

Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
# difference of Gaussians

Za = 10.0 * (Z2 - Z1)
Zb = 5.0 * (Z2 - Z1)

def bounds(scalar_fields):
    """
    Get the bounds of a set of scalar_fields
    :param scalar_fields : the scalar field set
    :return: a set of normalized vector field components
    """
    max_bound = -numpy.inf
    min_bound = numpy.inf

    for scalar_field in scalar_fields:
        max_lim = numpy.max(scalar_field)
        min_lim = numpy.min(scalar_field)
        if max_lim > max_bound:
            max_bound = max_lim
        if min_lim < min_bound:
            min_bound = min_lim

    return min_bound, max_bound

def plot_contour(x_dim, y_dim, x_steps, y_steps, scalar_field, v_min, v_max, file_path):
    plt.figure()

    x, y = numpy.mgrid[-x_dim/2:x_dim/2:x_steps*1j, -y_dim/2:y_dim/2:y_steps*1j]

    cs = plt.contourf(x, y, scalar_field, zorder=1, extent=[-x_dim/2.0, x_dim/2.0, -y_dim/2.0, y_dim/2.0],
                      vmin=v_min, vmax=v_max)
    cb = plt.colorbar(cs)

    plt.savefig(file_path + '.png')
    plt.close()

v_min, v_max = bounds([Za, Zb])
x_dim = y_dim = 6

y_steps = x.shape[0]
x_steps = y.shape[0]    

plot_contour(x_dim, y_dim, x_steps, y_steps, Za, v_min, v_max, 'Za')
plot_contour(x_dim, y_dim, x_steps, y_steps, Zb, v_min, v_max, 'Zb') 

How could I do that?

Thank you in advance.


Solution

  • If you want the colors in the colorbars to correspond to the same values within two contour plots, then you need to not only control the colorbar, but also control the levels in the contour plot. That is, to compare the same levels between the plots, the plots should have the same contour levels. This is easy to do. Here's an example of that plot:

    enter image description here

    There are two ways: 1) calculate the levels ahead of time; 2) use the levels from one plot to set the levels in the other. I'll do the second, since from this it should be clear how to do the first (using, for example, levels = numpy.linspace(v_min, vmax, 10), though, to be clear, I'm not using this here, but am letting mpl calculate the levels).

    First, here I'm also using:

    Za = 10.0 * (Z2 - Z1)
    Zb = 6.0 * (Z2 - Z1)   # 6, rather than 5
    

    Then, to plot:

    def plot_contour(x_dim, y_dim, x_steps, y_steps, scalar_field, file_path, v_min, v_max, levels=None):
        x, y = numpy.mgrid[-x_dim/2:x_dim/2:x_steps*1j, -y_dim/2:y_dim/2:y_steps*1j]
        cs = plt.contourf(x, y, scalar_field, zorder=1, cmap=cm.jet, extent=[-x_dim/2.0, x_dim/2.0, -y_dim/2.0, y_dim/2.0], vmin=v_min, vmax=v_max, levels=levels)
        plt.colorbar(cs)
        return cs.levels
    
    v_min, v_max = bounds([Za, Zb])
    
    plt.figure()
    plt.subplot(121)
    levels = plot_contour(x_dim, y_dim, x_steps, y_steps, Za, 'Za', v_min, v_max)
    plt.subplot(122)
    plot_contour(x_dim, y_dim, x_steps, y_steps, Zb, 'Zb', v_min, v_max, levels=levels) 
    plt.show()