使用matplotlib中的button_press_event或motion_notify_event动态突出显示数据点

时间:2019-03-19 00:43:32

标签: python-3.x matplotlib

我正在尝试动态打印通过单击选择的数据点。为此,我使用了matplotlib.pyplot的button_press_event;当我使用event.xdata和event.ydata设置标题时,以下代码可以正常工作,但是当我尝试使用data [np.rint(event.xdata)]设置标题时,它将停止工作。我正在尝试显示data []的原始x和y值,因为我的数据是对事件的连续四舍五入。xdata给我正确的data索引[]

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt

plt.figure()
data = np.random.rand(10)
plt.plot(data)

def onclick(event):
    plt.cla()
    plt.plot(data)
    x = np.rint(event.xdata)
    plt.gca().set_title('data at {} = {}'.format(x, event.ydata))
    #plt.gca().set_title('data at {} = {}'.format(x, data[x]))

plt.gcf().canvas.mpl_connect('button_press_event', onclick);

有人可以告诉我为什么下面的行不起作用吗?

plt.gca().set_title('data at {} = {}'.format(x, data[x]))

我正在使用python 3和jupyter笔记本。

2 个答案:

答案 0 :(得分:0)

现在上面的代码起作用了,我试图突出显示最接近光标的点。为此,我将函数def onclick(event)更改如下:

def onclick(event):
   plt.cla()
   plt.plot(data)
   x = int(np.rint(event.xdata))
   plt.gca().set_title('data at {} = {}'.format(x, data[x]))
   plt.plot(x,data[x],'o')
   fig.canvas.draw()

这很好。 This is how it looks!!

上面的代码在单击时仍然有效,因此尝试将其更改为鼠标移动。

def on_motion(event):
    x = int(np.rint(event.xdata))
    if x < 0:
        x = 0
    plt.gca().set_title('data at {} = {}'.format(x, data[x]))
    plt.plot(x,data[x],'ro')
    plt.draw()

plt.gcf().canvas.mpl_connect('motion_notify_event',on_motion);

移动鼠标时,这将创建多个红点。看起来它没有正确重绘。 Here is the image with multiple red dots

有人可以帮忙吗!

答案 1 :(得分:0)

现在,问题从识别特定点变为显示这些点,以便可以清楚地看到它们。尤其是当数据点的数量以百万为单位时。为此,我使用了3个窗口:

  • 一个显示完整数据的窗口,其中包含百万个数据点,并带有一个矩形数据选择框。
  • 第二个窗口,显示使用上述矩形选择的数据。此外,第二个窗口有其自己的矩形数据选择框。
  • 第三个窗口,显示使用上述矩形选择的数据。

该代码是以下代码的混合:

现在,在第三个窗口中,我可以选择一个数据点并显示其详细信息。单击此链接以查看此3 window zoom解决方案的外观。代码太大,但是共享一些重要部分:

std::vector<cv::Mat> inputMats; // vector of BGR matrices (3 channels each)
std::vector<cv::Mat> splitMats;
for (const auto& mat : matrices)
{
    std::vector<cv::Mat> channels;
    cv::split(mat, channels);
    splitMats.insert(splitMats.end(), channels.begin(), channels.end());
}
cv::Mat result;
cv::merge(splitMats, result);

现在主要代码已导入,这里可以调整缩放宽度。我的图表用于160万个数据点:

class DraggableRectangle:
def __init__(self, rect, data, zoomWidth, src, zoom, otherRect = None, otherZoomWiidth = 0, moreZoom = None):
    self.rect = rect
    self.data = data
    #Primary window details
    self.zoomWidth = zoomWidth
    self.axsrc  = src 
    self.axzoom = zoom
    #Secondary optional window details
    self.otherRect = otherRect
    self.otherZoomWiidth = otherZoomWiidth
    self.axMoreZoom = moreZoom

def connect(self):
    #connect to all the events we need
    self.cidpress = self.rect.figure.canvas.mpl_connect(
        'button_press_event', self.on_press)

def on_press(self, event):
    #on button press we will see if the mouse is over the desired window
    if event.inaxes == self.axsrc: 
        x = int(np.rint(event.xdata))
        # Restricting the window to go beyond the lowest point 
        if x - (self.zoomWidth/2) < 0:
            x = 0
        else: 
            # (x - zoomWidth/2) is used to make the point of click the center of the box
            x = int(x - (self.zoomWidth/2))
        self.rect.set_x(x)
        self.zoomStart = x
        self.axzoom.set_xlim(x , x + self.zoomWidth)
        self.axzoom.set_ylim(float(self.data[x:x+self.zoomWidth].min()-0.5), 
                             float(self.data[x:x+self.zoomWidth].max()+0.5) )
        if self.otherRect == None or self.otherZoomWiidth == 0:
            self.rect.figure.canvas.draw()
        else: #If second window is present
            self.otherRect.set_x(x)
            self.otherRect.set_height(self.data[x:x+self.zoomWidth].max()+0.5)
            self.axMoreZoom.set_xlim(x , x + self.zoomWidth)
            self.axMoreZoom.set_ylim(float(self.data[x:x+self.otherZoomWiidth].min()-0.5), 
                             float(self.data[x:x+self.otherZoomWiidth].max()+0.5) )
            self.rect.figure.canvas.draw()

def disconnect(self):
    #disconnect all the stored connection ids
    self.rect.figure.canvas.mpl_disconnect(self.cidpress)

在绘制窗口时,我们需要根据xlim和ylim缩放这些值。

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.patches import Rectangle
from matplotlib import gridspec

data = np.random.gamma(2, 2, 1600000)
zoomWidth_1 = 15000
zoomWidth_2 = int(zoomWidth_1 / 12)

最后创建矩形:

allData = plt.subplot(gs[0])
allData.set(title='All Data window')
plt.plot(data, alpha=0.5)
plt.gcf().canvas.draw()

# Zoom Window
slicedData_1 = plt.subplot(gs[1])
slicedData_1.set(xlim=(0, zoomWidth_1), 
                   ylim=(float(data[0:zoomWidth_1].min()-0.5), float(data[0:zoomWidth_1].max()+0.5)), 
                   autoscale_on=False,
                   title='Zoom window')
plt.plot(data, alpha=0.5)
plt.gcf().canvas.draw()

# More Zoom window
slicedData_2 = plt.subplot(gs[2])
slicedData_2.set(xlim=(0, zoomWidth_2), 
                   ylim=(float(data[0:zoomWidth_2].min()-0.5), float(data[0:zoomWidth_2].max()+0.5)), 
                   autoscale_on=False,
                   title='More Zoom window')
plt.plot(data, alpha=0.6)
plt.gcf().canvas.draw()