Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 353275c

Browse files
committed
Break reference cycle Line2D <-> Line2D._lineFunc.
Upon drawing, Line2D objects would store a reference to one of their own bound methods as their `_lineFunc` argument. This would lead to them being gc'ed not when going out of scope, but only when the "true" gc kicks in; additionally this led to some pickle-related bugs (#3627). One can easily sidestep this problem by not storing this bound method. To check the behavior, try (py3.4+ only): ``` import gc import weakref from matplotlib import pyplot as plt def f(): fig, ax = plt.subplots() img = ax.imshow([[0, 1], [2, 3]]) weakref.finalize(img, print, "gc'ing image") l, = plt.plot([0, 1]) weakref.finalize(l, print, "gc'ing line") fig.canvas.draw() img.remove() l.remove() f() print("we have left the function") gc.collect() print("and cleaned up our mess") ``` Before the patch, the AxesImage is gc'ed when the function exits but the Line2D only upon explicit garbage collection. After the patch, both are collected immediately.
1 parent 2a7f606 commit 353275c

File tree

2 files changed

+3
-12
lines changed

2 files changed

+3
-12
lines changed

lib/matplotlib/lines.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -445,12 +445,6 @@ def __init__(self, xdata, ydata,
445445

446446
self.set_data(xdata, ydata)
447447

448-
def __getstate__(self):
449-
state = super(Line2D, self).__getstate__()
450-
# _linefunc will be restored on draw time.
451-
state.pop('_lineFunc', None)
452-
return state
453-
454448
def contains(self, mouseevent):
455449
"""
456450
Test whether the mouse event occurred on the line. The pick
@@ -784,7 +778,7 @@ def draw(self, renderer):
784778
if funcname != '_draw_nothing':
785779
tpath, affine = transf_path.get_transformed_path_and_affine()
786780
if len(tpath.vertices):
787-
self._lineFunc = getattr(self, funcname)
781+
line_func = getattr(self, funcname)
788782
gc = renderer.new_gc()
789783
self._set_gc_clip(gc)
790784

@@ -807,7 +801,7 @@ def draw(self, renderer):
807801
if self.get_sketch_params() is not None:
808802
gc.set_sketch_params(*self.get_sketch_params())
809803

810-
self._draw_lines(renderer, gc, tpath, affine.frozen())
804+
line_func(renderer, gc, tpath, affine.frozen())
811805
gc.restore()
812806

813807
if self._marker and self._markersize > 0:
@@ -1250,9 +1244,6 @@ def set_dashes(self, seq):
12501244
else:
12511245
self.set_linestyle((0, seq))
12521246

1253-
def _draw_lines(self, renderer, gc, path, trans):
1254-
self._lineFunc(renderer, gc, path, trans)
1255-
12561247
def _draw_solid(self, renderer, gc, path, trans):
12571248
gc.set_linestyle('solid')
12581249
gc.set_dashes(self._dashOffset, self._dashSeq)

lib/matplotlib/tests/test_pickle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ def test_grid():
236236
fig = manager.canvas.figure
237237
ax = fig.add_subplot(1, 1, 1)
238238
ax.grid()
239-
# Drawing the grid triggers instance methods to be attached
239+
# Drawing the grid used to trigger instance methods to be attached
240240
# to the Line2D object (_lineFunc).
241241
manager.canvas.draw()
242242

0 commit comments

Comments
 (0)