反映对多个子图的事件处理

Reflect event handling on multiple subplots

我正在尝试创建一个包含 4 个子图的交互式图。理想情况下,单击其中一个子图会在其余子图中产生相同的结果(镜像点击)。

直到现在我只能单独点击它们并使用 mpldatacursor 获取特定数据。

在此图中,单击事件将导致所有 4 个图表显示 x、y、z 的相应数据:

import matplotlib.pyplot as plt
import numpy as np
from mpldatacursor import datacursor
fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2, 
ncols=2,sharex=True, sharey=True, figsize=(60, 20))
plt.subplots_adjust(wspace=0.08, hspace=0.08)
ax1.imshow(np.random.random((10,10)))
ax2.imshow(np.random.random((10,10)))
ax3.imshow(np.random.random((10,10)))
ax4.imshow(np.random.random((10,10)))
datacursor(display='multiple',formatter='x:{x:.0f}\n  y:{y:.0f}\n z:
{z}'.format,draggable=True,fontsize=10)
plt.show()

您使用的 mpldatacursor 包无法一次注释多个图像。但是您可以编写自己的 "datacursor",为图像添加注释。

这可能看起来如下。

import matplotlib.pyplot as plt
import numpy as np

fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2, 
                                          ncols=2,sharex=True, sharey=True)
plt.subplots_adjust(wspace=0.08, hspace=0.08)
ax1.imshow(np.random.random((10,10)))
ax2.imshow(np.random.random((10,10)))
ax3.imshow(np.random.random((10,10)))
ax4.imshow(np.random.random((10,10)))

class ImageCursor():
    def __init__(self, axes, fmt='x:{x}\ny:{y}\nz:{z:.3f}'):
        self.fmt = fmt
        self.axes = axes
        self.fig = self.axes[0].figure
        self.ims = []
        self.annot = []
        for ax in self.axes:
            ax.images[0].set_picker(True)
            self.ims.append(ax.images[0])
            annot = ax.annotate("",xy=(0,0), xytext=(-30,30),
                                textcoords="offset points",
                                arrowprops=dict(arrowstyle="->",color="w",
                                                connectionstyle="arc3"),
                                va="bottom", ha="left", fontsize=10,
                                bbox=dict(boxstyle="round", fc="w"),)
            annot.set_visible(False)
            self.annot.append(annot)
        self.cid = self.fig.canvas.mpl_connect("pick_event", self.pick)

    def pick(self,event):
        e = event.mouseevent
        if e.inaxes:
            x,y = int(np.round(e.xdata)), int(np.round(e.ydata))
            self.annotate((x,y))
    def annotate(self,X):
        for annot, im in zip(self.annot, self.ims):
            z = im.get_array()[X[1],X[0]]
            annot.set_visible(True)
            annot.set_text(self.fmt.format(x=X[0],y=X[1],z=z))
            annot.xy = X
        self.fig.canvas.draw_idle()

ic = ImageCursor([ax1,ax2,ax3,ax4])            

plt.show()