我正在使用 cartopy 在 GoogleTiles 卫星图像上绘制动画轨迹。我独立生成数千个帧,然后将它们 ffmpeg-ing 在一起,似乎保存地图图像并加载并用于未来的帧会更有效,而不是每次都从 Google 重新加载地图。
目前代码如下所示:
import cartopy.io.img_tiles as cimgt
google = cimgt.GoogleTiles(style='satellite')
ax = plt.axes(projection=google.crs)
ax.set_extent([west, east, south, north])
ax.add_image(google, 13)
ax.plot(data[t])
plt.savefig(fname = f'frame{t}.png')
并且此代码批量运行,其中
t
代表每个单独的帧。有没有办法保存然后加载地图图像以避免每次调用cimgt.GoogleTiles()
?
首先,我对相关代码行的评论:-
google = cimgt.GoogleTiles(style='satellite')
ax = plt.axes(projection=google.crs)
我的回答将尝试优化上述流程。
以下是有效的演示代码。
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.io.img_tiles as cimgt
import matplotlib.cm as cm
import numpy as np
import matplotlib
import cartopy
import matplotlib.path as mpath
# For demo purposes
extentd = [99.65, 101.25, 12.5, 13.75] #west,east,south,north
zoomlev = 9
noproj = ccrs.PlateCarree()
#geodproj = ccrs.Geodetic()
mercator = ccrs.Mercator()
# Setup style of map
google = cimgt.GoogleTiles(style='satellite', cache=True)
# Setup proper projection that can do clipping
# to meet the requirement
# There may be some warning about this
# Create a plot axes of choice
ax = plt.axes(projection=mercator)
ax.set_extent(extentd, crs=noproj)
# Request and process the images
imgfactory = ax.add_image(google, zoomlev)
# Check plot of the extent
ax.plot([extentd[0], extentd[1]], [extentd[2], extentd[3]], 'or-',
transform=ccrs.PlateCarree(), markersize=12, zorder=21)
# OK using plot_coords
#plot_coords(ax, polyx.exterior)
plt.title('Clipped Images from Google Tiles')
plt.show()
第一个绘图完成后,我们就可以获取在实际绘图中有用的隐藏信息。
# Get 'child0' object that contains the image data array
for ix,child in enumerate(ax.get_children()):
#print(child, type(child))
if isinstance(child, matplotlib.image.AxesImage):
print("* Found image object.")
child0 = child
ccmap = child0.get_cmap()
img_array = child0.get_array()
break
pass
在这一步,我们有
ccmap
,数据数组的颜色图img_array
,代表剪切图像的数据数组。两者都将在多张地图中重复使用。
它们可以保存到文件中以供将来使用。
接下来,我们使用数据数组进行检查图。
# Check plot of the image data array
# Note the use of 'img_array' and 'ccmap'
# This uses basic matplotlib axes
# and use degrees as basic units
ax2 = plt.subplot(111)
ax2.imshow(img_array, extent=extentd , origin='lower', cmap=ccmap)
plt.title('Image_data array aligned to lat-long extent')
plt.show()
最后一步,获得需要公共底图的最终绘图数组。
# Plot 3x2 array of maps
rows = 3
cols = 2
# Prep (x,y) data for extra features on each plot
xss = np.linspace(99.65, 101.25, 36)
# yss = 13+np.random.random(36)/2
# This uses PlateCarree projection, other projection can be problematic
fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(13, 15),
subplot_kw={'projection': ccrs.PlateCarree()})
# This uses Mercator
# Warning, image array takes v. long time to do image warping
#fig, ax = plt.subplots(nrows=rows, ncols=cols, figsize=(5.2, 6),
# subplot_kw={'projection': ccrs.Mercator()})
for i in range(rows):
for j in range(cols):
# Plot base raster map, using data array
ax[i][j].imshow(child0.get_array(), origin='lower',
cmap=child0.get_cmap(), extent=extentd, zorder=10)
# Plot individual data sets on subplots
ax[i][j].plot(xss, 13+np.random.random(len(xss))/2,
color='cyan', zorder=20,
transform=ccrs.PlateCarree(), linewidth=2)
# Write map title
ax[i][j].set_title("Row:"+str(i)+", Col:"+str(j))
ax[i][j].set_extent(extentd)
gl=ax[i][j].gridlines(crs=ccrs.PlateCarree(), draw_labels=[1,1,0,0],
lw=1, color='white', linestyle='--', zorder=20)
gl.top_labels = False
gl.right_labels = False
pass
plt.tight_layout()
plt.show()