From 96d3605b93c0f136cc155ce9fe1cdd2aab026b1c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 8 Feb 2015 20:49:24 -0500 Subject: [PATCH 01/79] ENH : add function to add displayhook for IPython - add `draw_all` function to pyplot - add `install_ipython_repl_hook` to pyplot which when run monkey-patches the ipython DisplayHook to call draw_all when ever the repl comes back. --- lib/matplotlib/pyplot.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index a44d8e15c730..b0b41cd3d1f9 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -22,6 +22,7 @@ import sys import warnings +import types import matplotlib import matplotlib.colorbar @@ -108,6 +109,35 @@ def _backend_selection(): _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() +def install_ipython_repl_hook(): + try: + from IPython.core.displayhook import DisplayHook + except ImportError: + return + dh = sys.displayhook + # make sure we really have an IPython thing + if not isinstance(dh, DisplayHook): + return + + orig_func = type(dh).finish_displayhook + + def finish_displayhook(self): + draw_all() + return orig_func(self) + + dh.finish_displayhook = types.MethodType(finish_displayhook, dh) + + +def draw_all(): + """ + Redraw all figures registered with the pyplot + state machine. + """ + for f_mgr in _pylab_helpers.Gcf.get_all_fig_managers(): + # TODO add logic to check if figure is dirty + f_mgr.canvas.draw() + + @docstring.copy_dedent(Artist.findobj) def findobj(o=None, match=None, include_self=True): if o is None: From d9f9d2a73dec58d3a61e830b224546d93a820a1e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 10 Feb 2015 01:02:23 -0500 Subject: [PATCH 02/79] ENH : greatly simplified last commit - renamed to `install_repl_displayhook` - should work with all shells? --- lib/matplotlib/pyplot.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index b0b41cd3d1f9..714ebf5217a8 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -109,23 +109,14 @@ def _backend_selection(): _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() -def install_ipython_repl_hook(): - try: - from IPython.core.displayhook import DisplayHook - except ImportError: - return +def install_repl_displayhook(): dh = sys.displayhook - # make sure we really have an IPython thing - if not isinstance(dh, DisplayHook): - return - - orig_func = type(dh).finish_displayhook - def finish_displayhook(self): + def displayhook(*args): + dh(*args) draw_all() - return orig_func(self) - dh.finish_displayhook = types.MethodType(finish_displayhook, dh) + sys.displayhook = displayhook def draw_all(): From 76a87fe636665b52d2cafcfb47e64d6766e6c609 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 10 Feb 2015 12:58:16 -0500 Subject: [PATCH 03/79] ENH : special case IPython display hook Something funny goes on with the zeromq based kernels and we aren't modifying the namespace we think we are modifying. --- lib/matplotlib/pyplot.py | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 714ebf5217a8..328baecb77be 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -110,13 +110,36 @@ def _backend_selection(): def install_repl_displayhook(): - dh = sys.displayhook - def displayhook(*args): - dh(*args) - draw_all() + class _WrongDisplayHook(Exception): + pass - sys.displayhook = displayhook + # see if we have IPython hooks around, if so monkey patch + try: + from IPython.core.displayhook import DisplayHook + dh = sys.displayhook + # make sure we really have an IPython thing + if not isinstance(dh, DisplayHook): + raise _WrongDisplayHook() + + orig_func = type(dh).finish_displayhook + + def finish_displayhook(self): + draw_all() + return orig_func(self) + + dh.finish_displayhook = types.MethodType(finish_displayhook, dh) + + # import failed or sys.displayhook is not of correct type, + # must not have IPython + except (ImportError, _WrongDisplayHook): + dh = sys.displayhook + + def displayhook(*args): + dh(*args) + draw_all() + + sys.displayhook = displayhook def draw_all(): From fb994e9f2422583c553fe32e4fba4a16185a798b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 10 Feb 2015 18:19:54 -0500 Subject: [PATCH 04/79] ENH : hook into IPython better Follow advice from @minrk and use existing IPython pluggable machinery rather than terrifying monkey-patching. --- lib/matplotlib/pyplot.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 328baecb77be..79cf81a70ba5 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -111,28 +111,26 @@ def _backend_selection(): def install_repl_displayhook(): - class _WrongDisplayHook(Exception): + class _NotIPython(Exception): pass # see if we have IPython hooks around, if so monkey patch try: - from IPython.core.displayhook import DisplayHook - dh = sys.displayhook - # make sure we really have an IPython thing - if not isinstance(dh, DisplayHook): - raise _WrongDisplayHook() - - orig_func = type(dh).finish_displayhook - - def finish_displayhook(self): - draw_all() - return orig_func(self) - - dh.finish_displayhook = types.MethodType(finish_displayhook, dh) + from IPython import get_ipython + ip = get_ipython() + if ip is None: + raise _NotIPython() + + # IPython >= 2 + try: + ip.events.register('post_execute', draw_all) + except AttributeError: + # IPython 1.x + ip.register_post_execute(draw_all) # import failed or sys.displayhook is not of correct type, # must not have IPython - except (ImportError, _WrongDisplayHook): + except (ImportError, _NotIPython): dh = sys.displayhook def displayhook(*args): From 51f08cd0050c47e22807f0a033142bca3af9f048 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 3 Mar 2015 09:09:31 -0500 Subject: [PATCH 05/79] MNT : install the replhook by default --- lib/matplotlib/pyplot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 79cf81a70ba5..e685e0ac3730 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -3854,3 +3854,4 @@ def spectral(): draw_if_interactive() _setup_pyplot_info_docstrings() +install_repl_displayhook() From 28dcf3c153619eb8572a3d021b26d7244373540c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 3 Mar 2015 09:13:03 -0500 Subject: [PATCH 06/79] ENH : move draw_all to Gcf class method --- lib/matplotlib/_pylab_helpers.py | 9 +++++++++ lib/matplotlib/pyplot.py | 10 +--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index 840f6bd8e652..e9329981497a 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -139,5 +139,14 @@ def set_active(cls, manager): cls._activeQue.append(manager) cls.figs[manager.num] = manager + @classmethod + def draw_all(cls): + """ + Redraw all figures registered with the pyplot + state machine. + """ + for f_mgr in cls.get_all_fig_managers(): + # TODO add logic to check if figure is dirty + f_mgr.canvas.draw() atexit.register(Gcf.destroy_all) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index e685e0ac3730..103f633bcf40 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -139,15 +139,7 @@ def displayhook(*args): sys.displayhook = displayhook - -def draw_all(): - """ - Redraw all figures registered with the pyplot - state machine. - """ - for f_mgr in _pylab_helpers.Gcf.get_all_fig_managers(): - # TODO add logic to check if figure is dirty - f_mgr.canvas.draw() +draw_all = _pylab_helpers.Gcf.draw_all @docstring.copy_dedent(Artist.findobj) From f9ac8d06a0c99f87c7837af53a4be4e7fcfd2486 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 15 Mar 2015 23:49:04 -0400 Subject: [PATCH 07/79] ENH : add dirty flag First pass at adding awareness of 'dirty' state to the draw tree. Changing properties of an artist (as indicated by a call to `self.pchanged()`) will make that artists axes and figure as 'dirty'. The state of the figure is queried by the `Gcf.draw_all` to only re-draw figure that are dirty. This is a major performance gain for expensive to draw figures. This is also (maybe) setting the stage for partial re-draws. --- lib/matplotlib/_pylab_helpers.py | 3 ++- lib/matplotlib/artist.py | 35 ++++++++++++++++++++++++++++++++ lib/matplotlib/axes/_base.py | 6 ++++++ lib/matplotlib/figure.py | 4 +++- 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index e9329981497a..f7593dfbaa4c 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -147,6 +147,7 @@ def draw_all(cls): """ for f_mgr in cls.get_all_fig_managers(): # TODO add logic to check if figure is dirty - f_mgr.canvas.draw() + if f_mgr.canvas.figure.dirty: + f_mgr.canvas.draw() atexit.register(Gcf.destroy_all) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 0d95f9877e4f..96888c55934d 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -68,6 +68,14 @@ def draw_wrapper(artist, renderer, *args, **kwargs): return draw_wrapper +def _dirty_figure_callback(self): + self.figure.dirty = True + + +def _dirty_axes_callback(self): + self.axes.dirty = True + + class Artist(object): """ Abstract base class for someone who renders into a @@ -109,6 +117,7 @@ def __init__(self): self._snap = None self._sketch = rcParams['path.sketch'] self._path_effects = rcParams['path.effects'] + self._dirty = True def __getstate__(self): d = self.__dict__.copy() @@ -210,9 +219,33 @@ def axes(self, new_axes): "probably trying to re-use an artist " "in more than one Axes which is not " "supported") + self._axes = new_axes + if new_axes is not None and new_axes is not self: + self.add_callback(_dirty_axes_callback) + return new_axes + @property + def dirty(self): + """ + If the artist is 'dirty' and needs to be re-drawn for the output to + match the internal state of the artist. + """ + return self._dirty + + @dirty.setter + def dirty(self, val): + # only trigger call-back stack on being marked as 'dirty' + # when not already dirty + # the draw process will take care of propagating the cleaning + # process + if not (self._dirty == val): + self._dirty = val + # only trigger propagation if marking as dirty + if self._dirty: + self.pchanged() + def get_window_extent(self, renderer): """ Get the axes bounding box in display space. @@ -572,6 +605,7 @@ def set_figure(self, fig): ACCEPTS: a :class:`matplotlib.figure.Figure` instance """ self.figure = fig + self.add_callback(_dirty_figure_callback) self.pchanged() def set_clip_box(self, clipbox): @@ -728,6 +762,7 @@ def draw(self, renderer, *args, **kwargs): 'Derived classes drawing method' if not self.get_visible(): return + self._dirty = False def set_alpha(self, alpha): """ diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 4bda0a0d55cf..129895f3c35a 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2064,6 +2064,7 @@ def draw(self, renderer=None, inframe=False): # will draw the edges if self.axison and self._frameon: self.patch.draw(renderer) + self.patch.dirty = False if _do_composite: # make a composite image, blending alpha @@ -2096,18 +2097,22 @@ def draw(self, renderer=None, inframe=False): self.patch.get_transform())) renderer.draw_image(gc, round(l), round(b), im) + im.dirty = False gc.restore() if dsu_rasterized: for zorder, a in dsu_rasterized: a.draw(renderer) + a.dirty = False renderer.stop_rasterizing() for zorder, a in dsu: a.draw(renderer) + a.dirty = False renderer.close_group('axes') self._cachedRenderer = renderer + self.dirty = False def draw_artist(self, a): """ @@ -2120,6 +2125,7 @@ def draw_artist(self, a): ' caches the render') raise AttributeError(msg) a.draw(self._cachedRenderer) + a.dirty = False def redraw_in_frame(self): """ diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 78ce8d98e18d..2a80cc36503a 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1029,6 +1029,7 @@ def draw(self, renderer): Render the figure using :class:`matplotlib.backend_bases.RendererBase` instance *renderer*. """ + # draw the figure bounding box, perhaps none for white figure if not self.get_visible(): return @@ -1105,11 +1106,12 @@ def draw_composite(): dsu.sort(key=itemgetter(0)) for zorder, a, func, args in dsu: func(*args) + a.dirty = False renderer.close_group('figure') self._cachedRenderer = renderer - + self.dirty = False self.canvas.draw_event(renderer) def draw_artist(self, a): From 6a6f8d9fcc9f93fc209f289d851350e29a82764d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 15 Mar 2015 23:54:13 -0400 Subject: [PATCH 08/79] ENH : add force logic to draw_all Add kwarg to Gcf.draw_all to force redraw of all figures (even if the figure does not think it needs it). --- lib/matplotlib/_pylab_helpers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index f7593dfbaa4c..28abd0a3904d 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -140,14 +140,14 @@ def set_active(cls, manager): cls.figs[manager.num] = manager @classmethod - def draw_all(cls): + def draw_all(cls, force=False): """ Redraw all figures registered with the pyplot state machine. """ for f_mgr in cls.get_all_fig_managers(): # TODO add logic to check if figure is dirty - if f_mgr.canvas.figure.dirty: + if force or f_mgr.canvas.figure.dirty: f_mgr.canvas.draw() atexit.register(Gcf.destroy_all) From b8bd396c3ad3b17272327a5c64a56356a24e5429 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 16 Mar 2015 00:17:26 -0400 Subject: [PATCH 09/79] ENH : first pass at making Line2D objects dirty-aware All set_* commands now set dirty to be True if the value is changed. This required pre-defining all of the Line2D private attributes in the `__init__` method so that all of the `set_*` methods work the first time through. --- lib/matplotlib/lines.py | 66 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 130f820e68bc..d1918174b742 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -314,26 +314,47 @@ def __init__(self, xdata, ydata, if drawstyle is None: drawstyle = 'default' + self._dashcapstyle = None + self._dashjoinstyle = None + self._solidjoinstyle = None + self._solidcapstyle = None self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) + self._linestyles = None + self._drawstyle = None + self._linewidth = None self.set_linestyle(linestyle) self.set_drawstyle(drawstyle) self.set_linewidth(linewidth) + + self._color = None self.set_color(color) self._marker = MarkerStyle() self.set_marker(marker) + + self._markevery = None + self._markersize = None + self._antialiased = None + self.set_markevery(markevery) self.set_antialiased(antialiased) self.set_markersize(markersize) + self._dashSeq = None + self._markeredgecolor = None + self._markeredgewidth = None + self._markerfacecolor = None + self._markerfacecoloralt = None + self.set_markerfacecolor(markerfacecolor) self.set_markerfacecoloralt(markerfacecoloralt) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) + self.set_fillstyle(fillstyle) self.verticalOffset = None @@ -457,6 +478,7 @@ def set_fillstyle(self, fs): ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top' | 'none'] """ self._marker.set_fillstyle(fs) + self.dirty = True def set_markevery(self, every): """Set the markevery property to subsample the plot when using markers. @@ -509,7 +531,8 @@ def set_markevery(self, every): axes-bounding-box-diagonal regardless of the actual axes data limits. """ - + if self._markevery != every: + self.dirty = True self._markevery = every def get_markevery(self): @@ -890,6 +913,8 @@ def set_antialiased(self, b): ACCEPTS: [True | False] """ + if self._antialiased != b: + self.dirty = True self._antialiased = b def set_color(self, color): @@ -898,6 +923,8 @@ def set_color(self, color): ACCEPTS: any matplotlib color """ + if color != self._color: + self.dirty = True self._color = color def set_drawstyle(self, drawstyle): @@ -911,6 +938,8 @@ def set_drawstyle(self, drawstyle): ACCEPTS: ['default' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post'] """ + if self._drawstyle != drawstyle: + self.dirty = True self._drawstyle = drawstyle def set_linewidth(self, w): @@ -919,7 +948,10 @@ def set_linewidth(self, w): ACCEPTS: float value in points """ - self._linewidth = float(w) + w = float(w) + if self._linewidth != w: + self.dirty = True + self._linewidth = w def set_linestyle(self, ls): """ @@ -1021,6 +1053,8 @@ def set_markeredgecolor(self, ec): """ if ec is None: ec = 'auto' + if self._markeredgecolor != ec: + self.dirty = True self._markeredgecolor = ec def set_markeredgewidth(self, ew): @@ -1031,6 +1065,8 @@ def set_markeredgewidth(self, ew): """ if ew is None: ew = rcParams['lines.markeredgewidth'] + if self._markeredgewidth != ew: + self.dirty = True self._markeredgewidth = ew def set_markerfacecolor(self, fc): @@ -1041,7 +1077,8 @@ def set_markerfacecolor(self, fc): """ if fc is None: fc = 'auto' - + if self._markerfacecolor != fc: + self.dirty = True self._markerfacecolor = fc def set_markerfacecoloralt(self, fc): @@ -1052,7 +1089,8 @@ def set_markerfacecoloralt(self, fc): """ if fc is None: fc = 'auto' - + if self._markerfacecoloralt != fc: + self.dirty = True self._markerfacecoloralt = fc def set_markersize(self, sz): @@ -1061,7 +1099,10 @@ def set_markersize(self, sz): ACCEPTS: float """ - self._markersize = float(sz) + sz = float(sz) + if self._markersize != sz: + self.dirty = True + self._markersize = sz def set_xdata(self, x): """ @@ -1071,6 +1112,7 @@ def set_xdata(self, x): """ self._xorig = x self._invalidx = True + self.dirty = True def set_ydata(self, y): """ @@ -1080,6 +1122,7 @@ def set_ydata(self, y): """ self._yorig = y self._invalidy = True + self.dirty = True def set_dashes(self, seq): """ @@ -1093,6 +1136,8 @@ def set_dashes(self, seq): self.set_linestyle('-') else: self.set_linestyle('--') + if self._dashSeq != seq: + self.dirty = True self._dashSeq = seq # TODO: offset ignored for now def _draw_lines(self, renderer, gc, path, trans): @@ -1276,6 +1321,8 @@ def set_dash_joinstyle(self, s): if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) + if self._dashjoinstyle != s: + self.dirty = True self._dashjoinstyle = s def set_solid_joinstyle(self, s): @@ -1287,6 +1334,9 @@ def set_solid_joinstyle(self, s): if s not in self.validJoin: raise ValueError('set_solid_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) + + if self._solidjoinstyle != s: + self.dirty = True self._solidjoinstyle = s def get_dash_joinstyle(self): @@ -1311,7 +1361,8 @@ def set_dash_capstyle(self, s): if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) - + if self._dashcapstyle != s: + self.dirty = True self._dashcapstyle = s def set_solid_capstyle(self, s): @@ -1324,7 +1375,8 @@ def set_solid_capstyle(self, s): if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) - + if self._solidcapstyle != s: + self.dirty = True self._solidcapstyle = s def get_dash_capstyle(self): From 17c4461f1251f749e418791af73161cd346d1622 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 16 Mar 2015 00:32:47 -0400 Subject: [PATCH 10/79] ENH : add dirty flag to missed Line2D.set_* methods --- lib/matplotlib/lines.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index d1918174b742..08a3445c8fd7 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -676,6 +676,7 @@ def set_transform(self, t): Artist.set_transform(self, t) self._invalidx = True self._invalidy = True + self.dirty = True def _is_sorted(self, x): """return true if x is sorted""" @@ -1044,6 +1045,7 @@ def set_marker(self, marker): """ self._marker.set_marker(marker) + self.dirty = True def set_markeredgecolor(self, ec): """ From 46af65a1ba857e902a1d8847c543e7d2980dc5db Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 16 Mar 2015 00:40:18 -0400 Subject: [PATCH 11/79] MNT : only set the figure call back if figure is not None --- lib/matplotlib/artist.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 96888c55934d..065ecd296f55 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -605,8 +605,9 @@ def set_figure(self, fig): ACCEPTS: a :class:`matplotlib.figure.Figure` instance """ self.figure = fig - self.add_callback(_dirty_figure_callback) - self.pchanged() + if self.figure and self.figure is not self: + self.add_callback(_dirty_figure_callback) + self.pchanged() def set_clip_box(self, clipbox): """ From ef08aa19cc6eafc7f184b3706040f4864aa9bfad Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 30 Mar 2015 23:41:12 -0400 Subject: [PATCH 12/79] MNT : rename dirty -> stale --- lib/matplotlib/_pylab_helpers.py | 4 ++-- lib/matplotlib/artist.py | 38 +++++++++++++++--------------- lib/matplotlib/axes/_base.py | 12 +++++----- lib/matplotlib/figure.py | 4 ++-- lib/matplotlib/lines.py | 40 ++++++++++++++++---------------- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index 28abd0a3904d..1fb79cd695bb 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -146,8 +146,8 @@ def draw_all(cls, force=False): state machine. """ for f_mgr in cls.get_all_fig_managers(): - # TODO add logic to check if figure is dirty - if force or f_mgr.canvas.figure.dirty: + # TODO add logic to check if figure is stale + if force or f_mgr.canvas.figure.stale: f_mgr.canvas.draw() atexit.register(Gcf.destroy_all) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 065ecd296f55..e8c215a2b900 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -68,12 +68,12 @@ def draw_wrapper(artist, renderer, *args, **kwargs): return draw_wrapper -def _dirty_figure_callback(self): - self.figure.dirty = True +def _stale_figure_callback(self): + self.figure.stale = True -def _dirty_axes_callback(self): - self.axes.dirty = True +def _stale_axes_callback(self): + self.axes.stale = True class Artist(object): @@ -117,7 +117,7 @@ def __init__(self): self._snap = None self._sketch = rcParams['path.sketch'] self._path_effects = rcParams['path.effects'] - self._dirty = True + self._stale = True def __getstate__(self): d = self.__dict__.copy() @@ -222,28 +222,28 @@ def axes(self, new_axes): self._axes = new_axes if new_axes is not None and new_axes is not self: - self.add_callback(_dirty_axes_callback) + self.add_callback(_stale_axes_callback) return new_axes @property - def dirty(self): + def stale(self): """ - If the artist is 'dirty' and needs to be re-drawn for the output to + If the artist is 'stale' and needs to be re-drawn for the output to match the internal state of the artist. """ - return self._dirty + return self._stale - @dirty.setter - def dirty(self, val): - # only trigger call-back stack on being marked as 'dirty' - # when not already dirty + @stale.setter + def stale(self, val): + # only trigger call-back stack on being marked as 'stale' + # when not already stale # the draw process will take care of propagating the cleaning # process - if not (self._dirty == val): - self._dirty = val - # only trigger propagation if marking as dirty - if self._dirty: + if not (self._stale == val): + self._stale = val + # only trigger propagation if marking as stale + if self._stale: self.pchanged() def get_window_extent(self, renderer): @@ -606,7 +606,7 @@ def set_figure(self, fig): """ self.figure = fig if self.figure and self.figure is not self: - self.add_callback(_dirty_figure_callback) + self.add_callback(_stale_figure_callback) self.pchanged() def set_clip_box(self, clipbox): @@ -763,7 +763,7 @@ def draw(self, renderer, *args, **kwargs): 'Derived classes drawing method' if not self.get_visible(): return - self._dirty = False + self._stale = False def set_alpha(self, alpha): """ diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 129895f3c35a..37254dd11cea 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2064,7 +2064,7 @@ def draw(self, renderer=None, inframe=False): # will draw the edges if self.axison and self._frameon: self.patch.draw(renderer) - self.patch.dirty = False + self.patch.stale = False if _do_composite: # make a composite image, blending alpha @@ -2097,22 +2097,22 @@ def draw(self, renderer=None, inframe=False): self.patch.get_transform())) renderer.draw_image(gc, round(l), round(b), im) - im.dirty = False + im.stale = False gc.restore() if dsu_rasterized: for zorder, a in dsu_rasterized: a.draw(renderer) - a.dirty = False + a.stale = False renderer.stop_rasterizing() for zorder, a in dsu: a.draw(renderer) - a.dirty = False + a.stale = False renderer.close_group('axes') self._cachedRenderer = renderer - self.dirty = False + self.stale = False def draw_artist(self, a): """ @@ -2125,7 +2125,7 @@ def draw_artist(self, a): ' caches the render') raise AttributeError(msg) a.draw(self._cachedRenderer) - a.dirty = False + a.stale = False def redraw_in_frame(self): """ diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 2a80cc36503a..14f5be4b0115 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1106,12 +1106,12 @@ def draw_composite(): dsu.sort(key=itemgetter(0)) for zorder, a, func, args in dsu: func(*args) - a.dirty = False + a.stale = False renderer.close_group('figure') self._cachedRenderer = renderer - self.dirty = False + self.stale = False self.canvas.draw_event(renderer) def draw_artist(self, a): diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 08a3445c8fd7..f670c3acb302 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -478,7 +478,7 @@ def set_fillstyle(self, fs): ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top' | 'none'] """ self._marker.set_fillstyle(fs) - self.dirty = True + self.stale = True def set_markevery(self, every): """Set the markevery property to subsample the plot when using markers. @@ -532,7 +532,7 @@ def set_markevery(self, every): """ if self._markevery != every: - self.dirty = True + self.stale = True self._markevery = every def get_markevery(self): @@ -676,7 +676,7 @@ def set_transform(self, t): Artist.set_transform(self, t) self._invalidx = True self._invalidy = True - self.dirty = True + self.stale = True def _is_sorted(self, x): """return true if x is sorted""" @@ -915,7 +915,7 @@ def set_antialiased(self, b): ACCEPTS: [True | False] """ if self._antialiased != b: - self.dirty = True + self.stale = True self._antialiased = b def set_color(self, color): @@ -925,7 +925,7 @@ def set_color(self, color): ACCEPTS: any matplotlib color """ if color != self._color: - self.dirty = True + self.stale = True self._color = color def set_drawstyle(self, drawstyle): @@ -940,7 +940,7 @@ def set_drawstyle(self, drawstyle): 'steps-post'] """ if self._drawstyle != drawstyle: - self.dirty = True + self.stale = True self._drawstyle = drawstyle def set_linewidth(self, w): @@ -951,7 +951,7 @@ def set_linewidth(self, w): """ w = float(w) if self._linewidth != w: - self.dirty = True + self.stale = True self._linewidth = w def set_linestyle(self, ls): @@ -1045,7 +1045,7 @@ def set_marker(self, marker): """ self._marker.set_marker(marker) - self.dirty = True + self.stale = True def set_markeredgecolor(self, ec): """ @@ -1056,7 +1056,7 @@ def set_markeredgecolor(self, ec): if ec is None: ec = 'auto' if self._markeredgecolor != ec: - self.dirty = True + self.stale = True self._markeredgecolor = ec def set_markeredgewidth(self, ew): @@ -1068,7 +1068,7 @@ def set_markeredgewidth(self, ew): if ew is None: ew = rcParams['lines.markeredgewidth'] if self._markeredgewidth != ew: - self.dirty = True + self.stale = True self._markeredgewidth = ew def set_markerfacecolor(self, fc): @@ -1080,7 +1080,7 @@ def set_markerfacecolor(self, fc): if fc is None: fc = 'auto' if self._markerfacecolor != fc: - self.dirty = True + self.stale = True self._markerfacecolor = fc def set_markerfacecoloralt(self, fc): @@ -1092,7 +1092,7 @@ def set_markerfacecoloralt(self, fc): if fc is None: fc = 'auto' if self._markerfacecoloralt != fc: - self.dirty = True + self.stale = True self._markerfacecoloralt = fc def set_markersize(self, sz): @@ -1103,7 +1103,7 @@ def set_markersize(self, sz): """ sz = float(sz) if self._markersize != sz: - self.dirty = True + self.stale = True self._markersize = sz def set_xdata(self, x): @@ -1114,7 +1114,7 @@ def set_xdata(self, x): """ self._xorig = x self._invalidx = True - self.dirty = True + self.stale = True def set_ydata(self, y): """ @@ -1124,7 +1124,7 @@ def set_ydata(self, y): """ self._yorig = y self._invalidy = True - self.dirty = True + self.stale = True def set_dashes(self, seq): """ @@ -1139,7 +1139,7 @@ def set_dashes(self, seq): else: self.set_linestyle('--') if self._dashSeq != seq: - self.dirty = True + self.stale = True self._dashSeq = seq # TODO: offset ignored for now def _draw_lines(self, renderer, gc, path, trans): @@ -1324,7 +1324,7 @@ def set_dash_joinstyle(self, s): raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) if self._dashjoinstyle != s: - self.dirty = True + self.stale = True self._dashjoinstyle = s def set_solid_joinstyle(self, s): @@ -1338,7 +1338,7 @@ def set_solid_joinstyle(self, s): + 'valid joinstyles are %s' % (self.validJoin,)) if self._solidjoinstyle != s: - self.dirty = True + self.stale = True self._solidjoinstyle = s def get_dash_joinstyle(self): @@ -1364,7 +1364,7 @@ def set_dash_capstyle(self, s): raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) if self._dashcapstyle != s: - self.dirty = True + self.stale = True self._dashcapstyle = s def set_solid_capstyle(self, s): @@ -1378,7 +1378,7 @@ def set_solid_capstyle(self, s): raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) if self._solidcapstyle != s: - self.dirty = True + self.stale = True self._solidcapstyle = s def get_dash_capstyle(self): From a8865f863f7286578175113dad4176f8c48a54fe Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 31 Mar 2015 00:30:05 -0400 Subject: [PATCH 13/79] ENH : add stale flag to all set_* methods in Artist --- lib/matplotlib/artist.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index e8c215a2b900..92c4da391256 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -316,6 +316,7 @@ def set_transform(self, t): self._transform = t self._transformSet = True self.pchanged() + self.stale = True def get_transform(self): """ @@ -532,6 +533,7 @@ def set_snap(self, snap): Only supported by the Agg and MacOSX backends. """ self._snap = snap + self.stale = True def get_sketch_params(self): """ @@ -579,6 +581,7 @@ def set_sketch_params(self, scale=None, length=None, randomness=None): self._sketch = None else: self._sketch = (scale, length or 128.0, randomness or 16.0) + self.stale = True def set_path_effects(self, path_effects): """ @@ -586,6 +589,7 @@ def set_path_effects(self, path_effects): matplotlib.patheffect._Base class or its derivatives. """ self._path_effects = path_effects + self.stale = True def get_path_effects(self): return self._path_effects @@ -608,6 +612,7 @@ def set_figure(self, fig): if self.figure and self.figure is not self: self.add_callback(_stale_figure_callback) self.pchanged() + self.stale = True def set_clip_box(self, clipbox): """ @@ -617,6 +622,7 @@ def set_clip_box(self, clipbox): """ self.clipbox = clipbox self.pchanged() + self.stale = True def set_clip_path(self, path, transform=None): """ @@ -669,8 +675,10 @@ def set_clip_path(self, path, transform=None): if not success: print(type(path), type(transform)) raise TypeError("Invalid arguments to set_clip_path") - + # this may result in the callbacks being hit twice, but grantees they + # will be hit at least once self.pchanged() + self.stale = True def get_alpha(self): """ @@ -719,7 +727,10 @@ def set_clip_on(self, b): ACCEPTS: [True | False] """ self._clipon = b + # This may result in the callbacks being hit twice, but ensures they + # are hit at least once self.pchanged() + self.stale = True def _set_gc_clip(self, gc): 'Set the clip properly for the gc' @@ -758,12 +769,13 @@ def set_agg_filter(self, filter_func): """ self._agg_filter = filter_func + self.stale = True def draw(self, renderer, *args, **kwargs): 'Derived classes drawing method' if not self.get_visible(): return - self._stale = False + self.stale = False def set_alpha(self, alpha): """ @@ -774,6 +786,7 @@ def set_alpha(self, alpha): """ self._alpha = alpha self.pchanged() + self.stale = True def set_visible(self, b): """ @@ -783,6 +796,7 @@ def set_visible(self, b): """ self._visible = b self.pchanged() + self.stale = True def set_animated(self, b): """ @@ -792,6 +806,7 @@ def set_animated(self, b): """ self._animated = b self.pchanged() + self.stale = True def update(self, props): """ @@ -814,6 +829,7 @@ def update(self, props): self.eventson = store if changed: self.pchanged() + self.stale = True def get_label(self): """ @@ -832,6 +848,7 @@ def set_label(self, s): else: self._label = None self.pchanged() + self.stale = True def get_zorder(self): """ @@ -848,6 +865,7 @@ def set_zorder(self, level): """ self.zorder = level self.pchanged() + self.stale = True def update_from(self, other): 'Copy properties from *other* to *self*.' @@ -862,6 +880,7 @@ def update_from(self, other): self._sketch = other._sketch self._path_effects = other._path_effects self.pchanged() + self.stale = True def properties(self): """ From 495b5a07f2d0129955ba7774fe845d224e57ccfa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 15 Apr 2015 08:44:43 -0400 Subject: [PATCH 14/79] STY : don't re-define variables --- lib/matplotlib/collections.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index d2f7a7081666..917a8d5b718f 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1115,13 +1115,14 @@ def set_segments(self, segments): _segments = [] for seg in segments: - if not np.ma.isMaskedArray(seg): seg = np.asarray(seg, np.float_) _segments.append(seg) + if self._uniform_offsets is not None: _segments = self._add_offsets(_segments) - self._paths = [mpath.Path(seg) for seg in _segments] + + self._paths = [mpath.Path(_seg) for _seg in _segments] set_verts = set_segments # for compatibility with PolyCollection set_paths = set_segments From 234cc9ce5c620ba7d40b1692ae1d12b62489669b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:26:21 -0400 Subject: [PATCH 15/79] ENH : add stale flags to Collection --- lib/matplotlib/collections.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 917a8d5b718f..6f13610d15df 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -321,6 +321,7 @@ def draw(self, renderer): gc.restore() renderer.close_group(self.__class__.__name__) + self.stale = False def set_pickradius(self, pr): self._pickradius = pr @@ -370,6 +371,7 @@ def set_urls(self, urls): self._urls = [None, ] else: self._urls = urls + self.stale = True def get_urls(self): return self._urls @@ -405,6 +407,7 @@ def set_hatch(self, hatch): ACCEPTS: [ '/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*' ] """ self._hatch = hatch + self.stale = True def get_hatch(self): 'Return the current hatching pattern' @@ -424,6 +427,7 @@ def set_offsets(self, offsets): self._offsets = offsets else: self._uniform_offsets = offsets + self.stale = True def get_offsets(self): """ @@ -446,6 +450,7 @@ def set_offset_position(self, offset_position): if offset_position not in ('screen', 'data'): raise ValueError("offset_position must be 'screen' or 'data'") self._offset_position = offset_position + self.stale = True def get_offset_position(self): """ @@ -469,6 +474,7 @@ def set_linewidth(self, lw): if lw is None: lw = mpl.rcParams['patch.linewidth'] self._linewidths = self._get_value(lw) + self.stale = True def set_linewidths(self, lw): """alias for set_linewidth""" @@ -540,6 +546,7 @@ def set_linestyle(self, ls): except ValueError: raise ValueError('Do not know how to convert %s to dashes' % ls) self._linestyles = dashes + self.stale = True def set_linestyles(self, ls): """alias for set_linestyle""" @@ -558,6 +565,7 @@ def set_antialiased(self, aa): if aa is None: aa = mpl.rcParams['patch.antialiased'] self._antialiaseds = self._get_bool(aa) + self.stale = True def set_antialiaseds(self, aa): """alias for set_antialiased""" @@ -598,6 +606,7 @@ def set_facecolor(self, c): c = mpl.rcParams['patch.facecolor'] self._facecolors_original = c self._facecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) + self.stale = True def set_facecolors(self, c): """alias for set_facecolor""" @@ -644,6 +653,7 @@ def set_edgecolor(self, c): c = mpl.rcParams['patch.edgecolor'] self._edgecolors_original = c self._edgecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) + self.stale = True def set_edgecolors(self, c): """alias for set_edgecolor""" @@ -697,6 +707,7 @@ def update_scalarmappable(self): self._facecolors = self.to_rgba(self._A, self._alpha) elif self._is_stroked: self._edgecolors = self.to_rgba(self._A, self._alpha) + self.stale = True def get_fill(self): 'return whether fill is set' @@ -721,7 +732,7 @@ def update_from(self, other): self.norm = other.norm self.cmap = other.cmap # self.update_dict = other.update_dict # do we need to copy this? -JJL - + self.stale = True # these are not available for the object inspector until after the # class is built so we define an initial set here for the init From 771977f329aab13224a58bb3fad2ca3c7c3238c3 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:32:13 -0400 Subject: [PATCH 16/79] ENH : add stale flag to _CollectionWithSizes --- lib/matplotlib/collections.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 6f13610d15df..ff404df051b4 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -801,6 +801,7 @@ def set_sizes(self, sizes, dpi=72.0): self._transforms[:, 0, 0] = scale self._transforms[:, 1, 1] = scale self._transforms[:, 2, 2] = 1.0 + self.stale = True @allow_rasterization def draw(self, renderer): From 1aaae204ed86eb0e98f9148723e081f7a972a98d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:32:52 -0400 Subject: [PATCH 17/79] ENH : add stale flag to PathCollection --- lib/matplotlib/collections.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index ff404df051b4..789a237bdfc0 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -825,9 +825,11 @@ def __init__(self, paths, sizes=None, **kwargs): Collection.__init__(self, **kwargs) self.set_paths(paths) self.set_sizes(sizes) + self.stale = True def set_paths(self, paths): self._paths = paths + self.stale = True def get_paths(self): return self._paths From 729ada7ad24c94f2ef9f84ac8ddc83bfe9bdf9a5 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:33:35 -0400 Subject: [PATCH 18/79] ENH : add stale flag to PolyCollection --- lib/matplotlib/collections.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 789a237bdfc0..8e6e62f23edf 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -859,6 +859,7 @@ def __init__(self, verts, sizes=None, closed=True, **kwargs): Collection.__init__(self, **kwargs) self.set_sizes(sizes) self.set_verts(verts, closed) + self.stale = True def set_verts(self, verts, closed=True): '''This allows one to delay initialization of the vertices.''' @@ -883,6 +884,7 @@ def set_verts(self, verts, closed=True): self._paths.append(mpath.Path(xy)) else: self._paths = [mpath.Path(xy) for xy in verts] + self.stale = True set_paths = set_verts From fa5cb4d2f54f413f8af42738b49f7e15e3f42323 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:35:43 -0400 Subject: [PATCH 19/79] ENH : add stale flag to EventCollection --- lib/matplotlib/collections.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 8e6e62f23edf..f5344df502b8 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1027,7 +1027,6 @@ class LineCollection(Collection): number of segments. """ - def __init__(self, segments, # Can be None. linewidths=None, colors=None, @@ -1139,6 +1138,7 @@ def set_segments(self, segments): _segments = self._add_offsets(_segments) self._paths = [mpath.Path(_seg) for _seg in _segments] + self.stale = True set_verts = set_segments # for compatibility with PolyCollection set_paths = set_segments @@ -1176,9 +1176,11 @@ def set_color(self, c): ACCEPTS: matplotlib color arg or sequence of rgba tuples """ self.set_edgecolor(c) + self.stale = True def get_color(self): return self._edgecolors + get_colors = get_color # for compatibility with old versions @@ -1353,6 +1355,7 @@ def switch_orientation(self): segments[i] = np.fliplr(segment) self.set_segments(segments) self._is_horizontal = not self.is_horizontal() + self.stale = True def set_orientation(self, orientation=None): ''' From 9cec66f269c0a7572d4a7dfeb9795ab826169c54 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 21 Apr 2015 17:35:56 -0400 Subject: [PATCH 20/79] ENH : add stale flag to QuadMesh --- lib/matplotlib/collections.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index f5344df502b8..c77be43c4b7b 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1729,6 +1729,7 @@ def get_paths(self): def set_paths(self): self._paths = self.convert_mesh_to_paths( self._meshWidth, self._meshHeight, self._coordinates) + self.stale = True def get_datalim(self, transData): return (self.get_transform() - transData).transform_bbox(self._bbox) @@ -1852,6 +1853,7 @@ def draw(self, renderer): self._antialiased, self.get_edgecolors()) gc.restore() renderer.close_group(self.__class__.__name__) + self.stale = False patchstr = artist.kwdoc(Collection) From fb3562b12c17c803dc69469d681f4cc56c6e58b4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 27 Apr 2015 08:57:03 -0400 Subject: [PATCH 21/79] ENH : add stale flag to Figure --- lib/matplotlib/figure.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 14f5be4b0115..4012e6ace1f3 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -426,6 +426,7 @@ def set_tight_layout(self, tight): tight = rcParams['figure.autolayout'] self._tight = bool(tight) self._tight_parameters = tight if isinstance(tight, dict) else {} + self.stale = True def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ @@ -465,6 +466,7 @@ def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): if allsubplots: self.subplots_adjust(bottom=bottom) + self.stale = True def get_children(self): 'get a list of artists contained in the figure' @@ -541,6 +543,7 @@ def suptitle(self, t, **kwargs): sup.remove() else: self._suptitle = sup + self.stale = True return self._suptitle def set_canvas(self, canvas): @@ -550,6 +553,7 @@ def set_canvas(self, canvas): ACCEPTS: a FigureCanvas instance """ self.canvas = canvas + self.stale = True def hold(self, b=None): """ @@ -652,6 +656,7 @@ def figimage(self, X, im.set_clim(vmin, vmax) self.images.append(im) im._remove_method = lambda h: self.images.remove(h) + self.stale = True return im def set_size_inches(self, *args, **kwargs): @@ -693,6 +698,7 @@ def set_size_inches(self, *args, **kwargs): manager = getattr(self.canvas, 'manager', None) if manager is not None: manager.resize(int(canvasw), int(canvash)) + self.stale = True def get_size_inches(self): """ @@ -758,6 +764,7 @@ def set_dpi(self, val): ACCEPTS: float """ self.dpi = val + self.stale = True def set_figwidth(self, val): """ @@ -766,6 +773,7 @@ def set_figwidth(self, val): ACCEPTS: float """ self.bbox_inches.x1 = val + self.stale = True def set_figheight(self, val): """ @@ -774,6 +782,7 @@ def set_figheight(self, val): ACCEPTS: float """ self.bbox_inches.y1 = val + self.stale = True def set_frameon(self, b): """ @@ -782,12 +791,14 @@ def set_frameon(self, b): ACCEPTS: boolean """ self.frameon = b + self.stale = True def delaxes(self, a): 'remove a from the figure and update the current axes' self._axstack.remove(a) for func in self._axobservers: func(self) + self.stale = True def _make_key(self, *args, **kwargs): 'make a hashable key out of args and kwargs' @@ -900,6 +911,7 @@ def add_axes(self, *args, **kwargs): self._axstack.add(key, a) self.sca(a) + self.stale = True return a @docstring.dedent_interpd @@ -987,6 +999,7 @@ def add_subplot(self, *args, **kwargs): self._axstack.add(key, a) self.sca(a) + self.stale = True return a def clf(self, keep_observers=False): @@ -1016,6 +1029,7 @@ def clf(self, keep_observers=False): if not keep_observers: self._axobservers = [] self._suptitle = None + self.stale = True def clear(self): """ @@ -1227,6 +1241,7 @@ def legend(self, handles, labels, *args, **kwargs): l = Legend(self, handles, labels, *args, **kwargs) self.legends.append(l) l._remove_method = lambda h: self.legends.remove(h) + self.stale = True return l @docstring.dedent_interpd @@ -1254,6 +1269,7 @@ def text(self, x, y, s, *args, **kwargs): self._set_artist_props(t) self.texts.append(t) t._remove_method = lambda h: self.texts.remove(h) + self.stale = True return t def _set_artist_props(self, a): @@ -1399,6 +1415,7 @@ def make_active(event): self.number = num plt.draw_if_interactive() + self.stale = True def add_axobserver(self, func): 'whenever the axes state change, ``func(self)`` will be called' @@ -1541,6 +1558,7 @@ def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): cb = cbar.colorbar_factory(cax, mappable, **kw) self.sca(current_ax) + self.stale = True return cb def subplots_adjust(self, *args, **kwargs): @@ -1569,6 +1587,7 @@ def subplots_adjust(self, *args, **kwargs): else: ax.update_params() ax.set_position(ax.figbox) + self.stale = True def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, mouse_pop=3, mouse_stop=2): From 6060a4cb7abf026bdbbb2d74b531d9de4aa77f70 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 28 Apr 2015 09:02:15 -0400 Subject: [PATCH 22/79] ENH : add stale flag to *Image* classes --- lib/matplotlib/image.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index d45726fccc15..d45782af5fa0 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -375,6 +375,7 @@ def draw(self, renderer, *args, **kwargs): im._gid = self.get_gid() renderer.draw_image(gc, l, b, im) gc.restore() + self.stale = False def contains(self, mouseevent): """ @@ -437,6 +438,7 @@ def set_data(self, A): self._rgbacache = None self._oldxslice = None self._oldyslice = None + self.stale = True def set_array(self, A): """ @@ -481,6 +483,7 @@ def set_interpolation(self, s): if s not in self._interpd: raise ValueError('Illegal interpolation string') self._interpolation = s + self.stale = True def set_resample(self, v): """ @@ -491,6 +494,7 @@ def set_resample(self, v): if v is None: v = rcParams['image.resample'] self._resample = v + self.stale = True def get_resample(self): """Return the image resample boolean""" @@ -508,6 +512,8 @@ def set_filternorm(self, filternorm): else: self._filternorm = 0 + self.stale = True + def get_filternorm(self): """Return the filternorm setting""" return self._filternorm @@ -523,6 +529,7 @@ def set_filterrad(self, filterrad): if r <= 0: raise ValueError("The filter radius must be a positive number") self._filterrad = r + self.stale = True def get_filterrad(self): """return the filterrad setting""" @@ -671,6 +678,7 @@ def set_extent(self, extent): self.axes.set_xlim((xmin, xmax), auto=None) if self.axes._autoscaleYon: self.axes.set_ylim((ymin, ymax), auto=None) + self.stale = True def get_extent(self): """Get the image extent: left, right, bottom, top""" @@ -792,6 +800,7 @@ def set_data(self, x, y, A): # accessed - JDH 3/3/2010 self._oldxslice = None self._oldyslice = None + self.stale = True def set_array(self, *args): raise NotImplementedError('Method not supported') @@ -904,6 +913,7 @@ def draw(self, renderer, *args, **kwargs): round(self.axes.bbox.ymin), im) gc.restore() + self.stale = False def set_data(self, x, y, A): A = cbook.safe_masked_invalid(A) @@ -937,6 +947,7 @@ def set_data(self, x, y, A): self._Ax = x self._Ay = y self._rgbacache = None + self.stale = True def set_array(self, *args): raise NotImplementedError('Method not supported') @@ -1060,6 +1071,7 @@ def draw(self, renderer, *args, **kwargs): gc.set_alpha(self.get_alpha()) renderer.draw_image(gc, round(self.ox), round(self.oy), im) gc.restore() + self.stale = False def write_png(self, fname): """Write the image to png file with fname""" @@ -1211,6 +1223,7 @@ def draw(self, renderer, *args, **kwargs): b = np.min([y0, y1]) renderer.draw_image(gc, round(l), round(b), im) gc.restore() + self.stale = True def imread(fname, format=None): From bd4bd0b83fb915d4dd0f444b53a8ba3c8f3aac06 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 28 Apr 2015 09:04:00 -0400 Subject: [PATCH 23/79] DOC : fix axis -> axes typo in comment --- lib/matplotlib/legend.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 243064a492ec..f856c1c11fee 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -112,7 +112,7 @@ class Legend(Artist): The location codes are:: - 'best' : 0, (only implemented for axis legends) + 'best' : 0, (only implemented for axes legends) 'upper right' : 1, 'upper left' : 2, 'lower left' : 3, @@ -128,7 +128,7 @@ class Legend(Artist): respect its parent. """ - codes = {'best': 0, # only implemented for axis legends + codes = {'best': 0, # only implemented for axes legends 'upper right': 1, 'upper left': 2, 'lower left': 3, From 72fae28d626b85917826da1e14b0a0e8a98894cb Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 29 Apr 2015 08:30:58 -0400 Subject: [PATCH 24/79] ENH : add stale flag to Legend --- lib/matplotlib/legend.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index f856c1c11fee..98e107849535 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -421,6 +421,7 @@ def _set_loc(self, loc): self._legend_box.set_offset(_findoffset) self._loc_real = loc + self.stale = True def _get_loc(self): return self._loc_real @@ -481,6 +482,7 @@ def draw(self, renderer): self._legend_box.draw(renderer) renderer.close_group('legend') + self.stale = False def _approx_text_height(self, renderer=None): """ @@ -807,6 +809,7 @@ def set_title(self, title, prop=None): self._legend_title_box.set_visible(True) else: self._legend_title_box.set_visible(False) + self.stale = True def get_title(self): 'return Text instance for the legend title' @@ -829,6 +832,7 @@ def set_frame_on(self, b): ACCEPTS: [ *True* | *False* ] """ self._drawFrame = b + self.stale = True def get_bbox_to_anchor(self): """ @@ -869,6 +873,7 @@ def set_bbox_to_anchor(self, bbox, transform=None): self._bbox_to_anchor = TransformedBbox(self._bbox_to_anchor, transform) + self.stale = True def _get_anchored_bbox(self, loc, bbox, parentbbox, renderer): """ From b2df645fa7213e150497728b9cd860dc519776e6 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:24:58 -0400 Subject: [PATCH 25/79] ENH : add stale flag to Offsetbox --- lib/matplotlib/offsetbox.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index b014950a4930..b3679ca78d99 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -174,6 +174,7 @@ def __setstate__(self, state): from .cbook import _InstanceMethodPickler if isinstance(self._offset, _InstanceMethodPickler): self._offset = self._offset.get_instancemethod() + self.stale = True def set_figure(self, fig): """ @@ -199,6 +200,7 @@ def set_offset(self, xy): accepts x, y, tuple, or a callable object. """ self._offset = xy + self.stale = True def get_offset(self, width, height, xdescent, ydescent, renderer): """ @@ -218,6 +220,7 @@ def set_width(self, width): accepts float """ self.width = width + self.stale = True def set_height(self, height): """ @@ -226,6 +229,7 @@ def set_height(self, height): accepts float """ self.height = height + self.stale = True def get_visible_children(self): """ @@ -273,6 +277,7 @@ def draw(self, renderer): c.draw(renderer) bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class PackerBase(OffsetBox): From 7780821d45996484fe9861725cf67aa243622ca6 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:25:17 -0400 Subject: [PATCH 26/79] ENH : add stale flag to PaddedBox --- lib/matplotlib/offsetbox.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index b3679ca78d99..3a087d56216e 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -546,6 +546,7 @@ def draw(self, renderer): c.draw(renderer) #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False def update_frame(self, bbox, fontsize=None): self.patch.set_bounds(bbox.x0, bbox.y0, @@ -553,6 +554,7 @@ def update_frame(self, bbox, fontsize=None): if fontsize: self.patch.set_mutation_scale(fontsize) + self.stale = True def draw_frame(self, renderer): # update the location and size of the legend From cae51d372786836c3ad75ca641b9c260290e2f8b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:25:58 -0400 Subject: [PATCH 27/79] ENH : add stale flag to DrawingArea --- lib/matplotlib/offsetbox.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 3a087d56216e..ecb9ae79669a 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -615,6 +615,7 @@ def set_offset(self, xy): self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): """ @@ -659,6 +660,7 @@ def draw(self, renderer): c.draw(renderer) bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class TextArea(OffsetBox): From ebf7b91e47ba4619e22b6c7525438f17c8e124a8 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:26:37 -0400 Subject: [PATCH 28/79] ENH : add stale flag to TextArea --- lib/matplotlib/offsetbox.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index ecb9ae79669a..0a13c1a8ad36 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -716,6 +716,7 @@ def __init__(self, s, def set_text(self, s): "set text" self._text.set_text(s) + self.stale = True def get_text(self): "get text" @@ -730,6 +731,7 @@ def set_multilinebaseline(self, t): singleline text. """ self._multilinebaseline = t + self.stale = True def get_multilinebaseline(self): """ @@ -745,6 +747,7 @@ def set_minimumdescent(self, t): it has minimum descent of "p" """ self._minimumdescent = t + self.stale = True def get_minimumdescent(self): """ @@ -768,6 +771,7 @@ def set_offset(self, xy): self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): """ @@ -823,6 +827,7 @@ def draw(self, renderer): self._text.draw(renderer) bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class AuxTransformBox(OffsetBox): From c5df7922d8b8f499eae5a0ff87e828c7acf2414a Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:29:18 -0400 Subject: [PATCH 29/79] ENH : add stale flag to AuxTransformBox --- lib/matplotlib/offsetbox.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 0a13c1a8ad36..1e4e03f4e32b 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -862,6 +862,7 @@ def add_artist(self, a): 'Add any :class:`~matplotlib.artist.Artist` to the container box' self._children.append(a) a.set_transform(self.get_transform()) + self.stale = True def get_transform(self): """ @@ -888,6 +889,7 @@ def set_offset(self, xy): self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): """ @@ -932,6 +934,7 @@ def draw(self, renderer): c.draw(renderer) bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class AnchoredOffsetbox(OffsetBox): From 74ebf824fc0ba0a3bba3bc3aa32a9b3eb1b834d9 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:31:03 -0400 Subject: [PATCH 30/79] STY : remove excessive indets --- lib/matplotlib/offsetbox.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 1e4e03f4e32b..d3955b25fb93 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1104,11 +1104,11 @@ def _offset(w, h, xd, yd, renderer, fontsize=fontsize, self=self): self.set_offset(_offset) def update_frame(self, bbox, fontsize=None): - self.patch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) + self.patch.set_bounds(bbox.x0, bbox.y0, + bbox.width, bbox.height) - if fontsize: - self.patch.set_mutation_scale(fontsize) + if fontsize: + self.patch.set_mutation_scale(fontsize) def draw(self, renderer): "draw the artist" From e0e0039681c62df56baf9e660a944be93a269064 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:34:50 -0400 Subject: [PATCH 31/79] ENH : add stale flag to AnchoredOffsetbox --- lib/matplotlib/offsetbox.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index d3955b25fb93..9880a5564ac6 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1014,6 +1014,7 @@ def __init__(self, loc, def set_child(self, child): "set the child to be anchored" self._child = child + self.stale = True def get_child(self): "return the child" @@ -1071,6 +1072,7 @@ def set_bbox_to_anchor(self, bbox, transform=None): self._bbox_to_anchor = Bbox.from_bounds(*bbox) self._bbox_to_anchor_transform = transform + self.stale = True def get_window_extent(self, renderer): ''' @@ -1131,6 +1133,7 @@ def draw(self, renderer): self.get_child().set_offset((px, py)) self.get_child().draw(renderer) + self.stale = False def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad): """ From cb0a22f26c87106887550c184e588663b596be56 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:39:44 -0400 Subject: [PATCH 32/79] ENH : add stale flag to OffsetImage --- lib/matplotlib/offsetbox.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 9880a5564ac6..f6a0c7f30a2a 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1248,12 +1248,14 @@ def __init__(self, arr, def set_data(self, arr): self._data = np.asarray(arr) self.image.set_data(self._data) + self.stale = True def get_data(self): return self._data def set_zoom(self, zoom): self._zoom = zoom + self.stale = True def get_zoom(self): return self._zoom @@ -1310,7 +1312,8 @@ def draw(self, renderer): Draw the children """ self.image.draw(renderer) - #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + # bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class AnnotationBbox(martist.Artist, _AnnotationBase): From 15451c731edb96fc17de6c5a8de4067ea2377b51 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 08:43:51 -0400 Subject: [PATCH 33/79] ENH : add stale flag to AnnotationBbox --- lib/matplotlib/offsetbox.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index f6a0c7f30a2a..4be462550335 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1406,6 +1406,7 @@ def xyann(self): @xyann.setter def xyann(self, xyann): self.xybox = xyann + self.stale = True @property def anncoords(self): @@ -1414,6 +1415,7 @@ def anncoords(self): @anncoords.setter def anncoords(self, coords): self.boxcoords = coords + self.stale = True def contains(self, event): t, tinfo = self.offsetbox.contains(event) @@ -1446,6 +1448,7 @@ def set_fontsize(self, s=None): s = rcParams["legend.fontsize"] self.prop = FontProperties(size=s) + self.stale = True def get_fontsize(self, s=None): """ @@ -1552,6 +1555,7 @@ def draw(self, renderer): self.patch.draw(renderer) self.offsetbox.draw(renderer) + self.stale = False class DraggableBase(object): From fb3181bd7fb00da90be2b10e7c1a005a3b3431e2 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:06:32 -0400 Subject: [PATCH 34/79] ENH : add stale flag to Patch --- lib/matplotlib/patches.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index bf65b002ccb6..2a9ab63c92f9 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -257,6 +257,7 @@ def set_antialiased(self, aa): if aa is None: aa = mpl.rcParams['patch.antialiased'] self._antialiased = aa + self.stale = True def set_aa(self, aa): """alias for set_antialiased""" @@ -272,6 +273,7 @@ def set_edgecolor(self, color): color = mpl.rcParams['patch.edgecolor'] self._original_edgecolor = color self._edgecolor = colors.colorConverter.to_rgba(color, self._alpha) + self.stale = True def set_ec(self, color): """alias for set_edgecolor""" @@ -291,6 +293,7 @@ def set_facecolor(self, color): if not self._fill: self._facecolor = list(self._facecolor) self._facecolor[3] = 0 + self.stale = True def set_fc(self, color): """alias for set_facecolor""" @@ -325,6 +328,7 @@ def set_alpha(self, alpha): # using self._fill and self._alpha self.set_facecolor(self._original_facecolor) self.set_edgecolor(self._original_edgecolor) + self.stale = True def set_linewidth(self, w): """ @@ -334,8 +338,11 @@ def set_linewidth(self, w): """ if w is None: w = mpl.rcParams['patch.linewidth'] + self._linewidth = float(w) + self.stale = True + def set_lw(self, lw): """alias for set_linewidth""" return self.set_linewidth(lw) @@ -375,6 +382,7 @@ def set_linestyle(self, ls): ls = cbook.ls_mapper.get(ls, ls) self._linestyle = ls + self.stale = True def set_ls(self, ls): """alias for set_linestyle""" @@ -388,6 +396,7 @@ def set_fill(self, b): """ self._fill = bool(b) self.set_facecolor(self._original_facecolor) + self.stale = True def get_fill(self): 'return whether fill is set' @@ -409,6 +418,7 @@ def set_capstyle(self, s): raise ValueError('set_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._capstyle = s + self.stale = True def get_capstyle(self): "Return the current capstyle" @@ -425,6 +435,7 @@ def set_joinstyle(self, s): raise ValueError('set_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._joinstyle = s + self.stale = True def get_joinstyle(self): "Return the current joinstyle" @@ -457,6 +468,7 @@ def set_hatch(self, hatch): ACCEPTS: ['/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*'] """ self._hatch = hatch + self.stale = True def get_hatch(self): 'Return the current hatching pattern' @@ -511,6 +523,7 @@ def draw(self, renderer): gc.restore() renderer.close_group('patch') + self.stale = False def get_path(self): """ From 8f8dba5df363762be87013d54edf81001e1f6a35 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:06:53 -0400 Subject: [PATCH 35/79] ENH : add stale flag to Rectangle --- lib/matplotlib/patches.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 2a9ab63c92f9..4db987038262 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -706,6 +706,7 @@ def set_x(self, x): ACCEPTS: float """ self._x = x + self.stale = True def set_y(self, y): """ @@ -714,6 +715,7 @@ def set_y(self, y): ACCEPTS: float """ self._y = y + self.stale = True def set_xy(self, xy): """ @@ -722,6 +724,7 @@ def set_xy(self, xy): ACCEPTS: 2-item sequence """ self._x, self._y = xy + self.stale = True def set_width(self, w): """ @@ -730,6 +733,7 @@ def set_width(self, w): ACCEPTS: float """ self._width = w + self.stale = True def set_height(self, h): """ @@ -738,6 +742,7 @@ def set_height(self, h): ACCEPTS: float """ self._height = h + self.stale = True def set_bounds(self, *args): """ @@ -753,6 +758,7 @@ def set_bounds(self, *args): self._y = b self._width = w self._height = h + self.stale = True def get_bbox(self): return transforms.Bbox.from_bounds(self._x, self._y, From cb82a8523cac9a74a47266714b66fac8b6f8f56d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:07:55 -0400 Subject: [PATCH 36/79] ENH : add stale flag to Polygon --- lib/matplotlib/patches.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 4db987038262..21ad92a22f70 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -943,6 +943,7 @@ def set_closed(self, closed): return self._closed = bool(closed) self.set_xy(self.get_xy()) + self.stale = True def get_xy(self): """ @@ -974,6 +975,7 @@ def set_xy(self, xy): if len(xy) > 2 and (xy[0] == xy[-1]).all(): xy = xy[:-1] self._path = Path(xy, closed=self._closed) + self.stale = True _get_xy = get_xy _set_xy = set_xy From 77450acdd6c8610c3c819ee08e7379ca26196d60 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:08:59 -0400 Subject: [PATCH 37/79] ENH : add stale flag to Wedge --- lib/matplotlib/patches.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 21ad92a22f70..4194d776afe1 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1047,22 +1047,27 @@ def _recompute_path(self): def set_center(self, center): self._path = None self.center = center + self.stale = True def set_radius(self, radius): self._path = None self.r = radius + self.stale = True def set_theta1(self, theta1): self._path = None self.theta1 = theta1 + self.stale = True def set_theta2(self, theta2): self._path = None self.theta2 = theta2 + self.stale = True def set_width(self, width): self._path = None self.width = width + self.stale = True def get_path(self): if self._path is None: From 9c954e84f9190e548be6cec400b5db9042a7fedd Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:18:14 -0400 Subject: [PATCH 38/79] ENH : add stale flag to FancyBboxPatch --- lib/matplotlib/patches.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 4194d776afe1..5db0c6d5f501 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1454,6 +1454,7 @@ def set_radius(self, radius): ACCEPTS: float """ self.width = self.height = 2 * radius + self.stale = True def get_radius(self): 'return the radius of the circle' @@ -2457,6 +2458,7 @@ def __init__(self, xy, width, height, self._mutation_scale = mutation_scale self._mutation_aspect = mutation_aspect + self.stale = True @docstring.dedent_interpd def set_boxstyle(self, boxstyle=None, **kw): @@ -2490,6 +2492,7 @@ def set_boxstyle(self, boxstyle=None, **kw): self._bbox_transmuter = boxstyle else: self._bbox_transmuter = BoxStyle(boxstyle, **kw) + self.stale = True def set_mutation_scale(self, scale): """ @@ -2498,6 +2501,7 @@ def set_mutation_scale(self, scale): ACCEPTS: float """ self._mutation_scale = scale + self.stale = True def get_mutation_scale(self): """ @@ -2512,6 +2516,7 @@ def set_mutation_aspect(self, aspect): ACCEPTS: float """ self._mutation_aspect = aspect + self.stale = True def get_mutation_aspect(self): """ @@ -2559,6 +2564,7 @@ def set_x(self, x): ACCEPTS: float """ self._x = x + self.stale = True def set_y(self, y): """ @@ -2567,6 +2573,7 @@ def set_y(self, y): ACCEPTS: float """ self._y = y + self.stale = True def set_width(self, w): """ @@ -2575,6 +2582,7 @@ def set_width(self, w): ACCEPTS: float """ self._width = w + self.stale = True def set_height(self, h): """ @@ -2583,6 +2591,7 @@ def set_height(self, h): ACCEPTS: float """ self._height = h + self.stale = True def set_bounds(self, *args): """ @@ -2598,6 +2607,7 @@ def set_bounds(self, *args): self._y = b self._width = w self._height = h + self.stale = True def get_bbox(self): return transforms.Bbox.from_bounds(self._x, self._y, From da78f69f96936cf1dc3c053ab7d9428e042f2f59 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:21:19 -0400 Subject: [PATCH 39/79] ENH : add stale flag to FancyArrowPatch --- lib/matplotlib/patches.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 5db0c6d5f501..d8fb136defae 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -4040,6 +4040,7 @@ def set_dpi_cor(self, dpi_cor): """ self._dpi_cor = dpi_cor + self.stale = True def get_dpi_cor(self): """ @@ -4057,16 +4058,19 @@ def set_positions(self, posA, posB): self._posA_posB[0] = posA if posB is not None: self._posA_posB[1] = posB + self.stale = True def set_patchA(self, patchA): """ set the begin patch. """ self.patchA = patchA + self.stale = True def set_patchB(self, patchB): """ set the begin patch """ self.patchB = patchB + self.stale = True def set_connectionstyle(self, connectionstyle, **kw): """ @@ -4095,6 +4099,7 @@ def set_connectionstyle(self, connectionstyle, **kw): self._connector = connectionstyle else: self._connector = ConnectionStyle(connectionstyle, **kw) + self.stale = True def get_connectionstyle(self): """ @@ -4126,6 +4131,7 @@ def set_arrowstyle(self, arrowstyle=None, **kw): self._arrow_transmuter = arrowstyle else: self._arrow_transmuter = ArrowStyle(arrowstyle, **kw) + self.stale = True def get_arrowstyle(self): """ @@ -4140,6 +4146,7 @@ def set_mutation_scale(self, scale): ACCEPTS: float """ self._mutation_scale = scale + self.stale = True def get_mutation_scale(self): """ @@ -4154,6 +4161,7 @@ def set_mutation_aspect(self, aspect): ACCEPTS: float """ self._mutation_aspect = aspect + self.stale = True def get_mutation_aspect(self): """ @@ -4261,6 +4269,7 @@ def draw(self, renderer): gc.restore() renderer.close_group('patch') + self.stale = False class ConnectionPatch(FancyArrowPatch): From 19398317a42409c98116d395f9cee8896646f2c8 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:22:52 -0400 Subject: [PATCH 40/79] ENH : add stale flag to FancyArrowPatch --- lib/matplotlib/patches.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index d8fb136defae..5da4a902cc7b 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -4488,6 +4488,7 @@ def set_annotation_clip(self, b): * None: the self.xy will be checked only if *xycoords* is "data" """ self._annotation_clip = b + self.stale = True def get_annotation_clip(self): """ From d8d52d81b8645dac60d6ed0622988c9f5072a930 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:25:36 -0400 Subject: [PATCH 41/79] ENH : add stale flag to QuiverKey --- lib/matplotlib/quiver.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index d9ee0cf5d1b1..04f18eb26085 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -336,6 +336,7 @@ def draw(self, renderer): self.text.set_x(self._text_x(x)) self.text.set_y(self._text_y(y)) self.text.draw(renderer) + self.stale = False def _set_transform(self): if self.coord == 'data': From 013e1a7ae0232d610bf3384ab02d4422caddcdfa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:36:41 -0400 Subject: [PATCH 42/79] ENH : add stale flag to Quiver --- lib/matplotlib/quiver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index 04f18eb26085..a25e46cb4a89 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -528,6 +528,7 @@ def draw(self, renderer): self.set_verts(verts, closed=False) self._new_UV = False mcollections.PolyCollection.draw(self, renderer) + self.stale = False def set_UVC(self, U, V, C=None): # We need to ensure we have a copy, not a reference @@ -548,6 +549,7 @@ def set_UVC(self, U, V, C=None): if C is not None: self.set_array(C) self._new_UV = True + self.stale = True def _dots_per_unit(self, units): """ From 406e8cefee9e735eb8f4bfbd4b0009c087db8b8a Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Thu, 30 Apr 2015 17:37:43 -0400 Subject: [PATCH 43/79] ENH : add stale flag to Barb --- lib/matplotlib/quiver.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index a25e46cb4a89..ddac93bd71d4 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -1137,6 +1137,7 @@ def set_UVC(self, U, V, C=None): # Update the offsets in case the masked data changed xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis])) self._offsets = xy + self.stale = True def set_offsets(self, xy): """ @@ -1152,6 +1153,8 @@ def set_offsets(self, xy): self.u, self.v) xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis])) mcollections.PolyCollection.set_offsets(self, xy) + self.stale = True + set_offsets.__doc__ = mcollections.PolyCollection.set_offsets.__doc__ barbs_doc = _barbs_doc From 329098246ccc0ce52132fc1ceaf3c588466588a7 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 4 May 2015 17:44:51 -0400 Subject: [PATCH 44/79] FIX : fix order of operation in __init__ functions --- lib/matplotlib/artist.py | 2 +- lib/matplotlib/collections.py | 3 ++- lib/matplotlib/patches.py | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 92c4da391256..b0d47abff004 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -86,6 +86,7 @@ class Artist(object): zorder = 0 def __init__(self): + self._stale = True self._axes = None self.figure = None @@ -117,7 +118,6 @@ def __init__(self): self._snap = None self._sketch = rcParams['path.sketch'] self._path_effects = rcParams['path.effects'] - self._stale = True def __getstate__(self): d = self.__dict__.copy() diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index c77be43c4b7b..2bbe90429042 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1103,7 +1103,6 @@ def __init__(self, segments, # Can be None. linewidths = (mpl.rcParams['lines.linewidth'],) if antialiaseds is None: antialiaseds = (mpl.rcParams['lines.antialiased'],) - self.set_linestyles(linestyles) colors = mcolors.colorConverter.to_rgba_array(colors) @@ -1122,6 +1121,8 @@ def __init__(self, segments, # Can be None. zorder=zorder, **kwargs) + self.set_linestyles(linestyles) + self.set_segments(segments) def set_segments(self, segments): diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 5da4a902cc7b..0e467fbd0ab1 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1444,8 +1444,8 @@ def __init__(self, xy, radius=5, **kwargs): %(Patch)s """ - self.radius = radius Ellipse.__init__(self, xy, radius * 2, radius * 2, **kwargs) + self.radius = radius def set_radius(self, radius): """ @@ -4002,6 +4002,7 @@ def __init__(self, posA=None, posB=None, Valid kwargs are: %(Patch)s """ + Patch.__init__(self, **kwargs) if posA is not None and posB is not None and path is None: self._posA_posB = [posA, posB] @@ -4021,8 +4022,6 @@ def __init__(self, posA=None, posB=None, self.shrinkA = shrinkA self.shrinkB = shrinkB - Patch.__init__(self, **kwargs) - self._path_original = path self.set_arrowstyle(arrowstyle) From c5412485540680830faa13b2cb7c6a6a046e4c0c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 4 May 2015 20:30:02 -0400 Subject: [PATCH 45/79] FIX : use canonical linestyles kwarg in contour LineCollections can have their line style set either via the explicit `linestyles` kwarg or via the imlicit `linestyle' which is set via `Artist` level `set_*` magic. --- lib/matplotlib/contour.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index 9d6a73f12c8f..970a4b5df8f3 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -964,7 +964,7 @@ def __init__(self, ax, *args, **kwargs): segs, antialiaseds=aa, linewidths=width, - linestyle=[lstyle], + linestyles=[lstyle], alpha=self.alpha, transform=self.get_transform(), zorder=zorder) From 30d10608d49c4034fc71635cbf3c641b388ec3bb Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 4 May 2015 20:31:59 -0400 Subject: [PATCH 46/79] MNT : remove unneeded call to set_linestyles This function is called as part of the `Collection.__init__` call so does not need to be re-called. This also fixes an issue with the default value of 'linestyles` (solid) taking precedence over a passed in `linestyle` kwarg. --- lib/matplotlib/collections.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index 2bbe90429042..aa00ca9c2c07 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -1121,8 +1121,6 @@ def __init__(self, segments, # Can be None. zorder=zorder, **kwargs) - self.set_linestyles(linestyles) - self.set_segments(segments) def set_segments(self, segments): From c1de4dd2fb351bb10578f52a8edc236654fe10c3 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 4 May 2015 20:57:45 -0400 Subject: [PATCH 47/79] FIX : fix init order in AnnotationBbox --- lib/matplotlib/offsetbox.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 4be462550335..04fa144ffa6d 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1353,6 +1353,13 @@ def __init__(self, offsetbox, xy, other parameters are identical to that of Annotation. """ + + martist.Artist.__init__(self, **kwargs) + _AnnotationBase.__init__(self, + xy, + xycoords=xycoords, + annotation_clip=annotation_clip) + self.offsetbox = offsetbox self.arrowprops = arrowprops @@ -1377,13 +1384,6 @@ def __init__(self, offsetbox, xy, self._arrow_relpos = None self.arrow_patch = None - _AnnotationBase.__init__(self, - xy, - xycoords=xycoords, - annotation_clip=annotation_clip) - - martist.Artist.__init__(self, **kwargs) - #self._fw, self._fh = 0., 0. # for alignment self._box_alignment = box_alignment From 79d971d870686a4c8900d40c454179107d360ca4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 4 May 2015 22:45:09 -0400 Subject: [PATCH 48/79] FIX : reorder __init__ of OffsetBox --- lib/matplotlib/offsetbox.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 04fa144ffa6d..47a402911b37 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1225,6 +1225,7 @@ def __init__(self, arr, **kwargs ): + OffsetBox.__init__(self) self._dpi_cor = dpi_cor self.image = BboxImage(bbox=self.get_window_extent, @@ -1243,8 +1244,6 @@ def __init__(self, arr, self.set_zoom(zoom) self.set_data(arr) - OffsetBox.__init__(self) - def set_data(self, arr): self._data = np.asarray(arr) self.image.set_data(self._data) From 2c10dcb8c3a175cb02af48e92666bea6992869ea Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 16:45:21 -0400 Subject: [PATCH 49/79] ENH : add stale flag to Spines --- lib/matplotlib/spines.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index f73ee15fbc73..a6938b9d899d 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -96,6 +96,7 @@ def set_smart_bounds(self, value): self.axes.yaxis.set_smart_bounds(value) elif self.spine_type in ('top', 'bottom'): self.axes.xaxis.set_smart_bounds(value) + self.stale = True def get_smart_bounds(self): """get whether the spine has smart bounds""" @@ -110,10 +111,12 @@ def set_patch_circle(self, center, radius): self._angle = 0 # circle drawn on axes transform self.set_transform(self.axes.transAxes) + self.stale = True def set_patch_line(self): """set the spine to be linear""" self._patch_type = 'line' + self.stale = True # Behavior copied from mpatches.Ellipse: def _recompute_transform(self): @@ -158,6 +161,7 @@ def register_axis(self, axis): self.axis = axis if self.axis is not None: self.axis.cla() + self.stale = True def cla(self): """Clear the current spine""" @@ -274,7 +278,9 @@ def _adjust_location(self): @allow_rasterization def draw(self, renderer): self._adjust_location() - return super(Spine, self).draw(renderer) + ret = super(Spine, self).draw(renderer) + self.stale = False + return ret def _calc_offset_transform(self): """calculate the offset transform performed by the spine""" @@ -388,6 +394,7 @@ def set_position(self, position): if self.axis is not None: self.axis.reset_ticks() + self.stale = True def get_position(self): """get the spine position""" @@ -437,6 +444,7 @@ def set_bounds(self, low, high): raise ValueError( 'set_bounds() method incompatible with circular spines') self._bounds = (low, high) + self.stale = True def get_bounds(self): """Get the bounds of the spine.""" @@ -486,3 +494,4 @@ def set_color(self, c): # The facecolor of a spine is always 'none' by default -- let # the user change it manually if desired. self.set_edgecolor(c) + self.stale = True From cd70834a8459c71e2b9545dc6ed07844a6355da4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 16:47:51 -0400 Subject: [PATCH 50/79] ENH : add stale flag to Cell --- lib/matplotlib/table.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index 605cbd92492a..4e58ce578b87 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -68,6 +68,7 @@ def __init__(self, xy, width, height, def set_transform(self, trans): Rectangle.set_transform(self, trans) # the text does not get the transform! + self.stale = True def set_figure(self, fig): Rectangle.set_figure(self, fig) @@ -79,6 +80,7 @@ def get_text(self): def set_fontsize(self, size): self._text.set_fontsize(size) + self.stale = True def get_fontsize(self): 'Return the cell fontsize' @@ -105,6 +107,7 @@ def draw(self, renderer): # position the text self._set_text_position(renderer) self._text.draw(renderer) + self.stale = False def _set_text_position(self, renderer): """ Set text up so it draws in the right place. @@ -145,6 +148,7 @@ def get_required_width(self, renderer): def set_text_props(self, **kwargs): 'update the text properties with kwargs' self._text.update(kwargs) + self.stale = True class CustomCell(Cell): From 3f3ef107db80c825793aeb41ebdd185924185f9d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 16:48:06 -0400 Subject: [PATCH 51/79] ENH : add stale flag to CustumCell --- lib/matplotlib/table.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index 4e58ce578b87..c304b1ca058e 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -190,6 +190,7 @@ def visible_edges(self, value): ) raise ValueError(msg) self._visible_edges = value + self.stale = True def get_path(self): 'Return a path where the edges specificed by _visible_edges are drawn' From 21c677f8edc6333f89568808b92ba9ea1fbb0d7e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 16:49:41 -0400 Subject: [PATCH 52/79] ENH : add stale flag to Table --- lib/matplotlib/table.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index c304b1ca058e..cc6f6a1970ad 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -290,6 +290,7 @@ def add_cell(self, row, col, *args, **kwargs): cell.set_clip_on(False) self._cells[(row, col)] = cell + self.stale = True @property def edges(self): @@ -298,6 +299,7 @@ def edges(self): @edges.setter def edges(self, value): self._edges = value + self.stale = True def _approx_text_height(self): return (self.FONTSIZE / 72.0 * self.figure.dpi / @@ -325,6 +327,7 @@ def draw(self, renderer): # for c in self._cells.itervalues(): # c.draw(renderer) renderer.close_group('table') + self.stale = False def _get_grid_bbox(self, renderer): """Get a bbox, in axes co-ordinates for the cells. @@ -408,6 +411,7 @@ def _do_cell_alignment(self): def auto_set_column_width(self, col): self._autoColumns.append(col) + self.stale = True def _auto_set_column_width(self, col, renderer): """ Automagically set width for column. @@ -427,6 +431,7 @@ def _auto_set_column_width(self, col, renderer): def auto_set_font_size(self, value=True): """ Automatically set font size. """ self._autoFontsize = value + self.stale = True def _auto_set_font_size(self, renderer): @@ -461,6 +466,7 @@ def set_fontsize(self, size): for cell in six.itervalues(self._cells): cell.set_fontsize(size) + self.stale = True def _offset(self, ox, oy): 'Move all the artists by ox,oy (axes coords)' From e9aa714bee8f9419a907137b4841e7ccdeabd634 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 16:57:00 -0400 Subject: [PATCH 53/79] ENH : add stale flag to Text --- lib/matplotlib/text.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index c7a22ad39b7c..625e81ae2c1d 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -297,6 +297,7 @@ def set_rotation_mode(self, m): self._rotation_mode = m else: raise ValueError("Unknown rotation_mode : %s" % repr(m)) + self.stale = True def get_rotation_mode(self): "get text rotation mode" @@ -313,6 +314,7 @@ def update_from(self, other): self._rotation = other._rotation self._picker = other._picker self._linespacing = other._linespacing + self.stale = True def _get_layout(self, renderer): """ @@ -786,6 +788,7 @@ def draw(self, renderer): gc.restore() renderer.close_group('text') + self.stale = False def get_color(self): "Return the color of the text" @@ -963,6 +966,7 @@ def set_backgroundcolor(self, color): self._bbox.update(dict(facecolor=color)) self._update_clip_properties() + self.stale = True def set_color(self, color): """ @@ -976,6 +980,7 @@ def set_color(self, color): except TypeError: color = tuple(color) self._color = color + self.stale = True def set_ha(self, align): 'alias for set_horizontalalignment' @@ -992,6 +997,7 @@ def set_horizontalalignment(self, align): raise ValueError('Horizontal alignment must be one of %s' % str(legal)) self._horizontalalignment = align + self.stale = True def set_ma(self, align): 'alias for set_verticalalignment' @@ -1011,6 +1017,7 @@ def set_multialignment(self, align): raise ValueError('Horizontal alignment must be one of %s' % str(legal)) self._multialignment = align + self.stale = True def set_linespacing(self, spacing): """ @@ -1020,6 +1027,7 @@ def set_linespacing(self, spacing): ACCEPTS: float (multiple of font size) """ self._linespacing = spacing + self.stale = True def set_family(self, fontname): """ @@ -1033,6 +1041,7 @@ def set_family(self, fontname): 'monospace' ] """ self._fontproperties.set_family(fontname) + self.stale = True def set_variant(self, variant): """ @@ -1041,6 +1050,7 @@ def set_variant(self, variant): ACCEPTS: [ 'normal' | 'small-caps' ] """ self._fontproperties.set_variant(variant) + self.stale = True def set_fontvariant(self, variant): 'alias for set_variant' @@ -1061,6 +1071,7 @@ def set_style(self, fontstyle): ACCEPTS: [ 'normal' | 'italic' | 'oblique'] """ self._fontproperties.set_style(fontstyle) + self.stale = True def set_fontstyle(self, fontstyle): 'alias for set_style' @@ -1075,6 +1086,7 @@ def set_size(self, fontsize): 'medium' | 'large' | 'x-large' | 'xx-large' ] """ self._fontproperties.set_size(fontsize) + self.stale = True def set_fontsize(self, fontsize): 'alias for set_size' @@ -1090,6 +1102,7 @@ def set_weight(self, weight): 'extra bold' | 'black' ] """ self._fontproperties.set_weight(weight) + self.stale = True def set_fontweight(self, weight): 'alias for set_weight' @@ -1105,6 +1118,7 @@ def set_stretch(self, stretch): 'ultra-expanded' ] """ self._fontproperties.set_stretch(stretch) + self.stale = True def set_fontstretch(self, stretch): 'alias for set_stretch' @@ -1126,6 +1140,7 @@ def set_x(self, x): ACCEPTS: float """ self._x = x + self.stale = True def set_y(self, y): """ @@ -1134,6 +1149,7 @@ def set_y(self, y): ACCEPTS: float """ self._y = y + self.stale = True def set_rotation(self, s): """ @@ -1142,6 +1158,7 @@ def set_rotation(self, s): ACCEPTS: [ angle in degrees | 'vertical' | 'horizontal' ] """ self._rotation = s + self.stale = True def set_va(self, align): 'alias for set_verticalalignment' @@ -1159,6 +1176,7 @@ def set_verticalalignment(self, align): str(legal)) self._verticalalignment = align + self.stale = True def set_text(self, s): """ @@ -1169,6 +1187,7 @@ def set_text(self, s): ACCEPTS: string or anything printable with '%s' conversion. """ self._text = '%s' % (s,) + self.stale = True @staticmethod def is_math_text(s): @@ -1201,6 +1220,7 @@ def set_fontproperties(self, fp): if is_string_like(fp): fp = FontProperties(fp) self._fontproperties = fp.copy() + self.stale = True def set_font_properties(self, fp): 'alias for set_fontproperties' @@ -1217,6 +1237,7 @@ def set_usetex(self, usetex): self._usetex = None else: self._usetex = bool(usetex) + self.stale = True def get_usetex(self): """ From 3eeb64d86cb071f5ba1460f61e8818238f70cecc Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 17:03:17 -0400 Subject: [PATCH 54/79] ENH : add stale flag to TextWithDash --- lib/matplotlib/text.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 625e81ae2c1d..00ac38d355ed 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -1385,6 +1385,7 @@ def draw(self, renderer): Text.draw(self, renderer) if self.get_dashlength() > 0.0: self.dashline.draw(renderer) + self.stale = False def update_coords(self, renderer): """ @@ -1504,6 +1505,7 @@ def set_dashlength(self, dl): ACCEPTS: float (canvas units) """ self._dashlength = dl + self.stale = True def get_dashdirection(self): """ @@ -1521,6 +1523,7 @@ def set_dashdirection(self, dd): ACCEPTS: int (1 is before, 0 is after) """ self._dashdirection = dd + self.stale = True def get_dashrotation(self): """ @@ -1538,6 +1541,7 @@ def set_dashrotation(self, dr): ACCEPTS: float (degrees) """ self._dashrotation = dr + self.stale = True def get_dashpad(self): """ @@ -1553,6 +1557,7 @@ def set_dashpad(self, dp): ACCEPTS: float (canvas units) """ self._dashpad = dp + self.stale = True def get_dashpush(self): """ @@ -1570,6 +1575,7 @@ def set_dashpush(self, dp): ACCEPTS: float (canvas units) """ self._dashpush = dp + self.stale = True def set_position(self, xy): """ @@ -1587,6 +1593,7 @@ def set_x(self, x): ACCEPTS: float """ self._dashx = float(x) + self.stale = True def set_y(self, y): """ @@ -1595,6 +1602,7 @@ def set_y(self, y): ACCEPTS: float """ self._dashy = float(y) + self.stale = True def set_transform(self, t): """ @@ -1605,6 +1613,7 @@ def set_transform(self, t): """ Text.set_transform(self, t) self.dashline.set_transform(t) + self.stale = True def get_figure(self): 'return the figure instance the artist belongs to' From 9706cc09335676bba7d40a56826ae131349f0b7d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 17:21:19 -0400 Subject: [PATCH 55/79] MNT : remove stale flags from Axes.draw The first pass at getting this to work put all of the logic to label artists as not stale in the Axes.draw method. Now that all of the draw methods are marked up this is not needed. --- lib/matplotlib/axes/_base.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 37254dd11cea..dd92fe43b506 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2064,7 +2064,6 @@ def draw(self, renderer=None, inframe=False): # will draw the edges if self.axison and self._frameon: self.patch.draw(renderer) - self.patch.stale = False if _do_composite: # make a composite image, blending alpha @@ -2097,18 +2096,15 @@ def draw(self, renderer=None, inframe=False): self.patch.get_transform())) renderer.draw_image(gc, round(l), round(b), im) - im.stale = False gc.restore() if dsu_rasterized: for zorder, a in dsu_rasterized: a.draw(renderer) - a.stale = False renderer.stop_rasterizing() for zorder, a in dsu: a.draw(renderer) - a.stale = False renderer.close_group('axes') self._cachedRenderer = renderer @@ -2125,7 +2121,6 @@ def draw_artist(self, a): ' caches the render') raise AttributeError(msg) a.draw(self._cachedRenderer) - a.stale = False def redraw_in_frame(self): """ From 16bcbdfe4dfcfb42f76fb3b78022155e42df6d7f Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 5 May 2015 17:59:12 -0400 Subject: [PATCH 56/79] DOC : add whats new entry --- .../whats_new/2015-05_interactive_OO.rst | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 doc/users/whats_new/2015-05_interactive_OO.rst diff --git a/doc/users/whats_new/2015-05_interactive_OO.rst b/doc/users/whats_new/2015-05_interactive_OO.rst new file mode 100644 index 000000000000..e66e6983d4be --- /dev/null +++ b/doc/users/whats_new/2015-05_interactive_OO.rst @@ -0,0 +1,37 @@ +Interactive OO usage +-------------------- + +All `Artists` now keep track of if their internal state has been +changed but not reflected in the display ('stale') by a call to +``draw``. It is thus possible to pragmatically determine if a given +`Figure` needs to be re-drawn in an interactive session. + +To facilitate interactive usage a ``draw_all`` method has been added +to ``pyplot`` which will redraw all of the figures which are 'stale'. + +To make this convenient for interactive use matplotlib now registers +a function either with IPython's 'post_execute' event or with the +displayhook in the standard python REPL to automatically call +``plt.draw_all`` just before control is returned to the REPL. This ensures +that the draw command is deferred and only called once. + +The upshot of this is that for interactive backends (including notebook) + +.. ipython :: python + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + + ln, = ax.plot([0, 1, 4, 9, 16]) + + plt.show() + + ln.set_color('g') + + +will automatically update the plot to be green. Subsequent +modifications to the `Artist` objects will do likewise. + +This is the first step of a larger consolidation and simplification of +the pyplot internals. From f824578ea0f4875cba9de2ad97b484ebb9ee2a00 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Wed, 6 May 2015 08:50:22 -0400 Subject: [PATCH 57/79] FIX : add missing stale flag to Line2D --- lib/matplotlib/lines.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index f670c3acb302..0b0216f77b68 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -800,6 +800,7 @@ def draw(self, renderer): gc.restore() renderer.close_group('line2d') + self.stale = False def get_antialiased(self): return self._antialiased From 8112b436af9b72a610af70093daef237f27f50fb Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 15 May 2015 23:15:16 -0400 Subject: [PATCH 58/79] MNT : use draw_idle not draw in Gcf.draw_all `draw_idle` has a better chance of not stepping on it's own toes and re-drawing multiple times in quick secession. I think this will also play nicer with the OSX backend? --- lib/matplotlib/_pylab_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index 1fb79cd695bb..b851f06981d7 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -148,6 +148,6 @@ def draw_all(cls, force=False): for f_mgr in cls.get_all_fig_managers(): # TODO add logic to check if figure is stale if force or f_mgr.canvas.figure.stale: - f_mgr.canvas.draw() + f_mgr.canvas.draw_idle() atexit.register(Gcf.destroy_all) From 05f6426080190ad1ed709a08b170583755f0c249 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:12:11 -0400 Subject: [PATCH 59/79] ENH : add stale flag to Axes.cla Set stale after clearing (just to be safe) --- lib/matplotlib/axes/_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index dd92fe43b506..de63cd84399e 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -973,6 +973,7 @@ def cla(self): if self._sharey: self.yaxis.set_visible(yaxis_visible) self.patch.set_visible(patch_visible) + self.stale = True def clear(self): """clear the axes""" From d29be280915fada123d5ed2464cf2185db67a2b2 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:13:26 -0400 Subject: [PATCH 60/79] ENH : add stale flag to mplot3D.art3D.* --- lib/mpl_toolkits/mplot3d/art3d.py | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 6381a685239f..a5feda47fac0 100755 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -75,6 +75,7 @@ def set_3d_properties(self, z=0, zdir='z'): x, y = self.get_position() self._position3d = np.array((x, y, z)) self._dir_vec = get_dir_vector(zdir) + self.stale = True def draw(self, renderer): proj = proj3d.proj_trans_points([self._position3d, \ @@ -89,12 +90,15 @@ def draw(self, renderer): self.set_position((proj[0][0], proj[1][0])) self.set_rotation(norm_text_angle(angle)) mtext.Text.draw(self, renderer) + self.stale = False + def text_2d_to_3d(obj, z=0, zdir='z'): """Convert a Text to a Text3D object.""" obj.__class__ = Text3D obj.set_3d_properties(z, zdir) + class Line3D(lines.Line2D): ''' 3D line object. @@ -119,12 +123,15 @@ def set_3d_properties(self, zs=0, zdir='z'): except TypeError: pass self._verts3d = juggle_axes(xs, ys, zs, zdir) + self.stale = True def draw(self, renderer): xs3d, ys3d, zs3d = self._verts3d xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) self.set_data(xs, ys) lines.Line2D.draw(self, renderer) + self.stale = False + def line_2d_to_3d(line, zs=0, zdir='z'): ''' @@ -170,9 +177,10 @@ def __init__(self, segments, *args, **kwargs): ''' LineCollection.__init__(self, segments, *args, **kwargs) - def set_sort_zpos(self,val): + def set_sort_zpos(self, val): '''Set the position to use for z-sorting.''' self._sort_zpos = val + self.stale = True def set_segments(self, segments): ''' @@ -202,12 +210,14 @@ def draw(self, renderer, project=False): self.do_3d_projection(renderer) LineCollection.draw(self, renderer) + def line_collection_2d_to_3d(col, zs=0, zdir='z'): """Convert a LineCollection to a Line3DCollection object.""" segments3d = paths_to_3d_segments(col.get_paths(), zs, zdir) col.__class__ = Line3DCollection col.set_segments(segments3d) + class Patch3D(Patch): ''' 3D patch object. @@ -322,10 +332,10 @@ def __init__(self, *args, **kwargs): PatchCollection.__init__(self, *args, **kwargs) self.set_3d_properties(zs, zdir) - - def set_sort_zpos(self,val): + def set_sort_zpos(self, val): '''Set the position to use for z-sorting.''' self._sort_zpos = val + self.stale = True def set_3d_properties(self, zs, zdir): # Force the collection to initialize the face and edgecolors @@ -340,6 +350,7 @@ def set_3d_properties(self, zs, zdir): self._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir) self._facecolor3d = self.get_facecolor() self._edgecolor3d = self.get_edgecolor() + self.stale = True def do_3d_projection(self, renderer): xs, ys, zs = self._offsets3d @@ -356,9 +367,9 @@ def do_3d_projection(self, renderer): self.set_edgecolors(ecs) PatchCollection.set_offsets(self, list(zip(vxs, vys))) - if vzs.size > 0 : + if vzs.size > 0: return min(vzs) - else : + else: return np.nan @@ -392,6 +403,7 @@ def __init__(self, *args, **kwargs): def set_sort_zpos(self, val): '''Set the position to use for z-sorting.''' self._sort_zpos = val + self.stale = True def set_3d_properties(self, zs, zdir): # Force the collection to initialize the face and edgecolors @@ -406,6 +418,7 @@ def set_3d_properties(self, zs, zdir): self._offsets3d = juggle_axes(xs, ys, np.atleast_1d(zs), zdir) self._facecolor3d = self.get_facecolor() self._edgecolor3d = self.get_edgecolor() + self.stale = True def do_3d_projection(self, renderer): xs, ys, zs = self._offsets3d @@ -453,6 +466,7 @@ def patch_collection_2d_to_3d(col, zs=0, zdir='z', depthshade=True): col._depthshade = depthshade col.set_3d_properties(zs, zdir) + class Poly3DCollection(PolyCollection): ''' A collection of 3D polygons. @@ -502,6 +516,7 @@ def set_zsort(self, zsort): self._zsort = zsort self._sort_zpos = None self._zsortfunc = zsortfunc + self.stale = True def get_vector(self, segments3d): """Optimize points for projection""" @@ -540,10 +555,12 @@ def set_3d_properties(self): self._facecolors3d = PolyCollection.get_facecolors(self) self._edgecolors3d = PolyCollection.get_edgecolors(self) self._alpha3d = PolyCollection.get_alpha(self) + self.stale = True def set_sort_zpos(self,val): '''Set the position to use for z-sorting.''' self._sort_zpos = val + self.stale = True def do_3d_projection(self, renderer): ''' @@ -631,6 +648,7 @@ def set_alpha(self, alpha): self._edgecolors3d, self._alpha) except (AttributeError, TypeError, IndexError): pass + self.stale = True def get_facecolors(self): return self._facecolors2d @@ -643,6 +661,7 @@ def get_edgecolors(self): def draw(self, renderer): return Collection.draw(self, renderer) + def poly_collection_2d_to_3d(col, zs=0, zdir='z'): """Convert a PolyCollection to a Poly3DCollection object.""" segments_3d = paths_to_3d_segments(col.get_paths(), zs, zdir) From 2970d303dd706907bad9dd97ce74340719bd81ca Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:13:56 -0400 Subject: [PATCH 61/79] ENH : add stale flag to Axes3D --- lib/mpl_toolkits/mplot3d/axes3d.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index b06186f6b955..3881370beab7 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -126,9 +126,11 @@ def __init__(self, fig, rect=None, *args, **kwargs): def set_axis_off(self): self._axis3don = False + self.stale = True def set_axis_on(self): self._axis3don = True + self.stale = True def have_units(self): """ @@ -342,6 +344,7 @@ def set_zmargin(self, m) : if m < 0 or m > 1 : raise ValueError("margin must be in range 0 to 1") self._zmargin = m + self.stale = True def margins(self, *args, **kw) : """ @@ -610,7 +613,7 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, **kw): if (other.figure != self.figure and other.figure.canvas is not None): other.figure.canvas.draw_idle() - + self.stale = True return left, right set_xlim = set_xlim3d @@ -665,7 +668,7 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): if (other.figure != self.figure and other.figure.canvas is not None): other.figure.canvas.draw_idle() - + self.stale = True return bottom, top set_ylim = set_ylim3d @@ -719,7 +722,7 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, **kw): if (other.figure != self.figure and other.figure.canvas is not None): other.figure.canvas.draw_idle() - + self.stale = True return bottom, top set_zlim = set_zlim3d @@ -771,6 +774,7 @@ def set_yscale(self, value, **kwargs) : self.yaxis._set_scale(value, **kwargs) self.autoscale_view(scalex=False, scalez=False) self._update_transScale() + self.stale = True set_yscale.__doc__ = maxes.Axes.set_yscale.__doc__ + """ .. versionadded :: 1.1.0 @@ -802,6 +806,7 @@ def set_zscale(self, value, **kwargs) : self.zaxis._set_scale(value, **kwargs) self.autoscale_view(scalex=False, scaley=False) self._update_transScale() + self.stale = True def set_zticks(self, *args, **kwargs): """ @@ -1216,6 +1221,7 @@ def set_frame_on(self, b): .. versionadded :: 1.1.0 """ self._frameon = bool(b) + self.stale = True def get_axisbelow(self): """ @@ -1241,6 +1247,7 @@ def set_axisbelow(self, b): This function was added for completeness. """ self._axisbelow = True + self.stale = True def grid(self, b=True, **kwargs): ''' @@ -1259,6 +1266,7 @@ def grid(self, b=True, **kwargs): if len(kwargs) : b = True self._draw_grid = cbook._string_to_bool(b) + self.stale = True def ticklabel_format(self, **kwargs) : """ From 83aafffabb495272da2cf083ba8d93620a50c3cc Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:14:18 -0400 Subject: [PATCH 62/79] ENH : add stale flag to mplot3d.Axis --- lib/mpl_toolkits/mplot3d/axis3d.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mpl_toolkits/mplot3d/axis3d.py b/lib/mpl_toolkits/mplot3d/axis3d.py index f0eb7b8107e1..6170203d1342 100755 --- a/lib/mpl_toolkits/mplot3d/axis3d.py +++ b/lib/mpl_toolkits/mplot3d/axis3d.py @@ -141,6 +141,7 @@ def set_pane_pos(self, xys): xys = np.asarray(xys) xys = xys[:,:2] self.pane.xy = xys + self.stale = True def set_pane_color(self, color): '''Set pane color to a RGBA tuple''' @@ -148,6 +149,7 @@ def set_pane_color(self, color): self.pane.set_edgecolor(color) self.pane.set_facecolor(color) self.pane.set_alpha(color[-1]) + self.stale = True def set_rotate_label(self, val): ''' @@ -155,6 +157,7 @@ def set_rotate_label(self, val): If set to None the label will be rotated if longer than 4 chars. ''' self._rotate_label = val + self.stale = True def get_rotate_label(self, text): if self._rotate_label is not None: @@ -416,6 +419,7 @@ def draw(self, renderer): tick.draw(renderer) renderer.close_group('axis3d') + self.stale = False def get_view_interval(self): """return the Interval instance for this 3d axis view limits""" From a55547503f0d61d11b4585926d9f6286469241aa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:29:23 -0400 Subject: [PATCH 63/79] DOC : fix docstrings which were lies --- lib/matplotlib/pyplot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 103f633bcf40..fec8acc9267c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -114,7 +114,8 @@ def install_repl_displayhook(): class _NotIPython(Exception): pass - # see if we have IPython hooks around, if so monkey patch + # see if we have IPython hooks around, if use them + try: from IPython import get_ipython ip = get_ipython() @@ -128,8 +129,7 @@ class _NotIPython(Exception): # IPython 1.x ip.register_post_execute(draw_all) - # import failed or sys.displayhook is not of correct type, - # must not have IPython + # import failed or ipython is not running except (ImportError, _NotIPython): dh = sys.displayhook From f4efac1f2f9beee7e78cc88c716897badbb4f515 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:36:44 -0400 Subject: [PATCH 64/79] MNT : add guards to only register repl hook once Multiple calls to install_repl_displayhook are effectively no-ops. --- lib/matplotlib/pyplot.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index fec8acc9267c..80082b031b30 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -108,8 +108,13 @@ def _backend_selection(): from matplotlib.backends import pylab_setup _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() +_BASE_DH = None +_IP_REGISTERED = False + def install_repl_displayhook(): + global _BASE_DH + global _IP_REGISTERED class _NotIPython(Exception): pass @@ -122,16 +127,25 @@ class _NotIPython(Exception): if ip is None: raise _NotIPython() + if _IP_REGISTERED: + return + # IPython >= 2 try: ip.events.register('post_execute', draw_all) except AttributeError: # IPython 1.x ip.register_post_execute(draw_all) + finally: + _IP_REGISTERED = True # import failed or ipython is not running except (ImportError, _NotIPython): - dh = sys.displayhook + + if _BASE_DH is not None: + return + + dh = _BASE_DH = sys.displayhook def displayhook(*args): dh(*args) From f41ae9e57b14b47caf464191d668a6075caa1629 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:49:40 -0400 Subject: [PATCH 65/79] DOC : added docstring to install_repl_displayhook --- lib/matplotlib/pyplot.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 80082b031b30..ea708cb8c067 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -113,6 +113,12 @@ def _backend_selection(): def install_repl_displayhook(): + """ + Install a repl display hook so that any stale figure are automatically + redrawn when control is returned to the repl. + + This works with both IPython terminals and vanilla python shells. + """ global _BASE_DH global _IP_REGISTERED From 096d714b89d3e6cfd9cc3fb90d65ee310ba617e3 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 00:51:31 -0400 Subject: [PATCH 66/79] ENH : added uninstall for repl displayhook --- lib/matplotlib/pyplot.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index ea708cb8c067..48876daad13a 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -159,6 +159,40 @@ def displayhook(*args): sys.displayhook = displayhook + +def uninstall_repl_displayhook(): + """ + Uninstalls the matplotlib display hook. + + .. warning + + Need IPython >= 2 for this to work. For IPython < 2 will raise a + ``NotImplementedError`` + + .. warning + + If you are using vanilla python and have installed another + display hook this will reset ``sys.displayhook`` to what ever + function was there when matplotlib installed it's displayhook, + possibly discarding your changes. + """ + global _BASE_DH + global _IP_REGISTERED + if _IP_REGISTERED: + from IPython import get_ipython + ip = get_ipython() + try: + ip.events.unregister('post_execute', draw_all) + except AttributeError: + raise NotImplementedError("Can not unregister events " + "in IPython < 2.0") + _IP_REGISTERED = False + + if _BASE_DH: + sys.displayhook = _BASE_DH + _BASE_DH = None + + draw_all = _pylab_helpers.Gcf.draw_all From 17d9ada1455b89bbf2e218fda2748cb2e4648767 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:09:40 -0400 Subject: [PATCH 67/79] FIX : order of operation is Poly3DCollection init Make sure parent class is `__init__`'d before trying to use a function that requires _stale attribute. --- lib/mpl_toolkits/mplot3d/art3d.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index a5feda47fac0..28ee8ef37e50 100755 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -484,10 +484,9 @@ def __init__(self, verts, *args, **kwargs): Note that this class does a bit of magic with the _facecolors and _edgecolors properties. ''' - - self.set_zsort(kwargs.pop('zsort', True)) - + zsort = kwargs.pop('zsort', True) PolyCollection.__init__(self, verts, *args, **kwargs) + self.set_zsort(zsort) _zsort_functions = { 'average': np.average, From 54da8cc1db27d48a7baf3134144b2ceb8962c267 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:29:44 -0400 Subject: [PATCH 68/79] ENH : integrate repl hook with is_interactive - add calls to {un}install in plt.i{on, off} - registered functions consult `mpl.is_interactive` before triggering draws --- lib/matplotlib/pyplot.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 48876daad13a..c871020f994c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -109,7 +109,7 @@ def _backend_selection(): _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() _BASE_DH = None -_IP_REGISTERED = False +_IP_REGISTERED = None def install_repl_displayhook(): @@ -136,14 +136,18 @@ class _NotIPython(Exception): if _IP_REGISTERED: return + def displayhook(): + if matplotlib.is_interactive(): + draw_all() + # IPython >= 2 try: - ip.events.register('post_execute', draw_all) + ip.events.register('post_execute', displayhook) except AttributeError: # IPython 1.x - ip.register_post_execute(draw_all) + ip.register_post_execute(displayhook) finally: - _IP_REGISTERED = True + _IP_REGISTERED = displayhook # import failed or ipython is not running except (ImportError, _NotIPython): @@ -155,7 +159,8 @@ class _NotIPython(Exception): def displayhook(*args): dh(*args) - draw_all() + if matplotlib.is_interactive(): + draw_all() sys.displayhook = displayhook @@ -182,11 +187,11 @@ def uninstall_repl_displayhook(): from IPython import get_ipython ip = get_ipython() try: - ip.events.unregister('post_execute', draw_all) + ip.events.unregister('post_execute', _IP_REGISTERED) except AttributeError: raise NotImplementedError("Can not unregister events " "in IPython < 2.0") - _IP_REGISTERED = False + _IP_REGISTERED = None if _BASE_DH: sys.displayhook = _BASE_DH @@ -252,11 +257,13 @@ def isinteractive(): def ioff(): 'Turn interactive mode off.' matplotlib.interactive(False) + uninstall_repl_displayhook() def ion(): 'Turn interactive mode on.' matplotlib.interactive(True) + install_repl_displayhook() def pause(interval): @@ -3900,4 +3907,9 @@ def spectral(): draw_if_interactive() _setup_pyplot_info_docstrings() +# just to be safe. Interactive mode can be turned on without +# calling `plt.ion()` so register it again here. +# This is safe because multiple calls to `install_repl_displayhook` +# are no-ops and the registered function respect `mpl.is_interactive()` +# to determine if they should trigger a draw. install_repl_displayhook() From a26831dbf634d9f8f239dc371c370f636206a8ae Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:33:41 -0400 Subject: [PATCH 69/79] FIX : logic for IPython hook registration Only set the global _IP_REGISTERED if the registration succeeds, with the finally block it would be set if _both_ failed. --- lib/matplotlib/pyplot.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index c871020f994c..5770013cbf2e 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -146,8 +146,8 @@ def displayhook(): except AttributeError: # IPython 1.x ip.register_post_execute(displayhook) - finally: - _IP_REGISTERED = displayhook + + _IP_REGISTERED = displayhook # import failed or ipython is not running except (ImportError, _NotIPython): From 1c99420059bbe0df8df3675f4e6d676443de7dc1 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:45:53 -0400 Subject: [PATCH 70/79] MNT : move repl install above boilerplate fold --- lib/matplotlib/pyplot.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 5770013cbf2e..9b92cbfbbf62 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2524,6 +2524,12 @@ def spy(Z, precision=0, marker=None, markersize=None, aspect='equal', hold=None, sci(ret) return ret +# just to be safe. Interactive mode can be turned on without +# calling `plt.ion()` so register it again here. +# This is safe because multiple calls to `install_repl_displayhook` +# are no-ops and the registered function respect `mpl.is_interactive()` +# to determine if they should trigger a draw. +install_repl_displayhook() ################# REMAINING CONTENT GENERATED BY boilerplate.py ############## @@ -3907,9 +3913,3 @@ def spectral(): draw_if_interactive() _setup_pyplot_info_docstrings() -# just to be safe. Interactive mode can be turned on without -# calling `plt.ion()` so register it again here. -# This is safe because multiple calls to `install_repl_displayhook` -# are no-ops and the registered function respect `mpl.is_interactive()` -# to determine if they should trigger a draw. -install_repl_displayhook() From a9faf4bee7c283086e5c2a40ac11a33e001037c6 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 11:14:46 -0400 Subject: [PATCH 71/79] ENH : add stale flag to Tick, XTick, YTick --- lib/matplotlib/axis.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 4c76686c88b7..986c64babc20 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -177,6 +177,8 @@ def get_children(self): def set_clip_path(self, clippath, transform=None): artist.Artist.set_clip_path(self, clippath, transform) self.gridline.set_clip_path(clippath, transform) + self.stale = True + set_clip_path.__doc__ = artist.Artist.set_clip_path.__doc__ def get_pad_pixels(self): @@ -200,6 +202,7 @@ def set_pad(self, val): ACCEPTS: float """ self._apply_params(pad=val) + self.stale = True def get_pad(self): 'Get the value of the tick label pad in points' @@ -251,6 +254,7 @@ def draw(self, renderer): self.label2.draw(renderer) renderer.close_group(self.__name__) + self.stale = False def set_label1(self, s): """ @@ -259,6 +263,8 @@ def set_label1(self, s): ACCEPTS: str """ self.label1.set_text(s) + self.stale = True + set_label = set_label1 def set_label2(self, s): @@ -268,6 +274,7 @@ def set_label2(self, s): ACCEPTS: str """ self.label2.set_text(s) + self.stale = True def _set_artist_props(self, a): a.set_figure(self.figure) @@ -349,6 +356,7 @@ def apply_tickdir(self, tickdir): else: self._tickmarkers = (mlines.TICKDOWN, mlines.TICKUP) self._pad = self._base_pad + self._size + self.stale = True def _get_text1(self): 'Get the default Text instance' @@ -450,6 +458,7 @@ def update_position(self, loc): self.gridline._invalid = True self._loc = loc + self.stale = True def get_view_interval(self): 'return the Interval instance for this axis view limits' @@ -483,6 +492,7 @@ def apply_tickdir(self, tickdir): else: self._tickmarkers = (mlines.TICKLEFT, mlines.TICKRIGHT) self._pad = self._base_pad + self._size + self.stale = True # how far from the y axis line the right of the ticklabel are def _get_text1(self): @@ -584,6 +594,7 @@ def update_position(self, loc): self.gridline._invalid = True self._loc = loc + self.stale = True def get_view_interval(self): 'return the Interval instance for this axis view limits' From e3fb8500e8d0b7b7be076811e4de2322e8b425a0 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 11:38:11 -0400 Subject: [PATCH 72/79] ENH : add stale flag to Axis, XAxis, YAxis --- lib/matplotlib/axis.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 986c64babc20..ba5e4e86497a 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -679,6 +679,7 @@ def set_label_coords(self, x, y, transform=None): self.label.set_transform(transform) self.label.set_position((x, y)) + self.stale = True def get_transform(self): return self._scale.get_transform() @@ -743,6 +744,7 @@ def cla(self): self.converter = None self.units = None self.set_units(None) + self.stale = True def reset_ticks(self): # build a few default ticks; grow as necessary later; only @@ -782,6 +784,7 @@ def set_tick_params(self, which='major', reset=False, **kw): if which == 'minor' or which == 'both': for tick in self.minorTicks: tick._apply_params(**self._minor_tick_kw) + self.stale = True @staticmethod def _translate_tick_kw(kw, to_init_kw=True): @@ -846,6 +849,7 @@ def set_clip_path(self, clippath, transform=None): artist.Artist.set_clip_path(self, clippath, transform) for child in self.majorTicks + self.minorTicks: child.set_clip_path(clippath, transform) + self.stale = True def get_view_interval(self): 'return the Interval instance for this axis view limits' @@ -928,6 +932,7 @@ def get_ticklabel_extents(self, renderer): def set_smart_bounds(self, value): """set the axis to have smart bounds""" self._smart_bounds = value + self.stale = True def get_smart_bounds(self): """get whether the axis has smart bounds""" @@ -1125,6 +1130,7 @@ def draw(self, renderer, *args, **kwargs): mpatches.bbox_artist(self.label, renderer) renderer.close_group(__name__) + self.stale = False def _get_label(self): raise NotImplementedError('Derived must override') @@ -1365,6 +1371,7 @@ def grid(self, b=None, which='major', **kwargs): if len(kwargs): tick.gridline.update(kwargs) self._major_tick_kw['gridOn'] = self._gridOnMajor + self.stale = True def update_units(self, data): """ @@ -1385,6 +1392,7 @@ def update_units(self, data): if neednew: self._update_axisinfo() + self.stale = True return True def _update_axisinfo(self): @@ -1452,6 +1460,7 @@ def set_units(self, u): self._update_axisinfo() self.callbacks.process('units') self.callbacks.process('units finalize') + self.stale = True def get_units(self): 'return the units for axis' @@ -1467,6 +1476,7 @@ def set_label_text(self, label, fontdict=None, **kwargs): if fontdict is not None: self.label.update(fontdict) self.label.update(kwargs) + self.stale = True return self.label def set_major_formatter(self, formatter): @@ -1478,6 +1488,7 @@ def set_major_formatter(self, formatter): self.isDefault_majfmt = False self.major.formatter = formatter formatter.set_axis(self) + self.stale = True def set_minor_formatter(self, formatter): """ @@ -1488,6 +1499,7 @@ def set_minor_formatter(self, formatter): self.isDefault_minfmt = False self.minor.formatter = formatter formatter.set_axis(self) + self.stale = True def set_major_locator(self, locator): """ @@ -1498,6 +1510,7 @@ def set_major_locator(self, locator): self.isDefault_majloc = False self.major.locator = locator locator.set_axis(self) + self.stale = True def set_minor_locator(self, locator): """ @@ -1508,6 +1521,7 @@ def set_minor_locator(self, locator): self.isDefault_minloc = False self.minor.locator = locator locator.set_axis(self) + self.stale = True def set_pickradius(self, pickradius): """ @@ -1567,6 +1581,7 @@ def set_ticklabels(self, ticklabels, *args, **kwargs): if tick.label2On: ret.append(tick.label2) + self.stale = True return ret def set_ticks(self, ticks, minor=False): @@ -1747,6 +1762,7 @@ def set_label_position(self, position): msg = "Position accepts only [ 'top' | 'bottom' ]" raise ValueError(msg) self.label_position = position + self.stale = True def _update_label_position(self, bboxes, bboxes2): """ @@ -1851,6 +1867,7 @@ def set_ticks_position(self, position): bottom=True, labelbottom=True) else: raise ValueError("invalid position: %s" % position) + self.stale = True def tick_top(self): 'use ticks only on top' @@ -1929,6 +1946,7 @@ def set_data_interval(self, vmin, vmax, ignore=False): else: Vmin, Vmax = self.get_data_interval() self.axes.dataLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + self.stale = True def set_default_intervals(self): 'set the default limits for the axis interval if they are not mutated' @@ -1946,6 +1964,7 @@ def set_default_intervals(self): self.axes.dataLim.intervalx = xmin, xmax if not viewMutated: self.axes.viewLim.intervalx = xmin, xmax + self.stale = True class YAxis(Axis): @@ -2065,6 +2084,7 @@ def set_label_position(self, position): msg = "Position accepts only [ 'left' | 'right' ]" raise ValueError(msg) self.label_position = position + self.stale = True def _update_label_position(self, bboxes, bboxes2): """ @@ -2127,6 +2147,7 @@ def set_offset_position(self, position): self.offsetText.set_ha(position) self.offsetText.set_position((x, y)) + self.stale = True def get_text_widths(self, renderer): bbox, bbox2 = self.get_ticklabel_extents(renderer) @@ -2176,6 +2197,7 @@ def set_ticks_position(self, position): left=True, labelleft=True) else: raise ValueError("invalid position: %s" % position) + self.stale = True def tick_right(self): 'use ticks only on right' @@ -2239,6 +2261,7 @@ def set_view_interval(self, vmin, vmax, ignore=False): else: self.axes.viewLim.intervaly = (max(vmin, vmax, Vmin), min(vmin, vmax, Vmax)) + self.stale = True def get_minpos(self): return self.axes.dataLim.minposy @@ -2254,6 +2277,7 @@ def set_data_interval(self, vmin, vmax, ignore=False): else: Vmin, Vmax = self.get_data_interval() self.axes.dataLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) + self.stale = True def set_default_intervals(self): 'set the default limits for the axis interval if they are not mutated' @@ -2271,3 +2295,4 @@ def set_default_intervals(self): self.axes.dataLim.intervaly = ymin, ymax if not viewMutated: self.axes.viewLim.intervaly = ymin, ymax + self.stale = True From 2beb5f9a8f7547f872553f4d3f3f64abe1953305 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 17 May 2015 23:55:38 -0400 Subject: [PATCH 73/79] ENH : add stale flag to _AxesBase --- lib/matplotlib/axes/_base.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index de63cd84399e..7622e5fa8281 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -474,6 +474,7 @@ def __setstate__(self, state): container = getattr(self, container_name) for artist in container: artist._remove_method = container.remove + self.stale = True def get_window_extent(self, *args, **kwargs): """ @@ -754,6 +755,7 @@ def set_position(self, pos, which='both'): self._position.set(pos) if which in ('both', 'original'): self._originalPosition.set(pos) + self.stale = True def reset_position(self): """Make the original position the active position""" @@ -768,6 +770,7 @@ def set_axes_locator(self, locator): returns a bbox. """ self._axes_locator = locator + self.stale = True def get_axes_locator(self): """ @@ -1083,6 +1086,7 @@ def set_aspect(self, aspect, adjustable=None, anchor=None): self.set_adjustable(adjustable) if anchor is not None: self.set_anchor(anchor) + self.stale = True def get_adjustable(self): return self._adjustable @@ -1099,6 +1103,7 @@ def set_adjustable(self, adjustable): self._adjustable = adjustable else: raise ValueError('argument must be "box", or "datalim"') + self.stale = True def get_anchor(self): return self._anchor @@ -1128,6 +1133,7 @@ def set_anchor(self, anchor): else: raise ValueError('argument must be among %s' % ', '.join(six.iterkeys(mtransforms.Bbox.coefs))) + self.stale = True def get_data_ratio(self): """ @@ -1789,6 +1795,7 @@ def set_xmargin(self, m): if m < 0 or m > 1: raise ValueError("margin must be in range 0 to 1") self._xmargin = m + self.stale = True def set_ymargin(self, m): """ @@ -1802,6 +1809,7 @@ def set_ymargin(self, m): if m < 0 or m > 1: raise ValueError("margin must be in range 0 to 1") self._ymargin = m + self.stale = True def margins(self, *args, **kw): """ @@ -1867,6 +1875,7 @@ def set_rasterization_zorder(self, z): zorder. """ self._rasterization_zorder = z + self.stale = True def get_rasterization_zorder(self): """ @@ -2153,6 +2162,7 @@ def set_frame_on(self, b): ACCEPTS: [ *True* | *False* ] """ self._frameon = b + self.stale = True def get_axisbelow(self): """ @@ -2168,6 +2178,7 @@ def set_axisbelow(self, b): ACCEPTS: [ *True* | *False* ] """ self._axisbelow = b + self.stale = True @docstring.dedent_interpd def grid(self, b=None, which='major', axis='both', **kwargs): @@ -2415,10 +2426,12 @@ def tick_params(self, axis='both', **kwargs): def set_axis_off(self): """turn off the axis""" self.axison = False + self.stale = True def set_axis_on(self): """turn on the axis""" self.axison = True + self.stale = True def get_axis_bgcolor(self): """Return the axis background color""" @@ -2434,7 +2447,7 @@ def set_axis_bgcolor(self, color): self._axisbg = color self.patch.set_facecolor(color) - + self.stale = True # data limits, ticks, tick labels, and formatting def invert_xaxis(self): @@ -2582,7 +2595,7 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, **kw): if (other.figure != self.figure and other.figure.canvas is not None): other.figure.canvas.draw_idle() - + self.stale = True return left, right def get_xscale(self): @@ -2611,6 +2624,7 @@ def set_xscale(self, value, **kwargs): self.xaxis._set_scale(value, **kwargs) self.autoscale_view(scaley=False) self._update_transScale() + self.stale = True def get_xticks(self, minor=False): """Return the x ticks as a list of locations""" @@ -2622,7 +2636,9 @@ def set_xticks(self, ticks, minor=False): ACCEPTS: sequence of floats """ - return self.xaxis.set_ticks(ticks, minor=minor) + ret = self.xaxis.set_ticks(ticks, minor=minor) + self.stale = True + return ret def get_xmajorticklabels(self): """ @@ -2681,8 +2697,10 @@ def set_xticklabels(self, labels, fontdict=None, minor=False, **kwargs): ACCEPTS: sequence of strings """ - return self.xaxis.set_ticklabels(labels, fontdict, - minor=minor, **kwargs) + ret = self.xaxis.set_ticklabels(labels, fontdict, + minor=minor, **kwargs) + self.stale = True + return ret def invert_yaxis(self): """ @@ -2830,7 +2848,7 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, **kw): if (other.figure != self.figure and other.figure.canvas is not None): other.figure.canvas.draw_idle() - + self.stale = True return bottom, top def get_yscale(self): @@ -2859,6 +2877,7 @@ def set_yscale(self, value, **kwargs): self.yaxis._set_scale(value, **kwargs) self.autoscale_view(scalex=False) self._update_transScale() + self.stale = True def get_yticks(self, minor=False): """Return the y ticks as a list of locations""" @@ -2875,7 +2894,8 @@ def set_yticks(self, ticks, minor=False): *minor*: [ *False* | *True* ] Sets the minor ticks if *True* """ - return self.yaxis.set_ticks(ticks, minor=minor) + ret = self.yaxis.set_ticks(ticks, minor=minor) + return ret def get_ymajorticklabels(self): """ From f15c8713a9aff75bb6779a320d7754e6f039375d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:50:49 -0400 Subject: [PATCH 74/79] MNT : hackily make boilerplate PY3 compatable Hide the python2 only code in a conditional --- boilerplate.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/boilerplate.py b/boilerplate.py index 4136dae102a3..927c9c886f9b 100644 --- a/boilerplate.py +++ b/boilerplate.py @@ -219,8 +219,9 @@ def format_value(value): else: def_edited = [] for val in defaults: - if isinstance(val, unicode): - val = val.encode('ascii', 'ignore') + if six.PY2: + if isinstance(val, unicode): + val = val.encode('ascii', 'ignore') def_edited.append(val) defaults = tuple(def_edited) From b2fbae76c738d5c24e559b98ed494e9b146c16aa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 16 May 2015 08:51:58 -0400 Subject: [PATCH 75/79] MNT : remove draw_if_interactive from boilerplate With the repl callback the pyplot function do not need to call `draw_if_interactive`. --- boilerplate.py | 5 +-- lib/matplotlib/pyplot.py | 88 +++------------------------------------- 2 files changed, 6 insertions(+), 87 deletions(-) diff --git a/boilerplate.py b/boilerplate.py index 927c9c886f9b..eabc728b4a64 100644 --- a/boilerplate.py +++ b/boilerplate.py @@ -56,7 +56,6 @@ def %(func)s(%(argspec)s): %(ax)s.hold(hold) try: %(ret)s = %(ax)s.%(func)s(%(call)s) - draw_if_interactive() finally: %(ax)s.hold(%(washold)s) %(mappable)s @@ -69,7 +68,6 @@ def %(func)s(%(argspec)s): @docstring.copy_dedent(Axes.%(func)s) def %(func)s(%(argspec)s): %(ret)s = gca().%(func)s(%(call)s) - draw_if_interactive() return %(ret)s """ @@ -85,7 +83,6 @@ def {name}(): if im is not None: im.set_cmap(cm.{name}) - draw_if_interactive() """ @@ -274,7 +271,7 @@ def format_value(value): # Since we can't avoid using some function names, # bail out if they are used as argument names - for reserved in ('gca', 'gci', 'draw_if_interactive'): + for reserved in ('gca', 'gci'): if reserved in bad: msg = 'Axes method %s has kwarg named %s' % (func, reserved) raise ValueError(msg) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 9b92cbfbbf62..2aeda57ba355 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2546,7 +2546,6 @@ def acorr(x, hold=None, **kwargs): ax.hold(hold) try: ret = ax.acorr(x, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2566,7 +2565,6 @@ def angle_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, try: ret = ax.angle_spectrum(x, Fs=Fs, Fc=Fc, window=window, pad_to=pad_to, sides=sides, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2584,7 +2582,6 @@ def arrow(x, y, dx, dy, hold=None, **kwargs): ax.hold(hold) try: ret = ax.arrow(x, y, dx, dy, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2602,7 +2599,6 @@ def axhline(y=0, xmin=0, xmax=1, hold=None, **kwargs): ax.hold(hold) try: ret = ax.axhline(y=y, xmin=xmin, xmax=xmax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2620,7 +2616,6 @@ def axhspan(ymin, ymax, xmin=0, xmax=1, hold=None, **kwargs): ax.hold(hold) try: ret = ax.axhspan(ymin, ymax, xmin=xmin, xmax=xmax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2638,7 +2633,6 @@ def axvline(x=0, ymin=0, ymax=1, hold=None, **kwargs): ax.hold(hold) try: ret = ax.axvline(x=x, ymin=ymin, ymax=ymax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2656,7 +2650,6 @@ def axvspan(xmin, xmax, ymin=0, ymax=1, hold=None, **kwargs): ax.hold(hold) try: ret = ax.axvspan(xmin, xmax, ymin=ymin, ymax=ymax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2674,7 +2667,6 @@ def bar(left, height, width=0.8, bottom=None, hold=None, **kwargs): ax.hold(hold) try: ret = ax.bar(left, height, width=width, bottom=bottom, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2692,7 +2684,6 @@ def barh(bottom, width, height=0.8, left=None, hold=None, **kwargs): ax.hold(hold) try: ret = ax.barh(bottom, width, height=height, left=left, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2710,7 +2701,6 @@ def broken_barh(xranges, yrange, hold=None, **kwargs): ax.hold(hold) try: ret = ax.broken_barh(xranges, yrange, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2743,7 +2733,6 @@ def boxplot(x, notch=False, sym=None, vert=True, whis=1.5, positions=None, flierprops=flierprops, medianprops=medianprops, meanprops=meanprops, capprops=capprops, whiskerprops=whiskerprops, manage_xticks=manage_xticks) - draw_if_interactive() finally: ax.hold(washold) @@ -2765,7 +2754,6 @@ def cohere(x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, ret = ax.cohere(x, y, NFFT=NFFT, Fs=Fs, Fc=Fc, detrend=detrend, window=window, noverlap=noverlap, pad_to=pad_to, sides=sides, scale_by_freq=scale_by_freq, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2783,7 +2771,6 @@ def clabel(CS, *args, **kwargs): ax.hold(hold) try: ret = ax.clabel(CS, *args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2801,7 +2788,6 @@ def contour(*args, **kwargs): ax.hold(hold) try: ret = ax.contour(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) if ret._A is not None: sci(ret) @@ -2819,7 +2805,6 @@ def contourf(*args, **kwargs): ax.hold(hold) try: ret = ax.contourf(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) if ret._A is not None: sci(ret) @@ -2842,7 +2827,6 @@ def csd(x, y, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, window=window, noverlap=noverlap, pad_to=pad_to, sides=sides, scale_by_freq=scale_by_freq, return_line=return_line, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2867,7 +2851,6 @@ def errorbar(x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, barsabove=barsabove, lolims=lolims, uplims=uplims, xlolims=xlolims, xuplims=xuplims, errorevery=errorevery, capthick=capthick, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2890,7 +2873,6 @@ def eventplot(positions, orientation='horizontal', lineoffsets=1, linelengths=1, lineoffsets=lineoffsets, linelengths=linelengths, linewidths=linewidths, colors=colors, linestyles=linestyles, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2908,7 +2890,6 @@ def fill(*args, **kwargs): ax.hold(hold) try: ret = ax.fill(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2927,7 +2908,6 @@ def fill_between(x, y1, y2=0, where=None, interpolate=False, hold=None, **kwargs try: ret = ax.fill_between(x, y1, y2=y2, where=where, interpolate=interpolate, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2945,7 +2925,6 @@ def fill_betweenx(y, x1, x2=0, where=None, hold=None, **kwargs): ax.hold(hold) try: ret = ax.fill_betweenx(y, x1, x2=x2, where=where, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -2972,7 +2951,6 @@ def hexbin(x, y, C=None, gridsize=100, bins=None, xscale='linear', linewidths=linewidths, edgecolors=edgecolors, reduce_C_function=reduce_C_function, mincnt=mincnt, marginals=marginals, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -2997,7 +2975,6 @@ def hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, histtype=histtype, align=align, orientation=orientation, rwidth=rwidth, log=log, color=color, label=label, stacked=stacked, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3017,7 +2994,6 @@ def hist2d(x, y, bins=10, range=None, normed=False, weights=None, cmin=None, try: ret = ax.hist2d(x, y, bins=bins, range=range, normed=normed, weights=weights, cmin=cmin, cmax=cmax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret[-1]) @@ -3037,7 +3013,6 @@ def hlines(y, xmin, xmax, colors='k', linestyles='solid', label='', hold=None, try: ret = ax.hlines(y, xmin, xmax, colors=colors, linestyles=linestyles, label=label, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3062,7 +3037,6 @@ def imshow(X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, vmax=vmax, origin=origin, extent=extent, shape=shape, filternorm=filternorm, filterrad=filterrad, imlim=imlim, resample=resample, url=url, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -3080,7 +3054,6 @@ def loglog(*args, **kwargs): ax.hold(hold) try: ret = ax.loglog(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3101,7 +3074,6 @@ def magnitude_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, ret = ax.magnitude_spectrum(x, Fs=Fs, Fc=Fc, window=window, pad_to=pad_to, sides=sides, scale=scale, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3119,7 +3091,6 @@ def pcolor(*args, **kwargs): ax.hold(hold) try: ret = ax.pcolor(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -3137,7 +3108,6 @@ def pcolormesh(*args, **kwargs): ax.hold(hold) try: ret = ax.pcolormesh(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -3157,7 +3127,6 @@ def phase_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, try: ret = ax.phase_spectrum(x, Fs=Fs, Fc=Fc, window=window, pad_to=pad_to, sides=sides, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3183,7 +3152,6 @@ def pie(x, explode=None, labels=None, colors=None, autopct=None, radius=radius, counterclock=counterclock, wedgeprops=wedgeprops, textprops=textprops, center=center, frame=frame) - draw_if_interactive() finally: ax.hold(washold) @@ -3201,7 +3169,6 @@ def plot(*args, **kwargs): ax.hold(hold) try: ret = ax.plot(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3221,7 +3188,6 @@ def plot_date(x, y, fmt='o', tz=None, xdate=True, ydate=False, hold=None, try: ret = ax.plot_date(x, y, fmt=fmt, tz=tz, xdate=xdate, ydate=ydate, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3244,7 +3210,6 @@ def psd(x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, window=window, noverlap=noverlap, pad_to=pad_to, sides=sides, scale_by_freq=scale_by_freq, return_line=return_line, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3262,7 +3227,6 @@ def quiver(*args, **kw): ax.hold(hold) try: ret = ax.quiver(*args, **kw) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -3280,7 +3244,6 @@ def quiverkey(*args, **kw): ax.hold(hold) try: ret = ax.quiverkey(*args, **kw) - draw_if_interactive() finally: ax.hold(washold) @@ -3289,9 +3252,9 @@ def quiverkey(*args, **kw): # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @_autogen_docstring(Axes.scatter) -def scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None, vmin=None, - vmax=None, alpha=None, linewidths=None, verts=None, hold=None, - **kwargs): +def scatter(x, y, s=20, c=None, marker='o', cmap=None, norm=None, vmin=None, + vmax=None, alpha=None, linewidths=None, verts=None, edgecolors=None, + hold=None, **kwargs): ax = gca() # allow callers to override the hold state by passing hold=True|False washold = ax.ishold() @@ -3301,8 +3264,8 @@ def scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None, vmin=None, try: ret = ax.scatter(x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm, vmin=vmin, vmax=vmax, alpha=alpha, - linewidths=linewidths, verts=verts, **kwargs) - draw_if_interactive() + linewidths=linewidths, verts=verts, + edgecolors=edgecolors, **kwargs) finally: ax.hold(washold) sci(ret) @@ -3320,7 +3283,6 @@ def semilogx(*args, **kwargs): ax.hold(hold) try: ret = ax.semilogx(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3338,7 +3300,6 @@ def semilogy(*args, **kwargs): ax.hold(hold) try: ret = ax.semilogy(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3363,7 +3324,6 @@ def specgram(x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, xextent=xextent, pad_to=pad_to, sides=sides, scale_by_freq=scale_by_freq, mode=mode, scale=scale, vmin=vmin, vmax=vmax, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret[-1]) @@ -3381,7 +3341,6 @@ def stackplot(x, *args, **kwargs): ax.hold(hold) try: ret = ax.stackplot(x, *args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3399,7 +3358,6 @@ def stem(*args, **kwargs): ax.hold(hold) try: ret = ax.stem(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3417,7 +3375,6 @@ def step(x, y, *args, **kwargs): ax.hold(hold) try: ret = ax.step(x, y, *args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3441,7 +3398,6 @@ def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None, arrowsize=arrowsize, arrowstyle=arrowstyle, minlength=minlength, transform=transform, zorder=zorder) - draw_if_interactive() finally: ax.hold(washold) sci(ret.lines) @@ -3459,7 +3415,6 @@ def tricontour(*args, **kwargs): ax.hold(hold) try: ret = ax.tricontour(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) if ret._A is not None: sci(ret) @@ -3477,7 +3432,6 @@ def tricontourf(*args, **kwargs): ax.hold(hold) try: ret = ax.tricontourf(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) if ret._A is not None: sci(ret) @@ -3495,7 +3449,6 @@ def tripcolor(*args, **kwargs): ax.hold(hold) try: ret = ax.tripcolor(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) sci(ret) @@ -3513,7 +3466,6 @@ def triplot(*args, **kwargs): ax.hold(hold) try: ret = ax.triplot(*args, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3536,7 +3488,6 @@ def violinplot(dataset, positions=None, vert=True, widths=0.5, showmeans=False, widths=widths, showmeans=showmeans, showextrema=showextrema, showmedians=showmedians, points=points, bw_method=bw_method) - draw_if_interactive() finally: ax.hold(washold) @@ -3556,7 +3507,6 @@ def vlines(x, ymin, ymax, colors='k', linestyles='solid', label='', hold=None, try: ret = ax.vlines(x, ymin, ymax, colors=colors, linestyles=linestyles, label=label, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3576,7 +3526,6 @@ def xcorr(x, y, normed=True, detrend=mlab.detrend_none, usevlines=True, try: ret = ax.xcorr(x, y, normed=normed, detrend=detrend, usevlines=usevlines, maxlags=maxlags, **kwargs) - draw_if_interactive() finally: ax.hold(washold) @@ -3594,7 +3543,6 @@ def barbs(*args, **kw): ax.hold(hold) try: ret = ax.barbs(*args, **kw) - draw_if_interactive() finally: ax.hold(washold) @@ -3605,7 +3553,6 @@ def barbs(*args, **kw): @docstring.copy_dedent(Axes.cla) def cla(): ret = gca().cla() - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3613,7 +3560,6 @@ def cla(): @docstring.copy_dedent(Axes.grid) def grid(b=None, which='major', axis='both', **kwargs): ret = gca().grid(b=b, which=which, axis=axis, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3621,7 +3567,6 @@ def grid(b=None, which='major', axis='both', **kwargs): @docstring.copy_dedent(Axes.legend) def legend(*args, **kwargs): ret = gca().legend(*args, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3629,7 +3574,6 @@ def legend(*args, **kwargs): @docstring.copy_dedent(Axes.table) def table(**kwargs): ret = gca().table(**kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3637,7 +3581,6 @@ def table(**kwargs): @docstring.copy_dedent(Axes.text) def text(x, y, s, fontdict=None, withdash=False, **kwargs): ret = gca().text(x, y, s, fontdict=fontdict, withdash=withdash, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3645,7 +3588,6 @@ def text(x, y, s, fontdict=None, withdash=False, **kwargs): @docstring.copy_dedent(Axes.annotate) def annotate(*args, **kwargs): ret = gca().annotate(*args, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3653,7 +3595,6 @@ def annotate(*args, **kwargs): @docstring.copy_dedent(Axes.ticklabel_format) def ticklabel_format(**kwargs): ret = gca().ticklabel_format(**kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3661,7 +3602,6 @@ def ticklabel_format(**kwargs): @docstring.copy_dedent(Axes.locator_params) def locator_params(axis='both', tight=None, **kwargs): ret = gca().locator_params(axis=axis, tight=tight, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3669,7 +3609,6 @@ def locator_params(axis='both', tight=None, **kwargs): @docstring.copy_dedent(Axes.tick_params) def tick_params(axis='both', **kwargs): ret = gca().tick_params(axis=axis, **kwargs) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3677,7 +3616,6 @@ def tick_params(axis='both', **kwargs): @docstring.copy_dedent(Axes.margins) def margins(*args, **kw): ret = gca().margins(*args, **kw) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3685,7 +3623,6 @@ def margins(*args, **kw): @docstring.copy_dedent(Axes.autoscale) def autoscale(enable=True, axis='both', tight=None): ret = gca().autoscale(enable=enable, axis=axis, tight=tight) - draw_if_interactive() return ret # This function was autogenerated by boilerplate.py. Do not edit as @@ -3700,7 +3637,6 @@ def autumn(): if im is not None: im.set_cmap(cm.autumn) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3715,7 +3651,6 @@ def bone(): if im is not None: im.set_cmap(cm.bone) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3730,7 +3665,6 @@ def cool(): if im is not None: im.set_cmap(cm.cool) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3745,7 +3679,6 @@ def copper(): if im is not None: im.set_cmap(cm.copper) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3760,7 +3693,6 @@ def flag(): if im is not None: im.set_cmap(cm.flag) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3775,7 +3707,6 @@ def gray(): if im is not None: im.set_cmap(cm.gray) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3790,7 +3721,6 @@ def hot(): if im is not None: im.set_cmap(cm.hot) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3805,7 +3735,6 @@ def hsv(): if im is not None: im.set_cmap(cm.hsv) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3820,7 +3749,6 @@ def jet(): if im is not None: im.set_cmap(cm.jet) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3835,7 +3763,6 @@ def pink(): if im is not None: im.set_cmap(cm.pink) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3850,7 +3777,6 @@ def prism(): if im is not None: im.set_cmap(cm.prism) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3865,7 +3791,6 @@ def spring(): if im is not None: im.set_cmap(cm.spring) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3880,7 +3805,6 @@ def summer(): if im is not None: im.set_cmap(cm.summer) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3895,7 +3819,6 @@ def winter(): if im is not None: im.set_cmap(cm.winter) - draw_if_interactive() # This function was autogenerated by boilerplate.py. Do not edit as @@ -3910,6 +3833,5 @@ def spectral(): if im is not None: im.set_cmap(cm.spectral) - draw_if_interactive() _setup_pyplot_info_docstrings() From 89923a67876a75543c65858e128ed90f621a4616 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 18 May 2015 00:10:09 -0400 Subject: [PATCH 76/79] MNT : remove non-boilerplate `draw_if_interactive` There is still one `draw_if_interactive` left in the `rcdefaults` call as the current scheme does not track when rcparams change. --- lib/matplotlib/pyplot.py | 77 +++++++--------------------------------- 1 file changed, 13 insertions(+), 64 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 2aeda57ba355..1acc3b447b3a 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -349,9 +349,7 @@ def sci(im): # (getp is simply imported) @docstring.copy(_setp) def setp(*args, **kwargs): - ret = _setp(*args, **kwargs) - draw_if_interactive() - return ret + return _setp(*args, **kwargs) def xkcd(scale=1, length=100, randomness=2): @@ -544,7 +542,6 @@ def make_active(event): _pylab_helpers.Gcf.set_active(figManager) figManager.canvas.figure.number = num - draw_if_interactive() return figManager.canvas.figure @@ -642,7 +639,6 @@ def clf(): Clear the current figure. """ gcf().clf() - draw_if_interactive() def draw(): @@ -707,27 +703,20 @@ def waitforbuttonpress(*args, **kwargs): @docstring.copy_dedent(Figure.text) def figtext(*args, **kwargs): - - ret = gcf().text(*args, **kwargs) - draw_if_interactive() - return ret + return gcf().text(*args, **kwargs) @docstring.copy_dedent(Figure.suptitle) def suptitle(*args, **kwargs): - ret = gcf().suptitle(*args, **kwargs) - draw_if_interactive() - return ret + return gcf().suptitle(*args, **kwargs) @docstring.Appender("Addition kwargs: hold = [True|False] overrides default hold state", "\n") @docstring.copy_dedent(Figure.figimage) def figimage(*args, **kwargs): # allow callers to override the hold state by passing hold=True|False - ret = gcf().figimage(*args, **kwargs) - draw_if_interactive() #sci(ret) # JDH figimage should not set current image -- it is not mappable, etc - return ret + return gcf().figimage(*args, **kwargs) def figlegend(handles, labels, loc, **kwargs): @@ -758,9 +747,7 @@ def figlegend(handles, labels, loc, **kwargs): :func:`~matplotlib.pyplot.legend` """ - l = gcf().legend(handles, labels, loc, **kwargs) - draw_if_interactive() - return l + return gcf().legend(handles, labels, loc, **kwargs) ## Figure and Axes hybrid ## @@ -869,7 +856,6 @@ def axes(*args, **kwargs): else: rect = arg a = gcf().add_axes(rect, **kwargs) - draw_if_interactive() return a @@ -885,7 +871,6 @@ def delaxes(*args): else: ax = args[0] ret = gcf().delaxes(ax) - draw_if_interactive() return ret @@ -922,11 +907,11 @@ def gca(**kwargs): -------- matplotlib.figure.Figure.gca : The figure's gca method. """ - ax = gcf().gca(**kwargs) - return ax + return gcf().gca(**kwargs) # More ways of creating axes: + def subplot(*args, **kwargs): """ Return a subplot axes positioned by the given grid definition. @@ -1025,7 +1010,6 @@ def subplot(*args, **kwargs): byebye.append(other) for ax in byebye: delaxes(ax) - draw_if_interactive() return a @@ -1277,7 +1261,6 @@ def subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs): byebye.append(other) for ax in byebye: delaxes(ax) - draw_if_interactive() return a @@ -1296,7 +1279,6 @@ def twinx(ax=None): if ax is None: ax=gca() ax1 = ax.twinx() - draw_if_interactive() return ax1 @@ -1310,7 +1292,6 @@ def twiny(ax=None): if ax is None: ax=gca() ax1 = ax.twiny() - draw_if_interactive() return ax1 @@ -1336,7 +1317,6 @@ def subplots_adjust(*args, **kwargs): """ fig = gcf() fig.subplots_adjust(*args, **kwargs) - draw_if_interactive() def subplot_tool(targetfig=None): @@ -1383,7 +1363,6 @@ def tight_layout(pad=1.08, h_pad=None, w_pad=None, rect=None): fig = gcf() fig.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) - draw_if_interactive() def box(on=None): @@ -1398,7 +1377,6 @@ def box(on=None): if on is None: on = not ax.get_frame_on() ax.set_frame_on(on) - draw_if_interactive() def title(s, *args, **kwargs): @@ -1443,9 +1421,7 @@ def title(s, *args, **kwargs): properties. """ - l = gca().set_title(s, *args, **kwargs) - draw_if_interactive() - return l + return gca().set_title(s, *args, **kwargs) ## Axis ## @@ -1510,10 +1486,7 @@ def axis(*v, **kwargs): :func:`xlim`, :func:`ylim` For setting the x- and y-limits individually. """ - ax = gca() - v = ax.axis(*v, **kwargs) - draw_if_interactive() - return v + return gca().axis(*v, **kwargs) def xlabel(s, *args, **kwargs): @@ -1533,9 +1506,7 @@ def xlabel(s, *args, **kwargs): :func:`~matplotlib.pyplot.text` For information on how override and the optional args work """ - l = gca().set_xlabel(s, *args, **kwargs) - draw_if_interactive() - return l + return gca().set_xlabel(s, *args, **kwargs) def ylabel(s, *args, **kwargs): @@ -1556,9 +1527,7 @@ def ylabel(s, *args, **kwargs): For information on how override and the optional args work. """ - l = gca().set_ylabel(s, *args, **kwargs) - draw_if_interactive() - return l + return gca().set_ylabel(s, *args, **kwargs) def xlim(*args, **kwargs): @@ -1586,7 +1555,6 @@ def xlim(*args, **kwargs): if not args and not kwargs: return ax.get_xlim() ret = ax.set_xlim(*args, **kwargs) - draw_if_interactive() return ret @@ -1614,7 +1582,6 @@ def ylim(*args, **kwargs): if not args and not kwargs: return ax.get_ylim() ret = ax.set_ylim(*args, **kwargs) - draw_if_interactive() return ret @@ -1633,9 +1600,7 @@ def xscale(*args, **kwargs): %(scale_docs)s """ - ax = gca() - ax.set_xscale(*args, **kwargs) - draw_if_interactive() + gca().set_xscale(*args, **kwargs) @docstring.dedent_interpd @@ -1653,9 +1618,7 @@ def yscale(*args, **kwargs): %(scale_docs)s """ - ax = gca() - ax.set_yscale(*args, **kwargs) - draw_if_interactive() + gca().set_yscale(*args, **kwargs) def xticks(*args, **kwargs): @@ -1695,7 +1658,6 @@ def xticks(*args, **kwargs): for l in labels: l.update(kwargs) - draw_if_interactive() return locs, silent_list('Text xticklabel', labels) @@ -1736,7 +1698,6 @@ def yticks(*args, **kwargs): for l in labels: l.update(kwargs) - draw_if_interactive() return ( locs, silent_list('Text yticklabel', labels) @@ -1751,7 +1712,6 @@ def minorticks_on(): minorticks_off() if drawing speed is a problem. """ gca().minorticks_on() - draw_if_interactive() def minorticks_off(): @@ -1759,7 +1719,6 @@ def minorticks_off(): Remove minor ticks from the current plot. """ gca().minorticks_off() - draw_if_interactive() def rgrids(*args, **kwargs): @@ -1802,7 +1761,6 @@ def rgrids(*args, **kwargs): else: lines, labels = ax.set_rgrids(*args, **kwargs) - draw_if_interactive() return ( silent_list('Line2D rgridline', lines), silent_list('Text rgridlabel', labels) ) @@ -1863,7 +1821,6 @@ def thetagrids(*args, **kwargs): else: lines, labels = ax.set_thetagrids(*args, **kwargs) - draw_if_interactive() return (silent_list('Line2D thetagridline', lines), silent_list('Text thetagridlabel', labels) ) @@ -2254,7 +2211,6 @@ def colorbar(mappable=None, cax=None, ax=None, **kw): ax = gca() ret = gcf().colorbar(mappable, cax = cax, ax=ax, **kw) - draw_if_interactive() return ret colorbar.__doc__ = matplotlib.colorbar.colorbar_doc @@ -2282,7 +2238,6 @@ def clim(vmin=None, vmax=None): raise RuntimeError('You must first define an image, e.g., with imshow') im.set_clim(vmin, vmax) - draw_if_interactive() def set_cmap(cmap): @@ -2304,7 +2259,6 @@ def set_cmap(cmap): if im is not None: im.set_cmap(cmap) - draw_if_interactive() @docstring.copy_dedent(_imread) @@ -2355,7 +2309,6 @@ def matshow(A, fignum=None, **kw): im = ax.matshow(A, **kw) sci(im) - draw_if_interactive() return im @@ -2373,7 +2326,6 @@ def polar(*args, **kwargs): """ ax = gca(polar=True) ret = ax.plot(*args, **kwargs) - draw_if_interactive() return ret @@ -2495,8 +2447,6 @@ def getname_val(identifier): if xname=='date': fig.autofmt_xdate() - draw_if_interactive() - def _autogen_docstring(base): """Autogenerated wrappers will get their docstring from a base function @@ -2517,7 +2467,6 @@ def spy(Z, precision=0, marker=None, markersize=None, aspect='equal', hold=None, ax.hold(hold) try: ret = ax.spy(Z, precision, marker, markersize, aspect, **kwargs) - draw_if_interactive() finally: ax.hold(washold) if isinstance(ret, cm.ScalarMappable): From 38f00afbf6594f79a6d861470b8fe70a07ec3f86 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 18 May 2015 00:11:45 -0400 Subject: [PATCH 77/79] MNT : make rcdefaults redraw all figures --- lib/matplotlib/pyplot.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 1acc3b447b3a..2de9711df408 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -311,7 +311,8 @@ def rc_context(rc=None, fname=None): @docstring.copy_dedent(matplotlib.rcdefaults) def rcdefaults(): matplotlib.rcdefaults() - draw_if_interactive() + if matplotlib.is_interactive(): + draw_all() # The current "image" (ScalarMappable) is retrieved or set From 9724f3d198f4a03d8f884beddf9256bb1842acbc Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 23 May 2015 23:04:27 -0400 Subject: [PATCH 78/79] ENH : add stale flag to ColorbarBase and Colorbar --- lib/matplotlib/colorbar.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index c4caae295681..3334b953f923 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -392,6 +392,7 @@ def set_ticks(self, ticks, update_ticks=True): if update_ticks: self.update_ticks() + self.stale = True def set_ticklabels(self, ticklabels, update_ticks=True): """ @@ -405,6 +406,7 @@ def set_ticklabels(self, ticklabels, update_ticks=True): self.update_ticks() else: warnings.warn("set_ticks() must have been called.") + self.stale = True def _config_axes(self, X, Y): ''' @@ -444,6 +446,7 @@ def _set_label(self): self.ax.set_ylabel(self._label, **self._labelkw) else: self.ax.set_xlabel(self._label, **self._labelkw) + self.stale = True def set_label(self, label, **kw): ''' @@ -548,6 +551,7 @@ def add_lines(self, levels, colors, linewidths, erase=True): self.lines.append(col) col.set_color(colors) self.ax.add_collection(col) + self.stale = True def _ticker(self): ''' @@ -942,6 +946,7 @@ def update_normal(self, mappable): CS = self.mappable if not CS.filled: self.add_lines(CS) + self.stale = True def update_bruteforce(self, mappable): ''' From 0abbcf6172eacaf63e5c1c4744e0c20ccfe6a833 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 23 May 2015 23:48:35 -0400 Subject: [PATCH 79/79] DOC: clearified whats new entry --- doc/users/whats_new/2015-05_interactive_OO.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/users/whats_new/2015-05_interactive_OO.rst b/doc/users/whats_new/2015-05_interactive_OO.rst index e66e6983d4be..926a2edbfe2c 100644 --- a/doc/users/whats_new/2015-05_interactive_OO.rst +++ b/doc/users/whats_new/2015-05_interactive_OO.rst @@ -15,7 +15,8 @@ displayhook in the standard python REPL to automatically call ``plt.draw_all`` just before control is returned to the REPL. This ensures that the draw command is deferred and only called once. -The upshot of this is that for interactive backends (including notebook) +The upshot of this is that for interactive backends (including +``%matplotlib notebook``) in interactive mode (with ``plt.ion()``) .. ipython :: python @@ -30,8 +31,8 @@ The upshot of this is that for interactive backends (including notebook) ln.set_color('g') -will automatically update the plot to be green. Subsequent -modifications to the `Artist` objects will do likewise. +will automatically update the plot to be green. Any subsequent +modifications to the ``Artist`` objects will do likewise. This is the first step of a larger consolidation and simplification of the pyplot internals.