Skip to content

Commit 97eb612

Browse files
committed
Merge pull request matplotlib#3627 from pelson/pickle_bug
BUG : Fixed Image and Renderer pickling
2 parents 68b34b0 + 4ba18d4 commit 97eb612

File tree

4 files changed

+59
-9
lines changed

4 files changed

+59
-9
lines changed

lib/matplotlib/backends/backend_agg.py

+8
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ def __init__(self, width, height, dpi):
104104
if __debug__: verbose.report('RendererAgg.__init__ done',
105105
'debug-annoying')
106106

107+
def __getstate__(self):
108+
# We only want to preserve the init keywords of the Renderer.
109+
# Anything else can be re-created.
110+
return {'width': self.width, 'height': self.height, 'dpi': self.dpi}
111+
112+
def __setstate__(self, state):
113+
self.__init__(state['width'], state['height'], state['dpi'])
114+
107115
def _get_hinting_flag(self):
108116
if rcParams['text.hinting']:
109117
return LOAD_FORCE_AUTOHINT

lib/matplotlib/image.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@
1010

1111
import os
1212
import warnings
13-
import math
1413

1514
import numpy as np
16-
from numpy import ma
1715

1816
from matplotlib import rcParams
1917
import matplotlib.artist as martist
@@ -113,6 +111,12 @@ def __init__(self, ax,
113111

114112
self.update(kwargs)
115113

114+
def __getstate__(self):
115+
state = super(_AxesImageBase, self).__getstate__()
116+
# We can't pickle the C Image cached object.
117+
state.pop('_imcache', None)
118+
return state
119+
116120
def get_size(self):
117121
"""Get the numrows, numcols of the input image"""
118122
if self._A is None:

lib/matplotlib/lines.py

+6
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,12 @@ def __init__(self, xdata, ydata,
352352
self._invalidy = True
353353
self.set_data(xdata, ydata)
354354

355+
def __getstate__(self):
356+
state = super(Line2D, self).__getstate__()
357+
# _linefunc will be restored on draw time.
358+
state.pop('_lineFunc', None)
359+
return state
360+
355361
def contains(self, mouseevent):
356362
"""
357363
Test whether the mouse event occurred on the line. The pick

lib/matplotlib/tests/test_pickle.py

+39-7
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ def test_simple():
107107
plt.plot(list(xrange(10)), label='foobar')
108108
plt.legend()
109109

110+
# Uncomment to debug any unpicklable objects. This is slow so is not
111+
# uncommented by default.
110112
# recursive_pickle(fig)
111113
pickle.dump(ax, BytesIO(), pickle.HIGHEST_PROTOCOL)
112114

@@ -195,17 +197,47 @@ def test_complete():
195197

196198
def test_no_pyplot():
197199
# tests pickle-ability of a figure not created with pyplot
198-
199-
import pickle as p
200200
from matplotlib.backends.backend_pdf import FigureCanvasPdf as fc
201201
from matplotlib.figure import Figure
202202

203203
fig = Figure()
204-
can = fc(fig)
204+
_ = fc(fig)
205205
ax = fig.add_subplot(1, 1, 1)
206206
ax.plot([1, 2, 3], [1, 2, 3])
207-
208-
# Uncomment to debug any unpicklable objects. This is slow so is not
209-
# uncommented by default.
210-
# recursive_pickle(fig)
211207
pickle.dump(fig, BytesIO(), pickle.HIGHEST_PROTOCOL)
208+
209+
210+
def test_renderer():
211+
from matplotlib.backends.backend_agg import RendererAgg
212+
renderer = RendererAgg(10, 20, 30)
213+
pickle.dump(renderer, BytesIO())
214+
215+
216+
def test_image():
217+
# Prior to v1.4.0 the Image would cache data which was not picklable
218+
# once it had been drawn.
219+
from matplotlib.backends.backend_agg import new_figure_manager
220+
manager = new_figure_manager(1000)
221+
fig = manager.canvas.figure
222+
ax = fig.add_subplot(1, 1, 1)
223+
ax.imshow(np.arange(12).reshape(3, 4))
224+
manager.canvas.draw()
225+
pickle.dump(fig, BytesIO())
226+
227+
228+
def test_grid():
229+
from matplotlib.backends.backend_agg import new_figure_manager
230+
manager = new_figure_manager(1000)
231+
fig = manager.canvas.figure
232+
ax = fig.add_subplot(1, 1, 1)
233+
ax.grid()
234+
# Drawing the grid triggers instance methods to be attached
235+
# to the Line2D object (_lineFunc).
236+
manager.canvas.draw()
237+
238+
pickle.dump(ax, BytesIO())
239+
240+
241+
if __name__ == '__main__':
242+
import nose
243+
nose.runmodule(argv=['-s'])

0 commit comments

Comments
 (0)