带有重新标准化颜色条的 Cartopy pcolormesh [英] Cartopy pcolormesh with re-normalized colorbar

查看:59
本文介绍了带有重新标准化颜色条的 Cartopy pcolormesh的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试绘制全球气溶胶光学深度 (AOD),这些值通常在 0.2 左右,但在某些地区可以达到 1.2 或更高.理想情况下,我想绘制这些较高的值,而又不丢失较小值的细节.对数刻度颜色条也不太合适,因此我尝试使用

但是,当使用pcolormesh等效项似乎无效时,它会在0到180度的经度(图的右半)之间涂抹一组值,而不是在等高线图中看到的波浪形图案:

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

我怎样才能使 pcolormesh 工作?当我对 Cartopy 投影/转换做错时,我通常会看到这一点,所以大概这与 Cartopy 环绕日期变更线的方式或简单 matplotlib 示例忽略的边缘情况之一有关,但我想不通出来.

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

解决方案

似乎与规范化类内部的屏蔽有关.所以这是一个有效的版本:

class MidpointNormalize(colors.Normalize):def __init __(self,vmin = None,vmax = None,midpoint = None,clip = False):self.midpoint =中点color.Normalize.__init__(self, vmin, vmax, clip)def __call __(自身,值,剪辑=无):结果,is_scalar = self.process_value(value)(vmin,),_ = self.process_value(self.vmin)(vmax,), _ = self.process_value(self.vmax)resdat = np.asarray(结果数据)结果 = 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)结果 = np.ma.array(res, mask=result.mask, copy=False)如果is_scalar:结果=结果[0]返回结果

完整代码:

 将matplotlib.pyplot导入为plt导入 matplotlib.colors 作为颜色将numpy导入为np将 cartopy.crs 导入为 ccr类 MidpointNormalize(colors.Normalize):def __init __(self,vmin = None,vmax = None,midpoint = None,clip = False):self.midpoint =中点color.Normalize.__init__(self, vmin, vmax, clip)def __call __(自身,值,剪辑=无):结果,is_scalar = self.process_value(value)(vmin,),_ = self.process_value(self.vmin)(vmax,),_ = self.process_value(self.vmax)resdat = np.asarray(结果数据)结果= np.ma.array(resdat,mask = result.mask,copy = False)x,y = [self.vmin,self.midpoint,self.vmax],[0,0.5,1]res = np.interp(结果,x,y)结果= np.ma.array(res,mask = result.mask,copy = False)如果is_scalar:结果=结果[0]返回结果def sample_data(shape =(73,145)):"""返回一些假数据的lons"、lats"和data"."""nlats,nlons =形状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)均值 = 0.5 * np.cos(2 * lats) * ((np.sin(2 * lats)) ** 2 + 2)lats = np.rad2deg(lats)lons = np.rad2deg(lons)数据=波动+均值返回 lons、lats、数据ax = plt.axes(projection=ccrs.Mollweide())lons, lats, data = sample_data()范数=范数=中点归一化(中点=0.8)cm = ax.pcolormesh(lons, lats, data,变换=ccrs.PlateCarree(),cmap ='spectral',norm = norm)ax.coastlines()plt.colorbar(cm,orientation ="horizo​​ntal")ax.set_global()plt.show()

产生

I'm trying to plot global Aerosol Optical Depths (AOD), and the values are typically around 0.2, but in some regions can reach 1.2 or more. Ideally I want to plot these high values, without losing the detail of the smaller values. A log scale color bar isn't really appropriate either, so I've tried to use two linear ranges as described in the docs:

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

This breaks when I try to do a pcolormesh plot with Cartopy though. Creating dummy data as per one of the gallery examples:

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()

Gives me this, which looks OK:

However, when using the pcolormesh equivalent does not seem to work, it has a smeared set of values between 0 and 180 degrees longitude (the right half of the plot) instead of the wavy pattern seen in the contour plot:

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

How can I make this work for pcolormesh? I typically see this when I've done something wrong with Cartopy projection/transformation so presumably this is something to do with the way Cartopy does wrapping around the dateline or one of the edge cases the simple matplotlib example ignores, but I can't figure it out.

Note that this only occurs when using the custom Normalization instance; without it, also pcolormesh works as expected.

解决方案

It seems to have something to do with the masking inside the normalization class. So here is a version that is working:

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

The complete code:

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()

produces

这篇关于带有重新标准化颜色条的 Cartopy pcolormesh的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