colormaps

This little notebook shows a couple of dataset (one synthetic and one real -- a map of souther Italy with topography and bathimetry) using different color palettes, just to reinforce the point that several scientists[*] have made: that we need to choose a correct colormap if we want to communicate truthfully the results and not artificially emphasize certain features simply as a consequence of using a "wrong" colormap (i.e. a perceptually non-uniform colormap).

references

In [7]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata

%matplotlib inline
# comment out the following if you're not on a Mac with HiDPI display
%config InlineBackend.figure_format = 'retina'

This javascript code enlarges the vertical size of the cell to display all the plots at once (with no scrollbar).

In [8]:
%%javascript
IPython.OutputArea.auto_scroll_threshold = 9999;

The following cell runs a little helper script to load new colormaps:

  1. jetsaw: sawtooth "jet" alternative by Matteo Niccoli
  2. landmark: a replica of the default colormap included in Landmark's Decision Space (similar to countless other variations commonly found in many seismic interpretation packages)
  3. all the Peter Kovesi maps -- I will just use two of them in this notebook, i.e. rainbow_bgyr_35-85_c73 and diverging-rainbow_bgymr_45-85_c67 which are better versions of the conventional rainbow map so often (ab)used.
In [9]:
%run aadm_colorpalette.py

The colormaps that I intend to test here belong to three main groups:

  • standard matplotlib colormaps (cubehelix, gist_earth,terrain,CMRmap, jet, gist_rainbow_r)
  • the new ones loaded in the above cellblock (jetsaw, landmark, rainbow_bgyr_35-85, diverging-rainbow_bgymr_45-85)
  • the new matplotlib 2.0 colormaps (magma, plasma, viridis, inferno)
In [10]:
cmaps=['cubehelix','gist_earth','terrain','CMRmap',\
       'jet', 'rainbow', 'gist_rainbow_r', \
       'jetsaw', 'landmark', 'rainbow_bgyr_35-85', 'diverging-rainbow_bgymr_45-85', \
       'magma', 'plasma', 'viridis', 'inferno']

This function is taken (and lightly modified) from the official matplotlib website, and it's a quick way to have a handy reference for these colormaps:

In [11]:
def plot_color_gradients(colormaps):
    gradient = np.linspace(0, 1, 256)
    gradient = np.vstack((gradient, gradient))
    nrows = len(colormaps)
    fig, axes = plt.subplots(nrows=nrows)
    fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99)
    for ax, name in zip(axes, colormaps):
        ax.imshow(gradient, aspect='auto', cmap=name)
        pos = list(ax.get_position().bounds)
        x_text = pos[0]
        y_text = pos[1] + pos[3]/2.
        fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10)
    for ax in axes:
        ax.set_axis_off()
In [12]:
plot_color_gradients(cmaps)

The problem with displaying colormaps in this way is that you don't get a feel for how they would really work, their subtleties etc. Plotting some 2D synthetic datasets certainly helps the evaluation of each colormap:

In [13]:
from matplotlib.mlab import bivariate_normal
# creating first dataset (a mountain and a trough)
N=100
X0, Y0 = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
Z0 = (bivariate_normal(X0,Y0,1.,1.,1.0,1.0))**2-0.4*(bivariate_normal(X0,Y0,1.0,1.0,-1.0,0.0))**2
Z0 = Z0/0.03

# creating second dataset (oblique stripes)
x = np.linspace(-np.pi, np.pi, 50)
y = np.linspace(-np.pi, np.pi, 50)
X1,Y1 = np.meshgrid(x,y)
Z1 = np.sin(X1 + Y1/4)

# plot
for ii in cmaps:
    f,ax=plt.subplots(nrows=1, ncols=2, figsize=(10,4))
    dis0=ax[0].pcolormesh(X0, Y0, Z0, cmap=ii)
    dis1=ax[1].pcolormesh(X1, Y1, Z1, cmap=ii)
    ax[1].set_xlim(-3,3)
    ax[1].set_ylim(-3,3)
    plt.colorbar(dis0, ax=ax[0])
    plt.colorbar(dis1, ax=ax[1])
    plt.suptitle(ii, fontsize=16)