Matplotlib中实现曲线图与图像子图同步动画的问题
Matplotlib动画:曲线与图像偏移不同步问题解决
问题描述
我用Matplotlib创建了包含曲线图和对应图像的Figure,希望两者同步偏移——让图像的白色区域跟随三条曲线重合的位置(多波长干涉图模拟)。将曲线图的三条曲线逐点复制到图像帧的R、G、B通道后,动画中曲线偏移速度明显快于图像颜色变化,调整图像纵横比、修改image extent等操作都未能解决问题。
原代码
from numpy import * import matplotlib.pyplot as plt from matplotlib import animation npts = 501 wavelength_blue = 0.45 wavelength_green = 0.55 wavelength_red = 0.65 z = 1.5 * linspace(-0.75, 0.75, npts) ## distance in microns nframes = 100 maxshift = 0.55 ## in microns of distance img_height = 100 img = 255 * ones((img_height,npts,3), 'uint8') (fig,axes) = plt.subplots(2, num='propagation_phase_shifted') p1 = axes[0].plot([], [], 'b-') p2 = axes[0].plot([], [], 'g-') p3 = axes[0].plot([], [], 'r-') axes[0].set_xlim((-0.8,0.8)) axes[0].set_ylim((-0.1,1.1)) p4 = axes[1].imshow(img, extent=[-0.8,0.8,-0.1,1.1], aspect=1/3) axes[0].xaxis.set_label_position('top') axes[0].xaxis.set_ticks_position('top') axes[0].set_xlabel('z-distance (um)') axes[0].set_ylabel('wave amplitude') axes[0].tick_params(axis='x', direction='out') plt.subplots_adjust(hspace=0.05) def animate(n): shift = (n / (nframes - 1.0)) * maxshift phi_red = 2.0 * pi * (z-shift) / wavelength_red phi_green = 2.0 * pi * (z-shift) / wavelength_green phi_blue = 2.0 * pi * (z-shift) / wavelength_blue y_red = 0.5 * (1.0 + cos(phi_red)) y_green = 0.5 * (1.0 + cos(phi_green)) y_blue = 0.5 * (1.0 + cos(phi_blue)) for x in range(img_height): img[x,:,0] = uint8(255 * y_red) img[x,:,1] = uint8(255 * y_green) img[x,:,2] = uint8(255 * y_blue) p1[0].set_data(z, y_red) p2[0].set_data(z, y_green) p3[0].set_data(z, y_blue) p4.set_data(img) return(p1[0],p2[0],p3[0],p4) anim = animation.FuncAnimation(fig, animate, frames=nframes, interval=20, blit=True) FFwriter = animation.FFMpegWriter(fps=30) anim.save('result.mp4', writer=FFwriter) plt.show()
问题根源
核心问题是曲线的x轴数据范围与图像的extent x范围不匹配:
- 曲线使用的x数据
z = 1.5 * linspace(-0.75, 0.75, npts),实际范围是-1.125 ~ 1.125 - 上下坐标轴的xlim和图像extent都设置为
-0.8 ~ 0.8
这导致图像的每一列对应x从-0.8到0.8的均匀分布,而曲线的x点是-1.125到1.125的均匀分布,两者的x轴刻度映射错位,偏移时自然无法同步。
修改后的代码
from numpy import * import matplotlib.pyplot as plt from matplotlib import animation npts = 501 wavelength_blue = 0.45 wavelength_green = 0.55 wavelength_red = 0.65 # 关键改动1:让z的范围与xlim、图像extent的x范围完全一致 z = linspace(-0.8, 0.8, npts) ## distance in microns nframes = 100 maxshift = 0.55 ## in microns of distance img_height = 100 img = 255 * ones((img_height,npts,3), 'uint8') (fig,axes) = plt.subplots(2, num='propagation_phase_shifted') p1 = axes[0].plot([], [], 'b-') p2 = axes[0].plot([], [], 'g-') p3 = axes[0].plot([], [], 'r-') axes[0].set_xlim((-0.8,0.8)) axes[0].set_ylim((-0.1,1.1)) # 关键改动2:设置aspect为auto,避免固定纵横比导致的显示扭曲 p4 = axes[1].imshow(img, extent=[-0.8,0.8,-0.1,1.1], aspect='auto') axes[0].xaxis.set_label_position('top') axes[0].xaxis.set_ticks_position('top') axes[0].set_xlabel('z-distance (um)') axes[0].set_ylabel('wave amplitude') axes[0].tick_params(axis='x', direction='out') plt.subplots_adjust(hspace=0.05) def animate(n): shift = (n / (nframes - 1.0)) * maxshift phi_red = 2.0 * pi * (z-shift) / wavelength_red phi_green = 2.0 * pi * (z-shift) / wavelength_green phi_blue = 2.0 * pi * (z-shift) / wavelength_blue y_red = 0.5 * (1.0 + cos(phi_red)) y_green = 0.5 * (1.0 + cos(phi_green)) y_blue = 0.5 * (1.0 + cos(phi_blue)) # 关键改动3:用矢量赋值替代循环,提升动画渲染效率 img[:, :, 0] = uint8(255 * y_red) img[:, :, 1] = uint8(255 * y_green) img[:, :, 2] = uint8(255 * y_blue) p1[0].set_data(z, y_red) p2[0].set_data(z, y_green) p3[0].set_data(z, y_blue) p4.set_data(img) return(p1[0],p2[0],p3[0],p4) anim = animation.FuncAnimation(fig, animate, frames=nframes, interval=20, blit=True) FFwriter = animation.FFMpegWriter(fps=30) anim.save('result.mp4', writer=FFwriter) plt.show()
关键改动说明
- 统一x轴范围:将
z的生成改为linspace(-0.8, 0.8, npts),让曲线的x数据范围与坐标轴xlim、图像extent的x范围完全一致,确保每个z点对应图像的一列,偏移时完全同步。 - 优化图像显示:将图像的
aspect设置为auto,避免固定纵横比导致的显示扭曲(也可根据需求设置为对应比例)。 - 效率优化:用矢量赋值
img[:, :, 0] = ...替代循环,大幅提升动画渲染速度。
内容的提问来源于stack exchange,提问作者nzh
相关产品推荐
相关产品推荐

