Python matplotlib 动画输出与显示的图形不同
Python matplotlib animation output differs from the displayed figure
我正在尝试通过在带有子图的图形上使用 matplotlib.animation 来创建视频。其中一个子图使用 cartopy 显示地图。
我写的代码是:
import pandas as pd
import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import matplotlib as mpl
import matplotlib.animation as animation
from IPython.display import HTML
data = pd.DataFrame({'data': np.sin(np.arange(0, 2, 0.2))}, index=pd.date_range(start='1/1/2018', periods=10))
extent = [-16, 10, 36, 48]
#create the figure
fig = plt.figure(figsize=(7,12))
#add subplots
ax = plt.subplot(211, projection=ccrs.PlateCarree())
ax_t = plt.subplot(212)
ax.coastlines(resolution='50m')
ax.add_feature(cfeature.BORDERS.with_scale('50m'))
ax.set_extent(extent, ccrs.PlateCarree())
sm = plt.cm.ScalarMappable(cmap=mpl.cm.Reds,norm=plt.Normalize(0,1))
sm._A = []
cb = plt.colorbar(sm, ax=ax, fraction=0.022, pad=0.02)
cb.set_label('Values')
color = (1.0, 1.0, 1.0)
hpoint = ax.plot(-3, 40, color=color, linewidth=2, marker='o', markersize=30, transform=ccrs.PlateCarree() )
#ax_t.plot(meanRMS)
data.plot(ax=ax_t)
ax_t.margins(x=0, tight=True)
ax_t.grid(True)
box1 = ax.get_position()
box2 = ax_t.get_position()
deltaheigh = box2.height * 0.3
ax_t.set_position([box1.x0, box1.y0 - deltaheigh*1.1 , box1.width , deltaheigh])
这段代码给出了我想要和期望的输出:
image in output
创建视频动画时:
frames = 1
iter_data = data.iterrows()
ndays = data.shape[0]
def makemap(n):
if n % frames == 0:
time, val = next(iter_data)
color = (1.0, 1.0-val[0], 1.0-val[0])
hpoint[0].set_color(color)
ax.set_title(time.strftime("%d %b %Y"), fontsize=20)
ani = animation.FuncAnimation(fig, makemap, frames=frames*(ndays-2), interval=100)
HTML(ani.to_html5_video())
我得到了一个不同 shape/format 的视频(更大的白色 canvas,图像甚至没有居中):
enter image description here
如何解决这个意外结果?
看来您 运行 使用的是 Jupyter notebook。在 notebook 中,当 matplotlib 图形以内联方式显示时,它使用选项 bbox_inches='tight'
保存图像。您可以在 matplotlib example 中看到这一点。不幸的是,此选项与保存动画不兼容,因为它会使动画帧的大小因图像而异。
解决这个问题的方法是手动调整图形和坐标轴的大小,而不是依靠紧密的 bbox 来为您消除空白。您可以通过手动保存图形而不是依赖 Jupyter 的内联显示来检查单个框架的实际外观,如下所示:
fig.savefig('myfig.png')
我正在尝试通过在带有子图的图形上使用 matplotlib.animation 来创建视频。其中一个子图使用 cartopy 显示地图。
我写的代码是:
import pandas as pd
import numpy as np
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.feature as cfeature
import matplotlib as mpl
import matplotlib.animation as animation
from IPython.display import HTML
data = pd.DataFrame({'data': np.sin(np.arange(0, 2, 0.2))}, index=pd.date_range(start='1/1/2018', periods=10))
extent = [-16, 10, 36, 48]
#create the figure
fig = plt.figure(figsize=(7,12))
#add subplots
ax = plt.subplot(211, projection=ccrs.PlateCarree())
ax_t = plt.subplot(212)
ax.coastlines(resolution='50m')
ax.add_feature(cfeature.BORDERS.with_scale('50m'))
ax.set_extent(extent, ccrs.PlateCarree())
sm = plt.cm.ScalarMappable(cmap=mpl.cm.Reds,norm=plt.Normalize(0,1))
sm._A = []
cb = plt.colorbar(sm, ax=ax, fraction=0.022, pad=0.02)
cb.set_label('Values')
color = (1.0, 1.0, 1.0)
hpoint = ax.plot(-3, 40, color=color, linewidth=2, marker='o', markersize=30, transform=ccrs.PlateCarree() )
#ax_t.plot(meanRMS)
data.plot(ax=ax_t)
ax_t.margins(x=0, tight=True)
ax_t.grid(True)
box1 = ax.get_position()
box2 = ax_t.get_position()
deltaheigh = box2.height * 0.3
ax_t.set_position([box1.x0, box1.y0 - deltaheigh*1.1 , box1.width , deltaheigh])
这段代码给出了我想要和期望的输出:
image in output
创建视频动画时:
frames = 1
iter_data = data.iterrows()
ndays = data.shape[0]
def makemap(n):
if n % frames == 0:
time, val = next(iter_data)
color = (1.0, 1.0-val[0], 1.0-val[0])
hpoint[0].set_color(color)
ax.set_title(time.strftime("%d %b %Y"), fontsize=20)
ani = animation.FuncAnimation(fig, makemap, frames=frames*(ndays-2), interval=100)
HTML(ani.to_html5_video())
我得到了一个不同 shape/format 的视频(更大的白色 canvas,图像甚至没有居中): enter image description here
如何解决这个意外结果?
看来您 运行 使用的是 Jupyter notebook。在 notebook 中,当 matplotlib 图形以内联方式显示时,它使用选项 bbox_inches='tight'
保存图像。您可以在 matplotlib example 中看到这一点。不幸的是,此选项与保存动画不兼容,因为它会使动画帧的大小因图像而异。
解决这个问题的方法是手动调整图形和坐标轴的大小,而不是依靠紧密的 bbox 来为您消除空白。您可以通过手动保存图形而不是依赖 Jupyter 的内联显示来检查单个框架的实际外观,如下所示:
fig.savefig('myfig.png')