diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 7dcfbf3fcf51..bca46679d5f8 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -55,8 +55,8 @@ from matplotlib import rcParams from matplotlib import is_interactive from matplotlib import get_backend -from matplotlib._pylab_helpers import Gcf from matplotlib import lines +from matplotlib._pylab_helpers import Gcf from matplotlib.transforms import Bbox, TransformedBbox, Affine2D @@ -141,60 +141,118 @@ def get_registered_canvas_class(format): return backend_class -class ShowBase(object): - """ - Simple base class to generate a show() callable in backends. +class _Backend(object): + # A backend can be defined by using the following pattern: + # + # @_Backend.export + # class FooBackend(_Backend): + # # override the attributes and methods documented below. - Subclass must override mainloop() method. - """ - def __call__(self, block=None): + # The following attributes and methods must be overridden by subclasses. + + # The `FigureCanvas` and `FigureManager` classes must be defined. + FigureCanvas = None + FigureManager = None + + # The following methods must be left as None for non-interactive backends. + # For interactive backends, `trigger_manager_draw` should be a function + # taking a manager as argument and triggering a canvas draw, and `mainloop` + # should be a function taking no argument and starting the backend main + # loop. + trigger_manager_draw = None + mainloop = None + + # The following methods will be automatically defined and exported, but + # can be overridden. + + @classmethod + def new_figure_manager(cls, num, *args, **kwargs): + """Create a new figure manager instance. + """ + # This import needs to happen here due to circular imports. + from matplotlib.figure import Figure + fig_cls = kwargs.pop('FigureClass', Figure) + fig = fig_cls(*args, **kwargs) + return cls.new_figure_manager_given_figure(num, fig) + + @classmethod + def new_figure_manager_given_figure(cls, num, figure): + """Create a new figure manager instance for the given figure. """ - Show all figures. If *block* is not None, then - it is a boolean that overrides all other factors - determining whether show blocks by calling mainloop(). - The other factors are: - it does not block if run inside ipython's "%pylab" mode - it does not block in interactive mode. + canvas = cls.FigureCanvas(figure) + manager = cls.FigureManager(canvas, num) + return manager + + @classmethod + def draw_if_interactive(cls): + if cls.trigger_manager_draw is not None and is_interactive(): + manager = Gcf.get_active() + if manager: + cls.trigger_manager_draw(manager) + + @classmethod + def show(cls, block=None): + """Show all figures. + + `show` blocks by calling `mainloop` if *block* is ``True``, or if it + is ``None`` and we are neither in IPython's ``%pylab`` mode, nor in + `interactive` mode. """ + if cls.mainloop is None: + return managers = Gcf.get_all_fig_managers() if not managers: return - for manager in managers: manager.show() + if block is None: + # Hack: Are we in IPython's pylab mode? + from matplotlib import pyplot + try: + # IPython versions >= 0.10 tack the _needmain attribute onto + # pyplot.show, and always set it to False, when in %pylab mode. + ipython_pylab = not pyplot.show._needmain + except AttributeError: + ipython_pylab = False + block = not ipython_pylab and not is_interactive() + # TODO: The above is a hack to get the WebAgg backend working with + # ipython's `%pylab` mode until proper integration is implemented. + if get_backend() == "WebAgg": + block = True + if block: + cls.mainloop() + + # This method is the one actually exporting the required methods. + + @staticmethod + def export(cls): + for name in ["FigureCanvas", + "FigureManager", + "new_figure_manager", + "new_figure_manager_given_figure", + "draw_if_interactive", + "show"]: + setattr(sys.modules[cls.__module__], name, getattr(cls, name)) + + # For back-compatibility, generate a shim `Show` class. + + class Show(ShowBase): + def mainloop(self): + return cls.mainloop() + + setattr(sys.modules[cls.__module__], "Show", Show) + return cls + + +class ShowBase(_Backend): + """ + Simple base class to generate a show() callable in backends. - if block is not None: - if block: - self.mainloop() - return - else: - return - - # Hack: determine at runtime whether we are - # inside ipython in pylab mode. - from matplotlib import pyplot - try: - ipython_pylab = not pyplot.show._needmain - # IPython versions >= 0.10 tack the _needmain - # attribute onto pyplot.show, and always set - # it to False, when in %pylab mode. - ipython_pylab = ipython_pylab and get_backend() != 'WebAgg' - # TODO: The above is a hack to get the WebAgg backend - # working with ipython's `%pylab` mode until proper - # integration is implemented. - except AttributeError: - ipython_pylab = False - - # Leave the following as a separate step in case we - # want to control this behavior with an rcParam. - if ipython_pylab: - return - - if not is_interactive() or get_backend() == 'WebAgg': - self.mainloop() + Subclass must override mainloop() method. + """ - def mainloop(self): - pass + def __call__(self, block=None): + return self.show(block=block) class RendererBase(object): diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index b0c876418344..a811401380c7 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -29,8 +29,8 @@ from collections import OrderedDict from math import radians, cos, sin from matplotlib import verbose, rcParams, __version__ -from matplotlib.backend_bases import (RendererBase, FigureManagerBase, - FigureCanvasBase) +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, RendererBase) from matplotlib.cbook import maxdict, restrict_dict from matplotlib.figure import Figure from matplotlib.font_manager import findfont, get_font @@ -394,24 +394,6 @@ def post_processing(image, dpi): gc, l + ox, height - b - h + oy, img) -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasAgg(figure) - manager = FigureManagerBase(canvas, num) - return manager - - class FigureCanvasAgg(FigureCanvasBase): """ The canvas the figure renders into. Calls the draw and print fig @@ -606,4 +588,7 @@ def print_tif(self, filename_or_obj, *args, **kwargs): print_tiff = print_tif -FigureCanvas = FigureCanvasAgg +@_Backend.export +class _BackendAgg(_Backend): + FigureCanvas = FigureCanvasAgg + FigureManager = FigureManagerBase diff --git a/lib/matplotlib/backends/backend_cairo.py b/lib/matplotlib/backends/backend_cairo.py index 9318cca4f885..c513872a588c 100644 --- a/lib/matplotlib/backends/backend_cairo.py +++ b/lib/matplotlib/backends/backend_cairo.py @@ -52,11 +52,12 @@ del _version_required from matplotlib.backend_bases import ( - RendererBase, GraphicsContextBase, FigureManagerBase, FigureCanvasBase) -from matplotlib.figure import Figure -from matplotlib.mathtext import MathTextParser -from matplotlib.path import Path -from matplotlib.transforms import Bbox, Affine2D + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) +from matplotlib.figure import Figure +from matplotlib.mathtext import MathTextParser +from matplotlib.path import Path +from matplotlib.transforms import Bbox, Affine2D from matplotlib.font_manager import ttfFontProperty @@ -452,24 +453,6 @@ def set_linewidth(self, w): self.ctx.set_line_width(self.renderer.points_to_pixels(w)) -def new_figure_manager(num, *args, **kwargs): # called by backends/__init__.py - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasCairo(figure) - manager = FigureManagerBase(canvas, num) - return manager - - class FigureCanvasCairo(FigureCanvasBase): def print_png(self, fobj, *args, **kwargs): width, height = self.get_width_height() @@ -555,4 +538,7 @@ def _save(self, fo, fmt, **kwargs): fo.close() -FigureCanvas = FigureCanvasCairo +@_Backend.export +class _BackendCairo(_Backend): + FigureCanvas = FigureCanvasCairo + FigureManager = FigureManagerBase diff --git a/lib/matplotlib/backends/backend_gdk.py b/lib/matplotlib/backends/backend_gdk.py index 8e9d424a8075..768d3201647f 100644 --- a/lib/matplotlib/backends/backend_gdk.py +++ b/lib/matplotlib/backends/backend_gdk.py @@ -24,7 +24,8 @@ from matplotlib import rcParams from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import ( - RendererBase, GraphicsContextBase, FigureManagerBase, FigureCanvasBase) + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) from matplotlib.cbook import restrict_dict, warn_deprecated from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser @@ -381,24 +382,6 @@ def set_linewidth(self, w): self.gdkGC.line_width = max(1, int(np.round(pixels))) -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGDK(figure) - manager = FigureManagerBase(canvas, num) - return manager - - class FigureCanvasGDK (FigureCanvasBase): def __init__(self, figure): FigureCanvasBase.__init__(self, figure) @@ -452,3 +435,9 @@ def _print_image(self, filename, format, *args, **kwargs): options['quality'] = str(options['quality']) pixbuf.save(filename, format, options=options) + + +@_Backend.export +class _BackendGDK(_Backend): + FigureCanvas = FigureCanvasGDK + FigureManager = FigureManagerBase diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index a5dec05faeaa..b3f7ec504bca 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -28,15 +28,14 @@ import matplotlib from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import RendererBase, GraphicsContextBase, \ - FigureManagerBase, FigureCanvasBase, NavigationToolbar2, cursors, TimerBase -from matplotlib.backend_bases import ShowBase +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, + TimerBase, cursors) from matplotlib.backends.backend_gdk import RendererGDK, FigureCanvasGDK -from matplotlib.cbook import is_writable_file_like +from matplotlib.cbook import is_writable_file_like, warn_deprecated from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool -from matplotlib.cbook import warn_deprecated from matplotlib import ( cbook, colors as mcolors, lines, markers, rcParams, verbose) @@ -63,41 +62,6 @@ def GTK_WIDGET_DRAWABLE(w): return flags & gtk.VISIBLE != 0 and flags & gtk.MAPPED != 0 -def draw_if_interactive(): - """ - Is called after every pylab drawing command - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw_idle() - - -class Show(ShowBase): - def mainloop(self): - if gtk.main_level() == 0: - gtk.main() - -show = Show() - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGTK(figure) - manager = FigureManagerGTK(canvas, num) - return manager - - class TimerGTK(TimerBase): ''' Subclass of :class:`backend_bases.TimerBase` using GTK for timer events. @@ -521,6 +485,7 @@ def stop_event_loop(self): FigureCanvasBase.stop_event_loop_default(self) stop_event_loop.__doc__=FigureCanvasBase.stop_event_loop_default.__doc__ + class FigureManagerGTK(FigureManagerBase): """ Attributes @@ -866,6 +831,7 @@ def get_filename_from_user (self): return filename, self.ext + class DialogLineprops(object): """ A GUI dialog for controlling lineprops @@ -1056,5 +1022,16 @@ def error_msg_gtk(msg, parent=None): dialog.destroy() -FigureCanvas = FigureCanvasGTK -FigureManager = FigureManagerGTK +@_Backend.export +class _BackendGTK(_Backend): + FigureCanvas = FigureCanvasGTK + FigureManager = FigureManagerGTK + + @staticmethod + def trigger_manager_draw(manager): + manager.canvas.draw_idle() + + @staticmethod + def mainloop(): + if gtk.main_level() == 0: + gtk.main() diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 4e53c1a4ee2e..a5f223a38753 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -28,10 +28,9 @@ import matplotlib from matplotlib._pylab_helpers import Gcf from matplotlib.backend_bases import ( - FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, NavigationToolbar2, RendererBase, TimerBase, cursors) -from matplotlib.backend_bases import ( - ShowBase, ToolContainerBase, StatusbarBase) +from matplotlib.backend_bases import ToolContainerBase, StatusbarBase from matplotlib.backend_managers import ToolManager from matplotlib.cbook import is_writable_file_like from matplotlib.figure import Figure @@ -54,22 +53,6 @@ cursors.SELECT_REGION : Gdk.Cursor.new(Gdk.CursorType.TCROSS), } -def draw_if_interactive(): - """ - Is called after every pylab drawing command - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw_idle() - -class Show(ShowBase): - def mainloop(self): - if Gtk.main_level() == 0: - Gtk.main() - -show = Show() - class TimerGTK3(TimerBase): ''' @@ -947,5 +930,18 @@ def error_msg_gtk(msg, parent=None): backend_tools.ToolRubberband = RubberbandGTK3 Toolbar = ToolbarGTK3 -FigureCanvas = FigureCanvasGTK3 -FigureManager = FigureManagerGTK3 + + +@_Backend.export +class _BackendGTK3(_Backend): + FigureCanvas = FigureCanvasGTK3 + FigureManager = FigureManagerGTK3 + + @staticmethod + def trigger_manager_draw(manager): + manager.canvas.draw_idle() + + @staticmethod + def mainloop(): + if Gtk.main_level() == 0: + Gtk.main() diff --git a/lib/matplotlib/backends/backend_gtk3agg.py b/lib/matplotlib/backends/backend_gtk3agg.py index f60ac9b8154d..a8bce0c4e6fc 100644 --- a/lib/matplotlib/backends/backend_gtk3agg.py +++ b/lib/matplotlib/backends/backend_gtk3agg.py @@ -6,9 +6,9 @@ import numpy as np import warnings -from . import backend_agg -from . import backend_gtk3 +from . import backend_agg, backend_gtk3 from .backend_cairo import cairo, HAS_CAIRO_CFFI +from .backend_gtk3 import _BackendGTK3 from matplotlib.figure import Figure from matplotlib import transforms @@ -97,24 +97,7 @@ class FigureManagerGTK3Agg(backend_gtk3.FigureManagerGTK3): pass -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGTK3Agg(figure) - manager = FigureManagerGTK3Agg(canvas, num) - return manager - - -FigureCanvas = FigureCanvasGTK3Agg -FigureManager = FigureManagerGTK3Agg -show = backend_gtk3.show +@_BackendGTK3.export +class _BackendGTK3Cairo(_BackendGTK3): + FigureCanvas = FigureCanvasGTK3Agg + FigureManager = FigureManagerGTK3Agg diff --git a/lib/matplotlib/backends/backend_gtk3cairo.py b/lib/matplotlib/backends/backend_gtk3cairo.py index b01f51b638ad..958689d8e6ba 100644 --- a/lib/matplotlib/backends/backend_gtk3cairo.py +++ b/lib/matplotlib/backends/backend_gtk3cairo.py @@ -3,11 +3,12 @@ import six -from . import backend_gtk3 -from . import backend_cairo +from . import backend_cairo, backend_gtk3 from .backend_cairo import cairo, HAS_CAIRO_CFFI +from .backend_gtk3 import _BackendGTK3 from matplotlib.figure import Figure + class RendererGTK3Cairo(backend_cairo.RendererCairo): def set_context(self, ctx): if HAS_CAIRO_CFFI: @@ -22,16 +23,14 @@ def set_context(self, ctx): class FigureCanvasGTK3Cairo(backend_gtk3.FigureCanvasGTK3, backend_cairo.FigureCanvasCairo): - def __init__(self, figure): - backend_gtk3.FigureCanvasGTK3.__init__(self, figure) def _renderer_init(self): """use cairo renderer""" self._renderer = RendererGTK3Cairo(self.figure.dpi) def _render_figure(self, width, height): - self._renderer.set_width_height (width, height) - self.figure.draw (self._renderer) + self._renderer.set_width_height(width, height) + self.figure.draw(self._renderer) def on_draw_event(self, widget, ctx): """ GtkDrawable draw event, like expose_event in GTK 2.X @@ -47,24 +46,7 @@ class FigureManagerGTK3Cairo(backend_gtk3.FigureManagerGTK3): pass -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGTK3Cairo(figure) - manager = FigureManagerGTK3Cairo(canvas, num) - return manager - - -FigureCanvas = FigureCanvasGTK3Cairo -FigureManager = FigureManagerGTK3Cairo -show = backend_gtk3.show +@_BackendGTK3.export +class _BackendGTK3Cairo(_BackendGTK3): + FigureCanvas = FigureCanvasGTK3Cairo + FigureManager = FigureManagerGTK3Cairo diff --git a/lib/matplotlib/backends/backend_gtkagg.py b/lib/matplotlib/backends/backend_gtkagg.py index f89a426c6eb9..aef7593fea63 100644 --- a/lib/matplotlib/backends/backend_gtkagg.py +++ b/lib/matplotlib/backends/backend_gtkagg.py @@ -11,10 +11,9 @@ import matplotlib from matplotlib.figure import Figure from matplotlib.backends.backend_agg import FigureCanvasAgg -from matplotlib.backends.backend_gtk import gtk, FigureManagerGTK, FigureCanvasGTK,\ - show, draw_if_interactive,\ - error_msg_gtk, PIXELS_PER_INCH, backend_version, \ - NavigationToolbar2GTK +from matplotlib.backends.backend_gtk import ( + gtk, _BackendGTK, FigureCanvasGTK, FigureManagerGTK, NavigationToolbar2GTK, + backend_version, error_msg_gtk, PIXELS_PER_INCH) from matplotlib.backends._gtkagg import agg_to_gtk_drawable @@ -36,26 +35,6 @@ def _get_toolbar(self, canvas): return toolbar -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - if DEBUG: print('backend_gtkagg.new_figure_manager') - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGTKAgg(figure) - figuremanager = FigureManagerGTKAgg(canvas, num) - if DEBUG: print('backend_gtkagg.new_figure_manager done') - return figuremanager - - class FigureCanvasGTKAgg(FigureCanvasGTK, FigureCanvasAgg): filetypes = FigureCanvasGTK.filetypes.copy() filetypes.update(FigureCanvasAgg.filetypes) @@ -115,14 +94,7 @@ def print_png(self, filename, *args, **kwargs): return agg.print_png(filename, *args, **kwargs) -"""\ -Traceback (most recent call last): - File "/home/titan/johnh/local/lib/python2.3/site-packages/matplotlib/backends/backend_gtk.py", line 304, in expose_event - self._render_figure(self._pixmap, w, h) - File "/home/titan/johnh/local/lib/python2.3/site-packages/matplotlib/backends/backend_gtkagg.py", line 77, in _render_figure - pixbuf = gtk.gdk.pixbuf_new_from_data( -ValueError: data length (3156672) is less then required by the other parameters (3160608) -""" - -FigureCanvas = FigureCanvasGTKAgg -FigureManager = FigureManagerGTKAgg +@_BackendGTK.export +class _BackendGTKAgg(_BackendGTK): + FigureCanvas = FigureCanvasGTKAgg + FigureManager = FigureManagerGTKAgg diff --git a/lib/matplotlib/backends/backend_gtkcairo.py b/lib/matplotlib/backends/backend_gtkcairo.py index 1440b85044a9..a8cdf076a93f 100644 --- a/lib/matplotlib/backends/backend_gtkcairo.py +++ b/lib/matplotlib/backends/backend_gtkcairo.py @@ -11,30 +11,15 @@ if gtk.pygtk_version < (2, 7, 0): import cairo.gtk +from matplotlib import cbook from matplotlib.backends import backend_cairo from matplotlib.backends.backend_gtk import * +from matplotlib.backends.backend_gtk import _BackendGTK backend_version = ('PyGTK(%d.%d.%d) ' % gtk.pygtk_version + 'Pycairo(%s)' % backend_cairo.backend_version) -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasGTKCairo(figure) - return FigureManagerGTK(canvas, num) - - class RendererGTKCairo (backend_cairo.RendererCairo): if gtk.pygtk_version >= (2,7,0): def set_pixmap (self, pixmap): @@ -53,6 +38,8 @@ def _renderer_init(self): self._renderer = RendererGTKCairo(self.figure.dpi) +# This class has been unused for a while at least. +@cbook.deprecated("2.1") class FigureManagerGTKCairo(FigureManagerGTK): def _get_toolbar(self, canvas): # must be inited after the window, drawingArea and figure @@ -64,10 +51,14 @@ def _get_toolbar(self, canvas): return toolbar +# This class has been unused for a while at least. +@cbook.deprecated("2.1") class NavigationToolbar2Cairo(NavigationToolbar2GTK): def _get_canvas(self, fig): return FigureCanvasGTKCairo(fig) -FigureCanvas = FigureCanvasGTKCairo -FigureManager = FigureManagerGTKCairo +@_BackendGTK.export +class _BackendGTKCairo(_BackendGTK): + FigureCanvas = FigureCanvasGTKCairo + FigureManager = FigureManagerGTK diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index e093e2799b8d..61e07a010b92 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -6,9 +6,9 @@ import os from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import FigureManagerBase, FigureCanvasBase, \ - NavigationToolbar2, TimerBase -from matplotlib.backend_bases import ShowBase +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, + TimerBase) from matplotlib.figure import Figure from matplotlib import rcParams @@ -21,12 +21,6 @@ from .backend_agg import RendererAgg, FigureCanvasAgg -class Show(ShowBase): - def mainloop(self): - _macosx.show() -show = Show() - - ######################################################################## # # The following functions and classes are for pylab and implement @@ -34,37 +28,6 @@ def mainloop(self): # ######################################################################## -def draw_if_interactive(): - """ - For performance reasons, we don't want to redraw the figure after - each draw command. Instead, we mark the figure as invalid, so that - it will be redrawn as soon as the event loop resumes via PyOS_InputHook. - This function should be called after each draw event, even if - matplotlib is not running interactively. - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.invalidate() - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - figure = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, figure) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasMac(figure) - manager = FigureManagerMac(canvas, num) - return manager - class TimerMac(_macosx.Timer, TimerBase): ''' @@ -248,5 +211,19 @@ def set_message(self, message): # ######################################################################## -FigureCanvas = FigureCanvasMac -FigureManager = FigureManagerMac +@_Backend.export +class _BackendMac(_Backend): + FigureCanvas = FigureCanvasMac + FigureManager = FigureManagerMac + + def trigger_manager_draw(manager): + # For performance reasons, we don't want to redraw the figure after + # each draw command. Instead, we mark the figure as invalid, so that it + # will be redrawn as soon as the event loop resumes via PyOS_InputHook. + # This function should be called after each draw event, even if + # matplotlib is not running interactively. + manager.canvas.invalidate() + + @staticmethod + def mainloop(): + _macosx.show() diff --git a/lib/matplotlib/backends/backend_nbagg.py b/lib/matplotlib/backends/backend_nbagg.py index 3f5ba467fcfc..7274ad688879 100644 --- a/lib/matplotlib/backends/backend_nbagg.py +++ b/lib/matplotlib/backends/backend_nbagg.py @@ -25,51 +25,14 @@ from IPython.utils.traitlets import Unicode, Bool, Float, List, Any from IPython.html.nbextensions import install_nbextension -from matplotlib import rcParams +from matplotlib import rcParams, is_interactive +from matplotlib._pylab_helpers import Gcf +from matplotlib.backends.backend_webagg_core import ( + FigureCanvasWebAggCore, FigureManagerWebAgg, NavigationToolbar2WebAgg, + TimerTornado) +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, NavigationToolbar2) from matplotlib.figure import Figure -from matplotlib import is_interactive -from matplotlib.backends.backend_webagg_core import (FigureManagerWebAgg, - FigureCanvasWebAggCore, - NavigationToolbar2WebAgg, - TimerTornado) -from matplotlib.backend_bases import (ShowBase, NavigationToolbar2, - FigureCanvasBase) - - -class Show(ShowBase): - - def __call__(self, block=None): - from matplotlib._pylab_helpers import Gcf - - managers = Gcf.get_all_fig_managers() - if not managers: - return - - interactive = is_interactive() - - for manager in managers: - manager.show() - - # plt.figure adds an event which puts the figure in focus - # in the activeQue. Disable this behaviour, as it results in - # figures being put as the active figure after they have been - # shown, even in non-interactive mode. - if hasattr(manager, '_cidgcf'): - manager.canvas.mpl_disconnect(manager._cidgcf) - - if not interactive and manager in Gcf._activeQue: - Gcf._activeQue.remove(manager) - -show = Show() - - -def draw_if_interactive(): - import matplotlib._pylab_helpers as pylab_helpers - - if is_interactive(): - manager = pylab_helpers.Gcf.get_active() - if manager is not None: - manager.show() def connection_info(): @@ -79,7 +42,6 @@ def connection_info(): use. """ - from matplotlib._pylab_helpers import Gcf result = [] for manager in Gcf.get_all_fig_managers(): fig = manager.canvas.figure @@ -222,38 +184,6 @@ def destroy(self): self._send_event('close') -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - from .._pylab_helpers import Gcf - - def closer(event): - Gcf.destroy(num) - - canvas = FigureCanvasNbAgg(figure) - if rcParams['nbagg.transparent']: - figure.patch.set_alpha(0) - manager = FigureManagerNbAgg(canvas, num) - - if is_interactive(): - manager.show() - figure.canvas.draw_idle() - - canvas.mpl_connect('close_event', closer) - - return manager - - def nbinstall(overwrite=False, user=True): """ Copies javascript dependencies to the '/nbextensions' folder in @@ -296,4 +226,47 @@ def nbinstall(overwrite=False, user=True): **({'user': user} if version_info >= (3, 0, 0, '') else {}) ) -#nbinstall() + +@_Backend.export +class _BackendNbAgg(_Backend): + FigureCanvas = FigureCanvasNbAgg + FigureManager = FigureManagerNbAgg + + @staticmethod + def new_figure_manager_given_figure(num, figure): + canvas = FigureCanvasNbAgg(figure) + if rcParams['nbagg.transparent']: + figure.patch.set_alpha(0) + manager = FigureManagerNbAgg(canvas, num) + if is_interactive(): + manager.show() + figure.canvas.draw_idle() + canvas.mpl_connect('close_event', lambda event: Gcf.destroy(num)) + return manager + + @staticmethod + def trigger_manager_draw(manager): + manager.show() + + @staticmethod + def show(): + from matplotlib._pylab_helpers import Gcf + + managers = Gcf.get_all_fig_managers() + if not managers: + return + + interactive = is_interactive() + + for manager in managers: + manager.show() + + # plt.figure adds an event which puts the figure in focus + # in the activeQue. Disable this behaviour, as it results in + # figures being put as the active figure after they have been + # shown, even in non-interactive mode. + if hasattr(manager, '_cidgcf'): + manager.canvas.mpl_disconnect(manager._cidgcf) + + if not interactive and manager in Gcf._activeQue: + Gcf._activeQue.remove(manager) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index f41c95588b26..87a5c1e64de7 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -31,8 +31,9 @@ import matplotlib from matplotlib import __version__, rcParams from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import (RendererBase, GraphicsContextBase, - FigureManagerBase, FigureCanvasBase) +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.cbook import (Bunch, get_realpath_and_stat, is_writable_file_like, maxdict) @@ -2425,28 +2426,6 @@ def finalize(self): ######################################################################## -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - # if a main-level app must be created, this is the usual place to - # do it -- see backend_wx, backend_wxagg and backend_tkagg for - # examples. Not all GUIs require explicit instantiation of a - # main-level app (egg backend_gtk, backend_gtkagg) for pylab - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasPdf(figure) - manager = FigureManagerPdf(canvas, num) - return manager - - class PdfPages(object): """ A multi-page PDF file. @@ -2624,5 +2603,7 @@ class FigureManagerPdf(FigureManagerBase): pass -FigureCanvas = FigureCanvasPdf -FigureManager = FigureManagerPdf +@_Backend.export +class _BackendPdf(_Backend): + FigureCanvas = FigureCanvasPdf + FigureManager = FigureManagerPdf diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index ac0c2d6c0ec0..6d57a3de4724 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -18,8 +18,9 @@ import numpy as np import matplotlib as mpl -from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.figure import Figure from matplotlib.text import Text @@ -743,32 +744,6 @@ class GraphicsContextPgf(GraphicsContextBase): ######################################################################## -def draw_if_interactive(): - pass - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - # if a main-level app must be created, this is the usual place to - # do it -- see backend_wx, backend_wxagg and backend_tkagg for - # examples. Not all GUIs require explicit instantiation of a - # main-level app (egg backend_gtk, backend_gtkagg) for pylab - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasPgf(figure) - manager = FigureManagerPgf(canvas, num) - return manager - - class TmpDirCleaner(object): remaining_tmpdirs = set() @@ -976,8 +951,10 @@ def __init__(self, *args): FigureManagerBase.__init__(self, *args) -FigureCanvas = FigureCanvasPgf -FigureManager = FigureManagerPgf +@_Backend.export +class _BackendPgf(_Backend): + FigureCanvas = FigureCanvasPgf + FigureManager = FigureManagerPgf def _cleanup_all(): diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 0e4e2011841c..f34795566fda 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -14,8 +14,9 @@ from tempfile import mkstemp from matplotlib import verbose, __version__, rcParams, checkdep_ghostscript from matplotlib.afm import AFM -from matplotlib.backend_bases import (RendererBase, GraphicsContextBase, - FigureManagerBase, FigureCanvasBase) +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) from matplotlib.cbook import (get_realpath_and_stat, is_writable_file_like, maxdict, file_requires_unicode) @@ -891,21 +892,6 @@ def shouldstroke(self): (len(self.get_rgb()) <= 3 or self.get_rgb()[3] != 0.0)) -def new_figure_manager(num, *args, **kwargs): - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasPS(figure) - manager = FigureManagerPS(canvas, num) - return manager - - class FigureCanvasPS(FigureCanvasBase): _renderer_class = RendererPS @@ -1785,5 +1771,8 @@ class FigureManagerPS(FigureManagerBase): } bind def""", ] -FigureCanvas = FigureCanvasPS -FigureManager = FigureManagerPS + +@_Backend.export +class _BackendPS(_Backend): + FigureCanvas = FigureCanvasPS + FigureManager = FigureManagerPS diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index c90a36c2a648..cac4b2d744e7 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -8,50 +8,24 @@ import signal import sys -import matplotlib - -from matplotlib.backend_bases import FigureManagerBase -from matplotlib.backend_bases import FigureCanvasBase -from matplotlib.backend_bases import NavigationToolbar2 - -from matplotlib.backend_bases import cursors -from matplotlib.backend_bases import TimerBase -from matplotlib.backend_bases import ShowBase - from matplotlib._pylab_helpers import Gcf +from matplotlib.backend_bases import ( + FigureCanvasBase, FigureManagerBase, NavigationToolbar2, TimerBase, + cursors) from matplotlib.figure import Figure - from matplotlib.widgets import SubplotTool from .qt_compat import QtCore, QtWidgets, _getSaveFileName, __version__ from .backend_qt5 import ( backend_version, SPECIAL_KEYS, SUPER, ALT, CTRL, SHIFT, MODIFIER_KEYS, - cursord, draw_if_interactive, _create_qApp, show, TimerQT, MainWindow, - FigureManagerQT, NavigationToolbar2QT, SubplotToolQt, error_msg_qt, - exception_handler) + cursord, _create_qApp, _BackendQT5, TimerQT, MainWindow, FigureManagerQT, + NavigationToolbar2QT, SubplotToolQt, error_msg_qt, exception_handler) from .backend_qt5 import FigureCanvasQT as FigureCanvasQT5 DEBUG = False -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - thisFig = Figure(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQT(figure) - manager = FigureManagerQT(canvas, num) - return manager - - class FigureCanvasQT(FigureCanvasQT5): def __init__(self, figure): @@ -84,5 +58,6 @@ def wheelEvent(self, event): 'steps = %i ' % (event.delta(), steps)) -FigureCanvas = FigureCanvasQT -FigureManager = FigureManagerQT +@_BackendQT5.export +class _BackendQT4(_BackendQT5): + FigureCanvas = FigureCanvasQT diff --git a/lib/matplotlib/backends/backend_qt4agg.py b/lib/matplotlib/backends/backend_qt4agg.py index 2ca9c3a0c02b..b6fd21fc388d 100644 --- a/lib/matplotlib/backends/backend_qt4agg.py +++ b/lib/matplotlib/backends/backend_qt4agg.py @@ -6,33 +6,12 @@ import six -import matplotlib -from matplotlib.figure import Figure - from .backend_agg import FigureCanvasAgg from .backend_qt4 import ( - QtCore, FigureCanvasQT, FigureManagerQT, NavigationToolbar2QT, - backend_version, draw_if_interactive, show) + QtCore, _BackendQT4, FigureCanvasQT, FigureManagerQT, NavigationToolbar2QT) from .backend_qt5agg import FigureCanvasQTAggBase -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQTAgg(figure) - return FigureManagerQT(canvas, num) - - class FigureCanvasQTAgg(FigureCanvasQTAggBase, FigureCanvasQT): """ The canvas the figure renders into. Calls the draw and print fig @@ -46,5 +25,6 @@ class FigureCanvasQTAgg(FigureCanvasQTAggBase, FigureCanvasQT): """ -FigureCanvas = FigureCanvasQTAgg -FigureManager = FigureManagerQT +@_BackendQT4.export +class _BackendQT4Agg(_BackendQT4): + FigureCanvas = FigureCanvasQTAgg diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index e9b069ffc28a..e3a9a77019b0 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -10,22 +10,16 @@ import matplotlib -from matplotlib.backend_bases import FigureManagerBase -from matplotlib.backend_bases import FigureCanvasBase -from matplotlib.backend_bases import NavigationToolbar2 - -from matplotlib.backend_bases import cursors -from matplotlib.backend_bases import TimerBase -from matplotlib.backend_bases import ShowBase - from matplotlib._pylab_helpers import Gcf -from matplotlib.figure import Figure - +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, + TimerBase, cursors) import matplotlib.backends.qt_editor.figureoptions as figureoptions +from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool +from matplotlib.figure import Figure from .qt_compat import (QtCore, QtGui, QtWidgets, _getSaveFileName, __version__, is_pyqt5) -from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool backend_version = __version__ @@ -98,15 +92,6 @@ } -def draw_if_interactive(): - """ - Is called after every pylab drawing command - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw_idle() - # make place holder qApp = None @@ -147,34 +132,6 @@ def _create_qApp(): pass -class Show(ShowBase): - def mainloop(self): - # allow KeyboardInterrupt exceptions to close the plot window. - signal.signal(signal.SIGINT, signal.SIG_DFL) - global qApp - qApp.exec_() - - -show = Show() - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - thisFig = Figure(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQT(figure) - manager = FigureManagerQT(canvas, num) - return manager - - class TimerQT(TimerBase): ''' Subclass of :class:`backend_bases.TimerBase` that uses Qt timer events. @@ -826,5 +783,19 @@ def exception_handler(type, value, tb): if len(msg): error_msg_qt(msg) -FigureCanvas = FigureCanvasQT -FigureManager = FigureManagerQT + +@_Backend.export +class _BackendQT5(_Backend): + FigureCanvas = FigureCanvasQT + FigureManager = FigureManagerQT + + @staticmethod + def trigger_manager_draw(manager): + manager.canvas.draw_idle() + + @staticmethod + def mainloop(): + # allow KeyboardInterrupt exceptions to close the plot window. + signal.signal(signal.SIGINT, signal.SIG_DFL) + global qApp + qApp.exec_() diff --git a/lib/matplotlib/backends/backend_qt5agg.py b/lib/matplotlib/backends/backend_qt5agg.py index 50d05a4f5c24..ec9a70c5bb68 100644 --- a/lib/matplotlib/backends/backend_qt5agg.py +++ b/lib/matplotlib/backends/backend_qt5agg.py @@ -10,33 +10,15 @@ import traceback from matplotlib import cbook -from matplotlib.figure import Figure from matplotlib.transforms import Bbox from .backend_agg import FigureCanvasAgg from .backend_qt5 import ( - QtCore, QtGui, FigureCanvasQT, FigureManagerQT, NavigationToolbar2QT, - backend_version, draw_if_interactive, show) + QtCore, QtGui, _BackendQT5, FigureCanvasQT, FigureManagerQT, + NavigationToolbar2QT, backend_version) from .qt_compat import QT_API -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasQTAgg(figure) - return FigureManagerQT(canvas, num) - - class FigureCanvasQTAggBase(FigureCanvasAgg): """ The canvas the figure renders into. Calls the draw and print fig @@ -190,5 +172,6 @@ def __init__(self, figure): self.figure.dpi = self._dpi_ratio * self.figure._original_dpi -FigureCanvas = FigureCanvasQTAgg -FigureManager = FigureManagerQT +@_BackendQT5.export +class _BackendQT5Agg(_BackendQT5): + FigureCanvas = FigureCanvasQTAgg diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 0d1506c68dfc..b42f9f1f312f 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -15,8 +15,9 @@ import uuid from matplotlib import verbose, __version__, rcParams -from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\ - FigureManagerBase, FigureCanvasBase +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + RendererBase) from matplotlib.backends.backend_mixed import MixedModeRenderer from matplotlib.cbook import is_writable_file_like, maxdict from matplotlib.colors import rgb2hex @@ -1254,21 +1255,6 @@ class FigureManagerSVG(FigureManagerBase): pass -def new_figure_manager(num, *args, **kwargs): - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasSVG(figure) - manager = FigureManagerSVG(canvas, num) - return manager - - svgProlog = """\ = 8.5: - # put a mpl icon on the window rather than the default tk icon. Tkinter - # doesn't allow colour icons on linux systems, but tk >=8.5 has a iconphoto - # command which we call directly. Source: - # http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html - icon_fname = os.path.join(rcParams['datapath'], 'images', 'matplotlib.ppm') - icon_img = Tk.PhotoImage(file=icon_fname) - try: - window.tk.call('wm', 'iconphoto', window._w, icon_img) - except (SystemExit, KeyboardInterrupt): - # re-raise exit type Exceptions - raise - except: - # log the failure, but carry on - verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) - - canvas = FigureCanvasTkAgg(figure, master=window) - figManager = FigureManagerTkAgg(canvas, num, window) - if matplotlib.is_interactive(): - figManager.show() - canvas.draw_idle() - return figManager - class TimerTk(TimerBase): ''' @@ -1095,5 +1042,46 @@ def destroy(self, *args, **kwargs): backend_tools.ToolSetCursor = SetCursorTk backend_tools.ToolRubberband = RubberbandTk Toolbar = ToolbarTk -FigureCanvas = FigureCanvasTkAgg -FigureManager = FigureManagerTkAgg + + +@_Backend.export +class _BackendTkAgg(_Backend): + FigureCanvas = FigureCanvasTkAgg + FigureManager = FigureManagerTkAgg + + @staticmethod + def new_figure_manager_given_figure(num, figure): + """ + Create a new figure manager instance for the given figure. + """ + _focus = windowing.FocusManager() + window = Tk.Tk(className="matplotlib") + window.withdraw() + + # Put a mpl icon on the window rather than the default tk icon. + # Tkinter doesn't allow colour icons on linux systems, but tk>=8.5 has + # a iconphoto command which we call directly. Source: + # http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html + icon_fname = os.path.join( + rcParams['datapath'], 'images', 'matplotlib.ppm') + icon_img = Tk.PhotoImage(file=icon_fname) + try: + window.tk.call('wm', 'foobar', window._w, icon_img) + except Exception as exc: + # log the failure (due e.g. to Tk version), but carry on + verbose.report('Could not load matplotlib icon: %s' % exc) + + canvas = FigureCanvasTkAgg(figure, master=window) + manager = FigureManagerTkAgg(canvas, num, window) + if matplotlib.is_interactive(): + manager.show() + canvas.draw_idle() + return manager + + @staticmethod + def trigger_manager_draw(manager): + manager.show() + + @staticmethod + def mainloop(): + Tk.mainloop() diff --git a/lib/matplotlib/backends/backend_webagg.py b/lib/matplotlib/backends/backend_webagg.py index efb92c17c9a0..e39bf2cb2bab 100644 --- a/lib/matplotlib/backends/backend_webagg.py +++ b/lib/matplotlib/backends/backend_webagg.py @@ -37,60 +37,13 @@ import matplotlib from matplotlib import rcParams from matplotlib import backend_bases +from matplotlib.backend_bases import _Backend from matplotlib.figure import Figure from matplotlib._pylab_helpers import Gcf from . import backend_webagg_core as core from .backend_webagg_core import TimerTornado -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasWebAgg(figure) - manager = core.FigureManagerWebAgg(canvas, num) - return manager - - -def draw_if_interactive(): - """ - Is called after every pylab drawing command - """ - if matplotlib.is_interactive(): - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw_idle() - - -class Show(backend_bases.ShowBase): - def mainloop(self): - WebAggApplication.initialize() - - url = "http://127.0.0.1:{port}{prefix}".format( - port=WebAggApplication.port, - prefix=WebAggApplication.url_prefix) - - if rcParams['webagg.open_in_browser']: - import webbrowser - webbrowser.open(url) - else: - print("To view figure, visit {0}".format(url)) - - WebAggApplication.start() - - -show = Show().mainloop - - class ServerThread(threading.Thread): def run(self): tornado.ioloop.IOLoop.instance().start() @@ -381,4 +334,27 @@ def ipython_inline_display(figure): port=WebAggApplication.port).decode('utf-8') -FigureCanvas = FigureCanvasWebAgg +@_Backend.export +class _BackendWebAgg(_Backend): + FigureCanvas = FigureCanvasWebAgg + FigureManager = FigureManagerWebAgg + + @staticmethod + def trigger_manager_draw(manager): + manager.canvas.draw_idle() + + @staticmethod + def show(): + WebAggApplication.initialize() + + url = "http://127.0.0.1:{port}{prefix}".format( + port=WebAggApplication.port, + prefix=WebAggApplication.url_prefix) + + if rcParams['webagg.open_in_browser']: + import webbrowser + webbrowser.open(url) + else: + print("To view figure, visit {0}".format(url)) + + WebAggApplication.start() diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index 132361afc95f..917f4a437364 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -26,29 +26,12 @@ import datetime from matplotlib.backends import backend_agg +from matplotlib.backend_bases import _Backend from matplotlib.figure import Figure from matplotlib import backend_bases from matplotlib import _png -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - FigureClass = kwargs.pop('FigureClass', Figure) - thisFig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, thisFig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - canvas = FigureCanvasWebAggCore(figure) - manager = FigureManagerWebAgg(canvas, num) - return manager - - # http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes _SHIFT_LUT = {59: ':', 61: '+', @@ -566,3 +549,9 @@ def _timer_set_interval(self): if self._timer is not None: self._timer_stop() self._timer_start() + + +@_Backend.export +class _BackendWebAggCoreAgg(_Backend): + FigureCanvas = FigureCanvasWebAggCore + FigureManager = FigureManagerWebAgg diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 6e9c0c916d4a..f6bc3d23a50f 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -28,11 +28,9 @@ import numpy as np import matplotlib -from matplotlib import cbook -from matplotlib.backend_bases import (RendererBase, GraphicsContextBase, - FigureCanvasBase, FigureManagerBase, NavigationToolbar2, - cursors, TimerBase) -from matplotlib.backend_bases import ShowBase +from matplotlib.backend_bases import ( + _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, + NavigationToolbar2, RendererBase, TimerBase, cursors) from matplotlib.backend_bases import _has_pil from matplotlib._pylab_helpers import Gcf @@ -1166,72 +1164,6 @@ def _onEnter(self, evt): ######################################################################## -def _create_wx_app(): - """ - Creates a wx.App instance if it has not been created sofar. - """ - wxapp = wx.GetApp() - if wxapp is None: - wxapp = wx.App(False) - wxapp.SetExitOnFrameDelete(True) - # retain a reference to the app object so it does not get garbage - # collected and cause segmentation faults - _create_wx_app.theWxApp = wxapp - - -def draw_if_interactive(): - """ - This should be overridden in a windowing environment if drawing - should be done in interactive python mode - """ - DEBUG_MSG("draw_if_interactive()", 1, None) - - if matplotlib.is_interactive(): - - figManager = Gcf.get_active() - if figManager is not None: - figManager.canvas.draw_idle() - - -class Show(ShowBase): - def mainloop(self): - needmain = not wx.App.IsMainLoopRunning() - if needmain: - wxapp = wx.GetApp() - if wxapp is not None: - wxapp.MainLoop() - -show = Show() - - -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - # in order to expose the Figure constructor to the pylab - # interface we need to create the figure here - DEBUG_MSG("new_figure_manager()", 3, None) - _create_wx_app() - - FigureClass = kwargs.pop('FigureClass', Figure) - fig = FigureClass(*args, **kwargs) - return new_figure_manager_given_figure(num, fig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - fig = figure - frame = FigureFrameWx(num, fig) - figmgr = frame.get_figure_manager() - if matplotlib.is_interactive(): - figmgr.frame.Show() - figure.canvas.draw_idle() - - return figmgr - - class FigureFrameWx(wx.Frame): def __init__(self, num, fig): # On non-Windows platform, explicitly set the position - fix @@ -1886,6 +1818,43 @@ def OnPrintPage(self, page): # ######################################################################## -FigureCanvas = FigureCanvasWx -FigureManager = FigureManagerWx Toolbar = NavigationToolbar2Wx + + +@_Backend.export +class _BackendWx(_Backend): + FigureCanvas = FigureCanvasWx + FigureManager = FigureManagerWx + _frame_class = FigureFrameWx + + @staticmethod + def trigger_manager_draw(manager): + manager.canvas.draw_idle() + + @classmethod + def new_figure_manager(cls, num, *args, **kwargs): + # Create a wx.App instance if it has not been created sofar. + wxapp = wx.GetApp() + if wxapp is None: + wxapp = wx.App(False) + wxapp.SetExitOnFrameDelete(True) + # Retain a reference to the app object so that it does not get + # garbage collected. + _BackendWx._theWxApp = wxapp + return super(_BackendWx, cls).new_figure_manager(num, *args, **kwargs) + + @classmethod + def new_figure_manager_given_figure(cls, num, figure): + frame = cls._frame_class(num, figure) + figmgr = frame.get_figure_manager() + if matplotlib.is_interactive(): + figmgr.frame.Show() + figure.canvas.draw_idle() + return figmgr + + @staticmethod + def mainloop(): + if not wx.App.IsMainLoopRunning(): + wxapp = wx.GetApp() + if wxapp is not None: + wxapp.MainLoop() diff --git a/lib/matplotlib/backends/backend_wxagg.py b/lib/matplotlib/backends/backend_wxagg.py index 36d10a8a41e6..368115e27646 100644 --- a/lib/matplotlib/backends/backend_wxagg.py +++ b/lib/matplotlib/backends/backend_wxagg.py @@ -10,15 +10,12 @@ from . import wx_compat as wxc from . import backend_wx -from .backend_wx import (FigureManagerWx, FigureCanvasWx, +from .backend_wx import (_BackendWx, FigureManagerWx, FigureCanvasWx, FigureFrameWx, DEBUG_MSG, NavigationToolbar2Wx, Toolbar) import wx -show = backend_wx.Show() - - class FigureFrameWxAgg(FigureFrameWx): def get_canvas(self, fig): return FigureCanvasWxAgg(self, -1, fig) @@ -101,36 +98,8 @@ def get_canvas(self, frame, fig): return FigureCanvasWxAgg(frame, -1, fig) -def new_figure_manager(num, *args, **kwargs): - """ - Create a new figure manager instance - """ - # in order to expose the Figure constructor to the pylab - # interface we need to create the figure here - DEBUG_MSG("new_figure_manager()", 3, None) - backend_wx._create_wx_app() - - FigureClass = kwargs.pop('FigureClass', Figure) - fig = FigureClass(*args, **kwargs) - - return new_figure_manager_given_figure(num, fig) - - -def new_figure_manager_given_figure(num, figure): - """ - Create a new figure manager instance for the given figure. - """ - frame = FigureFrameWxAgg(num, figure) - figmgr = frame.get_figure_manager() - if matplotlib.is_interactive(): - figmgr.frame.Show() - figure.canvas.draw_idle() - return figmgr - - -# # agg/wxPython image conversion functions (wxPython >= 2.8) -# + def _convert_agg_to_wx_image(agg, bbox): """ @@ -193,5 +162,8 @@ def _WX28_clipped_agg_as_bitmap(agg, bbox): return destBmp -FigureCanvas = FigureCanvasWxAgg -FigureManager = FigureManagerWx + +@_BackendWx.export +class _BackendWxAgg(_BackendWx): + FigureCanvas = FigureCanvasWxAgg + _frame_class = FigureFrameWxAgg