是否可以在 matplotlib (python) 中的数据之上绘制等高线?

Is it possible to plot contours on top of data in matplotlib (python)?

下面是我为一组数据创建的图形,顶部绘制了等高线。这正是我所需要的,我只需要将它绘制为我的 7 个模型运行的一系列子图,以及彩色盐度数据和绘制在顶部的等高线。

但是,当我尝试绘制子图时,我可以获得盐度数据,但我无法在顶部绘制等高线(或颜色条,但这是另一个问题)。理想情况下,这应该看起来像图 1 的 7 个迷你版本。但是,我收到以下错误:

TypeError: inner() got multiple values for argument 'ax'

当我将相同的东西绘制为单个图形时,我没有得到,并且找不到解决方法。

不幸的是,每个数据文件都是 5GB,所以我无法上传它们。例如,我创建了一个虚拟数据集和一个基本绘图脚本来尝试在数据上绘制等高线。我也画了一些等高线,虽然和我的不完全一样,因为我的是测深,所以需要改造。

对于任何错误,我们深表歉意 - python 还很新! 非常感谢任何建议,以及关于如何改进我的提问的评论!

import xarray as xa
import numpy as np
import matplotlib.pyplot as plt
import cmocean.cm as cm
import cartopy.crs as ccrs

#-----------Example Salinity Data---------------

data1 = 15 + 8 * np.random.randn(4,3)
salinity1 = xa.DataArray(data1)
salinity1 = xa.DataArray(data1, dims=['lat', 'lon'])
lons = np.linspace(-2, 6, 3)
lats = np.linspace(54, 62, 4)
salinity1 = xa.DataArray(data1, coords=[lats, lons], dims=['lat', 'lon'])
salt_ocean1 = salinity1

#-----------Example Contour Data---------------

xp = np.arange(-8, 10, 2)
yp = np.arange(-8, 10, 2)
zp = np.ndarray((9,9))
for x in range(0, len(xp)):
    for y in range(0, len(yp)):
        zp[x][y] = xp[x]**2 + yp[y]**2


#-----------Plotting (single figure)---------------

map_proj = ccrs.PlateCarree(central_longitude = 6)


ax = salt_ocean1.plot(transform = ccrs.PlateCarree(),
                      subplot_kws={"projection":map_proj},
                      cmap = cm.haline,
                      add_colorbar=False)

ax2 = plt.contour(xp, yp, zp)

您的示例等高线数据远离非洲海岸,因此我对其进行了一些更改,使其位于示例盐度数据的同一区域。 (也许你用了两次“lons”这个例子,也是为了“lats”?)

xp = np.arange(-3, 7, 2)
yp = np.arange(52, 62, 2)
xx, yy = np.meshgrid(xp, yp)
zp = (xx-xx.mean())**2 + (yy-yy.mean())**2

您可能只使用 xarray 中的绘图方法(它本身使用 Matplotlib)就可以得到您的结果。例如,参见文档中的“构面”部分:
http://xarray.pydata.org/en/stable/user-guide/plotting.html#faceting

我个人更喜欢直接使用 Matplotlib 创建图形和坐标轴,然后使用 ax=ax.

将要绘制的坐标轴传递到 xarray 上
map_proj = ccrs.PlateCarree(central_longitude=6)

fig, axs = plt.subplots(3,3, figsize=(10,9.5), constrained_layout=True, facecolor='w',
                        subplot_kw=dict(projection=map_proj))
axs = axs.ravel()

# loop over each axes
for i, ax in enumerate(axs, start=1):
    
    # set map extent
    ax.set_extent([-5, 10, 50, 65], crs=ccrs.PlateCarree())
    
    # add some cartopy features
    ax.coastlines(resolution='50m', alpha=.4)
    
    # Plot model data
    qm = salt_ocean1.plot(ax=ax, cmap=cm.haline, add_colorbar=False, transform=ccrs.PlateCarree())
    c = ax.contour(xp, yp, zp, levels=8, cmap='Blues', linewidths=2, transform=ccrs.PlateCarree())
    
    # do this after using xarray (it overrides the title)
    ax.set_title(f'model run: {i}')

# create 1 colorbar for all subplots using (ax=axs)
cb = fig.colorbar(qm, ax=axs, label='Salinity [g/kg]', shrink=.5)

请注意,使用 transform=ccrs.PlateCarree() 将地理投影分配给数据。对于与 contour 一起使用的 Numpy 数组,这始终是必需的,因为它们没有任何元数据。我怀疑对于 xarray 数据集,它取决于可用的元数据,但对于此示例数据,它是必需的。但是,如果您的模型或水深测量数据具有不同的投影,则此投影需要更改。

cartopy 画廊有很多示例展示了如何添加任何特征,如海岸线、土地、国家等:
https://scitools.org.uk/cartopy/docs/v0.13/gallery.html