Matplotlib子图独立缩放功能实现问题求助
解决Matplotlib多子图独立缩放的问题
我帮你找到了问题的根源,并且修正了代码,现在两个子图可以各自独立缩放和平移了!
问题分析
你的代码里有两个关键问题导致同步缩放:
- 在
zoom_factory方法中,你重复绑定了滚动事件到整个figure(fig.canvas.mpl_connect('scroll_event', zoom)),加上之前的self.ax.canvas.mpl_connect,相当于每个子图的缩放逻辑都被绑定了两次,而且没有判断事件来源。 - 缩放函数
zoom里没有检查事件是否发生在当前子图内,所以不管鼠标在哪个子图滚动,两个子图的缩放逻辑都会触发。
修正后的完整代码
from matplotlib.pyplot import figure, show import matplotlib.pyplot as plt import numpy class ZoomPan: def __init__(self,ax): self.press = None self.cur_xlim = None self.cur_ylim = None self.x0 = None self.y0 = None self.x1 = None self.y1 = None self.xpress = None self.ypress = None self.ax = ax def zoom_factory(self, base_scale = 2.): def zoom(event): # 关键:只处理当前子图内的滚动事件 if event.inaxes != self.ax: return ax = self.ax cur_xlim = ax.get_xlim() cur_ylim = ax.get_ylim() xdata = event.xdata # get event x location ydata = event.ydata # get event y location if event.button == 'down': # deal with zoom in scale_factor = 1 / base_scale elif event.button == 'up': # deal with zoom out scale_factor = base_scale else: # deal with something that should never happen scale_factor = 1 print(event.button) new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor new_height = (cur_ylim[1] - cur_ylim[0]) * scale_factor relx = (cur_xlim[1] - xdata)/(cur_xlim[1] - cur_xlim[0]) rely = (cur_ylim[1] - ydata)/(cur_ylim[1] - cur_ylim[0]) ax.set_xlim([xdata - new_width * (1-relx), xdata + new_width * (relx)]) ax.set_ylim([ydata - new_height * (1-rely), ydata + new_height * (rely)]) ax.figure.canvas.draw() ax = self.ax # 只绑定一次到canvas,并且后续通过event.inaxes判断子图 self.ax.canvas.mpl_connect('scroll_event',zoom) # 移除重复的figure绑定 # fig.canvas.mpl_connect('scroll_event', zoom) return zoom def pan_factory(self): def onPress(event): ax = self.ax if event.inaxes != ax: return self.cur_xlim = ax.get_xlim() self.cur_ylim = ax.get_ylim() self.press = self.x0, self.y0, event.xdata, event.ydata self.x0, self.y0, self.xpress, self.ypress = self.press def onRelease(event): ax = self.ax self.press = None ax.figure.canvas.draw() def onMotion(event): ax = self.ax if self.press is None: return if event.inaxes != ax: return dx = event.xdata - self.xpress dy = event.ydata - self.ypress self.cur_xlim -= dx self.cur_ylim -= dy ax.set_xlim(self.cur_xlim) ax.set_ylim(self.cur_ylim) ax.figure.canvas.draw() ax = self.ax fig = ax.get_figure() # get the figure of interest # attach the call back fig.canvas.mpl_connect('button_press_event',onPress) fig.canvas.mpl_connect('button_release_event',onRelease) fig.canvas.mpl_connect('motion_notify_event',onMotion) #return the function return onMotion def setscatter(scatter_label,ax): ax.set_title(scatter_label) x,y,s,c = numpy.random.rand(4,200) s *= 200 ax.scatter(x,y,s,c) scale = 1.1 zp = ZoomPan(ax) zp.zoom_factory(base_scale=scale) # 绑定平移功能确保生效 zp.pan_factory() def main(): fig, axs = plt.subplots(nrows=1,ncols=2) setscatter('ax',axs[0]) setscatter('bx',axs[1]) fig.tight_layout() plt.show() if __name__ == '__main__': main()
关键修改点说明
- 添加事件来源判断:在
zoom函数开头加入if event.inaxes != self.ax: return,这样只有当鼠标滚动事件发生在当前子图内时,才会执行缩放逻辑,避免影响其他子图。 - 移除重复的事件绑定:删掉
fig.canvas.mpl_connect('scroll_event', zoom)这行,因为self.ax.canvas已经指向了figure的canvas,重复绑定会导致同一个事件触发多次回调。 - 补充平移功能绑定:在
setscatter函数里添加了zp.pan_factory(),确保平移功能稳定生效。
现在运行代码,两个子图就可以各自独立缩放和平移了,鼠标在哪个子图上操作,就只会影响那个子图~
内容的提问来源于stack exchange,提问作者chapter3
相关产品推荐
相关产品推荐

