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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy