|
|
可以的,需要给子图添加事件监听器来实现这个功能。以下是完整的实现代码:
- import matplotlib.pyplot as plt
- import matplotlib.gridspec as gridspec
- class InteractiveFigure:
- def __init__(self):
- self.fig = plt.figure(figsize=(19.2, 10.8), dpi=100)
- self.fig.subplots_adjust(left=0.1, right=0.9, top=0.95, bottom=0.05)
-
- # 创建原始网格布局
- self.gs = gridspec.GridSpec(nrows=2, ncols=3)
- self.ax1 = self.fig.add_subplot(self.gs[0, 0])
- self.ax2 = self.fig.add_subplot(self.gs[0, 1])
- self.ax3 = self.fig.add_subplot(self.gs[0, 2])
- self.ax3r = self.ax3.twinx()
- self.ax4 = self.fig.add_subplot(self.gs[1, 0])
- self.ax5_6 = self.fig.add_subplot(self.gs[1, 1:3])
-
- # 保存原始布局信息
- self.original_layout = {
- 'fig': {'left': 0.1, 'right': 0.9, 'top': 0.95, 'bottom': 0.05},
- 'grid': self.gs,
- 'axes': [self.ax1, self.ax2, self.ax3, self.ax3r, self.ax4, self.ax5_6]
- }
-
- self.is_zoomed = False # 标记是否处于放大状态
- self.current_zoomed_axes = None # 当前被放大的坐标轴
-
- # 绑定点击事件到所有坐标轴
- self.bind_click_events()
-
- def bind_click_events(self):
- """为所有坐标轴绑定点击事件"""
- for ax in self.original_layout['axes']:
- # 跳过双Y轴中的第二个Y轴,避免重复处理
- if ax is not self.ax3r:
- ax.figure.canvas.mpl_connect('button_press_event',
- lambda event, ax=ax: self.on_click(event, ax))
-
- def on_click(self, event, ax):
- """点击事件处理函数"""
- if event.inaxes != ax:
- return
-
- if not self.is_zoomed:
- self.zoom_axes(ax)
- else:
- self.restore_layout()
-
- def zoom_axes(self, ax):
- """放大指定坐标轴"""
- # 隐藏所有其他坐标轴
- for other_ax in self.original_layout['axes']:
- other_ax.set_visible(False)
-
- # 显示点击的坐标轴及其相关坐标轴(针对双Y轴)
- if ax in [self.ax3, self.ax3r]:
- self.ax3.set_visible(True)
- self.ax3r.set_visible(True)
- else:
- ax.set_visible(True)
-
- # 调整布局:点击的坐标轴占满整个画布
- self.fig.subplots_adjust(left=0.05, right=0.95, top=0.95, bottom=0.05)
-
- # 如果是双Y轴情况,需要重新调整子图位置
- if ax in [self.ax3, self.ax3r]:
- # 移除原来的坐标轴并重新创建以重新布局
- self.ax3.remove()
- self.ax3r.remove()
-
- # 创建占满整个画布的坐标轴
- self.ax3 = self.fig.add_subplot(111)
- self.ax3r = self.ax3.twinx()
-
- # 这里需要重新绘制原始数据(为了示例,我们只创建空坐标轴)
- # 实际应用中,需要保存原始数据并重新绘制
-
- self.is_zoomed = True
- self.current_zoomed_axes = ax
- self.fig.canvas.draw()
-
- def restore_layout(self):
- """恢复原始布局"""
- # 恢复所有坐标轴的可见性
- for ax in self.original_layout['axes']:
- ax.set_visible(True)
-
- # 恢复原始布局设置
- self.fig.subplots_adjust(**self.original_layout['fig'])
-
- # 如果之前放大的是双Y轴,需要恢复原始布局
- if self.current_zoomed_axes in [self.ax3, self.ax3r]:
- # 清除当前坐标轴
- plt.clf()
-
- # 按照原始布局重新创建所有子图
- self.gs = gridspec.GridSpec(nrows=2, ncols=3)
- self.ax1 = self.fig.add_subplot(self.gs[0, 0])
- self.ax2 = self.fig.add_subplot(self.gs[0, 1])
- self.ax3 = self.fig.add_subplot(self.gs[0, 2])
- self.ax3r = self.ax3.twinx()
- self.ax4 = self.fig.add_subplot(self.gs[1, 0])
- self.ax5_6 = self.fig.add_subplot(self.gs[1, 1:3])
-
- # 这里需要重新绘制原始数据
-
- self.is_zoomed = False
- self.current_zoomed_axes = None
- self.bind_click_events() # 重新绑定事件
- self.fig.canvas.draw()
- # 使用示例
- if __name__ == "__main__":
- interactive_fig = InteractiveFigure()
-
- # 为每个子图添加一些示例数据
- interactive_fig.ax1.plot([1, 2, 3], [1, 4, 9])
- interactive_fig.ax1.set_title("子图1")
-
- interactive_fig.ax2.plot([1, 2, 3], [3, 2, 1])
- interactive_fig.ax2.set_title("子图2")
-
- interactive_fig.ax3.plot([1, 2, 3], [2, 4, 6], 'r-')
- interactive_fig.ax3.set_title("子图3(双Y轴)")
- interactive_fig.ax3.set_ylabel("左Y轴", color='r')
-
- interactive_fig.ax3r.plot([1, 2, 3], [10, 20, 30], 'b-')
- interactive_fig.ax3r.set_ylabel("右Y轴", color='b')
-
- interactive_fig.ax4.plot([1, 2, 3], [5, 5, 5])
- interactive_fig.ax4.set_title("子图4")
-
- interactive_fig.ax5_6.plot([1, 2, 3], [0, 1, 0])
- interactive_fig.ax5_6.set_title("子图5-6")
-
- plt.show()
复制代码
关键实现要点:
1. zoom_axes()方法:隐藏其他子图,将被点击的子图放大到全屏
- 对于普通子图:直接设置该子图为可见,其他为不可见
- 对于双Y轴子图:需要同时显示主坐标轴和双生坐标轴
2. restore_layout()方法:恢复原始布局
- 重新设置所有子图为可见
- 恢复原始的布局参数
- 对于双Y轴子图,需要重新创建坐标轴以确保布局正确
3. 事件绑定:
- 为每个子图绑定点击事件(跳过双生坐标轴避免重复)
- 点击时判断当前状态,执行放大或恢复操作
4. 状态管理:
- is_zoomed:标记是否处于放大状态
- current_zoomed_axes:记录当前被放大的坐标轴
- original_layout:保存原始布局信息用于恢复
注意事项:
- 在实际应用中,需要保存每个子图的绘图数据,在恢复布局时重新绘制
- 双Y轴子图需要特殊处理,确保两个坐标轴都能正确显示和隐藏
- 可以通过调整subplots_adjust参数来优化放大时的边距
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|