Created
March 21, 2019 14:03
-
-
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).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""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