Permalink
Browse files

Merge pull request #1175 from pelson/pickle2

Pickling support added. Various whitespace fixes as a result of reading *lots* of code.
  • Loading branch information...
2 parents cf7618c + 1e08190 commit 4c1e36d82161364447d7139a1e3f47f126116192 @efiring efiring committed Sep 1, 2012
Showing with 1,073 additions and 517 deletions.
  1. +11 −0 doc/users/whats_new.rst
  2. +1 −0 lib/matplotlib/__init__.py
  3. +2 −1 lib/matplotlib/_pylab_helpers.py
  4. +8 −1 lib/matplotlib/artist.py
  5. +60 −19 lib/matplotlib/axes.py
  6. +0 −1 lib/matplotlib/axis.py
  7. +1 −1 lib/matplotlib/backends/__init__.py
  8. +8 −2 lib/matplotlib/backends/backend_agg.py
  9. +51 −44 lib/matplotlib/backends/backend_cairo.py
  10. +10 −1 lib/matplotlib/backends/backend_cocoaagg.py
  11. +8 −1 lib/matplotlib/backends/backend_emf.py
  12. +7 −0 lib/matplotlib/backends/backend_fltkagg.py
  13. +8 −4 lib/matplotlib/backends/backend_gdk.py
  14. +8 −3 lib/matplotlib/backends/backend_gtk.py
  15. +8 −1 lib/matplotlib/backends/backend_gtk3agg.py
  16. +8 −1 lib/matplotlib/backends/backend_gtk3cairo.py
  17. +10 −1 lib/matplotlib/backends/backend_gtkagg.py
  18. +8 −1 lib/matplotlib/backends/backend_gtkcairo.py
  19. +12 −1 lib/matplotlib/backends/backend_macosx.py
  20. +8 −1 lib/matplotlib/backends/backend_pdf.py
  21. +9 −1 lib/matplotlib/backends/backend_pgf.py
  22. +8 −1 lib/matplotlib/backends/backend_ps.py
  23. +10 −3 lib/matplotlib/backends/backend_qt.py
  24. +10 −3 lib/matplotlib/backends/backend_qt4.py
  25. +9 −1 lib/matplotlib/backends/backend_qt4agg.py
  26. +10 −2 lib/matplotlib/backends/backend_qtagg.py
  27. +9 −1 lib/matplotlib/backends/backend_svg.py
  28. +10 −2 lib/matplotlib/backends/backend_template.py
  29. +8 −1 lib/matplotlib/backends/backend_tkagg.py
  30. +9 −0 lib/matplotlib/backends/backend_wx.py
  31. +8 −2 lib/matplotlib/backends/backend_wxagg.py
  32. +139 −70 lib/matplotlib/cbook.py
  33. +12 −10 lib/matplotlib/colorbar.py
  34. +7 −0 lib/matplotlib/contour.py
  35. +68 −3 lib/matplotlib/figure.py
  36. +3 −3 lib/matplotlib/image.py
  37. +2 −14 lib/matplotlib/legend.py
  38. +2 −19 lib/matplotlib/legend_handler.py
  39. +10 −0 lib/matplotlib/markers.py
  40. +23 −77 lib/matplotlib/offsetbox.py
  41. +25 −17 lib/matplotlib/patches.py
  42. +193 −172 lib/matplotlib/projections/polar.py
  43. +8 −11 lib/matplotlib/pyplot.py
  44. BIN lib/matplotlib/tests/baseline_images/test_pickle/multi_pickle.png
  45. +199 −0 lib/matplotlib/tests/test_pickle.py
  46. +25 −18 lib/matplotlib/ticker.py
  47. +20 −2 lib/matplotlib/transforms.py
