实现多子图3D散点图的悬停标注联动功能
实现Matplotlib多3D子图悬停标注联动
要实现多3D子图间的悬停标注联动,需要通过自定义mplcursors的事件回调,同步所有子图中同一样本点的标注状态。核心思路是:捕获当前子图的悬停点索引,然后在其他子图中定位对应索引的样本点,手动触发标注显示。
以下是修改后的完整代码:
%matplotlib ipympl import plotly.express as px import matplotlib.pyplot as plt import mplcursors df = px.data.iris() fig = plt.figure(figsize=(12, 8)) ax = fig.add_subplot(121, projection='3d') # 保存散点对象,用于后续获取数据点索引 scatter1 = ax.scatter(df['sepal_length'], df['sepal_width'], df['petal_length'], marker='.') ax.set_xlabel('Sepal Length') ax.set_ylabel('Sepal Width') ax.set_zlabel('Petal Length') ax.set_title("Scatter plot of sepal length, sepal width, and petal length") ax2 = fig.add_subplot(122, projection='3d') # 保存第二个子图的散点对象 scatter2 = ax2.scatter(df['sepal_length'], df['sepal_width'], df['petal_width'], marker='.') ax2.set_xlabel('Sepal Length') ax2.set_ylabel('Sepal Width') ax2.set_zlabel('Petal Width') ax2.set_title("Scatter plot of sepal length, sepal width, and petal width") # 创建cursor对象,禁用自动高亮,改为手动控制 cursor = mplcursors.cursor(hover=True, highlight=False) def on_hover(sel): # 获取当前悬停点的索引 index = sel.target.index # 清除所有已有的高亮和标注 for c in cursor.cursors: c.clear() # 在当前子图高亮并显示标注 sel.annotation.set_text(f"样本索引: {index}\n" f"Sepal Length: {df.iloc[index]['sepal_length']:.2f}\n" f"Sepal Width: {df.iloc[index]['sepal_width']:.2f}\n" f"Petal Length: {df.iloc[index]['petal_length']:.2f}") # 在第二个子图高亮对应索引的点并显示标注 sel2 = cursor.add_highlight(scatter2.get_paths()[index], ax=ax2) sel2.annotation.set_text(f"样本索引: {index}\n" f"Sepal Length: {df.iloc[index]['sepal_length']:.2f}\n" f"Sepal Width: {df.iloc[index]['sepal_width']:.2f}\n" f"Petal Width: {df.iloc[index]['petal_width']:.2f}") # 绑定悬停事件回调 cursor.connect("add", on_hover) plt.show()
关键说明:
- 保存每个子图的
scatter对象,用于后续定位对应索引的数据点。 - 禁用mplcursors的自动高亮(
highlight=False),改为通过回调手动控制所有子图的高亮和标注。 - 在
on_hover回调中:- 获取当前悬停点的样本索引;
- 清除所有子图已有的标注,避免残留;
- 为当前子图和其他子图的对应样本点分别设置标注内容并高亮。
这样就能实现鼠标悬停任意子图的样本点时,所有子图的同一样本点自动显示对应标注。
内容的提问来源于stack exchange,提问作者user32147
相关产品推荐
相关产品推荐

