Andrey Lyubimov
Andrey Lyubimov

Reputation: 673

How to fight with "maximum recursion depth exceeded" using matplotlib.pyplot

The following code adds point on canvas by left click, draws a polyline with the drawn points by right click and also draws a sliding point on the lines while a cursor is moving. The only problem is that the execution stops pretty soon after "sliding" because of the title reason. How can I overcome this problem and slide as much as wanted?

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()

Traceback:

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

Upvotes: 1

Views: 2249

Answers (1)

Andrey Lyubimov
Andrey Lyubimov

Reputation: 673

Okey, fellas, I got it. The problem was due to intensive use of plt.show() in the event handler. Replacing it with event.canvas.draw() does the job.

Upvotes: 5

Related Questions