Cartopy pcolormesh与重新标准化的colorbar

时间:2017-05-15 16:02:22

标签: python matplotlib cartopy

我正在尝试绘制全球气溶胶光学深度(AOD),其值通常约为0.2,但在某些地区可达到1.2或更高。理想情况下,我想绘制这些高值,而不会丢失较小值的细节。对数刻度颜色条也不合适,所以我尝试使用docs中描述的两个线性范围:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button id="go">Go</button>
<div id="randominfo"></div>

当我尝试使用Cartopy进行pcolormesh绘图时,这会中断。根据一个图库示例创建虚拟数据:

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
import cartopy.crs as ccrs


class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        res = np.ma.masked_array(np.interp(value, x, y))
        return res

给我这个,看起来不错: working contourf plot

然而,当使用pcolormesh等效似乎不起作用时,它有一组介于0到180度经度(图的右半部分)的值,而不是在等高线图中看到的波浪图案:

def sample_data(shape=(73, 145)):
    """Returns ``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


ax = plt.axes(projection=ccrs.Mollweide())
lons, lats, data = sample_data()
ax.contourf(lons, lats, data,
            transform=ccrs.PlateCarree(),
            cmap='spectral', norm=MidpointNormalize(midpoint=0.8))
ax.coastlines()
ax.set_global()
plt.show()

broken pcolormesh plot

如何为pcolormesh做这项工作?当我对Cartopy投影/转换做错时,我通常会看到这一点,所以这可能与Cartopy绕日期线缠绕的方式或简单的matplotlib示例忽略的边缘情况有关,但我无法想象它出来了。

请注意,这仅在使用自定义规范化实例时发生;没有它,pcolormesh也按预期工作。

1 个答案:

答案 0 :(得分:2)

它似乎与规范化类中的屏蔽有关。 所以这是一个正在运行的版本:

class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        result, is_scalar = self.process_value(value)
        (vmin,), _ = self.process_value(self.vmin)
        (vmax,), _ = self.process_value(self.vmax)
        resdat = np.asarray(result.data)
        result = np.ma.array(resdat, mask=result.mask, copy=False)
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        res = np.interp(result, x, y)
        result = np.ma.array(res, mask=result.mask, copy=False)
        if is_scalar:
            result = result[0]
        return result

完整的代码:

import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
import cartopy.crs as ccrs

class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        result, is_scalar = self.process_value(value)
        (vmin,), _ = self.process_value(self.vmin)
        (vmax,), _ = self.process_value(self.vmax)
        resdat = np.asarray(result.data)
        result = np.ma.array(resdat, mask=result.mask, copy=False)
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        res = np.interp(result, x, y)
        result = np.ma.array(res, mask=result.mask, copy=False)
        if is_scalar:
            result = result[0]
        return result

def sample_data(shape=(73, 145)):
    """Returns ``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


ax = plt.axes(projection=ccrs.Mollweide())
lons, lats, data = sample_data()

norm = norm=MidpointNormalize(midpoint=0.8)
cm = ax.pcolormesh(lons, lats, data, 
            transform=ccrs.PlateCarree(),
            cmap='spectral', norm=norm )

ax.coastlines()
plt.colorbar(cm, orientation="horizontal")
ax.set_global()
plt.show()

产生

enter image description here