如何使 matplotlib 缩放和平移工具与线标记一起使用

How do I make matplotlib zoom and pan tool work with line markers

我开发了一个程序来绘制来自光谱仪的输入。我尝试与之通信的设备额定发送不超过 3 个像素的不良信息(这部分是不可避免的)。我想要做的是让一个选择器选择 3 个可能的坏数据位,这样我就可以在固件中说明它们,因为这三个点不会改变。到目前为止,我的应用程序可以激活选取器(通过 ctrl-shift-f12 热键)并且我可以按预期 select 和 deselect 数据点。当我尝试使用 NabigationToolbar2Wx() 中提供的 matplotlibs 缩放或平移工具时,问题就来了。当我尝试使用其中任何一个时,我得到: ValueError: 'markevery' is iterable but not a valid form of numpy fancy indexing; markevery=[283, 286, 290, 292] 我正在使用 python 2.7.9,matplotlib,带有 wxPython 演示文稿。

def on_pixel_picker(self, event):
    self.CaptureMouse()
    mouseevent = event.mouseevent
    line = self.axes.get_lines()[0]
    index = list(line.get_xdata()).index(int(mouseevent.xdata))
    if mouseevent.button is not 1:
        try:
            self.markers.remove(index)
        except ValueError:
            pass
        line.set_markevery(self.markers)
        self.figure.canvas.draw()
        self.ReleaseMouse()
        return
    if index in self.markers:
        return
    self.markers.append(index)
    self.markers.sort()
    line.set_marker('o')
    line.set_markevery(self.markers)
    self.figure.canvas.draw()
    self.ReleaseMouse()

这是回溯:

File "C:\Spectrometer\ApogeeSpectrovision.py", line 28, in <module>
  application.MainLoop()
File "C:\Python27\Lib\site-packages\wx-3.0-msw\wx\_core.py", line 8657, in MainLoop
  wx.PyApp.MainLoop(self)
File "C:\Python27\Lib\site-packages\wx-3.0-msw\wx\_core.py", line 7952, in MainLoop
  return _core_.PyApp_MainLoop(*args, **kwargs)
File "C:\Python27\Lib\site-packages\matplotlib\backends\backend_wx.py", line 1016, in _onPaint
  self.draw(drawDC=drawDC)
File "C:\Python27\Lib\site-packages\matplotlib\backends\backend_wxagg.py", line 46, in draw
  FigureCanvasAgg.draw(self)
File "C:\Python27\Lib\site-packages\matplotlib\backends\backend_agg.py", line 469, in draw
  self.figure.draw(self.renderer)
File "C:\Python27\Lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper
  draw(artist, renderer, *args, **kwargs)
File "C:\Python27\Lib\site-packages\matplotlib\figure.py", line 1085, in draw
  func(*args)
File "C:\Python27\Lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper
  draw(artist, renderer, *args, **kwargs)
File "C:\Python27\Lib\site-packages\matplotlib\axes\_base.py", line 2110, in draw
  a.draw(renderer)
File "C:\Python27\Lib\site-packages\matplotlib\artist.py", line 59, in draw_wrapper
  draw(artist, renderer, *args, **kwargs)
File "C:\Python27\Lib\site-packages\matplotlib\lines.py", line 737, in draw
  affine, self.axes.transAxes)
File "C:\Python27\Lib\site-packages\matplotlib\lines.py", line 181, in _mark_every_path
  'markevery=%s' % (markevery,))

ValueError: `markevery` is iterable but not a valid form of numpy fancy indexing; markevery=[283, 286, 290, 292]

关于我为什么会收到此错误以及如何修复它的任何想法?我的数据点靠得很近,所以这种缩放和平移功能是必要的。

我为那些有兴趣或可能有同样问题的人想出来了。我先稍微解释一下这个问题。向左平移绘图时,标记将在图形移动时停留在屏幕上的相同位置;这意味着标记会在您四处移动时跟踪图形。如果您将它向左移动太远以至于该点落在线上,则会发生异常。如果将它向右移动,标记将留在线上的正确位置,但如果将它移出屏幕,则会发生异常。工具栏中的缩放工具根本不起作用。我一点击它就给了我一个例外。在 lines.py 的 matplotib 源代码深处,第 730 行左右,它检查 markevery 并相应地绘制;但是,如果 markevery 不在可见索引中,则会发生异常。

    if markevery is not None:
        subsampled = _mark_every_path(new_markevery, tpath,
                                      affine, self.axes.transData)

我进行了修复:

    if markevery is not None:
        new_markevery = []
        xdata = self.get_xdata()
        ydata = self.get_ydata()
        for mark in markevery:
            point = (xdata[mark], ydata[mark])
            if point in tpath.vertices:
                new_markevery.append(np.where(tpath.vertices==point)[0][0])
        subsampled = _mark_every_path(new_markevery, tpath,
                                      affine, self.axes.transData)

确保该点可见,并获取 tpath.vertices 的新索引,而不是整个路径的索引。这是阻止它在平移时跟踪图形的关键。此修复还解决了缩放工具问题。