View
11 doc/users/whats_new.rst
@@ -100,6 +100,17 @@ minimum and maximum colorbar extensions.
plt.show()
+Figures are picklable
+---------------------
+
+Philip Elson added an experimental feature to make figures picklable
+for quick and easy short-term storage of plots. Pickle files
+are not designed for long term storage, are unsupported when restoring a pickle
+saved in another matplotlib version and are insecure when restoring a pickle
+from an untrusted source. Having said this, they are useful for short term
+storage for later modification inside matplotlib.
+
+
Set default bounding box in matplotlibrc
------------------------------------------
View
1 lib/matplotlib/__init__.py
@@ -1085,6 +1085,7 @@ def tk_window_focus():
'matplotlib.tests.test_mathtext',
'matplotlib.tests.test_mlab',
'matplotlib.tests.test_patches',
+ 'matplotlib.tests.test_pickle',
'matplotlib.tests.test_rcparams',
'matplotlib.tests.test_simplification',
'matplotlib.tests.test_spines',
View
3 lib/matplotlib/_pylab_helpers.py
@@ -14,7 +14,7 @@ def error_msg(msg):
class Gcf(object):
"""
- Manage a set of integer-numbered figures.
+ Singleton to manage a set of integer-numbered figures.
This class is never instantiated; it consists of two class
attributes (a list and a dictionary), and a set of static
@@ -132,6 +132,7 @@ def set_active(manager):
Gcf._activeQue.append(manager)
Gcf.figs[manager.num] = manager
+
atexit.register(Gcf.destroy_all)
View
9 lib/matplotlib/artist.py
@@ -103,6 +103,13 @@ def __init__(self):
self._gid = None
self._snap = None
+ def __getstate__(self):
+ d = self.__dict__.copy()
+ # remove the unpicklable remove method, this will get re-added on load
+ # (by the axes) if the artist lives on an axes.
+ d['_remove_method'] = None
+ return d
+
def remove(self):
"""
Remove the artist from the figure if possible. The effect
@@ -122,7 +129,7 @@ def remove(self):
# the _remove_method attribute directly. This would be a protected
# attribute if Python supported that sort of thing. The callback
# has one parameter, which is the child to be removed.
- if self._remove_method != None:
+ if self._remove_method is not None:
self._remove_method(self)
else:
raise NotImplementedError('cannot remove artist')
View
79 lib/matplotlib/axes.py
@@ -153,9 +153,8 @@ def set_default_color_cycle(clist):
DeprecationWarning)
-class _process_plot_var_args:
+class _process_plot_var_args(object):
"""
-
Process variable length arguments to the plot command, so that
plot commands like the following are supported::
@@ -171,6 +170,14 @@ def __init__(self, axes, command='plot'):
self.command = command
self.set_color_cycle()
+ def __getstate__(self):
+ # note: it is not possible to pickle a itertools.cycle instance
+ return {'axes': self.axes, 'command': self.command}
+
+ def __setstate__(self, state):
+ self.__dict__ = state.copy()
+ self.set_color_cycle()
+
def set_color_cycle(self, clist=None):
if clist is None:
clist = rcParams['axes.color_cycle']
@@ -281,7 +288,7 @@ def _plot_args(self, tup, kwargs):
linestyle, marker, color = _process_plot_format(tup[-1])
tup = tup[:-1]
elif len(tup) == 3:
- raise ValueError, 'third arg must be a format string'
+ raise ValueError('third arg must be a format string')
else:
linestyle, marker, color = None, None, None
kw = {}
@@ -354,6 +361,7 @@ class Axes(martist.Artist):
def __str__(self):
return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds)
+
def __init__(self, fig, rect,
axisbg = None, # defaults to rc axes.facecolor
frameon = True,
@@ -488,6 +496,15 @@ def __init__(self, fig, rect,
self._ycid = self.yaxis.callbacks.connect('units finalize',
self.relim)
+ def __setstate__(self, state):
+ self.__dict__ = state
+ # put the _remove_method back on all artists contained within the axes
+ for container_name in ['lines', 'collections', 'tables', 'patches',
+ 'texts', 'images']:
+ container = getattr(self, container_name)
+ for artist in container:
+ artist._remove_method = container.remove
+
def get_window_extent(self, *args, **kwargs):
"""
get the axes bounding box in display space; *args* and
@@ -1472,7 +1489,7 @@ def _update_line_limits(self, line):
return
line_trans = line.get_transform()
-
+
if line_trans == self.transData:
data_path = path
@@ -1491,8 +1508,8 @@ def _update_line_limits(self, line):
else:
data_path = trans_to_data.transform_path(path)
else:
- # for backwards compatibility we update the dataLim with the
- # coordinate range of the given path, even though the coordinate
+ # for backwards compatibility we update the dataLim with the
+ # coordinate range of the given path, even though the coordinate
# systems are completely different. This may occur in situations
# such as when ax.transAxes is passed through for absolute
# positioning.
@@ -1502,7 +1519,7 @@ def _update_line_limits(self, line):
updatex, updatey = line_trans.contains_branch_seperately(
self.transData
)
- self.dataLim.update_from_path(data_path,
+ self.dataLim.update_from_path(data_path,
self.ignore_existing_data_limits,
updatex=updatex,
updatey=updatey)
@@ -2199,11 +2216,11 @@ def ticklabel_format(self, **kwargs):
cb = False
else:
cb = True
- raise NotImplementedError, "comma style remains to be added"
+ raise NotImplementedError("comma style remains to be added")
elif style == '':
sb = None
else:
- raise ValueError, "%s is not a valid style value"
+ raise ValueError("%s is not a valid style value")
try:
if sb is not None:
if axis == 'both' or axis == 'x':
@@ -3706,9 +3723,9 @@ def hlines(self, y, xmin, xmax, colors='k', linestyles='solid',
xmax = np.resize( xmax, y.shape )
if len(xmin)!=len(y):
- raise ValueError, 'xmin and y are unequal sized sequences'
+ raise ValueError('xmin and y are unequal sized sequences')
if len(xmax)!=len(y):
- raise ValueError, 'xmax and y are unequal sized sequences'
+ raise ValueError('xmax and y are unequal sized sequences')
verts = [ ((thisxmin, thisy), (thisxmax, thisy))
for thisxmin, thisxmax, thisy in zip(xmin, xmax, y)]
@@ -3785,9 +3802,9 @@ def vlines(self, x, ymin, ymax, colors='k', linestyles='solid',
ymax = np.resize( ymax, x.shape )
if len(ymin)!=len(x):
- raise ValueError, 'ymin and x are unequal sized sequences'
+ raise ValueError('ymin and x are unequal sized sequences')
if len(ymax)!=len(x):
- raise ValueError, 'ymax and x are unequal sized sequences'
+ raise ValueError('ymax and x are unequal sized sequences')
Y = np.array([ymin, ymax]).T
@@ -4768,7 +4785,7 @@ def make_iterable(x):
if len(height) == 1:
height *= nbars
else:
- raise ValueError, 'invalid orientation: %s' % orientation
+ raise ValueError('invalid orientation: %s' % orientation)
if len(linewidth) < nbars:
linewidth *= nbars
@@ -4826,7 +4843,7 @@ def make_iterable(x):
bottom = [bottom[i] - height[i]/2. for i in xrange(len(bottom))]
else:
- raise ValueError, 'invalid alignment: %s' % align
+ raise ValueError('invalid alignment: %s' % align)
args = zip(left, bottom, width, height, color, edgecolor, linewidth)
for l, b, w, h, c, e, lw in args:
@@ -5701,7 +5718,7 @@ def computeConfInterval(data, med, iq, bootstrap):
else:
x = [x[:,i] for i in xrange(nc)]
else:
- raise ValueError, "input x can have no more than 2 dimensions"
+ raise ValueError("input x can have no more than 2 dimensions")
if not hasattr(x[0], '__len__'):
x = [x]
col = len(x)
@@ -7069,10 +7086,10 @@ def _pcolorargs(self, funcname, *args):
Nx = X.shape[-1]
Ny = Y.shape[0]
- if len(X.shape) <> 2 or X.shape[0] == 1:
+ if len(X.shape) != 2 or X.shape[0] == 1:
x = X.reshape(1,Nx)
X = x.repeat(Ny, axis=0)
- if len(Y.shape) <> 2 or Y.shape[1] == 1:
+ if len(Y.shape) != 2 or Y.shape[1] == 1:
y = Y.reshape(Ny, 1)
Y = y.repeat(Nx, axis=1)
if X.shape != Y.shape:
@@ -8815,7 +8832,15 @@ def __init__(self, fig, *args, **kwargs):
# _axes_class is set in the subplot_class_factory
self._axes_class.__init__(self, fig, self.figbox, **kwargs)
-
+ def __reduce__(self):
+ # get the first axes class which does not inherit from a subplotbase
+ not_subplotbase = lambda c: issubclass(c, Axes) and \
+ not issubclass(c, SubplotBase)
+ axes_class = [c for c in self.__class__.mro() if not_subplotbase(c)][0]
+ r = [_PicklableSubplotClassConstructor(),
+ (axes_class,),
+ self.__getstate__()]
+ return tuple(r)
def get_geometry(self):
"""get the subplot geometry, eg 2,2,3"""
@@ -8897,6 +8922,22 @@ def subplot_class_factory(axes_class=None):
# This is provided for backward compatibility
Subplot = subplot_class_factory()
+
+class _PicklableSubplotClassConstructor(object):
+ """
+ This stub class exists to return the appropriate subplot
+ class when __call__-ed with an axes class. This is purely to
+ allow Pickling of Axes and Subplots.
+ """
+ def __call__(self, axes_class):
+ # create a dummy object instance
+ subplot_instance = _PicklableSubplotClassConstructor()
+ subplot_class = subplot_class_factory(axes_class)
+ # update the class to the desired subplot class
+ subplot_instance.__class__ = subplot_class
+ return subplot_instance
+
+
docstring.interpd.update(Axes=martist.kwdoc(Axes))
docstring.interpd.update(Subplot=martist.kwdoc(Axes))
View
1 lib/matplotlib/axis.py
@@ -597,7 +597,6 @@ class Ticker:
formatter = None
-
class Axis(artist.Artist):
"""
View
2 lib/matplotlib/backends/__init__.py
@@ -52,6 +52,6 @@ def do_nothing(*args, **kwargs): pass
matplotlib.verbose.report('backend %s version %s' % (backend,backend_version))
- return new_figure_manager, draw_if_interactive, show
+ return backend_mod, new_figure_manager, draw_if_interactive, show
View
10 lib/matplotlib/backends/backend_agg.py
@@ -385,7 +385,6 @@ def post_processing(image, dpi):
image)
-
def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
@@ -396,7 +395,14 @@ def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasAgg(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasAgg(figure)
manager = FigureManagerBase(canvas, num)
return manager
View
95 lib/matplotlib/backends/backend_cairo.py
@@ -26,15 +26,15 @@
def _fn_name(): return sys._getframe(1).f_code.co_name
try:
- import cairo
+ import cairo
except ImportError:
- raise ImportError("Cairo backend requires that pycairo is installed.")
+ raise ImportError("Cairo backend requires that pycairo is installed.")
_version_required = (1,2,0)
if cairo.version_info < _version_required:
- raise ImportError ("Pycairo %d.%d.%d is installed\n"
- "Pycairo %d.%d.%d or later is required"
- % (cairo.version_info + _version_required))
+ raise ImportError ("Pycairo %d.%d.%d is installed\n"
+ "Pycairo %d.%d.%d or later is required"
+ % (cairo.version_info + _version_required))
backend_version = cairo.version
del _version_required
@@ -183,27 +183,27 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name()))
if ismath:
- self._draw_mathtext(gc, x, y, s, prop, angle)
+ self._draw_mathtext(gc, x, y, s, prop, angle)
else:
- ctx = gc.ctx
- ctx.new_path()
- ctx.move_to (x, y)
- ctx.select_font_face (prop.get_name(),
- self.fontangles [prop.get_style()],
- self.fontweights[prop.get_weight()])
-
- size = prop.get_size_in_points() * self.dpi / 72.0
-
- ctx.save()
- if angle:
- ctx.rotate (-angle * np.pi / 180)
- ctx.set_font_size (size)
- if sys.version_info[0] < 3:
- ctx.show_text (s.encode("utf-8"))
- else:
- ctx.show_text (s)
- ctx.restore()
+ ctx = gc.ctx
+ ctx.new_path()
+ ctx.move_to (x, y)
+ ctx.select_font_face (prop.get_name(),
+ self.fontangles [prop.get_style()],
+ self.fontweights[prop.get_weight()])
+
+ size = prop.get_size_in_points() * self.dpi / 72.0
+
+ ctx.save()
+ if angle:
+ ctx.rotate (-angle * np.pi / 180)
+ ctx.set_font_size (size)
+ if sys.version_info[0] < 3:
+ ctx.show_text (s.encode("utf-8"))
+ else:
+ ctx.show_text (s)
+ ctx.restore()
def _draw_mathtext(self, gc, x, y, s, prop, angle):
if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name()))
@@ -215,28 +215,28 @@ def _draw_mathtext(self, gc, x, y, s, prop, angle):
ctx.save()
ctx.translate(x, y)
if angle:
- ctx.rotate (-angle * np.pi / 180)
+ ctx.rotate (-angle * np.pi / 180)
for font, fontsize, s, ox, oy in glyphs:
- ctx.new_path()
- ctx.move_to(ox, oy)
-
- fontProp = ttfFontProperty(font)
- ctx.save()
- ctx.select_font_face (fontProp.name,
- self.fontangles [fontProp.style],
- self.fontweights[fontProp.weight])
-
- size = fontsize * self.dpi / 72.0
- ctx.set_font_size(size)
- ctx.show_text(s.encode("utf-8"))
- ctx.restore()
+ ctx.new_path()
+ ctx.move_to(ox, oy)
+
+ fontProp = ttfFontProperty(font)
+ ctx.save()
+ ctx.select_font_face (fontProp.name,
+ self.fontangles [fontProp.style],
+ self.fontweights[fontProp.weight])
+
+ size = fontsize * self.dpi / 72.0
+ ctx.set_font_size(size)
+ ctx.show_text(s.encode("utf-8"))
+ ctx.restore()
for ox, oy, w, h in rects:
- ctx.new_path()
- ctx.rectangle (ox, oy, w, h)
- ctx.set_source_rgb (0, 0, 0)
- ctx.fill_preserve()
+ ctx.new_path()
+ ctx.rectangle (ox, oy, w, h)
+ ctx.set_source_rgb (0, 0, 0)
+ ctx.fill_preserve()
ctx.restore()
@@ -397,10 +397,17 @@ def new_figure_manager(num, *args, **kwargs): # called by backends/__init__.py
"""
Create a new figure manager instance
"""
- if _debug: print('%s.%s()' % (self.__class__.__name__, _fn_name()))
+ if _debug: print('%s()' % (_fn_name()))
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasCairo(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasCairo(figure)
manager = FigureManagerBase(canvas, num)
return manager
View
11 lib/matplotlib/backends/backend_cocoaagg.py
@@ -35,12 +35,21 @@
mplBundle = NSBundle.bundleWithPath_(os.path.dirname(__file__))
+
def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass( *args, **kwargs )
- canvas = FigureCanvasCocoaAgg(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasCocoaAgg(figure)
return FigureManagerCocoaAgg(canvas, num)
+
## Below is the original show() function:
#def show():
# for manager in Gcf.get_all_fig_managers():
View
9 lib/matplotlib/backends/backend_emf.py
@@ -688,7 +688,14 @@ def new_figure_manager(num, *args, **kwargs):
# main-level app (egg backend_gtk, backend_gtkagg) for pylab
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasEMF(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasEMF(figure)
manager = FigureManagerEMF(canvas, num)
return manager
View
7 lib/matplotlib/backends/backend_fltkagg.py
@@ -78,6 +78,13 @@ def new_figure_manager(num, *args, **kwargs):
"""
FigureClass = kwargs.pop('FigureClass', Figure)
figure = FigureClass(*args, **kwargs)
+ return new_figure_manager_given_figure(num, figure)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
window = Fltk.Fl_Double_Window(10,10,30,30)
canvas = FigureCanvasFltkAgg(figure)
window.end()
View
12 lib/matplotlib/backends/backend_gdk.py
@@ -422,11 +422,15 @@ def new_figure_manager(num, *args, **kwargs):
"""
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGDK(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGDK(figure)
manager = FigureManagerBase(canvas, num)
- # equals:
- #manager = FigureManagerBase (FigureCanvasGDK (Figure(*args, **kwargs),
- # num)
return manager
View
11 lib/matplotlib/backends/backend_gtk.py
@@ -90,10 +90,15 @@ def new_figure_manager(num, *args, **kwargs):
"""
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGTK(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGTK(figure)
manager = FigureManagerGTK(canvas, num)
- # equals:
- #manager = FigureManagerGTK(FigureCanvasGTK(Figure(*args, **kwargs), num)
return manager
View
9 lib/matplotlib/backends/backend_gtk3agg.py
@@ -78,7 +78,14 @@ def new_figure_manager(num, *args, **kwargs):
"""
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGTK3Agg(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGTK3Agg(figure)
manager = FigureManagerGTK3Agg(canvas, num)
return manager
View
9 lib/matplotlib/backends/backend_gtk3cairo.py
@@ -45,7 +45,14 @@ def new_figure_manager(num, *args, **kwargs):
"""
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGTK3Cairo(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGTK3Cairo(figure)
manager = FigureManagerGTK3Cairo(canvas, num)
return manager
View
11 lib/matplotlib/backends/backend_gtkagg.py
@@ -33,17 +33,26 @@ def _get_toolbar(self, canvas):
toolbar = None
return toolbar
+
def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
"""
if DEBUG: print('backend_gtkagg.new_figure_manager')
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGTKAgg(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGTKAgg(figure)
return FigureManagerGTKAgg(canvas, num)
if DEBUG: print('backend_gtkagg.new_figure_manager done')
+
class FigureCanvasGTKAgg(FigureCanvasGTK, FigureCanvasAgg):
filetypes = FigureCanvasGTK.filetypes.copy()
filetypes.update(FigureCanvasAgg.filetypes)
View
9 lib/matplotlib/backends/backend_gtkcairo.py
@@ -26,7 +26,14 @@ def new_figure_manager(num, *args, **kwargs):
if _debug: print('backend_gtkcairo.%s()' % fn_name())
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasGTKCairo(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasGTKCairo(figure)
return FigureManagerGTK(canvas, num)
View
13 lib/matplotlib/backends/backend_macosx.py
@@ -233,9 +233,20 @@ def new_figure_manager(num, *args, **kwargs):
"""
if not _macosx.verify_main_display():
import warnings
- warnings.warn("Python is not installed as a framework. The MacOSX backend may not work correctly if Python is not installed as a framework. Please see the Python documentation for more information on installing Python as a framework on Mac OS X")
+ warnings.warn("Python is not installed as a framework. The MacOSX "
+ "backend may not work correctly if Python is not "
+ "installed as a framework. Please see the Python "
+ "documentation for more information on installing "
+ "Python as a framework on Mac OS X")
FigureClass = kwargs.pop('FigureClass', Figure)
figure = FigureClass(*args, **kwargs)
+ return new_figure_manager_given_figure(num, figure)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
canvas = FigureCanvasMac(figure)
manager = FigureManagerMac(canvas, num)
return manager
View
9 lib/matplotlib/backends/backend_pdf.py
@@ -2182,7 +2182,14 @@ def new_figure_manager(num, *args, **kwargs):
# main-level app (egg backend_gtk, backend_gtkagg) for pylab
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasPdf(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasPdf(figure)
manager = FigureManagerPdf(canvas, num)
return manager
View
10 lib/matplotlib/backends/backend_pgf.py
@@ -598,6 +598,7 @@ class GraphicsContextPgf(GraphicsContextBase):
def draw_if_interactive():
pass
+
def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
@@ -608,7 +609,14 @@ def new_figure_manager(num, *args, **kwargs):
# main-level app (egg backend_gtk, backend_gtkagg) for pylab
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasPgf(thisFig)
+ return new_figure_manager_given_figure(thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasPgf(figure)
manager = FigureManagerPgf(canvas, num)
return manager
View
9 lib/matplotlib/backends/backend_ps.py
@@ -944,7 +944,14 @@ def shouldstroke(self):
def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasPS(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasPS(figure)
manager = FigureManagerPS(canvas, num)
return manager
View
13 lib/matplotlib/backends/backend_qt.py
@@ -69,9 +69,16 @@ def new_figure_manager( num, *args, **kwargs ):
Create a new figure manager instance
"""
FigureClass = kwargs.pop('FigureClass', Figure)
- thisFig = FigureClass( *args, **kwargs )
- canvas = FigureCanvasQT( thisFig )
- manager = FigureManagerQT( canvas, num )
+ thisFig = FigureClass(*args, **kwargs)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasQT(figure)
+ manager = FigureManagerQT(canvas, num)
return manager
View
13 lib/matplotlib/backends/backend_qt4.py
@@ -72,9 +72,16 @@ def new_figure_manager( num, *args, **kwargs ):
"""
Create a new figure manager instance
"""
- thisFig = Figure( *args, **kwargs )
- canvas = FigureCanvasQT( thisFig )
- manager = FigureManagerQT( canvas, num )
+ thisFig = Figure(*args, **kwargs)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasQT(figure)
+ manager = FigureManagerQT(canvas, num)
return manager
View
10 lib/matplotlib/backends/backend_qt4agg.py
@@ -23,9 +23,17 @@ def new_figure_manager( num, *args, **kwargs ):
if DEBUG: print('backend_qtagg.new_figure_manager')
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass( *args, **kwargs )
- canvas = FigureCanvasQTAgg( thisFig )
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasQTAgg(figure)
return FigureManagerQT( canvas, num )
+
class NavigationToolbar2QTAgg(NavigationToolbar2QT):
def _get_canvas(self, fig):
return FigureCanvasQTAgg(fig)
View
12 lib/matplotlib/backends/backend_qtagg.py
@@ -23,8 +23,16 @@ def new_figure_manager( num, *args, **kwargs ):
if DEBUG: print('backend_qtagg.new_figure_manager')
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass( *args, **kwargs )
- canvas = FigureCanvasQTAgg( thisFig )
- return FigureManagerQTAgg( canvas, num )
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasQTAgg(figure)
+ return FigureManagerQTAgg(canvas, num)
+
class NavigationToolbar2QTAgg(NavigationToolbar2QT):
def _get_canvas(self, fig):
View
10 lib/matplotlib/backends/backend_svg.py
@@ -1151,10 +1151,18 @@ class FigureManagerSVG(FigureManagerBase):
def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasSVG(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasSVG(figure)
manager = FigureManagerSVG(canvas, num)
return manager
+
svgProlog = u"""\
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
View
12 lib/matplotlib/backends/backend_template.py
@@ -184,13 +184,21 @@ def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
"""
- # if a main-level app must be created, this is the usual place to
+ # if a main-level app must be created, this (and
+ # new_figure_manager_given_figure) is the usual place to
# do it -- see backend_wx, backend_wxagg and backend_tkagg for
# examples. Not all GUIs require explicit instantiation of a
# main-level app (egg backend_gtk, backend_gtkagg) for pylab
FigureClass = kwargs.pop('FigureClass', Figure)
thisFig = FigureClass(*args, **kwargs)
- canvas = FigureCanvasTemplate(thisFig)
+ return new_figure_manager_given_figure(num, thisFig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ canvas = FigureCanvasTemplate(figure)
manager = FigureManagerTemplate(canvas, num)
return manager
View
9 lib/matplotlib/backends/backend_tkagg.py
@@ -74,9 +74,16 @@ def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
"""
- _focus = windowing.FocusManager()
FigureClass = kwargs.pop('FigureClass', Figure)
figure = FigureClass(*args, **kwargs)
+ return new_figure_manager_given_figure(num, figure)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ _focus = windowing.FocusManager()
window = Tk.Tk()
if Tk.TkVersion >= 8.5:
View
9 lib/matplotlib/backends/backend_wx.py
@@ -1456,13 +1456,22 @@ def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
fig = FigureClass(*args, **kwargs)
+ return new_figure_manager_given_figure(num, fig)
+
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ fig = figure
frame = FigureFrameWx(num, fig)
figmgr = frame.get_figure_manager()
if matplotlib.is_interactive():
figmgr.frame.Show()
return figmgr
+
class FigureFrameWx(wx.Frame):
def __init__(self, num, fig):
# On non-Windows platform, explicitly set the position - fix
View
10 lib/matplotlib/backends/backend_wxagg.py
@@ -121,14 +121,20 @@ def new_figure_manager(num, *args, **kwargs):
FigureClass = kwargs.pop('FigureClass', Figure)
fig = FigureClass(*args, **kwargs)
- frame = FigureFrameWxAgg(num, fig)
+
+ return new_figure_manager_given_figure(num, fig)
+
+def new_figure_manager_given_figure(num, figure):
+ """
+ Create a new figure manager instance for the given figure.
+ """
+ frame = FigureFrameWxAgg(num, figure)
figmgr = frame.get_figure_manager()
if matplotlib.is_interactive():
figmgr.frame.Show()
return figmgr
-
#
# agg/wxPython image conversion functions (wxPython >= 2.8)
#
View
209 lib/matplotlib/cbook.py
@@ -152,6 +152,90 @@ def __call__(self, s):
if self.is_missing(s): return self.missingval
return int(s)
+
+class _BoundMethodProxy(object):
+ '''
+ Our own proxy object which enables weak references to bound and unbound
+ methods and arbitrary callables. Pulls information about the function,
+ class, and instance out of a bound method. Stores a weak reference to the
+ instance to support garbage collection.
+
+ @organization: IBM Corporation
+ @copyright: Copyright (c) 2005, 2006 IBM Corporation
+ @license: The BSD License
+
+ Minor bugfixes by Michael Droettboom
+ '''
+ def __init__(self, cb):
+ try:
+ try:
+ self.inst = ref(cb.im_self)
+ except TypeError:
+ self.inst = None
+ self.func = cb.im_func
+ self.klass = cb.im_class
+ except AttributeError:
+ self.inst = None
+ self.func = cb
+ self.klass = None
+
+ def __getstate__(self):
+ d = self.__dict__.copy()
+ # de-weak reference inst
+ inst = d['inst']
+ if inst is not None:
+ d['inst'] = inst()
+ return d
+
+ def __setstate__(self, statedict):
+ self.__dict__ = statedict
+ inst = statedict['inst']
+ # turn inst back into a weakref
+ if inst is not None:
+ self.inst = ref(inst)
+
+ def __call__(self, *args, **kwargs):
+ '''
+ Proxy for a call to the weak referenced object. Take
+ arbitrary params to pass to the callable.
+
+ Raises `ReferenceError`: When the weak reference refers to
+ a dead object
+ '''
+ if self.inst is not None and self.inst() is None:
+ raise ReferenceError
+ elif self.inst is not None:
+ # build a new instance method with a strong reference to the instance
+ if sys.version_info[0] >= 3:
+ mtd = types.MethodType(self.func, self.inst())
+ else:
+ mtd = new.instancemethod(self.func, self.inst(), self.klass)
+ else:
+ # not a bound method, just return the func
+ mtd = self.func
+ # invoke the callable and return the result
+ return mtd(*args, **kwargs)
+
+ def __eq__(self, other):
+ '''
+ Compare the held function and instance with that held by
+ another proxy.
+ '''
+ try:
+ if self.inst is None:
+ return self.func == other.func and other.inst is None
+ else:
+ return self.func == other.func and self.inst() == other.inst()
+ except Exception:
+ return False
+
+ def __ne__(self, other):
+ '''
+ Inverse of __eq__.
+ '''
+ return not self.__eq__(other)
+
+
class CallbackRegistry:
"""
Handle registering and disconnecting for a set of signals and
@@ -190,73 +274,6 @@ def ondrink(x):
`"Mindtrove" blog
<http://mindtrove.info/articles/python-weak-references/>`_.
"""
- class BoundMethodProxy(object):
- '''
- Our own proxy object which enables weak references to bound and unbound
- methods and arbitrary callables. Pulls information about the function,
- class, and instance out of a bound method. Stores a weak reference to the
- instance to support garbage collection.
-
- @organization: IBM Corporation
- @copyright: Copyright (c) 2005, 2006 IBM Corporation
- @license: The BSD License
-
- Minor bugfixes by Michael Droettboom
- '''
- def __init__(self, cb):
- try:
- try:
- self.inst = ref(cb.im_self)
- except TypeError:
- self.inst = None
- self.func = cb.im_func
- self.klass = cb.im_class
- except AttributeError:
- self.inst = None
- self.func = cb
- self.klass = None
-
- def __call__(self, *args, **kwargs):
- '''
- Proxy for a call to the weak referenced object. Take
- arbitrary params to pass to the callable.
-
- Raises `ReferenceError`: When the weak reference refers to
- a dead object
- '''
- if self.inst is not None and self.inst() is None:
- raise ReferenceError
- elif self.inst is not None:
- # build a new instance method with a strong reference to the instance
- if sys.version_info[0] >= 3:
- mtd = types.MethodType(self.func, self.inst())
- else:
- mtd = new.instancemethod(self.func, self.inst(), self.klass)
- else:
- # not a bound method, just return the func
- mtd = self.func
- # invoke the callable and return the result
- return mtd(*args, **kwargs)
-
- def __eq__(self, other):
- '''
- Compare the held function and instance with that held by
- another proxy.
- '''
- try:
- if self.inst is None:
- return self.func == other.func and other.inst is None
- else:
- return self.func == other.func and self.inst() == other.inst()
- except Exception:
- return False
-
- def __ne__(self, other):
- '''
- Inverse of __eq__.
- '''
- return not self.__eq__(other)
-
def __init__(self, *args):
if len(args):
warnings.warn(
@@ -266,6 +283,15 @@ def __init__(self, *args):
self._cid = 0
self._func_cid_map = {}
+ def __getstate__(self):
+ # We cannot currently pickle the callables in the registry, so
+ # return an empty dictionary.
+ return {}
+
+ def __setstate__(self, state):
+ # re-initialise an empty callback registry
+ self.__init__()
+
def connect(self, s, func):
"""
register *func* to be called when a signal *s* is generated
@@ -279,7 +305,7 @@ def connect(self, s, func):
cid = self._cid
self._func_cid_map[s][func] = cid
self.callbacks.setdefault(s, dict())
- proxy = self.BoundMethodProxy(func)
+ proxy = _BoundMethodProxy(func)
self.callbacks[s][cid] = proxy
return cid
@@ -375,7 +401,7 @@ class silent_list(list):
"""
override repr when returning a list of matplotlib artists to
prevent long, meaningless output. This is meant to be used for a
- homogeneous list of a give type
+ homogeneous list of a given type
"""
def __init__(self, type, seq=None):
self.type = type
@@ -385,7 +411,15 @@ def __repr__(self):
return '<a list of %d %s objects>' % (len(self), self.type)
def __str__(self):
- return '<a list of %d %s objects>' % (len(self), self.type)
+ return repr(self)
+
+ def __getstate__(self):
+ # store a dictionary of this SilentList's state
+ return {'type': self.type, 'seq': self[:]}
+
+ def __setstate__(self, state):
+ self.type = state['type']
+ self.extend(state['seq'])
def strip_math(s):
'remove latex formatting from mathtext'
@@ -1879,6 +1913,41 @@ def is_math_text(s):
return even_dollars
+
+class _NestedClassGetter(object):
+ # recipe from http://stackoverflow.com/a/11493777/741316
+ """
+ When called with the containing class as the first argument,
+ and the name of the nested class as the second argument,
+ returns an instance of the nested class.
+ """
+ def __call__(self, containing_class, class_name):
+ nested_class = getattr(containing_class, class_name)
+
+ # make an instance of a simple object (this one will do), for which we
+ # can change the __class__ later on.
+ nested_instance = _NestedClassGetter()
+
+ # set the class of the instance, the __init__ will never be called on
+ # the class but the original state will be set later on by pickle.
+ nested_instance.__class__ = nested_class
+ return nested_instance
+
+
+class _InstanceMethodPickler(object):
+ """
+ Pickle cannot handle instancemethod saving. _InstanceMethodPickler
+ provides a solution to this.
+ """
+ def __init__(self, instancemethod):
+ """Takes an instancemethod as its only argument."""
+ self.parent_obj = instancemethod.im_self
+ self.instancemethod_name = instancemethod.im_func.__name__
+
+ def get_instancemethod(self):
+ return getattr(self.parent_obj, self.instancemethod_name)
+
+
# Numpy > 1.6.x deprecates putmask in favor of the new copyto.
# So long as we support versions 1.6.x and less, we need the
# following local version of putmask. We choose to make a
View
22 lib/matplotlib/colorbar.py
@@ -185,6 +185,12 @@
docstring.interpd.update(colorbar_doc=colorbar_doc)
+def _set_ticks_on_axis_warn(*args, **kw):
+ # a top level function which gets put in at the axes'
+ # set_xticks set_yticks by _patch_ax
+ warnings.warn("Use the colorbar set_ticks() method instead.")
+
+
class ColorbarBase(cm.ScalarMappable):
'''
Draw a colorbar in an existing axes.
@@ -287,11 +293,10 @@ def _extend_upper(self):
return self.extend in ('both', 'max')
def _patch_ax(self):
- def _warn(*args, **kw):
- warnings.warn("Use the colorbar set_ticks() method instead.")
-
- self.ax.set_xticks = _warn
- self.ax.set_yticks = _warn
+ # bind some methods to the axes to warn users
+ # against using those methods.
+ self.ax.set_xticks = _set_ticks_on_axis_warn
+ self.ax.set_yticks = _set_ticks_on_axis_warn
def draw_all(self):
'''
@@ -531,16 +536,13 @@ def _ticker(self):
intv = self._values[0], self._values[-1]
else:
intv = self.vmin, self.vmax
- locator.create_dummy_axis()
- formatter.create_dummy_axis()
+ locator.create_dummy_axis(minpos=intv[0])
+ formatter.create_dummy_axis(minpos=intv[0])
locator.set_view_interval(*intv)
locator.set_data_interval(*intv)
formatter.set_view_interval(*intv)
formatter.set_data_interval(*intv)
- # the dummy axis is expecting a minpos
- locator.axis.get_minpos = lambda : intv[0]
- formatter.axis.get_minpos = lambda : intv[0]
b = np.array(locator())
ticks = self._locate(b)
inrange = (ticks > -0.001) & (ticks < 1.001)
View
7 lib/matplotlib/contour.py
@@ -851,6 +851,13 @@ def __init__(self, ax, *args, **kwargs):
self.collections.append(col)
self.changed() # set the colors
+ def __getstate__(self):
+ state = self.__dict__.copy()
+ # the C object Cntr cannot currently be pickled. This isn't a big issue
+ # as it is not actually used once the contour has been calculated
+ state['Cntr'] = None
+ return state
+
def legend_elements(self, variable_name='x', str_format=str):
"""
Return a list of artist and labels suitable for passing through
View
71 lib/matplotlib/figure.py
@@ -17,12 +17,15 @@
import numpy as np
-from matplotlib import rcParams, docstring
+from matplotlib import rcParams
+from matplotlib import docstring
+from matplotlib import __version__ as _mpl_version
import matplotlib.artist as martist
from matplotlib.artist import Artist, allow_rasterization
import matplotlib.cbook as cbook
+
from matplotlib.cbook import Stack, iterable
from matplotlib import _image
@@ -114,7 +117,6 @@ def add(self, key, a):
a_existing = self.get(key)
if a_existing is not None:
Stack.remove(self, (key, a_existing))
- import warnings
warnings.warn(
"key %s already existed; Axes is being replaced" % key)
# I don't think the above should ever happen.
@@ -1170,11 +1172,74 @@ def _gci(self):
return im
return None
+ def __getstate__(self):
+ state = self.__dict__.copy()
+ # the axobservers cannot currently be pickled.
+ # Additionally, the canvas cannot currently be pickled, but this has
+ # the benefit of meaning that a figure can be detached from one canvas,
+ # and re-attached to another.
+ for attr_to_pop in ('_axobservers', 'show', 'canvas', '_cachedRenderer') :
+ state.pop(attr_to_pop, None)
+
+ # add version information to the state
+ state['__mpl_version__'] = _mpl_version
+
+ # check to see if the figure has a manager and whether it is registered
+ # with pyplot
+ if getattr(self.canvas, 'manager', None) is not None:
+ manager = self.canvas.manager
+ import matplotlib._pylab_helpers
+ if manager in matplotlib._pylab_helpers.Gcf.figs.viewvalues():
+ state['_restore_to_pylab'] = True
+
+ return state
+
+ def __setstate__(self, state):
+ version = state.pop('__mpl_version__')
+ restore_to_pylab = state.pop('_restore_to_pylab', False)
+
+ if version != _mpl_version:
+ import warnings
+ warnings.warn("This figure was saved with matplotlib version %s "
+ "and is unlikely to function correctly." %
+ (version, ))
+
+ self.__dict__ = state
+
+ # re-initialise some of the unstored state information
+ self._axobservers = []
+ self.canvas = None
+
+ if restore_to_pylab:
+ # lazy import to avoid circularity
+ import matplotlib.pyplot as plt
+ import matplotlib._pylab_helpers as pylab_helpers
+ allnums = plt.get_fignums()
+ num = max(allnums) + 1 if allnums else 1
+ mgr = plt._backend_mod.new_figure_manager_given_figure(num, self)
+
+ # XXX The following is a copy and paste from pyplot. Consider
+ # factoring to pylab_helpers
+
+ if self.get_label():
+ mgr.set_window_title(self.get_label())
+
+ # make this figure current on button press event
+ def make_active(event):
+ pylab_helpers.Gcf.set_active(mgr)
+
+ mgr._cidgcf = mgr.canvas.mpl_connect('button_press_event',
+ make_active)
+
+ pylab_helpers.Gcf.set_active(mgr)
+ self.number = num
+
+ plt.draw_if_interactive()
+
def add_axobserver(self, func):
'whenever the axes state change, ``func(self)`` will be called'
self._axobservers.append(func)
-
def savefig(self, *args, **kwargs):
"""
Save the current figure.
View
6 lib/matplotlib/image.py
@@ -1075,10 +1075,10 @@ def get_window_extent(self, renderer=None):
else:
raise ValueError("unknown type of bbox")
-
def contains(self, mouseevent):
"""Test whether the mouse event occured within the image."""
- if callable(self._contains): return self._contains(self,mouseevent)
+ if callable(self._contains):
+ return self._contains(self, mouseevent)
if not self.get_visible():# or self.get_figure()._renderer is None:
return False,{}
@@ -1137,7 +1137,7 @@ def make_image(self, renderer, magnification=1.0):
numrows, numcols = self._A.shape[:2]
if not self.interp_at_native and widthDisplay==numcols and heightDisplay==numrows:
- im.set_interpolation(0)
+ im.set_interpolation(0)
# resize viewport to display
rx = widthDisplay / numcols
View
16 lib/matplotlib/legend.py
@@ -236,7 +236,6 @@ def __init__(self, parent, handles, labels,
self.legendHandles = []
self._legend_title_box = None
-
self._handler_map = handler_map
localdict = locals()
@@ -386,7 +385,6 @@ def _set_artist_props(self, a):
a.set_axes(self.axes)
a.set_transform(self.get_transform())
-
def _set_loc(self, loc):
# find_offset function will be provided to _legend_box and
# _legend_box will draw itself at the location of the return
@@ -415,7 +413,7 @@ def _findoffset_best(self, width, height, xdescent, ydescent, renderer):
return ox+xdescent, oy+ydescent
def _findoffset_loc(self, width, height, xdescent, ydescent, renderer):
- "Heper function to locate the legend using the location code"
+ "Helper function to locate the legend using the location code"
if iterable(self._loc) and len(self._loc)==2:
# when loc is a tuple of axes(or figure) coordinates.
@@ -433,10 +431,8 @@ def draw(self, renderer):
"Draw everything that belongs to the legend"
if not self.get_visible(): return
-
renderer.open_group('legend')
-
fontsize = renderer.points_to_pixels(self._fontsize)
# if mode == fill, set the width of the legend_box to the
@@ -463,7 +459,6 @@ def draw(self, renderer):
renderer.close_group('legend')
-
def _approx_text_height(self, renderer=None):
"""
Return the approximate height of the text. This is used to place
@@ -577,7 +572,6 @@ def _init_legend_box(self, handles, labels):
# is an instance of offsetbox.TextArea which contains legend
# text.
-
text_list = [] # the list of text instances
handle_list = [] # the list of text instances
@@ -589,22 +583,20 @@ def _init_legend_box(self, handles, labels):
labelboxes = []
handleboxes = []
-
# The approximate height and descent of text. These values are
# only used for plotting the legend handle.
descent = 0.35*self._approx_text_height()*(self.handleheight - 0.7)
# 0.35 and 0.7 are just heuristic numbers. this may need to be improbed
height = self._approx_text_height() * self.handleheight - descent
# each handle needs to be drawn inside a box of (x, y, w, h) =
- # (0, -descent, width, height). And their corrdinates should
+ # (0, -descent, width, height). And their coordinates should
# be given in the display coordinates.
# The transformation of each handle will be automatically set
# to self.get_trasnform(). If the artist does not uses its
# default trasnform (eg, Collections), you need to
# manually set their transform to the self.get_transform().
-
legend_handler_map = self.get_legend_handler_map()
for orig_handle, lab in zip(handles, labels):
@@ -632,12 +624,8 @@ def _init_legend_box(self, handles, labels):
handlebox)
handle_list.append(handle)
-
-
-
handleboxes.append(handlebox)
-
if len(handleboxes) > 0:
# We calculate number of rows in each column. The first
View
21 lib/matplotlib/legend_handler.py
@@ -154,10 +154,9 @@ def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize):
return xdata, xdata_marker
-
class HandlerNpointsYoffsets(HandlerNpoints):
def __init__(self, numpoints=None, yoffsets=None, **kw):
- HandlerNpoints.__init__(self,numpoints=numpoints, **kw)
+ HandlerNpoints.__init__(self, numpoints=numpoints, **kw)
self._yoffsets = yoffsets
def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize):
@@ -169,17 +168,13 @@ def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize):
return ydata
-
-
-
class HandlerLine2D(HandlerNpoints):
"""
Handler for Line2D instances
"""
def __init__(self, marker_pad=0.3, numpoints=None, **kw):
HandlerNpoints.__init__(self, marker_pad=marker_pad, numpoints=numpoints, **kw)
-
def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize,
trans):
@@ -198,7 +193,6 @@ def create_artists(self, legend, orig_handle,
legline.set_drawstyle('default')
legline.set_marker("")
-
legline_marker = Line2D(xdata_marker, ydata[:len(xdata_marker)])
self.update_prop(legline_marker, orig_handle, legend)
#legline_marker.update_from(orig_handle)
@@ -217,7 +211,6 @@ def create_artists(self, legend, orig_handle,
return [legline, legline_marker]
-
class HandlerPatch(HandlerBase):
"""
Handler for Patches
@@ -250,7 +243,6 @@ def create_artists(self, legend, orig_handle,
return [p]
-
class HandlerLineCollection(HandlerLine2D):
"""
Handler for LineCollections
@@ -285,7 +277,6 @@ def create_artists(self, legend, orig_handle,
return [legline]
-
class HandlerRegularPolyCollection(HandlerNpointsYoffsets):
"""
Handler for RegularPolyCollections.
@@ -340,11 +331,9 @@ def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize,
trans):
-
xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent,
width, height, fontsize)
-
ydata = self.get_ydata(legend, xdescent, ydescent,
width, height, fontsize)
@@ -362,6 +351,7 @@ def create_artists(self, legend, orig_handle,
return [p]
+
class HandlerPathCollection(HandlerRegularPolyCollection):
"""
Handler for PathCollections, which are used by scatter
@@ -410,8 +400,6 @@ def get_err_size(self, legend, xdescent, ydescent, width, height, fontsize):
return xerr_size, yerr_size
-
-
def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize,
trans):
@@ -431,7 +419,6 @@ def create_artists(self, legend, orig_handle,
xerr_size, yerr_size = self.get_err_size(legend, xdescent, ydescent,
width, height, fontsize)
-
legline_marker = Line2D(xdata_marker, ydata_marker)
# when plotlines are None (only errorbars are drawn), we just
@@ -452,7 +439,6 @@ def create_artists(self, legend, orig_handle,
newsz = legline_marker.get_markersize()*legend.markerscale
legline_marker.set_markersize(newsz)
-
handle_barlinecols = []
handle_caplines = []
@@ -501,7 +487,6 @@ def create_artists(self, legend, orig_handle,
return artists
-
class HandlerStem(HandlerNpointsYoffsets):
"""
Handler for Errorbars
@@ -516,7 +501,6 @@ def __init__(self, marker_pad=0.3, numpoints=None,
self._bottom = bottom
-
def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize):
if self._yoffsets is None:
ydata = height*(0.5*legend._scatteryoffsets + 0.5)
@@ -525,7 +509,6 @@ def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize):
return ydata
-
def create_artists(self, legend, orig_handle,
xdescent, ydescent, width, height, fontsize,
trans):
View
10 lib/matplotlib/markers.py
@@ -113,6 +113,16 @@ def __init__(self, marker=None, fillstyle='full'):
self.set_marker(marker)
self.set_fillstyle(fillstyle)
+ def __getstate__(self):
+ d = self.__dict__.copy()
+ d.pop('_marker_function')
+ return d
+
+ def __setstate__(self, statedict):
+ self.__dict__ = statedict
+ self.set_marker(self._marker)
+ self._recache()
+
def _recache(self):
self._path = Path(np.empty((0,2)))
self._transform = IdentityTransform()
View
100 lib/matplotlib/offsetbox.py
@@ -131,7 +131,6 @@ def _get_aligned_offsets(hd_list, height, align="baseline"):
return height, descent, offsets
-
class OffsetBox(martist.Artist):
"""
The OffsetBox is a simple container artist. The child artist are meant
@@ -144,6 +143,24 @@ def __init__(self, *args, **kwargs):
self._children = []
self._offset = (0, 0)
+ def __getstate__(self):
+ state = martist.Artist.__getstate__(self)
+
+ # pickle cannot save instancemethods, so handle them here
+ from cbook import _InstanceMethodPickler
+ import inspect
+
+ offset = state['_offset']
+ if inspect.ismethod(offset):
+ state['_offset'] = _InstanceMethodPickler(offset)
+ return state
+
+ def __setstate__(self, state):
+ self.__dict__ = state
+ from cbook import _InstanceMethodPickler
+ if isinstance(self._offset, _InstanceMethodPickler):
+ self._offset = self._offset.get_instancemethod()
+
def set_figure(self, fig):
"""
Set the figure
@@ -343,7 +360,7 @@ def get_extent_offsets(self, renderer):
class HPacker(PackerBase):
"""
The HPacker has its children packed horizontally. It automatically
- adjust the relative positions of children in the drawing time.
+ adjusts the relative positions of children at draw time.
"""
def __init__(self, pad=None, sep=None, width=None, height=None,
align="baseline", mode="fixed",
@@ -364,12 +381,10 @@ def __init__(self, pad=None, sep=None, width=None, height=None,
super(HPacker, self).__init__(pad, sep, width, height,
align, mode, children)
-
def get_extent_offsets(self, renderer):
"""
update offset of children and return the extents of the box
"""
-
dpicor = renderer.points_to_pixels(1.)
pad = self.pad * dpicor
sep = self.sep * dpicor
@@ -391,7 +406,6 @@ def get_extent_offsets(self, renderer):
self.height,
self.align)
-
pack_list = [(w, xd) for w,h,xd,yd in whd_list]
width, xoffsets_ = _get_packed_offsets(pack_list, self.width,
sep, self.mode)
@@ -406,8 +420,6 @@ def get_extent_offsets(self, renderer):
zip(xoffsets, yoffsets)
-
-
class PaddedBox(OffsetBox):
def __init__(self, child, pad=None, draw_frame=False, patch_attrs=None):
"""
@@ -438,7 +450,6 @@ def __init__(self, child, pad=None, draw_frame=False, patch_attrs=None):
self._drawFrame = draw_frame
-
def get_extent_offsets(self, renderer):
"""
update offset of childrens and return the extents of the box
@@ -453,7 +464,6 @@ def get_extent_offsets(self, renderer):
xd+pad, yd+pad, \
[(0, 0)]
-
def draw(self, renderer):
"""
Update the location of children if necessary and draw them
@@ -517,8 +527,6 @@ def __init__(self, width, height, xdescent=0.,
self.dpi_transform = mtransforms.Affine2D()
-
-
def get_transform(self):
"""
Return the :class:`~matplotlib.transforms.Transform` applied
@@ -532,7 +540,6 @@ def set_transform(self, t):
"""
pass
-
def set_offset(self, xy):
"""
set offset of the container.
@@ -544,14 +551,12 @@ def set_offset(self, xy):
self.offset_transform.clear()
self.offset_transform.translate(xy[0], xy[1])
-
def get_offset(self):
"""
return offset of the container.
"""
return self._offset
-
def get_window_extent(self, renderer):
'''
get the bounding box in display space.
@@ -560,7 +565,6 @@ def get_window_extent(self, renderer):
ox, oy = self.get_offset() #w, h, xd, yd)
return mtransforms.Bbox.from_bounds(ox-xd, oy-yd, w, h)
-
def get_extent(self, renderer):
"""
Return with, height, xdescent, ydescent of box
@@ -571,14 +575,12 @@ def get_extent(self, renderer):
return self.width*dpi_cor, self.height*dpi_cor, \
self.xdescent*dpi_cor, self.ydescent*dpi_cor
-
def add_artist(self, a):
'Add any :class:`~matplotlib.artist.Artist` to the container box'
self._children.append(a)
if not a.is_transform_set():
a.set_transform(self.get_transform())
-
def draw(self, renderer):
"""
Draw the children
@@ -601,9 +603,6 @@ class TextArea(OffsetBox):
of the TextArea instance is the width and height of the its child
text.
"""
-
-
-
def __init__(self, s,
textprops=None,
multilinebaseline=None,
@@ -639,7 +638,6 @@ def __init__(self, s,
self._multilinebaseline = multilinebaseline
self._minimumdescent = minimumdescent
-
def set_text(self, s):
"set text"
self._text.set_text(s)
@@ -658,14 +656,12 @@ def set_multilinebaseline(self, t):
"""
self._multilinebaseline = t
-
def get_multilinebaseline(self):
"""
get multilinebaseline .
"""
return self._multilinebaseline
-
def set_minimumdescent(self, t):
"""
Set minimumdescent .
@@ -675,21 +671,18 @@ def set_minimumdescent(self, t):
"""
self._minimumdescent = t
-
def get_minimumdescent(self):
"""
get minimumdescent.
"""
return self._minimumdescent
-
def set_transform(self, t):
"""
set_transform is ignored.
"""
pass
-
def set_offset(self, xy):
"""
set offset of the container.
@@ -701,14 +694,12 @@ def set_offset(self, xy):
self.offset_transform.clear()
self.offset_transform.translate(xy[0], xy[1])
-
def get_offset(self):
"""
return offset of the container.
"""