撇号背景颜色(数据域之外)

时间:2016-01-20 11:05:19

标签: python matplotlib background cartopy

在Cartopy地图中,我希望该区域不被任何数据(我的域之外)覆盖,例如浅灰色。 玩了REngine并看过这个例子Change the background colour of a projected Matplotlib axis,但仍然无法做出我想做的事。

这是一个人为的例子,我用红线表示域边界。相反,我想让红线以外的区域在浅灰色中着色。

非常感谢!

修改 将投影更改为LambertConformal以证明下面提出的解决方案(Cartopy background color (outside of data domain))仅适用于矩形网格。请参见下面的其他图表 The domain bounds drawn The proposed solution

background_patch

enter image description here

1 个答案:

答案 0 :(得分:2)

当然,如果您不使用cartopy,可以单独用matplotlib来实现:

import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.patches as mpatches
from matplotlib.path import Path
import numpy as np


# Create some lons/lats
lats = np.linspace(20,40,50)
lons = np.linspace(110,130,50)
lons,lats = np.meshgrid(lons,lats)

# Some data with 'cloud'.
thedata = np.zeros_like(lats)
thedata[5:8, 7:13] = 1

ax = plt.axes()

mycmap = mcolors.ListedColormap(['white', 'black'])
bounds=[0, 0.5, 1]
norm = mcolors.BoundaryNorm(bounds, mycmap.N)

im = ax.pcolormesh(lons, lats, thedata, cmap=mycmap,
                   norm=norm)

data_extent = np.array((lons[0,0], lons[-1,-1], lats[0,0], lats[-1,-1]))

# Make the extent larger to see a margin outside of the domain
ax.set_xlim(data_extent[:2] + [-1, 1])
ax.set_ylim(data_extent[2:] + [-1, 1])

# Create a path which has the exterior of the map, with an interior of the data we care about.
path_with_hole = Path([[-180, 90],
                       [180, 90],
                       [180, -90],
                       [-180, -90],
                       [-180, 90],
                       [data_extent[0], data_extent[2]],
                       [data_extent[1], data_extent[2]],
                       [data_extent[1], data_extent[3]],
                       [data_extent[0], data_extent[3]],
                       [data_extent[0], data_extent[2]]],
                      codes=[Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO,
                             Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO])

geom = mpatches.PathPatch(path_with_hole, facecolor='lightgrey',
                          edgecolor='white',
                          hatch='xxxx', alpha=0.6)
ax.add_patch(geom, )

plt.show()

figure_mpl

关键是我们生成一个Path,它将地图作为外部,我们感兴趣的域作为内部。我们可以通过将它转换为补丁(你在matplotlib图中实际看到的东西)将该路径添加到轴上。

我们可以用一种明显的方式在图表中使用这种技术:

import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.patches as mpatches
from matplotlib.path import Path
import numpy as np


# Create some lons/lats
lats = np.linspace(20,40,50)
lons = np.linspace(110,130,50)
lons,lats = np.meshgrid(lons,lats)

# Some data with 'cloud'.
thedata = np.zeros_like(lats)
thedata[5:8, 7:13] = 1

pc = ccrs.PlateCarree()
ax = plt.axes(projection=ccrs.Mercator())
ax.coastlines()

# Some decoration to see where we are
gl = ax.gridlines(crs=pc,
                  draw_labels=True,
                  linewidth=2, color='gray', alpha=0.5,
                  linestyle='--')
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER

mycmap = mcolors.ListedColormap(['white', 'black'])
bounds=[0, 0.5, 1]
norm = mcolors.BoundaryNorm(bounds, mycmap.N)

im = ax.pcolormesh(lons, lats, thedata, cmap=mycmap,
                   norm=norm, transform=pc)

proj_extent = np.array(list(pc.x_limits) + list(pc.y_limits))
data_extent = np.array((lons[0,0], lons[-1,-1], lats[0,0], lats[-1,-1]))

# Make the extent larger to see a margin outside of the domain
ax.set_extent(data_extent + [-2, 2, -2, 2])

# Create a path which has the exterior of the map, with an interior of the data we care about.
path_with_hole = Path([[proj_extent[0], proj_extent[3]],
                       [proj_extent[1], proj_extent[3]],
                       [proj_extent[1], proj_extent[2]],
                       [proj_extent[0], proj_extent[2]],
                       [proj_extent[0], proj_extent[3]],
                       [data_extent[0], data_extent[2]],
                       [data_extent[1], data_extent[2]],
                       [data_extent[1], data_extent[3]],
                       [data_extent[0], data_extent[3]],
                       [data_extent[0], data_extent[2]]],
                      codes=[Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO,
                             Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO])

geom = mpatches.PathPatch(path_with_hole, facecolor='lightgrey',
                          edgecolor='white',
                          hatch='xxxx', alpha=0.6, transform=pc)
ax.add_patch(geom)

plt.show()

HTH

编辑:您的问题特别提及LambertConformal,以及此解决方案似乎不起作用的事实。事实证明,问题不在于解决方案,而是Cartopy的LambertConformal定义本身具有太低的分辨率。

解决方法非常严重:必须覆盖LambertConformal投影并修改幻数阈值。这将在未来变得更加容易。

class BetterLambertConformal(ccrs.LambertConformal):
    def __init__(self, *args, **kwargs):
        ccrs.LambertConformal.__init__(self, *args, **kwargs)
        self._threshold = 1e4

    @property
    def threshold(self):
        return self._threshold

ax = plt.axes(projection=BetterLambertConformal())

cartopy figure