使用Cartopy屏蔽海洋或陆地数据

7

我希望能够在全球范围内从海表面温度数据中屏蔽陆地区域。我正在使用Cartopy绘制这些数据。

import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from netCDF4 import Dataset

f = Dataset('sst.mnmean.nc')
sst = f.variables['sst'][0,:,:]
lats = f.variables['lat'][:]
lons = f.variables['lon'][:]

ax = plt.axes(projection=ccrs.PlateCarree())
ax.coastlines()
plot = ax.contourf(lons, lats, sst, 60, transform=ccrs.PlateCarree())
cb = plt.colorbar(plot)
plt.show()

上述代码绘制的数据如下所示:
enter image description here 我想要将陆地从中遮盖掉。

请发布您的代码! - Jason
请澄清你的问题,我认为你的意思是如何删除与陆地相关联的温度数据? - Maljam
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Kushal
@Maljam 你是如何编辑我的问题,以便在问题本身中显示图片的? - Kushal
@Kushal,在文本框上方有一个图片按钮(在“{}”按钮旁边)。 - Maljam
@Maljam 谢谢。我刚发现在我没有10个仓库之前,我无法插入图片。不管怎样还是感谢你。另外请看第二个答案。我已经知道如何做了。你可能可以从那里链接的图片中得到遮罩的想法。 - Kushal
3个回答

15

我仔细阅读了cartopy文档,并发现了一个名为add_feature的方法。代码如下:

import numpy as np
import matplotlib.pyplot as plt
import cartopy as cart
from mpl_toolkits.basemap import Basemap
from netCDF4 import Dataset

f = Dataset('sst.mnmean.nc')
sst = f.variables['sst'][0,:,:]
lats = f.variables['lat'][:]
lons = f.variables['lon'][:]

ax = plt.axes(projection=cart.crs.PlateCarree())
ax.coastlines()
ax.add_feature(cart.feature.LAND, zorder=100, edgecolor='k')
ax.set_global()
plot = ax.contourf(lons, lats, sst, 60, transform=cart.crs.PlateCarree())
cb = plt.colorbar(plot)
plt.show()

现在的情节看起来像这个。 要遮盖海洋,请将cart.feature.LAND更改为cart.feature.OCEAN


2
有用的解决方案。但是你能否建议使用cart.feature.LAND来遮盖数组中的值,而不是用于绘图? - Pauli
我不确定使用cartopy来遮蔽数组是否明智,因为它主要用于可视化。原因是数据的分辨率可能与cartopy特征的分辨率不匹配,即使您可以将其提取为数组。我认为最好的方法是绘制整个数组并在绘图中进行遮罩处理。希望这有所帮助。 - Kushal
@Kushal 我觉得他的问题的要点是,如果你想使用Cartopy来遮罩等高线数据,但是保留底图的原始背景。 - undefined

3
所接受的解决方案实际上并没有掩盖数据,而是通过覆盖地图的部分来遮盖绘图。虽然这对于给定的问题很好用,但有时需要一个真正的掩码来去除数据中不需要的部分。这样的掩码可以基于陆地或海洋的光栅地图轻松创建。
使用下面的代码,创建一个临时图形,其分辨率与给定数据相对应。在绘制陆地地图之后,使用tostring_rgb()获取地图的<rasterized image>。该图像类似于二进制图像,然后可以直接用于创建数据的掩码。
这种解决方案的优点在于它可以应用于更一般的问题,例如在陆地和海洋上分别绘制两个不同的数据集。当绘制像图像一样的数据时,由于可以考虑光栅化掩码的颜色梯度,因此可以使用透明度实现平滑的边缘。这可以通过PIL.Image.fromarray(mask),然后跟随convert('L')和最后在给定图像上应用putalpha(mask)轻松完成。
import matplotlib.pyplot as plt
import numpy as np
import cartopy
import netCDF4

# load data
data = netCDF4.Dataset('sst.mnmean.nc')
sst  = data.variables['sst'][0,:,:]
lats = data.variables['lat'][:]
lons = data.variables['lon'][:]

# prepare temporary plot and create mask from rasterized map
proj = {'projection': cartopy.crs.PlateCarree()}
fig, ax = plt.subplots(figsize=(len(lons)/100, len(lats)/100), dpi=100, subplot_kw=proj)
fig.subplots_adjust(left=0.0, bottom=0.0, right=1.0, top=1.0)
ax.set_frame_on(False)

ax.add_feature(cartopy.feature.LAND, facecolor='black')
fig.canvas.draw()
mask = fig.canvas.tostring_rgb()
ncols, nrows = fig.canvas.get_width_height()
plt.close(fig)

mask = np.frombuffer(mask, dtype=np.uint8).reshape(nrows, ncols, 3)
mask = mask.mean(axis=2)
sst  = np.where(mask>0, sst, np.nan)

# create actual plot
fig, ax = plt.subplots(subplot_kw=proj)
ax.contourf(lons, lats, sst, 60, transform=cartopy.crs.PlateCarree(central_longitude=180))
ax.coastlines()
plt.show()

Resulting plot


-4

如果需要屏蔽土地区域,使用底图会更容易些。

from mpl_toolkits.basemap import Basemap
map = Basemap(projection='mill',lon_0=180) # create projection
....                                       # whatever processing needed
map.fillcontinents(color='coral')          # mask land mass

在此处查看底图示例


3
自从几年前开始,Basemap已经不再维护,安装它并避免因依赖关系无法满足而破坏您的环境是一个很大的挑战。一个新的解决方案在cartopy中,不仅用于绘图,还可用于计算,将是一个很好的选择。 - Pauli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接