From 380c531d58dd0dacbd303f06f2c2d3711eee1ff4 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 8 Oct 2018 21:21:32 +0200 Subject: [PATCH] Attach a FigureCanvasBase by default to Figures. This is particularly useful for headless cases, where one just wants to take advantage of `print_figure`, which is defined on the base class. For example, one can now do for : figure = Figure() # do some plotting figure.savefig(...) and let `figure` get gc'd at the next loop iteration; a pyplot-based solution would instead have to explicitly close() the figure or reuse it after clf()'ing it. Also simplifies various places in the codebase where we had to handle the case of `.canvas = None` previously. --- lib/matplotlib/artist.py | 4 +--- lib/matplotlib/axes/_base.py | 6 ++---- lib/matplotlib/figure.py | 6 +++--- lib/mpl_toolkits/mplot3d/axes3d.py | 28 +++++++++++----------------- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index 15f42ec6d56b..94a7c40896e0 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -449,9 +449,7 @@ def pickable(self): -------- set_picker, get_picker, pick """ - return (self.figure is not None and - self.figure.canvas is not None and - self._picker is not None) + return self.figure is not None and self._picker is not None def pick(self, mouseevent): """ diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 6b89e26c8dcb..cf04272b509b 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -3241,8 +3241,7 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, if other is not self: other.set_xlim(self.viewLim.intervalx, emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): + if other.figure != self.figure: other.figure.canvas.draw_idle() self.stale = True return left, right @@ -3630,8 +3629,7 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, if other is not self: other.set_ylim(self.viewLim.intervaly, emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): + if other.figure != self.figure: other.figure.canvas.draw_idle() self.stale = True return bottom, top diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index c86672c95dc9..0c3086d0ccbf 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -23,6 +23,7 @@ import matplotlib.artist as martist from matplotlib.artist import Artist, allow_rasterization +from matplotlib.backend_bases import FigureCanvasBase import matplotlib.cbook as cbook import matplotlib.colorbar as cbar import matplotlib.image as mimage @@ -364,7 +365,7 @@ def __init__(self, self._set_artist_props(self.patch) self.patch.set_antialiased(False) - self.canvas = None + FigureCanvasBase(self) # Set self.canvas. self._suptitle = None if subplotpars is None: @@ -398,8 +399,7 @@ def __init__(self, def _repr_html_(self): # We can't use "isinstance" here, because then we'd end up importing # webagg unconditiionally. - if (self.canvas is not None and - 'WebAgg' in self.canvas.__class__.__name__): + if 'WebAgg' in type(self.canvas).__name__: from matplotlib.backends import backend_webagg return backend_webagg.ipython_inline_display(self) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 3aa24d5e6e02..5e66bde94aed 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -652,8 +652,7 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, if other is not self: other.set_xlim(self.xy_viewLim.intervalx, emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): + if other.figure != self.figure: other.figure.canvas.draw_idle() self.stale = True return left, right @@ -711,8 +710,7 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, if other is not self: other.set_ylim(self.xy_viewLim.intervaly, emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): + if other.figure != self.figure: other.figure.canvas.draw_idle() self.stale = True return bottom, top @@ -770,8 +768,7 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, if other is not self: other.set_zlim(self.zz_viewLim.intervalx, emit=False, auto=auto) - if (other.figure != self.figure and - other.figure.canvas is not None): + if other.figure != self.figure: other.figure.canvas.draw_idle() self.stale = True return bottom, top @@ -1070,17 +1067,14 @@ def mouse_init(self, rotate_btn=1, zoom_btn=3): """ self.button_pressed = None - canv = self.figure.canvas - if canv is not None: - c1 = canv.mpl_connect('motion_notify_event', self._on_move) - c2 = canv.mpl_connect('button_press_event', self._button_press) - c3 = canv.mpl_connect('button_release_event', self._button_release) - self._cids = [c1, c2, c3] - else: - cbook._warn_external("Axes3D.figure.canvas is 'None', mouse " - "rotation disabled. Set canvas then call " - "Axes3D.mouse_init().") - + self._cids = [ + self.figure.canvas.mpl_connect( + 'motion_notify_event', self._on_move), + self.figure.canvas.mpl_connect( + 'button_press_event', self._button_press), + self.figure.canvas.mpl_connect( + 'button_release_event', self._button_release), + ] # coerce scalars into array-like, then convert into # a regular list to avoid comparisons against None # which breaks in recent versions of numpy.