我正在使用 Cartopy 在多个 Matplotlib 子图中显示 GSHHSFeature 海岸线,并在其上叠加不同的数据。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
xss = np.linspace(-21, 36, 36)
extent = [-21, 36, 33, 64] # west,east,south,north
fig, ax = plt.subplots(nrows=3, ncols=2, figsize=(13, 15),
subplot_kw={'projection': ccrs.PlateCarree()})
for i in range(rows):
for j in range(cols):
ax[i][j].set_extent(extent)
ax[i][j].add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))
# Plot individual data sets on subplots
ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
# Write map title
ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
plt.tight_layout()
plt.show()
绘制海岸线是一项耗时的操作,特别是在使用“完整”数据集比例时。由于每个子图中的底图都是相同的,因此我一直在寻找仅创建一次并在循环中重用它的方法。
有没有办法可以缓存特征甚至整个子图轴并定义像
ax[i][j].plot_my_basemap(map_ax)
或ax[i][j] = copy_axis_from(map_ax)
这样的函数?
# Create a plot axes of choice
map_ax = plt.axes(projection=ccrs.PlateCarree())
map_ax.set_extent(extentd)
# Request and process the basemap features
map_ax.add_feature(cfeature.GSHHSFeature(scale="intermediate", edgecolor="black", facecolor="#bca89f"))
fig, ax = plt.subplots(nrows=3, ncols=2, figsize=(13, 15),
subplot_kw={'projection': ccrs.PlateCarree()})
for i in range(rows):
for j in range(cols):
ax[i][j].plot_my_basemap(map_ax)
# Plot individual data sets on subplots
ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
# Write map title
ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
plt.tight_layout()
plt.show()
这个问题的答案(我从中改编了我的示例)显示了如何使用 Google 平铺图像执行此操作,但这种方法在我的情况下不起作用,因为海岸线不是图像对象,而是 cartopy.mpl.feature_artist .特色艺术家。
我还尝试直接重用map_ax,更改其属性并将其分配给子图,但这在matplotlib中不起作用:
for i in range(rows):
for j in range(cols):
props = ax[i][j].properties()
props = dict((k, props[k]) for k in ["position", "subplotspec"])
ax[i][j] = map_ax.update(props)
# Plot individual data sets on subplots
ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
# Write map title
ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
我希望能够定义和重用诸如 Basemap 对象之类的东西https://github.com/matplotlib/basemap/issues/354(但我不想使用 Basemap,因为它将被 Cartopy 取代)并且它已经与 Matplotlib 3.8 存在兼容性问题)
如果您每次都使用
plt.show()
,则此方法不起作用,但如果您保存每个图像,则只需更新由 Line2D
创建的 ax.plot
对象上的 y 数据即可。
我使用标准
coastlines
调用只是为了加快此示例的速度。我还删除了 tight_layout
,因为它正在移动每次迭代的子图。在图形创建中使用 layout='compressed'
使我的布局更加一致。
请注意,大多数(全部?)matplotlib 绘图方法返回的艺术家都有某种
set_data
方法,因此如果您的真实示例使用 plot
以外的其他内容,这应该是通用的。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import numpy as np
xss = np.linspace(-21, 36, 36)
extent = [-21, 36, 33, 64] # west,east,south,north
nrows = 3
ncols = 2
fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(13, 15),
subplot_kw={'projection': ccrs.PlateCarree()},
layout='compressed')
for n in range(3):
for i in range(nrows):
for j in range(ncols):
if n == 0:
# Set up maps and plot first data.
ax[i][j].set_extent(extent)
ax[i][j].coastlines()
# Plot individual data sets on subplots
ax[i][j].plot(xss, np.random.uniform(low=33, high=64, size=(len(xss),)), color='cyan', zorder=20, transform=ccrs.PlateCarree(), linewidth=2)
else:
# Replace line y-data.
ax[i][j].get_lines()[0].set_ydata(np.random.uniform(low=33, high=64, size=(len(xss),)))
# Write map title
ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
plt.savefig(f'myplot{n}.png')