如何使用 matplotlib.pyplot 应对“超出最大递归深度”

And*_*mov 1 python matplotlib

以下代码通过左键单击在画布上添加点,通过右键单击用绘制的点绘制多段线,并在光标移动时在线上绘制滑动点。唯一的问题是,由于标题原因,执行在“滑动”后很快就停止了。我怎样才能克服这个问题并随心所欲地滑动?

import matplotlib.pyplot as plt


class DumbyRemove:
    def __init__(self):
        pass

    def remove(self):
        pass

the_points = list()
drawn_points = list()
moving_point = DumbyRemove()


def draw_polyline():
    global the_points, drawn_points
    if len(the_points) < 2:
        return
    start_point = the_points[0]
    for end_point in the_points[1:]:
        xs = (start_point[0], end_point[0])
        ys = (start_point[1], end_point[1])
        start_point = end_point
        line = plt.Line2D(xs, ys, marker='.', color=(0.7, 0.3, 0.3))
        plt.gcf().gca().add_artist(line)
    drawn_points = drawn_points + the_points
    the_points = list()
    plt.show()


def button_press_callback(event):
    global the_points

    if event.button == 1:
        the_points.append((event.xdata, event.ydata))
        p = plt.Line2D((event.xdata, event.xdata), (event.ydata, event.ydata), marker='o', color='r')
        plt.gcf().gca().add_artist(p)
        plt.show()
    else:
        draw_polyline()


def handle_motion(event):
    global moving_point
    if len(drawn_points) < 2:
        return
    x = event.xdata
    start_point = drawn_points[0]
    for end_point in drawn_points[1:]:
        start_x, start_y = start_point
        end_x, end_y = end_point
        if end_x < start_x:
            end_x, start_x = start_x, end_x
            end_y, start_y = start_y, end_y
        if start_x <= x <= end_x:
            d = end_x - start_x
            lam = (x - start_x) / d
            y = start_y * (1 - lam) + end_y * lam
            moving_point.remove()
            moving_point = plt.Line2D((x, x), (y, y), marker='o', color='r')
            plt.gcf().gca().add_artist(moving_point)
            break
        start_point = end_point
    plt.show()

fig = plt.gcf()
fig.add_subplot(111, aspect='equal')

fig.canvas.mpl_connect('button_press_event', button_press_callback)
fig.canvas.mpl_connect('motion_notify_event', handle_motion)

plt.show()
Run Code Online (Sandbox Code Playgroud)

追溯:

Exception in Tkinter callback
    x = self.convert_xunits(self._x)
    File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 186, in convert_xunits
    ax = getattr(self, 'axes', None)
RuntimeError: maximum recursion depth exceeded while calling a Python object
Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1536, in __call__
    return self.func(*args)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 605, in destroy
    Gcf.destroy(self._num)
  File "C:\Python27\lib\site-packages\matplotlib\_pylab_helpers.py", line 60, in destroy
    manager.canvas.mpl_disconnect(manager._cidgcf)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 2366, in mpl_disconnect
    return self.callbacks.disconnect(cid)
  File "C:\Python27\lib\site-packages\matplotlib\cbook.py", line 552, in disconnect
    del functions[function]
  File "C:\Python27\lib\weakref.py", line 327, in __delitem__
    del self.data[ref(key)]
RuntimeError: maximum recursion depth exceeded
Run Code Online (Sandbox Code Playgroud)

And*_*mov 5

好吧,伙计们,我明白了。该问题是由于在事件处理程序中大量使用plt.show()造成的。event.canvas.draw()替换它就可以了。

  • 我可以确认这个解决方案也适用于我,我在任何鼠标事件的处理程序中调用 **plt.show()** 。更改为 **event.canvas.draw()** 解决了问题。 (2认同)