Skip to content

Instantly share code, notes, and snippets.

@mikkopitkanen
Created March 21, 2019 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikkopitkanen/7f089c59b622543ef1c45d19820612f9 to your computer and use it in GitHub Desktop.
Save mikkopitkanen/7f089c59b622543ef1c45d19820612f9 to your computer and use it in GitHub Desktop.
An example on how to normalize and create offset to colorbar using matplotlib. This example simply combines two separate examples from the online sources mentioned in the code, so the credits go to the original authors (see the docstrings).
"""Show how to normalize and offset colorbar.
mikko.pitkanen@fmi.fi, 2018-03-06
Credits to people at scitools.org.uk and matplotlib.org.
Adopted from (on 2018-03-06):
http://scitools.org.uk/cartopy/docs/latest/gallery/waves.html#sphx-glr-gallery-waves-py
Contains public sector information licensed under the Open Government Licence
v2.0.
"""
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import matplotlib.colors
import colorcet as cc
class MidpointNormalize(matplotlib.colors.Normalize):
"""Subclass Normalize for offsetting the colormap center color.
Adopted from (on 2018-02-23):
https://matplotlib.org/users/colormapnorms.html#custom-normalization-two-linear-ranges
Copyright (c) 2012-2013 Matplotlib Development Team; All Rights Reserved
"""
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
# extend vmin and vmax range by 1e-10, because sometimes a zero width
# bin causes an error
# this is the minor modification to the original code
x = [self.vmin-1e-10, self.midpoint, self.vmax+1e-10]
y = [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y))
def sample_data(shape=(73, 145)):
"""Return ``lons``, ``lats`` and ``data`` of some fake data."""
nlats, nlons = shape
lats = np.linspace(-np.pi / 2, np.pi / 2, nlats)
lons = np.linspace(0, 2 * np.pi, nlons)
lons, lats = np.meshgrid(lons, lats)
wave = 0.75 * (np.sin(2 * lats) ** 8) * np.cos(4 * lons)
mean = 0.5 * np.cos(2 * lats) * ((np.sin(2 * lats)) ** 2 + 2)
lats = np.rad2deg(lats)
lons = np.rad2deg(lons)
data = wave + mean
return lons, lats, data
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Mollweide())
lons, lats, data = sample_data()
# define suitable data value levels manually
levels = np.linspace(-1.5, 0.7, 12)
# use MidpointNormalize to offset the white value from the
# center of colorbar to 0.0.
# use a diverging colorcet cmap for nice colors
cb = ax.contourf(lons, lats, data,
transform=ccrs.PlateCarree(),
cmap=cc.m_coolwarm,
norm=MidpointNormalize(midpoint=0.0),
levels=levels)
# use the levels also for colorbar ticks
fig.colorbar(cb, drawedges=True, ticks=levels)
ax.coastlines()
ax.set_global()
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment