From 1d45632cfdcd50346698ff7b4fb3febe79ea6108 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 11 Feb 2018 22:46:52 -0500 Subject: [PATCH 01/10] Delete GTK2 embedding examples. --- .../embedding_in_gtk2_sgskip.py | 55 ---- .../embedding_in_gtk_sgskip.py | 36 --- examples/user_interfaces/mpl_with_glade.glade | 276 ------------------ ..._glade_316.glade => mpl_with_glade3.glade} | 0 ...16_sgskip.py => mpl_with_glade3_sgskip.py} | 12 +- .../user_interfaces/mpl_with_glade_sgskip.py | 105 ------- tutorials/introductory/sample_plots.py | 4 +- 7 files changed, 10 insertions(+), 478 deletions(-) delete mode 100644 examples/user_interfaces/embedding_in_gtk2_sgskip.py delete mode 100644 examples/user_interfaces/embedding_in_gtk_sgskip.py delete mode 100644 examples/user_interfaces/mpl_with_glade.glade rename examples/user_interfaces/{mpl_with_glade_316.glade => mpl_with_glade3.glade} (100%) rename examples/user_interfaces/{mpl_with_glade_316_sgskip.py => mpl_with_glade3_sgskip.py} (78%) delete mode 100644 examples/user_interfaces/mpl_with_glade_sgskip.py diff --git a/examples/user_interfaces/embedding_in_gtk2_sgskip.py b/examples/user_interfaces/embedding_in_gtk2_sgskip.py deleted file mode 100644 index 176809367f0c..000000000000 --- a/examples/user_interfaces/embedding_in_gtk2_sgskip.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -================= -Embedding In GTK2 -================= - -show how to add a matplotlib FigureCanvasGTK or FigureCanvasGTKAgg widget and -a toolbar to a gtk.Window -""" -import gtk - -from matplotlib.figure import Figure -import numpy as np - -# uncomment to select /GTK/GTKAgg/GTKCairo -#from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas -from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas -#from matplotlib.backends.backend_gtkcairo import FigureCanvasGTKCairo as FigureCanvas - -# or NavigationToolbar for classic -#from matplotlib.backends.backend_gtk import NavigationToolbar2GTK as NavigationToolbar -from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar - -# implement the default mpl key bindings -from matplotlib.backend_bases import key_press_handler - -win = gtk.Window() -win.connect("destroy", lambda x: gtk.main_quit()) -win.set_default_size(400, 300) -win.set_title("Embedding in GTK") - -vbox = gtk.VBox() -win.add(vbox) - -fig = Figure(figsize=(5, 4), dpi=100) -ax = fig.add_subplot(111) -t = np.arange(0.0, 3.0, 0.01) -s = np.sin(2*np.pi*t) - -ax.plot(t, s) - - -canvas = FigureCanvas(fig) # a gtk.DrawingArea -vbox.pack_start(canvas) -toolbar = NavigationToolbar(canvas, win) -vbox.pack_start(toolbar, False, False) - - -def on_key_event(event): - print('you pressed %s' % event.key) - key_press_handler(event, canvas, toolbar) - -canvas.mpl_connect('key_press_event', on_key_event) - -win.show_all() -gtk.main() diff --git a/examples/user_interfaces/embedding_in_gtk_sgskip.py b/examples/user_interfaces/embedding_in_gtk_sgskip.py deleted file mode 100644 index 7da96306a982..000000000000 --- a/examples/user_interfaces/embedding_in_gtk_sgskip.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -================ -Embedding In GTK -================ - -Show how to add a matplotlib FigureCanvasGTK or FigureCanvasGTKAgg widget to a -gtk.Window -""" - -import gtk - -from matplotlib.figure import Figure -import numpy as np - -# uncomment to select /GTK/GTKAgg/GTKCairo -#from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas -from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas -#from matplotlib.backends.backend_gtkcairo import FigureCanvasGTKCairo as FigureCanvas - - -win = gtk.Window() -win.connect("destroy", lambda x: gtk.main_quit()) -win.set_default_size(400, 300) -win.set_title("Embedding in GTK") - -f = Figure(figsize=(5, 4), dpi=100) -a = f.add_subplot(111) -t = np.arange(0.0, 3.0, 0.01) -s = np.sin(2*np.pi*t) -a.plot(t, s) - -canvas = FigureCanvas(f) # a gtk.DrawingArea -win.add(canvas) - -win.show_all() -gtk.main() diff --git a/examples/user_interfaces/mpl_with_glade.glade b/examples/user_interfaces/mpl_with_glade.glade deleted file mode 100644 index 96e3278b490e..000000000000 --- a/examples/user_interfaces/mpl_with_glade.glade +++ /dev/null @@ -1,276 +0,0 @@ - - - - - - - True - window1 - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_NORMAL - GDK_GRAVITY_NORTH_WEST - True - - - - - - - 4 - True - False - 2 - - - - True - - - - True - _File - True - - - - - - - True - gtk-new - True - - - - - - - True - gtk-open - True - - - - - - - True - gtk-save - True - - - - - - - True - gtk-save-as - True - - - - - - - True - - - - - - True - gtk-quit - True - - - - - - - - - - - True - _Edit - True - - - - - - - True - gtk-cut - True - - - - - - - True - gtk-copy - True - - - - - - - True - gtk-paste - True - - - - - - - True - gtk-delete - True - - - - - - - - - - - True - _View - True - - - - - - - - - - - True - _Help - True - - - - - - - True - _About - True - - - - - - - - - - 0 - False - False - - - - - - - - - - True - True - GTK_RELIEF_NORMAL - True - - - - - True - 0.5 - 0.5 - 0 - 0 - 0 - 0 - 0 - 0 - - - - True - False - 2 - - - - True - gtk-dialog-info - 4 - 0.5 - 0.5 - 0 - 0 - - - 0 - False - False - - - - - - True - Click Me! - True - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - - - - 0 - False - False - - - - - - - diff --git a/examples/user_interfaces/mpl_with_glade_316.glade b/examples/user_interfaces/mpl_with_glade3.glade similarity index 100% rename from examples/user_interfaces/mpl_with_glade_316.glade rename to examples/user_interfaces/mpl_with_glade3.glade diff --git a/examples/user_interfaces/mpl_with_glade_316_sgskip.py b/examples/user_interfaces/mpl_with_glade3_sgskip.py similarity index 78% rename from examples/user_interfaces/mpl_with_glade_316_sgskip.py rename to examples/user_interfaces/mpl_with_glade3_sgskip.py index b5cb5a6637fb..ee0c752cd0bb 100644 --- a/examples/user_interfaces/mpl_with_glade_316_sgskip.py +++ b/examples/user_interfaces/mpl_with_glade3_sgskip.py @@ -1,10 +1,12 @@ """ -========================= -Matplotlib With Glade 316 -========================= +======================= +Matplotlib With Glade 3 +======================= """ +import os + from gi.repository import Gtk from matplotlib.figure import Figure @@ -21,7 +23,9 @@ def on_window1_destroy(self, widget): def main(): builder = Gtk.Builder() - builder.add_objects_from_file("mpl_with_glade_316.glade", ("window1", "")) + builder.add_objects_from_file(os.path.join(os.path.dirname(__file__), + "mpl_with_glade3.glade"), + ("window1", "")) builder.connect_signals(Window1Signals()) window = builder.get_object("window1") sw = builder.get_object("scrolledwindow1") diff --git a/examples/user_interfaces/mpl_with_glade_sgskip.py b/examples/user_interfaces/mpl_with_glade_sgskip.py deleted file mode 100644 index 9000942fe210..000000000000 --- a/examples/user_interfaces/mpl_with_glade_sgskip.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -===================== -Matplotlib With Glade -===================== - -""" -import matplotlib -matplotlib.use('GTK') - -from matplotlib.figure import Figure -from matplotlib.axes import Subplot -from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas -from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar -from matplotlib.widgets import SpanSelector - -import numpy as np -import gtk -import gtk.glade - - -def simple_msg(msg, parent=None, title=None): - dialog = gtk.MessageDialog( - parent=None, - type=gtk.MESSAGE_INFO, - buttons=gtk.BUTTONS_OK, - message_format=msg) - if parent is not None: - dialog.set_transient_for(parent) - if title is not None: - dialog.set_title(title) - dialog.show() - dialog.run() - dialog.destroy() - return None - - -class GladeHandlers(object): - def on_buttonClickMe_clicked(event): - simple_msg('Nothing to say, really', - parent=widgets['windowMain'], - title='Thanks!') - - -class WidgetsWrapper(object): - def __init__(self): - self.widgets = gtk.glade.XML('mpl_with_glade.glade') - self.widgets.signal_autoconnect(GladeHandlers.__dict__) - - self['windowMain'].connect('destroy', lambda x: gtk.main_quit()) - self['windowMain'].move(10, 10) - self.figure = Figure(figsize=(8, 6), dpi=72) - self.axis = self.figure.add_subplot(111) - - t = np.arange(0.0, 3.0, 0.01) - s = np.sin(2*np.pi*t) - self.axis.plot(t, s) - self.axis.set_xlabel('time (s)') - self.axis.set_ylabel('voltage') - - self.canvas = FigureCanvas(self.figure) # a gtk.DrawingArea - self.canvas.show() - self.canvas.set_size_request(600, 400) - self.canvas.set_events( - gtk.gdk.BUTTON_PRESS_MASK | - gtk.gdk.KEY_PRESS_MASK | - gtk.gdk.KEY_RELEASE_MASK - ) - self.canvas.set_flags(gtk.HAS_FOCUS | gtk.CAN_FOCUS) - self.canvas.grab_focus() - - def keypress(widget, event): - print('key press') - - def buttonpress(widget, event): - print('button press') - - self.canvas.connect('key_press_event', keypress) - self.canvas.connect('button_press_event', buttonpress) - - def onselect(xmin, xmax): - print(xmin, xmax) - - span = SpanSelector(self.axis, onselect, 'horizontal', useblit=False, - rectprops=dict(alpha=0.5, facecolor='red')) - - self['vboxMain'].pack_start(self.canvas, True, True) - self['vboxMain'].show() - - # below is optional if you want the navigation toolbar - self.navToolbar = NavigationToolbar(self.canvas, self['windowMain']) - self.navToolbar.lastDir = '/var/tmp/' - self['vboxMain'].pack_start(self.navToolbar) - self.navToolbar.show() - - sep = gtk.HSeparator() - sep.show() - self['vboxMain'].pack_start(sep, True, True) - - self['vboxMain'].reorder_child(self['buttonClickMe'], -1) - - def __getitem__(self, key): - return self.widgets.get_widget(key) - -widgets = WidgetsWrapper() -gtk.main() diff --git a/tutorials/introductory/sample_plots.py b/tutorials/introductory/sample_plots.py index edd2beb4bab3..0757e5b1f2f8 100644 --- a/tutorials/introductory/sample_plots.py +++ b/tutorials/introductory/sample_plots.py @@ -397,9 +397,9 @@ For examples of how to embed Matplotlib in different toolkits, see: - * :doc:`/gallery/user_interfaces/embedding_in_gtk2_sgskip` + * :doc:`/gallery/user_interfaces/embedding_in_gtk3_sgskip` * :doc:`/gallery/user_interfaces/embedding_in_wx2_sgskip` - * :doc:`/gallery/user_interfaces/mpl_with_glade_sgskip` + * :doc:`/gallery/user_interfaces/mpl_with_glade3_sgskip` * :doc:`/gallery/user_interfaces/embedding_in_qt_sgskip` * :doc:`/gallery/user_interfaces/embedding_in_tk_sgskip` From c0324d871d8ea2a1c0686023b8a1de24eb77c44b Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 11 Feb 2018 22:49:41 -0500 Subject: [PATCH 02/10] Explicitly require GTK 3.0 in GTK3 examples. This silences a warning from PyGI. --- examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py | 2 ++ examples/user_interfaces/embedding_in_gtk3_sgskip.py | 2 ++ examples/user_interfaces/mpl_with_glade3_sgskip.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py b/examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py index ebead87f6ed6..7dfd1a5c56d5 100644 --- a/examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py +++ b/examples/user_interfaces/embedding_in_gtk3_panzoom_sgskip.py @@ -6,6 +6,8 @@ Demonstrate NavigationToolbar with GTK3 accessed via pygobject. """ +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk from matplotlib.backends.backend_gtk3 import ( diff --git a/examples/user_interfaces/embedding_in_gtk3_sgskip.py b/examples/user_interfaces/embedding_in_gtk3_sgskip.py index a5e6271488ba..af76a0d724f2 100644 --- a/examples/user_interfaces/embedding_in_gtk3_sgskip.py +++ b/examples/user_interfaces/embedding_in_gtk3_sgskip.py @@ -7,6 +7,8 @@ GTK3 accessed via pygobject. """ +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk from matplotlib.backends.backend_gtk3agg import ( diff --git a/examples/user_interfaces/mpl_with_glade3_sgskip.py b/examples/user_interfaces/mpl_with_glade3_sgskip.py index ee0c752cd0bb..ffdf22e32ce0 100644 --- a/examples/user_interfaces/mpl_with_glade3_sgskip.py +++ b/examples/user_interfaces/mpl_with_glade3_sgskip.py @@ -7,6 +7,8 @@ import os +import gi +gi.require_version('Gtk', '3.0') from gi.repository import Gtk from matplotlib.figure import Figure From 34f60995bef54fd8fac150c2387027e5aacb3750 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 11 Feb 2018 22:52:24 -0500 Subject: [PATCH 03/10] Remove deprecated backend methods. --- lib/matplotlib/backends/_backend_tk.py | 88 +---------------------- lib/matplotlib/backends/backend_agg.py | 5 -- lib/matplotlib/backends/backend_qt5agg.py | 11 --- lib/matplotlib/backends/backend_tkagg.py | 11 --- lib/matplotlib/backends/backend_wxagg.py | 6 -- 5 files changed, 3 insertions(+), 118 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index e5ef40caf74f..3b48cfa4a14d 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -15,7 +15,7 @@ import matplotlib.backends.windowing as windowing import matplotlib -from matplotlib import backend_tools, cbook, rcParams +from matplotlib import backend_tools, rcParams from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, StatusbarBase, TimerBase, ToolContainerBase, cursors) @@ -294,10 +294,6 @@ def _update_pointer_position(self, guiEvent=None): else: self.leave_notify_event(guiEvent) - show = cbook.deprecated("2.2", name="FigureCanvasTk.show", - alternative="FigureCanvasTk.draw")( - lambda self: self.draw()) - def draw_idle(self): 'update drawing area only if idle' if self._idle is False: @@ -511,22 +507,8 @@ def _get_toolmanager(self): toolmanager = None return toolmanager - def resize(self, width, height=None): - # before 09-12-22, the resize method takes a single *event* - # parameter. On the other hand, the resize method of other - # FigureManager class takes *width* and *height* parameter, - # which is used to change the size of the window. For the - # Figure.set_size_inches with forward=True work with Tk - # backend, I changed the function signature but tried to keep - # it backward compatible. -JJL - - # when a single parameter is given, consider it as a event - if height is None: - cbook.warn_deprecated("2.2", "FigureManagerTkAgg.resize now takes " - "width and height as separate arguments") - width = width.width - else: - self.canvas._tkcanvas.master.geometry("%dx%d" % (width, height)) + def resize(self, width, height): + self.canvas._tkcanvas.master.geometry("%dx%d" % (width, height)) if self.toolbar is not None: self.toolbar.configure(width=width) @@ -572,70 +554,6 @@ def full_screen_toggle(self): self.window.attributes('-fullscreen', not is_fullscreen) -@cbook.deprecated("2.2") -class AxisMenu(object): - def __init__(self, master, naxes): - self._master = master - self._naxes = naxes - self._mbar = Tk.Frame(master=master, relief=Tk.RAISED, borderwidth=2) - self._mbar.pack(side=Tk.LEFT) - self._mbutton = Tk.Menubutton( - master=self._mbar, text="Axes", underline=0) - self._mbutton.pack(side=Tk.LEFT, padx="2m") - self._mbutton.menu = Tk.Menu(self._mbutton) - self._mbutton.menu.add_command( - label="Select All", command=self.select_all) - self._mbutton.menu.add_command( - label="Invert All", command=self.invert_all) - self._axis_var = [] - self._checkbutton = [] - for i in range(naxes): - self._axis_var.append(Tk.IntVar()) - self._axis_var[i].set(1) - self._checkbutton.append(self._mbutton.menu.add_checkbutton( - label = "Axis %d" % (i+1), - variable=self._axis_var[i], - command=self.set_active)) - self._mbutton.menu.invoke(self._mbutton.menu.index("Select All")) - self._mbutton['menu'] = self._mbutton.menu - self._mbar.tk_menuBar(self._mbutton) - self.set_active() - - def adjust(self, naxes): - if self._naxes < naxes: - for i in range(self._naxes, naxes): - self._axis_var.append(Tk.IntVar()) - self._axis_var[i].set(1) - self._checkbutton.append( self._mbutton.menu.add_checkbutton( - label = "Axis %d" % (i+1), - variable=self._axis_var[i], - command=self.set_active)) - elif self._naxes > naxes: - for i in range(self._naxes-1, naxes-1, -1): - del self._axis_var[i] - self._mbutton.menu.forget(self._checkbutton[i]) - del self._checkbutton[i] - self._naxes = naxes - self.set_active() - - def get_indices(self): - a = [i for i in range(len(self._axis_var)) if self._axis_var[i].get()] - return a - - def set_active(self): - self._master.set_active(self.get_indices()) - - def invert_all(self): - for a in self._axis_var: - a.set(not a.get()) - self.set_active() - - def select_all(self): - for a in self._axis_var: - a.set(1) - self.set_active() - - class NavigationToolbar2Tk(NavigationToolbar2, Tk.Frame): """ Attributes diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index 82b724cc8b53..bb5daa14f4d2 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -68,11 +68,6 @@ class RendererAgg(RendererBase): context instance that controls the colors/styles """ - @property - @cbook.deprecated("2.2") - def debug(self): - return 1 - # we want to cache the fonts at the class level so that when # multiple figures are created we can reuse them. This helps with # a bug on windows where the creation of too many figures leads to diff --git a/lib/matplotlib/backends/backend_qt5agg.py b/lib/matplotlib/backends/backend_qt5agg.py index 4783143d83d6..ab8cbe4994b3 100644 --- a/lib/matplotlib/backends/backend_qt5agg.py +++ b/lib/matplotlib/backends/backend_qt5agg.py @@ -4,7 +4,6 @@ import ctypes -from matplotlib import cbook from matplotlib.transforms import Bbox from .backend_agg import FigureCanvasAgg @@ -20,11 +19,6 @@ def __init__(self, figure): super().__init__(figure=figure) self._bbox_queue = [] - @property - @cbook.deprecated("2.1") - def blitbox(self): - return self._bbox_queue - def paintEvent(self, e): """Copy the image from the Agg canvas to the qt.drawable. @@ -91,11 +85,6 @@ def print_figure(self, *args, **kwargs): self.draw() -@cbook.deprecated("2.2") -class FigureCanvasQTAggBase(FigureCanvasQTAgg): - pass - - @_BackendQT5.export class _BackendQT5Agg(_BackendQT5): FigureCanvas = FigureCanvasQTAgg diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index 68444504bf9a..b4690a6d461f 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -1,4 +1,3 @@ -from .. import cbook from . import tkagg # Paint image to Tk photo blitter extension. from .backend_agg import FigureCanvasAgg from ._backend_tk import ( @@ -17,16 +16,6 @@ def blit(self, bbox=None): self._master.update_idletasks() -@cbook.deprecated("2.2") -class FigureManagerTkAgg(FigureManagerTk): - pass - - -@cbook.deprecated("2.2") -class NavigationToolbar2TkAgg(NavigationToolbar2Tk): - pass - - @_BackendTk.export class _BackendTkAgg(_BackendTk): FigureCanvas = FigureCanvasTkAgg diff --git a/lib/matplotlib/backends/backend_wxagg.py b/lib/matplotlib/backends/backend_wxagg.py index 041f274a78b1..ee628fc0dc9b 100644 --- a/lib/matplotlib/backends/backend_wxagg.py +++ b/lib/matplotlib/backends/backend_wxagg.py @@ -6,7 +6,6 @@ import wx import matplotlib -from matplotlib import cbook from . import wx_compat as wxc from .backend_agg import FigureCanvasAgg from .backend_wx import ( @@ -72,11 +71,6 @@ def blit(self, bbox=None): filetypes = FigureCanvasAgg.filetypes -@cbook.deprecated("2.2", alternative="NavigationToolbar2WxAgg") -class Toolbar(NavigationToolbar2WxAgg): - pass - - # agg/wxPython image conversion functions (wxPython >= 2.8) def _convert_agg_to_wx_image(agg, bbox): From 40e3879765aa2b4575a88c90d9039917e66243ac Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 11 Feb 2018 22:53:04 -0500 Subject: [PATCH 04/10] Remove deprecated backends. --- INSTALL.rst | 1 - doc/api/backend_gtkagg_api.rst | 11 - doc/api/backend_gtkcairo_api.rst | 11 - doc/api/index_backend_api.rst | 2 - doc/glossary/index.rst | 11 +- doc/users/shell.rst | 2 +- .../ginput_manual_clabel_sgskip.py | 2 +- examples/widgets/cursor.py | 2 +- examples/widgets/span_selector.py | 2 +- lib/matplotlib/animation.py | 2 - lib/matplotlib/backends/backend_gdk.py | 438 ------- lib/matplotlib/backends/backend_gtk.py | 1037 ----------------- lib/matplotlib/backends/backend_gtkagg.py | 96 -- lib/matplotlib/backends/backend_gtkcairo.py | 74 -- lib/matplotlib/pyplot.py | 13 +- lib/matplotlib/rcsetup.py | 7 +- matplotlibrc.template | 5 +- pytest.ini | 4 - setup.cfg.template | 17 +- setup.py | 2 - setupext.py | 122 -- src/_backend_gdk.c | 72 -- src/_gtkagg.cpp | 155 --- tutorials/introductory/usage.py | 18 +- 24 files changed, 26 insertions(+), 2080 deletions(-) delete mode 100644 doc/api/backend_gtkagg_api.rst delete mode 100644 doc/api/backend_gtkcairo_api.rst delete mode 100644 lib/matplotlib/backends/backend_gdk.py delete mode 100644 lib/matplotlib/backends/backend_gtk.py delete mode 100644 lib/matplotlib/backends/backend_gtkagg.py delete mode 100644 lib/matplotlib/backends/backend_gtkcairo.py delete mode 100644 src/_backend_gdk.c delete mode 100644 src/_gtkagg.cpp diff --git a/INSTALL.rst b/INSTALL.rst index fcbe2d03a292..ac21f225a245 100644 --- a/INSTALL.rst +++ b/INSTALL.rst @@ -159,7 +159,6 @@ optional Matplotlib backends and the capabilities they provide. * `PyQt4 `_ (>= 4.4) or `PySide `_: for the Qt4Agg backend; * `PyQt5 `_: for the Qt5Agg backend; - * :term:`pygtk` (>= 2.4): for the GTK and the GTKAgg backend; * :term:`wxpython` (>= 2.9 or later): for the WX or WXAgg backend; * `cairocffi `__ (>= v0.8): for cairo based backends; diff --git a/doc/api/backend_gtkagg_api.rst b/doc/api/backend_gtkagg_api.rst deleted file mode 100644 index f5a37bf4d345..000000000000 --- a/doc/api/backend_gtkagg_api.rst +++ /dev/null @@ -1,11 +0,0 @@ - -:mod:`matplotlib.backends.backend_gtkagg` -========================================= - -**TODO** We'll add this later, importing the gtk backends requires an active -X-session, which is not compatible with cron jobs. - -.. .. automodule:: matplotlib.backends.backend_gtkagg -.. :members: -.. :undoc-members: -.. :show-inheritance: diff --git a/doc/api/backend_gtkcairo_api.rst b/doc/api/backend_gtkcairo_api.rst deleted file mode 100644 index 562f8ea6e7ce..000000000000 --- a/doc/api/backend_gtkcairo_api.rst +++ /dev/null @@ -1,11 +0,0 @@ - -:mod:`matplotlib.backends.backend_gtkcairo` -=========================================== - -**TODO** We'll add this later, importing the gtk backends requires an active -X-session, which is not compatible with cron jobs. - -.. .. automodule:: matplotlib.backends.backend_gtkcairo -.. :members: -.. :undoc-members: -.. :show-inheritance: diff --git a/doc/api/index_backend_api.rst b/doc/api/index_backend_api.rst index 813c3770214e..5141e275a4f9 100644 --- a/doc/api/index_backend_api.rst +++ b/doc/api/index_backend_api.rst @@ -10,8 +10,6 @@ backends backend_tools_api.rst backend_agg_api.rst backend_cairo_api.rst - backend_gtkagg_api.rst - backend_gtkcairo_api.rst backend_gtk3agg_api.rst backend_gtk3cairo_api.rst backend_nbagg_api.rst diff --git a/doc/glossary/index.rst b/doc/glossary/index.rst index 487caed10f4a..544e78b95acd 100644 --- a/doc/glossary/index.rst +++ b/doc/glossary/index.rst @@ -74,16 +74,9 @@ Glossary features of PyGObject. However Matplotlib does not use any of these missing features. - pygtk - `pygtk `_ provides python wrappers for - the :term:`GTK` widgets library for use with the GTK or GTKAgg - backend. Widely used on linux, and is often packages as - 'python-gtk2' - PyGObject - Like :term:`pygtk`, `PyGObject ` provides - python wrappers for the :term:`GTK` widgets library; unlike pygtk, - PyGObject wraps GTK3 instead of the now obsolete GTK2. + `PyGObject `_ provides Python wrappers for the + :term:`GTK` widgets library pyqt `pyqt `_ provides python diff --git a/doc/users/shell.rst b/doc/users/shell.rst index 99625f1957c7..63e214c6ae67 100644 --- a/doc/users/shell.rst +++ b/doc/users/shell.rst @@ -100,7 +100,7 @@ up python. Then:: >>> xlabel('hi mom') should work out of the box. This is also likely to work with recent -versions of the qt4agg and gtkagg backends, and with the macosx backend +versions of the qt4agg and gtk3agg backends, and with the macosx backend on the Macintosh. Note, in batch mode, i.e. when making figures from scripts, interactive mode can be slow since it redraws diff --git a/examples/event_handling/ginput_manual_clabel_sgskip.py b/examples/event_handling/ginput_manual_clabel_sgskip.py index 36bd70728155..abe1e345d86b 100644 --- a/examples/event_handling/ginput_manual_clabel_sgskip.py +++ b/examples/event_handling/ginput_manual_clabel_sgskip.py @@ -7,7 +7,7 @@ waitforbuttonpress and manual clabel placement. This script must be run interactively using a backend that has a -graphical user interface (for example, using GTKAgg backend, but not +graphical user interface (for example, using GTK3Agg backend, but not PS backend). See also ginput_demo.py diff --git a/examples/widgets/cursor.py b/examples/widgets/cursor.py index 5648563d6e35..0e049b6ff80c 100644 --- a/examples/widgets/cursor.py +++ b/examples/widgets/cursor.py @@ -20,7 +20,7 @@ ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) -# set useblit = True on gtkagg for enhanced performance +# Set useblit=True on some backends for enhanced performance. cursor = Cursor(ax, useblit=True, color='red', linewidth=2) plt.show() diff --git a/examples/widgets/span_selector.py b/examples/widgets/span_selector.py index 854defc87a0f..0ea8904e3471 100644 --- a/examples/widgets/span_selector.py +++ b/examples/widgets/span_selector.py @@ -38,7 +38,7 @@ def onselect(xmin, xmax): ax2.set_ylim(thisy.min(), thisy.max()) fig.canvas.draw() -# set useblit True on gtkagg for enhanced performance +# Set useblit=True on some backends for enhanced performance. span = SpanSelector(ax1, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index a1aef1d3e5d2..3bc1070cc789 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1,6 +1,4 @@ # TODO: -# * Loop Delay is broken on GTKAgg. This is because source_remove() is not -# working as we want. PyGTK bug? # * Documentation -- this will need a new section of the User's Guide. # Both for Animations and just timers. # - Also need to update http://www.scipy.org/Cookbook/Matplotlib/Animations diff --git a/lib/matplotlib/backends/backend_gdk.py b/lib/matplotlib/backends/backend_gdk.py deleted file mode 100644 index 7d18922fc370..000000000000 --- a/lib/matplotlib/backends/backend_gdk.py +++ /dev/null @@ -1,438 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import warnings - -import gobject -import gtk; gdk = gtk.gdk -import pango -pygtk_version_required = (2,2,0) -if gtk.pygtk_version < pygtk_version_required: - raise ImportError ("PyGTK %d.%d.%d is installed\n" - "PyGTK %d.%d.%d or later is required" - % (gtk.pygtk_version + pygtk_version_required)) -del pygtk_version_required - -import numpy as np - -import matplotlib -from matplotlib import rcParams -from matplotlib._pylab_helpers import Gcf -from matplotlib.backend_bases import ( - _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, - RendererBase) -from matplotlib.cbook import warn_deprecated -from matplotlib.mathtext import MathTextParser -from matplotlib.transforms import Affine2D -from matplotlib.backends._backend_gdk import pixbuf_get_pixels_array - -backend_version = "%d.%d.%d" % gtk.pygtk_version - -# Image formats that this backend supports - for FileChooser and print_figure() -IMAGE_FORMAT = sorted(['bmp', 'eps', 'jpg', 'png', 'ps', 'svg']) # 'raw', 'rgb' -IMAGE_FORMAT_DEFAULT = 'png' - - -class RendererGDK(RendererBase): - fontweights = { - 100 : pango.WEIGHT_ULTRALIGHT, - 200 : pango.WEIGHT_LIGHT, - 300 : pango.WEIGHT_LIGHT, - 400 : pango.WEIGHT_NORMAL, - 500 : pango.WEIGHT_NORMAL, - 600 : pango.WEIGHT_BOLD, - 700 : pango.WEIGHT_BOLD, - 800 : pango.WEIGHT_HEAVY, - 900 : pango.WEIGHT_ULTRABOLD, - 'ultralight' : pango.WEIGHT_ULTRALIGHT, - 'light' : pango.WEIGHT_LIGHT, - 'normal' : pango.WEIGHT_NORMAL, - 'medium' : pango.WEIGHT_NORMAL, - 'semibold' : pango.WEIGHT_BOLD, - 'bold' : pango.WEIGHT_BOLD, - 'heavy' : pango.WEIGHT_HEAVY, - 'ultrabold' : pango.WEIGHT_ULTRABOLD, - 'black' : pango.WEIGHT_ULTRABOLD, - } - - # cache for efficiency, these must be at class, not instance level - layoutd = {} # a map from text prop tups to pango layouts - rotated = {} # a map from text prop tups to rotated text pixbufs - - def __init__(self, gtkDA, dpi): - # widget gtkDA is used for: - # '.create_pango_layout(s)' - # cmap line below) - self.gtkDA = gtkDA - self.dpi = dpi - self._cmap = gtkDA.get_colormap() - self.mathtext_parser = MathTextParser("Agg") - - def set_pixmap (self, pixmap): - self.gdkDrawable = pixmap - - def set_width_height (self, width, height): - """w,h is the figure w,h not the pixmap w,h - """ - self.width, self.height = width, height - - def draw_path(self, gc, path, transform, rgbFace=None): - transform = transform + Affine2D(). \ - scale(1.0, -1.0).translate(0, self.height) - polygons = path.to_polygons(transform, self.width, self.height) - for polygon in polygons: - # draw_polygon won't take an arbitrary sequence -- it must be a list - # of tuples - polygon = [(int(np.round(x)), int(np.round(y))) for x, y in polygon] - if rgbFace is not None: - saveColor = gc.gdkGC.foreground - gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace) - self.gdkDrawable.draw_polygon(gc.gdkGC, True, polygon) - gc.gdkGC.foreground = saveColor - if gc.gdkGC.line_width > 0: - self.gdkDrawable.draw_lines(gc.gdkGC, polygon) - - def draw_image(self, gc, x, y, im): - bbox = gc.get_clip_rectangle() - - if bbox != None: - l,b,w,h = bbox.bounds - #rectangle = (int(l), self.height-int(b+h), - # int(w), int(h)) - # set clip rect? - - rows, cols = im.shape[:2] - - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, - has_alpha=True, bits_per_sample=8, - width=cols, height=rows) - - array = pixbuf_get_pixels_array(pixbuf) - array[:, :, :] = im[::-1] - - gc = self.new_gc() - - - y = self.height-y-rows - - try: # new in 2.2 - # can use None instead of gc.gdkGC, if don't need clipping - self.gdkDrawable.draw_pixbuf (gc.gdkGC, pixbuf, 0, 0, - int(x), int(y), cols, rows, - gdk.RGB_DITHER_NONE, 0, 0) - except AttributeError: - # deprecated in 2.2 - pixbuf.render_to_drawable(self.gdkDrawable, gc.gdkGC, 0, 0, - int(x), int(y), cols, rows, - gdk.RGB_DITHER_NONE, 0, 0) - - def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None): - x, y = int(x), int(y) - - if x < 0 or y < 0: # window has shrunk and text is off the edge - return - - if angle not in (0,90): - warnings.warn('backend_gdk: unable to draw text at angles ' + - 'other than 0 or 90') - elif ismath: - self._draw_mathtext(gc, x, y, s, prop, angle) - - elif angle==90: - self._draw_rotated_text(gc, x, y, s, prop, angle) - - else: - layout, inkRect, logicalRect = self._get_pango_layout(s, prop) - l, b, w, h = inkRect - if (x + w > self.width or y + h > self.height): - return - - self.gdkDrawable.draw_layout(gc.gdkGC, x, y-h-b, layout) - - def _draw_mathtext(self, gc, x, y, s, prop, angle): - ox, oy, width, height, descent, font_image, used_characters = \ - self.mathtext_parser.parse(s, self.dpi, prop) - - if angle == 90: - width, height = height, width - x -= width - y -= height - - imw = font_image.get_width() - imh = font_image.get_height() - - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, has_alpha=True, - bits_per_sample=8, width=imw, height=imh) - - array = pixbuf_get_pixels_array(pixbuf) - - rgb = gc.get_rgb() - array[:,:,0] = int(rgb[0]*255) - array[:,:,1] = int(rgb[1]*255) - array[:,:,2] = int(rgb[2]*255) - array[:,:,3] = ( - np.fromstring(font_image.as_str(), np.uint8).reshape((imh, imw))) - - # can use None instead of gc.gdkGC, if don't need clipping - self.gdkDrawable.draw_pixbuf(gc.gdkGC, pixbuf, 0, 0, - int(x), int(y), imw, imh, - gdk.RGB_DITHER_NONE, 0, 0) - - def _draw_rotated_text(self, gc, x, y, s, prop, angle): - """ - Draw the text rotated 90 degrees, other angles are not supported - """ - # this function (and its called functions) is a bottleneck - # Pango 1.6 supports rotated text, but pygtk 2.4.0 does not yet have - # wrapper functions - # GTK+ 2.6 pixbufs support rotation - - gdrawable = self.gdkDrawable - ggc = gc.gdkGC - - layout, inkRect, logicalRect = self._get_pango_layout(s, prop) - l, b, w, h = inkRect - x = int(x-h) - y = int(y-w) - - if (x < 0 or y < 0 or # window has shrunk and text is off the edge - x + w > self.width or y + h > self.height): - return - - key = (x,y,s,angle,hash(prop)) - imageVert = self.rotated.get(key) - if imageVert != None: - gdrawable.draw_image(ggc, imageVert, 0, 0, x, y, h, w) - return - - imageBack = gdrawable.get_image(x, y, w, h) - imageVert = gdrawable.get_image(x, y, h, w) - imageFlip = gtk.gdk.Image(type=gdk.IMAGE_FASTEST, - visual=gdrawable.get_visual(), - width=w, height=h) - if imageFlip == None or imageBack == None or imageVert == None: - warnings.warn("Could not renderer vertical text") - return - imageFlip.set_colormap(self._cmap) - for i in range(w): - for j in range(h): - imageFlip.put_pixel(i, j, imageVert.get_pixel(j,w-i-1) ) - - gdrawable.draw_image(ggc, imageFlip, 0, 0, x, y, w, h) - gdrawable.draw_layout(ggc, x, y-b, layout) - - imageIn = gdrawable.get_image(x, y, w, h) - for i in range(w): - for j in range(h): - imageVert.put_pixel(j, i, imageIn.get_pixel(w-i-1,j) ) - - gdrawable.draw_image(ggc, imageBack, 0, 0, x, y, w, h) - gdrawable.draw_image(ggc, imageVert, 0, 0, x, y, h, w) - self.rotated[key] = imageVert - - def _get_pango_layout(self, s, prop): - """ - Create a pango layout instance for Text 's' with properties 'prop'. - Return - pango layout (from cache if already exists) - - Note that pango assumes a logical DPI of 96 - Ref: pango/fonts.c/pango_font_description_set_size() manual page - """ - # problem? - cache gets bigger and bigger, is never cleared out - # two (not one) layouts are created for every text item s (then they - # are cached) - why? - - key = self.dpi, s, hash(prop) - value = self.layoutd.get(key) - if value != None: - return value - - size = prop.get_size_in_points() * self.dpi / 96.0 - size = np.round(size) - - font_str = '%s, %s %i' % (prop.get_name(), prop.get_style(), size,) - font = pango.FontDescription(font_str) - - # later - add fontweight to font_str - font.set_weight(self.fontweights[prop.get_weight()]) - - layout = self.gtkDA.create_pango_layout(s) - layout.set_font_description(font) - inkRect, logicalRect = layout.get_pixel_extents() - - self.layoutd[key] = layout, inkRect, logicalRect - return layout, inkRect, logicalRect - - def flipy(self): - return True - - def get_canvas_width_height(self): - return self.width, self.height - - def get_text_width_height_descent(self, s, prop, ismath): - if ismath: - ox, oy, width, height, descent, font_image, used_characters = \ - self.mathtext_parser.parse(s, self.dpi, prop) - return width, height, descent - - layout, inkRect, logicalRect = self._get_pango_layout(s, prop) - l, b, w, h = inkRect - ll, lb, lw, lh = logicalRect - - return w, h + 1, h - lh - - def new_gc(self): - return GraphicsContextGDK(renderer=self) - - def points_to_pixels(self, points): - return points/72.0 * self.dpi - - -class GraphicsContextGDK(GraphicsContextBase): - # a cache shared by all class instances - _cached = {} # map: rgb color -> gdk.Color - - _joind = { - 'bevel' : gdk.JOIN_BEVEL, - 'miter' : gdk.JOIN_MITER, - 'round' : gdk.JOIN_ROUND, - } - - _capd = { - 'butt' : gdk.CAP_BUTT, - 'projecting' : gdk.CAP_PROJECTING, - 'round' : gdk.CAP_ROUND, - } - - - def __init__(self, renderer): - GraphicsContextBase.__init__(self) - self.renderer = renderer - self.gdkGC = gtk.gdk.GC(renderer.gdkDrawable) - self._cmap = renderer._cmap - - - def rgb_to_gdk_color(self, rgb): - """ - rgb - an RGB tuple (three 0.0-1.0 values) - return an allocated gtk.gdk.Color - """ - try: - return self._cached[tuple(rgb)] - except KeyError: - color = self._cached[tuple(rgb)] = \ - self._cmap.alloc_color( - int(rgb[0]*65535),int(rgb[1]*65535),int(rgb[2]*65535)) - return color - - - #def set_antialiased(self, b): - # anti-aliasing is not supported by GDK - - def set_capstyle(self, cs): - GraphicsContextBase.set_capstyle(self, cs) - self.gdkGC.cap_style = self._capd[self._capstyle] - - - def set_clip_rectangle(self, rectangle): - GraphicsContextBase.set_clip_rectangle(self, rectangle) - if rectangle is None: - return - l,b,w,h = rectangle.bounds - rectangle = (int(l), self.renderer.height-int(b+h)+1, - int(w), int(h)) - #rectangle = (int(l), self.renderer.height-int(b+h), - # int(w+1), int(h+2)) - self.gdkGC.set_clip_rectangle(rectangle) - - def set_dashes(self, dash_offset, dash_list): - GraphicsContextBase.set_dashes(self, dash_offset, dash_list) - - if dash_list == None: - self.gdkGC.line_style = gdk.LINE_SOLID - else: - pixels = self.renderer.points_to_pixels(np.asarray(dash_list)) - dl = [max(1, int(np.round(val))) for val in pixels] - self.gdkGC.set_dashes(dash_offset, dl) - self.gdkGC.line_style = gdk.LINE_ON_OFF_DASH - - - def set_foreground(self, fg, isRGBA=False): - GraphicsContextBase.set_foreground(self, fg, isRGBA) - self.gdkGC.foreground = self.rgb_to_gdk_color(self.get_rgb()) - - - def set_joinstyle(self, js): - GraphicsContextBase.set_joinstyle(self, js) - self.gdkGC.join_style = self._joind[self._joinstyle] - - - def set_linewidth(self, w): - GraphicsContextBase.set_linewidth(self, w) - if w == 0: - self.gdkGC.line_width = 0 - else: - pixels = self.renderer.points_to_pixels(w) - self.gdkGC.line_width = max(1, int(np.round(pixels))) - - -class FigureCanvasGDK (FigureCanvasBase): - def __init__(self, figure): - FigureCanvasBase.__init__(self, figure) - if self.__class__ == matplotlib.backends.backend_gdk.FigureCanvasGDK: - warn_deprecated('2.0', message="The GDK backend is " - "deprecated. It is untested, known to be " - "broken and will be removed in Matplotlib 3.0. " - "Use the Agg backend instead. " - "See Matplotlib usage FAQ for" - " more info on backends.", - alternative="Agg") - self._renderer_init() - - def _renderer_init(self): - self._renderer = RendererGDK (gtk.DrawingArea(), self.figure.dpi) - - def _render_figure(self, pixmap, width, height): - self._renderer.set_pixmap (pixmap) - self._renderer.set_width_height (width, height) - self.figure.draw (self._renderer) - - filetypes = FigureCanvasBase.filetypes.copy() - filetypes['jpg'] = 'JPEG' - filetypes['jpeg'] = 'JPEG' - - def print_jpeg(self, filename, *args, **kwargs): - return self._print_image(filename, 'jpeg') - print_jpg = print_jpeg - - def print_png(self, filename, *args, **kwargs): - return self._print_image(filename, 'png') - - def _print_image(self, filename, format, *args, **kwargs): - width, height = self.get_width_height() - pixmap = gtk.gdk.Pixmap (None, width, height, depth=24) - self._render_figure(pixmap, width, height) - - # jpg colors don't match the display very well, png colors match - # better - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, 0, 8, - width, height) - pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), - 0, 0, 0, 0, width, height) - - # set the default quality, if we are writing a JPEG. - # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save - options = {k: kwargs[k] for k in ['quality'] if k in kwargs} - if format in ['jpg', 'jpeg']: - options.setdefault('quality', rcParams['savefig.jpeg_quality']) - 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 deleted file mode 100644 index 10a6ddcfcf51..000000000000 --- a/lib/matplotlib/backends/backend_gtk.py +++ /dev/null @@ -1,1037 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import logging -import os -import sys -import warnings - -if six.PY3: - warnings.warn( - "The gtk* backends have not been tested with Python 3.x", - ImportWarning) - -try: - import gobject - import gtk; gdk = gtk.gdk - import pango -except ImportError: - raise ImportError("Gtk* backend requires pygtk to be installed.") - -pygtk_version_required = (2,4,0) -if gtk.pygtk_version < pygtk_version_required: - raise ImportError ("PyGTK %d.%d.%d is installed\n" - "PyGTK %d.%d.%d or later is required" - % (gtk.pygtk_version + pygtk_version_required)) -del pygtk_version_required - -_new_tooltip_api = (gtk.pygtk_version[1] >= 12) - -import matplotlib -from matplotlib._pylab_helpers import Gcf -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, warn_deprecated -from matplotlib.figure import Figure -from matplotlib.widgets import SubplotTool - -from matplotlib import ( - cbook, colors as mcolors, lines, markers, rcParams) - -_log = logging.getLogger(__name__) - -backend_version = "%d.%d.%d" % gtk.pygtk_version - -# the true dots per inch on the screen; should be display dependent -# see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi -PIXELS_PER_INCH = 96 - -# Hide the benign warning that it can't stat a file that doesn't -warnings.filterwarnings('ignore', '.*Unable to retrieve the file info for.*', gtk.Warning) - -cursord = { - cursors.MOVE : gdk.Cursor(gdk.FLEUR), - cursors.HAND : gdk.Cursor(gdk.HAND2), - cursors.POINTER : gdk.Cursor(gdk.LEFT_PTR), - cursors.SELECT_REGION : gdk.Cursor(gdk.TCROSS), - cursors.WAIT : gdk.Cursor(gdk.WATCH), - } - -# ref gtk+/gtk/gtkwidget.h -def GTK_WIDGET_DRAWABLE(w): - flags = w.flags(); - return flags & gtk.VISIBLE != 0 and flags & gtk.MAPPED != 0 - - -class TimerGTK(TimerBase): - ''' - Subclass of :class:`backend_bases.TimerBase` using GTK for timer events. - - Attributes - ---------- - interval : int - The time between timer events in milliseconds. Default is 1000 ms. - single_shot : bool - Boolean flag indicating whether this timer should operate as single - shot (run once and then stop). Defaults to False. - callbacks : list - Stores list of (func, args) tuples that will be called upon timer - events. This list can be manipulated directly, or the functions - `add_callback` and `remove_callback` can be used. - - ''' - def _timer_start(self): - # Need to stop it, otherwise we potentially leak a timer id that will - # never be stopped. - self._timer_stop() - self._timer = gobject.timeout_add(self._interval, self._on_timer) - - def _timer_stop(self): - if self._timer is not None: - gobject.source_remove(self._timer) - self._timer = None - - def _timer_set_interval(self): - # Only stop and restart it if the timer has already been started - if self._timer is not None: - self._timer_stop() - self._timer_start() - - def _on_timer(self): - TimerBase._on_timer(self) - - # Gtk timeout_add() requires that the callback returns True if it - # is to be called again. - if len(self.callbacks) > 0 and not self._single: - return True - else: - self._timer = None - return False - - -class FigureCanvasGTK (gtk.DrawingArea, FigureCanvasBase): - keyvald = {65507 : 'control', - 65505 : 'shift', - 65513 : 'alt', - 65508 : 'control', - 65506 : 'shift', - 65514 : 'alt', - 65361 : 'left', - 65362 : 'up', - 65363 : 'right', - 65364 : 'down', - 65307 : 'escape', - 65470 : 'f1', - 65471 : 'f2', - 65472 : 'f3', - 65473 : 'f4', - 65474 : 'f5', - 65475 : 'f6', - 65476 : 'f7', - 65477 : 'f8', - 65478 : 'f9', - 65479 : 'f10', - 65480 : 'f11', - 65481 : 'f12', - 65300 : 'scroll_lock', - 65299 : 'break', - 65288 : 'backspace', - 65293 : 'enter', - 65379 : 'insert', - 65535 : 'delete', - 65360 : 'home', - 65367 : 'end', - 65365 : 'pageup', - 65366 : 'pagedown', - 65438 : '0', - 65436 : '1', - 65433 : '2', - 65435 : '3', - 65430 : '4', - 65437 : '5', - 65432 : '6', - 65429 : '7', - 65431 : '8', - 65434 : '9', - 65451 : '+', - 65453 : '-', - 65450 : '*', - 65455 : '/', - 65439 : 'dec', - 65421 : 'enter', - 65511 : 'super', - 65512 : 'super', - 65406 : 'alt', - 65289 : 'tab', - } - - # Setting this as a static constant prevents - # this resulting expression from leaking - event_mask = (gdk.BUTTON_PRESS_MASK | - gdk.BUTTON_RELEASE_MASK | - gdk.EXPOSURE_MASK | - gdk.KEY_PRESS_MASK | - gdk.KEY_RELEASE_MASK | - gdk.ENTER_NOTIFY_MASK | - gdk.LEAVE_NOTIFY_MASK | - gdk.POINTER_MOTION_MASK | - gdk.POINTER_MOTION_HINT_MASK) - - def __init__(self, figure): - if self.__class__ == matplotlib.backends.backend_gtk.FigureCanvasGTK: - warn_deprecated('2.0', message="The GTK backend is " - "deprecated. It is untested, known to be " - "broken and will be removed in Matplotlib 3.0. " - "Use the GTKAgg backend instead. " - "See Matplotlib usage FAQ for" - " more info on backends.", - alternative="GTKAgg") - FigureCanvasBase.__init__(self, figure) - gtk.DrawingArea.__init__(self) - - self._idle_draw_id = 0 - self._need_redraw = True - self._pixmap_width = -1 - self._pixmap_height = -1 - self._lastCursor = None - - self.connect('scroll_event', self.scroll_event) - self.connect('button_press_event', self.button_press_event) - self.connect('button_release_event', self.button_release_event) - self.connect('configure_event', self.configure_event) - self.connect('expose_event', self.expose_event) - self.connect('key_press_event', self.key_press_event) - self.connect('key_release_event', self.key_release_event) - self.connect('motion_notify_event', self.motion_notify_event) - self.connect('leave_notify_event', self.leave_notify_event) - self.connect('enter_notify_event', self.enter_notify_event) - - self.set_events(self.__class__.event_mask) - - self.set_double_buffered(False) - self.set_flags(gtk.CAN_FOCUS) - self._renderer_init() - - self.last_downclick = {} - - def destroy(self): - #gtk.DrawingArea.destroy(self) - self.close_event() - if self._idle_draw_id != 0: - gobject.source_remove(self._idle_draw_id) - - def scroll_event(self, widget, event): - x = event.x - # flipy so y=0 is bottom of canvas - y = self.allocation.height - event.y - if event.direction==gdk.SCROLL_UP: - step = 1 - else: - step = -1 - FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) - return False # finish event propagation? - - def button_press_event(self, widget, event): - x = event.x - # flipy so y=0 is bottom of canvas - y = self.allocation.height - event.y - dblclick = (event.type == gdk._2BUTTON_PRESS) - if not dblclick: - # GTK is the only backend that generates a DOWN-UP-DOWN-DBLCLICK-UP event - # sequence for a double click. All other backends have a DOWN-UP-DBLCLICK-UP - # sequence. In order to provide consistency to matplotlib users, we will - # eat the extra DOWN event in the case that we detect it is part of a double - # click. - # first, get the double click time in milliseconds. - current_time = event.get_time() - last_time = self.last_downclick.get(event.button,0) - dblclick_time = gtk.settings_get_for_screen(gdk.screen_get_default()).get_property('gtk-double-click-time') - delta_time = current_time-last_time - if delta_time < dblclick_time: - del self.last_downclick[event.button] # we do not want to eat more than one event. - return False # eat. - self.last_downclick[event.button] = current_time - FigureCanvasBase.button_press_event(self, x, y, event.button, dblclick=dblclick, guiEvent=event) - return False # finish event propagation? - - def button_release_event(self, widget, event): - x = event.x - # flipy so y=0 is bottom of canvas - y = self.allocation.height - event.y - FigureCanvasBase.button_release_event(self, x, y, event.button, guiEvent=event) - return False # finish event propagation? - - def key_press_event(self, widget, event): - key = self._get_key(event) - FigureCanvasBase.key_press_event(self, key, guiEvent=event) - return True # stop event propagation - - def key_release_event(self, widget, event): - key = self._get_key(event) - FigureCanvasBase.key_release_event(self, key, guiEvent=event) - return True # stop event propagation - - def motion_notify_event(self, widget, event): - if event.is_hint: - x, y, state = event.window.get_pointer() - else: - x, y, state = event.x, event.y, event.state - - # flipy so y=0 is bottom of canvas - y = self.allocation.height - y - FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) - return False # finish event propagation? - - def leave_notify_event(self, widget, event): - FigureCanvasBase.leave_notify_event(self, event) - - def enter_notify_event(self, widget, event): - x, y, state = event.window.get_pointer() - FigureCanvasBase.enter_notify_event(self, event, xy=(x, y)) - - def _get_key(self, event): - if event.keyval in self.keyvald: - key = self.keyvald[event.keyval] - elif event.keyval < 256: - key = chr(event.keyval) - else: - key = None - - for key_mask, prefix in ( - [gdk.MOD4_MASK, 'super'], - [gdk.MOD1_MASK, 'alt'], - [gdk.CONTROL_MASK, 'ctrl'], ): - if event.state & key_mask: - key = '{0}+{1}'.format(prefix, key) - - return key - - def configure_event(self, widget, event): - if widget.window is None: - return - w, h = event.width, event.height - if w < 3 or h < 3: - return # empty fig - - # resize the figure (in inches) - dpi = self.figure.dpi - self.figure.set_size_inches(w/dpi, h/dpi, forward=False) - self._need_redraw = True - - return False # finish event propagation? - - def draw(self): - # Note: FigureCanvasBase.draw() is inconveniently named as it clashes - # with the deprecated gtk.Widget.draw() - - self._need_redraw = True - if GTK_WIDGET_DRAWABLE(self): - self.queue_draw() - # do a synchronous draw (its less efficient than an async draw, - # but is required if/when animation is used) - self.window.process_updates (False) - - def draw_idle(self): - if self._idle_draw_id != 0: - return - def idle_draw(*args): - try: - self.draw() - finally: - self._idle_draw_id = 0 - return False - self._idle_draw_id = gobject.idle_add(idle_draw) - - - def _renderer_init(self): - """Override by GTK backends to select a different renderer - Renderer should provide the methods: - set_pixmap () - set_width_height () - that are used by - _render_figure() / _pixmap_prepare() - """ - self._renderer = RendererGDK (self, self.figure.dpi) - - - def _pixmap_prepare(self, width, height): - """ - Make sure _._pixmap is at least width, height, - create new pixmap if necessary - """ - create_pixmap = False - if width > self._pixmap_width: - # increase the pixmap in 10%+ (rather than 1 pixel) steps - self._pixmap_width = max (int (self._pixmap_width * 1.1), - width) - create_pixmap = True - - if height > self._pixmap_height: - self._pixmap_height = max (int (self._pixmap_height * 1.1), - height) - create_pixmap = True - - if create_pixmap: - self._pixmap = gdk.Pixmap (self.window, self._pixmap_width, - self._pixmap_height) - self._renderer.set_pixmap (self._pixmap) - - - def _render_figure(self, pixmap, width, height): - """used by GTK and GTKcairo. GTKAgg overrides - """ - self._renderer.set_width_height (width, height) - self.figure.draw (self._renderer) - - - def expose_event(self, widget, event): - """Expose_event for all GTK backends. Should not be overridden. - """ - toolbar = self.toolbar - # if toolbar: - # toolbar.set_cursor(cursors.WAIT) - if GTK_WIDGET_DRAWABLE(self): - if self._need_redraw: - x, y, w, h = self.allocation - self._pixmap_prepare (w, h) - self._render_figure(self._pixmap, w, h) - self._need_redraw = False - x, y, w, h = event.area - self.window.draw_drawable (self.style.fg_gc[self.state], - self._pixmap, x, y, x, y, w, h) - # if toolbar: - # toolbar.set_cursor(toolbar._lastCursor) - return False # finish event propagation? - - filetypes = FigureCanvasBase.filetypes.copy() - filetypes['jpg'] = 'JPEG' - filetypes['jpeg'] = 'JPEG' - filetypes['png'] = 'Portable Network Graphics' - - def print_jpeg(self, filename, *args, **kwargs): - return self._print_image(filename, 'jpeg') - print_jpg = print_jpeg - - def print_png(self, filename, *args, **kwargs): - return self._print_image(filename, 'png') - - def _print_image(self, filename, format, *args, **kwargs): - if self.flags() & gtk.REALIZED == 0: - # for self.window(for pixmap) and has a side effect of altering - # figure width,height (via configure-event?) - gtk.DrawingArea.realize(self) - - width, height = self.get_width_height() - pixmap = gdk.Pixmap (self.window, width, height) - self._renderer.set_pixmap (pixmap) - self._render_figure(pixmap, width, height) - - # jpg colors don't match the display very well, png colors match - # better - pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, 0, 8, width, height) - pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), - 0, 0, 0, 0, width, height) - - # set the default quality, if we are writing a JPEG. - # http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#method-gdkpixbuf--save - options = {k: kwargs[k] for k in ['quality'] if k in kwargs} - if format in ['jpg', 'jpeg']: - options.setdefault('quality', rcParams['savefig.jpeg_quality']) - options['quality'] = str(options['quality']) - - if isinstance(filename, six.string_types): - try: - pixbuf.save(filename, format, options=options) - except gobject.GError as exc: - error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) - elif is_writable_file_like(filename): - if hasattr(pixbuf, 'save_to_callback'): - def save_callback(buf, data=None): - data.write(buf) - try: - pixbuf.save_to_callback(save_callback, format, user_data=filename, options=options) - except gobject.GError as exc: - error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self) - else: - raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8") - else: - raise ValueError("filename must be a path or a file-like object") - - def new_timer(self, *args, **kwargs): - """ - Creates a new backend-specific subclass of :class:`backend_bases.Timer`. - This is useful for getting periodic events through the backend's native - event loop. Implemented only for backends with GUIs. - - Other Parameters - ---------------- - interval : scalar - Timer interval in milliseconds - callbacks : list - Sequence of (func, args, kwargs) where ``func(*args, **kwargs)`` - will be executed by the timer every *interval*. - """ - return TimerGTK(*args, **kwargs) - - def flush_events(self): - gtk.gdk.threads_enter() - while gtk.events_pending(): - gtk.main_iteration(True) - gtk.gdk.flush() - gtk.gdk.threads_leave() - - -class FigureManagerGTK(FigureManagerBase): - """ - Attributes - ---------- - canvas : `FigureCanvas` - The FigureCanvas instance - num : int or str - The Figure number - toolbar : gtk.Toolbar - The gtk.Toolbar (gtk only) - vbox : gtk.VBox - The gtk.VBox containing the canvas and toolbar (gtk only) - window : gtk.Window - The gtk.Window (gtk only) - - """ - def __init__(self, canvas, num): - FigureManagerBase.__init__(self, canvas, num) - - self.window = gtk.Window() - self.window.set_wmclass("matplotlib", "Matplotlib") - self.set_window_title("Figure %d" % num) - if window_icon: - try: - self.window.set_icon_from_file(window_icon) - except: - # some versions of gtk throw a glib.GError but not - # all, so I am not sure how to catch it. I am unhappy - # diong a blanket catch here, but an not sure what a - # better way is - JDH - _log.info('Could not load matplotlib ' - 'icon: %s', sys.exc_info()[1]) - - self.vbox = gtk.VBox() - self.window.add(self.vbox) - self.vbox.show() - - self.canvas.show() - - self.vbox.pack_start(self.canvas, True, True) - - self.toolbar = self._get_toolbar(canvas) - - # calculate size for window - w = int (self.canvas.figure.bbox.width) - h = int (self.canvas.figure.bbox.height) - - if self.toolbar is not None: - self.toolbar.show() - self.vbox.pack_end(self.toolbar, False, False) - - tb_w, tb_h = self.toolbar.size_request() - h += tb_h - self.window.set_default_size (w, h) - - def destroy(*args): - Gcf.destroy(num) - self.window.connect("destroy", destroy) - self.window.connect("delete_event", destroy) - if matplotlib.is_interactive(): - self.window.show() - self.canvas.draw_idle() - - def notify_axes_change(fig): - 'this will be called whenever the current axes is changed' - if self.toolbar is not None: self.toolbar.update() - self.canvas.figure.add_axobserver(notify_axes_change) - - self.canvas.grab_focus() - - def destroy(self, *args): - if hasattr(self, 'toolbar') and self.toolbar is not None: - self.toolbar.destroy() - if hasattr(self, 'vbox'): - self.vbox.destroy() - if hasattr(self, 'window'): - self.window.destroy() - if hasattr(self, 'canvas'): - self.canvas.destroy() - self.__dict__.clear() #Is this needed? Other backends don't have it. - - if Gcf.get_num_fig_managers()==0 and \ - not matplotlib.is_interactive() and \ - gtk.main_level() >= 1: - gtk.main_quit() - - def show(self): - # show the figure window - self.window.show() - # raise the window above others and release the "above lock" - self.window.set_keep_above(True) - self.window.set_keep_above(False) - - def full_screen_toggle(self): - self._full_screen_flag = not self._full_screen_flag - if self._full_screen_flag: - self.window.fullscreen() - else: - self.window.unfullscreen() - _full_screen_flag = False - - - def _get_toolbar(self, canvas): - # must be inited after the window, drawingArea and figure - # attrs are set - if rcParams['toolbar'] == 'toolbar2': - toolbar = NavigationToolbar2GTK (canvas, self.window) - else: - toolbar = None - return toolbar - - def get_window_title(self): - return self.window.get_title() - - def set_window_title(self, title): - self.window.set_title(title) - - def resize(self, width, height): - 'set the canvas size in pixels' - #_, _, cw, ch = self.canvas.allocation - #_, _, ww, wh = self.window.allocation - #self.window.resize (width-cw+ww, height-ch+wh) - self.window.resize(width, height) - - -class NavigationToolbar2GTK(NavigationToolbar2, gtk.Toolbar): - def __init__(self, canvas, window): - self.win = window - gtk.Toolbar.__init__(self) - NavigationToolbar2.__init__(self, canvas) - - def set_message(self, s): - self.message.set_label(s) - - def set_cursor(self, cursor): - self.canvas.window.set_cursor(cursord[cursor]) - gtk.main_iteration() - - def release(self, event): - try: del self._pixmapBack - except AttributeError: pass - - def draw_rubberband(self, event, x0, y0, x1, y1): - 'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/189744' - drawable = self.canvas.window - if drawable is None: - return - - gc = drawable.new_gc() - - height = self.canvas.figure.bbox.height - y1 = height - y1 - y0 = height - y0 - - w = abs(x1 - x0) - h = abs(y1 - y0) - - rect = [int(val)for val in (min(x0,x1), min(y0, y1), w, h)] - try: - lastrect, pixmapBack = self._pixmapBack - except AttributeError: - #snap image back - if event.inaxes is None: - return - - ax = event.inaxes - l,b,w,h = [int(val) for val in ax.bbox.bounds] - b = int(height)-(b+h) - axrect = l,b,w,h - self._pixmapBack = axrect, gtk.gdk.Pixmap(drawable, w, h) - self._pixmapBack[1].draw_drawable(gc, drawable, l, b, 0, 0, w, h) - else: - drawable.draw_drawable(gc, pixmapBack, 0, 0, *lastrect) - drawable.draw_rectangle(gc, False, *rect) - - - def _init_toolbar(self): - self.set_style(gtk.TOOLBAR_ICONS) - self._init_toolbar2_4() - - - def _init_toolbar2_4(self): - basedir = os.path.join(rcParams['datapath'],'images') - if not _new_tooltip_api: - self.tooltips = gtk.Tooltips() - - for text, tooltip_text, image_file, callback in self.toolitems: - if text is None: - self.insert( gtk.SeparatorToolItem(), -1 ) - continue - fname = os.path.join(basedir, image_file + '.png') - image = gtk.Image() - image.set_from_file(fname) - tbutton = gtk.ToolButton(image, text) - self.insert(tbutton, -1) - tbutton.connect('clicked', getattr(self, callback)) - if _new_tooltip_api: - tbutton.set_tooltip_text(tooltip_text) - else: - tbutton.set_tooltip(self.tooltips, tooltip_text, 'Private') - - toolitem = gtk.SeparatorToolItem() - self.insert(toolitem, -1) - # set_draw() not making separator invisible, - # bug #143692 fixed Jun 06 2004, will be in GTK+ 2.6 - toolitem.set_draw(False) - toolitem.set_expand(True) - - toolitem = gtk.ToolItem() - self.insert(toolitem, -1) - self.message = gtk.Label() - toolitem.add(self.message) - - self.show_all() - - def get_filechooser(self): - fc = FileChooserDialog( - title='Save the figure', - parent=self.win, - path=os.path.expanduser(rcParams['savefig.directory']), - filetypes=self.canvas.get_supported_filetypes(), - default_filetype=self.canvas.get_default_filetype()) - fc.set_current_name(self.canvas.get_default_filename()) - return fc - - def save_figure(self, *args): - chooser = self.get_filechooser() - fname, format = chooser.get_filename_from_user() - chooser.destroy() - if fname: - startpath = os.path.expanduser(rcParams['savefig.directory']) - # Save dir for next time, unless empty str (i.e., use cwd). - if startpath != "": - rcParams['savefig.directory'] = ( - os.path.dirname(six.text_type(fname))) - try: - self.canvas.figure.savefig(fname, format=format) - except Exception as e: - error_msg_gtk(str(e), parent=self) - - def configure_subplots(self, button): - toolfig = Figure(figsize=(6,3)) - canvas = self._get_canvas(toolfig) - toolfig.subplots_adjust(top=0.9) - tool = SubplotTool(self.canvas.figure, toolfig) - - w = int(toolfig.bbox.width) - h = int(toolfig.bbox.height) - - window = gtk.Window() - if window_icon: - try: - window.set_icon_from_file(window_icon) - except: - # we presumably already logged a message on the - # failure of the main plot, don't keep reporting - pass - window.set_title("Subplot Configuration Tool") - window.set_default_size(w, h) - vbox = gtk.VBox() - window.add(vbox) - vbox.show() - - canvas.show() - vbox.pack_start(canvas, True, True) - window.show() - - def _get_canvas(self, fig): - return FigureCanvasGTK(fig) - - -class FileChooserDialog(gtk.FileChooserDialog): - """GTK+ 2.4 file selector which presents the user with a menu - of supported image formats - """ - def __init__ (self, - title = 'Save file', - parent = None, - action = gtk.FILE_CHOOSER_ACTION_SAVE, - buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_SAVE, gtk.RESPONSE_OK), - path = None, - filetypes = [], - default_filetype = None - ): - super().__init__(title, parent, action, buttons) - super().set_do_overwrite_confirmation(True) - self.set_default_response(gtk.RESPONSE_OK) - - if not path: - path = os.getcwd() + os.sep - - # create an extra widget to list supported image formats - self.set_current_folder (path) - self.set_current_name ('image.' + default_filetype) - - hbox = gtk.HBox(spacing=10) - hbox.pack_start(gtk.Label ("File Format:"), expand=False) - - liststore = gtk.ListStore(gobject.TYPE_STRING) - cbox = gtk.ComboBox(liststore) - cell = gtk.CellRendererText() - cbox.pack_start(cell, True) - cbox.add_attribute(cell, 'text', 0) - hbox.pack_start(cbox) - - self.filetypes = filetypes - self.sorted_filetypes = sorted(six.iteritems(filetypes)) - default = 0 - for i, (ext, name) in enumerate(self.sorted_filetypes): - cbox.append_text("%s (*.%s)" % (name, ext)) - if ext == default_filetype: - default = i - cbox.set_active(default) - self.ext = default_filetype - - def cb_cbox_changed (cbox, data=None): - """File extension changed""" - head, filename = os.path.split(self.get_filename()) - root, ext = os.path.splitext(filename) - ext = ext[1:] - new_ext = self.sorted_filetypes[cbox.get_active()][0] - self.ext = new_ext - - if ext in self.filetypes: - filename = root + '.' + new_ext - elif ext == '': - filename = filename.rstrip('.') + '.' + new_ext - - self.set_current_name(filename) - cbox.connect("changed", cb_cbox_changed) - - hbox.show_all() - self.set_extra_widget(hbox) - - def get_filename_from_user (self): - while True: - filename = None - if self.run() != int(gtk.RESPONSE_OK): - break - filename = self.get_filename() - break - - return filename, self.ext - - -class DialogLineprops(object): - """ - A GUI dialog for controlling lineprops - """ - signals = ( - 'on_combobox_lineprops_changed', - 'on_combobox_linestyle_changed', - 'on_combobox_marker_changed', - 'on_colorbutton_linestyle_color_set', - 'on_colorbutton_markerface_color_set', - 'on_dialog_lineprops_okbutton_clicked', - 'on_dialog_lineprops_cancelbutton_clicked', - ) - - linestyles = [ls for ls in lines.Line2D.lineStyles if ls.strip()] - linestyled = {s: i for i, s in enumerate(linestyles)} - - markers = [m for m in markers.MarkerStyle.markers - if isinstance(m, six.string_types)] - markerd = {s: i for i, s in enumerate(markers)} - - def __init__(self, lines): - import gtk.glade - - datadir = matplotlib.get_data_path() - gladefile = os.path.join(datadir, 'lineprops.glade') - if not os.path.exists(gladefile): - raise IOError( - 'Could not find gladefile lineprops.glade in %s' % datadir) - - self._inited = False - self._updateson = True # suppress updates when setting widgets manually - self.wtree = gtk.glade.XML(gladefile, 'dialog_lineprops') - self.wtree.signal_autoconnect( - {s: getattr(self, s) for s in self.signals}) - - self.dlg = self.wtree.get_widget('dialog_lineprops') - - self.lines = lines - - cbox = self.wtree.get_widget('combobox_lineprops') - cbox.set_active(0) - self.cbox_lineprops = cbox - - cbox = self.wtree.get_widget('combobox_linestyles') - for ls in self.linestyles: - cbox.append_text(ls) - cbox.set_active(0) - self.cbox_linestyles = cbox - - cbox = self.wtree.get_widget('combobox_markers') - for m in self.markers: - cbox.append_text(m) - cbox.set_active(0) - self.cbox_markers = cbox - self._lastcnt = 0 - self._inited = True - - def show(self): - 'populate the combo box' - self._updateson = False - # flush the old - cbox = self.cbox_lineprops - for i in range(self._lastcnt-1,-1,-1): - cbox.remove_text(i) - - # add the new - for line in self.lines: - cbox.append_text(line.get_label()) - cbox.set_active(0) - - self._updateson = True - self._lastcnt = len(self.lines) - self.dlg.show() - - def get_active_line(self): - 'get the active line' - ind = self.cbox_lineprops.get_active() - line = self.lines[ind] - return line - - def get_active_linestyle(self): - 'get the active lineinestyle' - ind = self.cbox_linestyles.get_active() - ls = self.linestyles[ind] - return ls - - def get_active_marker(self): - 'get the active lineinestyle' - ind = self.cbox_markers.get_active() - m = self.markers[ind] - return m - - def _update(self): - 'update the active line props from the widgets' - if not self._inited or not self._updateson: return - line = self.get_active_line() - ls = self.get_active_linestyle() - marker = self.get_active_marker() - line.set_linestyle(ls) - line.set_marker(marker) - - button = self.wtree.get_widget('colorbutton_linestyle') - color = button.get_color() - r, g, b = [val/65535. for val in (color.red, color.green, color.blue)] - line.set_color((r,g,b)) - - button = self.wtree.get_widget('colorbutton_markerface') - color = button.get_color() - r, g, b = [val/65535. for val in (color.red, color.green, color.blue)] - line.set_markerfacecolor((r,g,b)) - - line.figure.canvas.draw() - - def on_combobox_lineprops_changed(self, item): - 'update the widgets from the active line' - if not self._inited: return - self._updateson = False - line = self.get_active_line() - - ls = line.get_linestyle() - if ls is None: ls = 'None' - self.cbox_linestyles.set_active(self.linestyled[ls]) - - marker = line.get_marker() - if marker is None: marker = 'None' - self.cbox_markers.set_active(self.markerd[marker]) - - rgba = mcolors.to_rgba(line.get_color()) - color = gtk.gdk.Color(*[int(val*65535) for val in rgba[:3]]) - button = self.wtree.get_widget('colorbutton_linestyle') - button.set_color(color) - - rgba = mcolors.to_rgba(line.get_markerfacecolor()) - color = gtk.gdk.Color(*[int(val*65535) for val in rgba[:3]]) - button = self.wtree.get_widget('colorbutton_markerface') - button.set_color(color) - self._updateson = True - - def on_combobox_linestyle_changed(self, item): - self._update() - - def on_combobox_marker_changed(self, item): - self._update() - - def on_colorbutton_linestyle_color_set(self, button): - self._update() - - def on_colorbutton_markerface_color_set(self, button): - 'called colorbutton marker clicked' - self._update() - - def on_dialog_lineprops_okbutton_clicked(self, button): - self._update() - self.dlg.hide() - - def on_dialog_lineprops_cancelbutton_clicked(self, button): - self.dlg.hide() - -# set icon used when windows are minimized -# Unfortunately, the SVG renderer (rsvg) leaks memory under earlier -# versions of pygtk, so we have to use a PNG file instead. -try: - if gtk.pygtk_version < (2, 8, 0) or sys.platform == 'win32': - icon_filename = 'matplotlib.png' - else: - icon_filename = 'matplotlib.svg' - window_icon = os.path.join(rcParams['datapath'], 'images', icon_filename) -except: - window_icon = None - _log.info('Could not load matplotlib icon: %s', sys.exc_info()[1]) - -def error_msg_gtk(msg, parent=None): - if parent is not None: # find the toplevel gtk.Window - parent = parent.get_toplevel() - if parent.flags() & gtk.TOPLEVEL == 0: - parent = None - - if not isinstance(msg, six.string_types): - msg = ','.join(map(str, msg)) - - dialog = gtk.MessageDialog( - parent = parent, - type = gtk.MESSAGE_ERROR, - buttons = gtk.BUTTONS_OK, - message_format = msg) - dialog.run() - dialog.destroy() - - -@_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_gtkagg.py b/lib/matplotlib/backends/backend_gtkagg.py deleted file mode 100644 index 2aefadfb3ec5..000000000000 --- a/lib/matplotlib/backends/backend_gtkagg.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -Render to gtk from agg -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib -from matplotlib.cbook import warn_deprecated -from matplotlib.backends.backend_agg import FigureCanvasAgg -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 - - -class NavigationToolbar2GTKAgg(NavigationToolbar2GTK): - def _get_canvas(self, fig): - return FigureCanvasGTKAgg(fig) - - -class FigureManagerGTKAgg(FigureManagerGTK): - def _get_toolbar(self, canvas): - # must be inited after the window, drawingArea and figure - # attrs are set - if matplotlib.rcParams['toolbar']=='toolbar2': - toolbar = NavigationToolbar2GTKAgg (canvas, self.window) - else: - toolbar = None - return toolbar - - -class FigureCanvasGTKAgg(FigureCanvasGTK, FigureCanvasAgg): - filetypes = FigureCanvasGTK.filetypes.copy() - filetypes.update(FigureCanvasAgg.filetypes) - - def __init__(self, *args, **kwargs): - warn_deprecated('2.2', - message=('The GTKAgg backend is deprecated. It is ' - 'untested and will be removed in Matplotlib ' - '3.0. Use the GTK3Agg backend instead. See ' - 'Matplotlib usage FAQ for more info on ' - 'backends.'), - alternative='GTK3Agg') - super().__init__(*args, **kwargs) - - def configure_event(self, widget, event=None): - - if widget.window is None: - return - try: - del self.renderer - except AttributeError: - pass - w,h = widget.window.get_size() - if w==1 or h==1: return # empty fig - - # compute desired figure size in inches - dpival = self.figure.dpi - winch = w/dpival - hinch = h/dpival - self.figure.set_size_inches(winch, hinch, forward=False) - self._need_redraw = True - self.resize_event() - return True - - def _render_figure(self, pixmap, width, height): - FigureCanvasAgg.draw(self) - - buf = self.buffer_rgba() - ren = self.get_renderer() - w = int(ren.width) - h = int(ren.height) - - pixbuf = gtk.gdk.pixbuf_new_from_data( - buf, gtk.gdk.COLORSPACE_RGB, True, 8, w, h, w*4) - pixmap.draw_pixbuf(pixmap.new_gc(), pixbuf, 0, 0, 0, 0, w, h, - gtk.gdk.RGB_DITHER_NONE, 0, 0) - - def blit(self, bbox=None): - agg_to_gtk_drawable(self._pixmap, self.renderer._renderer, bbox) - x, y, w, h = self.allocation - self.window.draw_drawable(self.style.fg_gc[self.state], self._pixmap, - 0, 0, 0, 0, w, h) - - def print_png(self, filename, *args, **kwargs): - # Do this so we can save the resolution of figure in the PNG file - agg = self.switch_backends(FigureCanvasAgg) - return agg.print_png(filename, *args, **kwargs) - - -@_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 deleted file mode 100644 index 48da2ae7a9fa..000000000000 --- a/lib/matplotlib/backends/backend_gtkcairo.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -GTK+ Matplotlib interface using cairo (not GDK) drawing operations. -Author: Steve Chaplin -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import gtk -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) - - -class RendererGTKCairo (backend_cairo.RendererCairo): - if gtk.pygtk_version >= (2,7,0): - def set_pixmap (self, pixmap): - self.gc.ctx = pixmap.cairo_create() - else: - def set_pixmap (self, pixmap): - self.gc.ctx = cairo.gtk.gdk_cairo_create (pixmap) - - -class FigureCanvasGTKCairo(backend_cairo.FigureCanvasCairo, FigureCanvasGTK): - filetypes = FigureCanvasGTK.filetypes.copy() - filetypes.update(backend_cairo.FigureCanvasCairo.filetypes) - - def __init__(self, *args, **kwargs): - warn_deprecated('2.2', - message=('The GTKCairo backend is deprecated. It is ' - 'untested and will be removed in Matplotlib ' - '3.0. Use the GTK3Cairo backend instead. See ' - 'Matplotlib usage FAQ for more info on ' - 'backends.'), - alternative='GTK3Cairo') - super().__init__(*args, **kwargs) - - def _renderer_init(self): - """Override to use cairo (rather than GDK) renderer""" - 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 - # attrs are set - if matplotlib.rcParams['toolbar']=='toolbar2': - toolbar = NavigationToolbar2GTKCairo (canvas, self.window) - else: - toolbar = None - 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) - - -@_BackendGTK.export -class _BackendGTKCairo(_BackendGTK): - FigureCanvas = FigureCanvasGTKCairo - FigureManager = FigureManagerGTK diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index c89d41f9589c..a4ebe6c36c0a 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -95,16 +95,11 @@ def _backend_selection(): if not PyQt5.QtWidgets.qApp.startingUp(): # The mainloop is running. rcParams['backend'] = 'qt5Agg' - elif ('gtk' in sys.modules and - backend not in ('GTK', 'GTKAgg', 'GTKCairo')): - if 'gi' in sys.modules: - from gi.repository import GObject - ml = GObject.MainLoop - else: - import gobject - ml = gobject.MainLoop + elif 'gtk' in sys.modules and 'gi' in sys.modules: + from gi.repository import GObject + ml = GObject.MainLoop if ml().is_running(): - rcParams['backend'] = 'gtk' + 'Agg' * is_agg_backend + rcParams['backend'] = 'GTK3Agg' elif 'Tkinter' in sys.modules and not backend == 'TkAgg': # import Tkinter pass # what if anything do we need to do for tkinter? diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index a4434f1ba5d4..f929b2db2709 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -35,17 +35,14 @@ # The capitalized forms are needed for ipython at present; this may # change for later versions. -interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'MacOSX', - 'Qt4Agg', 'Qt5Agg', 'TkAgg', 'WX', 'WXAgg', - 'GTK3Cairo', 'GTK3Agg', 'WebAgg', 'nbAgg'] -interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'GTK3Agg', 'GTK3Cairo', +interactive_bk = ['GTK3Agg', 'GTK3Cairo', 'MacOSX', 'nbAgg', 'Qt4Agg', 'Qt4Cairo', 'Qt5Agg', 'Qt5Cairo', 'TkAgg', 'TkCairo', 'WebAgg', 'WX', 'WXAgg', 'WXCairo'] -non_interactive_bk = ['agg', 'cairo', 'gdk', +non_interactive_bk = ['agg', 'cairo', 'pdf', 'pgf', 'ps', 'svg', 'template'] all_backends = interactive_bk + non_interactive_bk diff --git a/matplotlibrc.template b/matplotlibrc.template index 3c9d6f4cbc7b..689bfdf0282c 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -29,9 +29,8 @@ ##### CONFIGURATION BEGINS HERE -## The default backend; one of GTK GTKAgg GTKCairo GTK3Agg GTK3Cairo -## MacOSX Qt4Agg Qt5Agg TkAgg WX WXAgg Agg Cairo GDK PS PDF SVG -## Template. +## The default backend; one of GTK3Agg GTK3Cairo MacOSX Qt4Agg Qt5Agg TkAgg +## WX WXAgg Agg Cairo PS PDF SVG Template. ## You can also deploy your own backend outside of matplotlib by ## referring to the module name (which must be in the PYTHONPATH) as ## 'module://my_backend'. diff --git a/pytest.ini b/pytest.ini index 341532077417..18f30b251b4b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -24,11 +24,7 @@ pep8ignore = matplotlib/backends/qt_editor/formlayout.py E301 E402 E501 matplotlib/backends/backend_agg.py E225 E228 E231 E261 E301 E302 E303 E701 matplotlib/backends/backend_cairo.py E203 E211 E221 E231 E261 E272 E302 E303 E401 E402 E701 E711 - matplotlib/backends/backend_gdk.py E202 E203 E211 E221 E225 E231 E261 E302 E303 E402 E501 E702 E711 - matplotlib/backends/backend_gtk.py E201 E202 E203 E211 E221 E222 E225 E231 E251 E261 E262 E301 E302 E303 E401 E402 E501 E701 E702 E703 matplotlib/backends/backend_gtk3.py E201 E202 E203 E211 E221 E222 E225 E231 E251 E261 E262 E301 E302 E401 E402 E501 E701 - matplotlib/backends/backend_gtkagg.py E211 E225 E231 E261 E302 E501 E701 - matplotlib/backends/backend_gtkcairo.py E211 E225 E231 E402 E701 matplotlib/backends/backend_macosx.py E222 E225 E231 E261 E701 E711 matplotlib/backends/backend_pgf.py E261 E302 E303 E731 matplotlib/backends/backend_ps.py E202 E203 E225 E228 E231 E261 E262 E271 E301 E302 E303 E401 E402 E501 E701 diff --git a/setup.cfg.template b/setup.cfg.template index f53084083ea6..8d4669492afb 100644 --- a/setup.cfg.template +++ b/setup.cfg.template @@ -34,7 +34,7 @@ [gui_support] # Matplotlib supports multiple GUI toolkits, including -# GTK, MacOSX, Qt4, Qt5, Tk, and WX. Support for many of +# GTK3, MacOSX, Qt4, Qt5, Tk, and WX. Support for many of # these toolkits requires AGG, the Anti-Grain Geometry library, # which is provided by Matplotlib and built by default. # @@ -43,8 +43,6 @@ # these GUI toolkits during installation and, if present, compiles the # required extensions to support the toolkit. # -# - GTK 2.x support of any kind requires the GTK runtime environment -# headers and PyGTK. # - Tk support requires Tk development headers and Tkinter. # - Mac OSX backend requires the Cocoa headers included with XCode. # - Windowing is MS-Windows specific, and requires the "windows.h" @@ -66,10 +64,8 @@ # #agg = auto #cairo = auto -#gtk = auto #gtk3agg = auto #gtk3cairo = auto -#gtkagg = auto #macosx = auto #pyside = auto #qt4agg = auto @@ -80,13 +76,12 @@ [rc_options] # User-configurable options # -# Default backend, one of: Agg, Cairo, GTK, GTKAgg, GTKCairo, -# GTK3Agg, GTK3Cairo, MacOSX, Pdf, Ps, Qt4Agg, Qt5Agg, SVG, TkAgg, WX, WXAgg. +# Default backend, one of: Agg, Cairo, GTK3Agg, GTK3Cairo, MacOSX, Pdf, Ps, +# Qt4Agg, Qt5Agg, SVG, TkAgg, WX, WXAgg. # -# The Agg, Ps, Pdf and SVG backends do not require external -# dependencies. Do not choose GTK, GTKAgg, GTKCairo, MacOSX, or TkAgg -# if you have disabled the relevant extension modules. Agg will be used -# by default. +# The Agg, Ps, Pdf and SVG backends do not require external dependencies. Do +# not choose MacOSX, or TkAgg if you have disabled the relevant extension +# modules. Agg will be used by default. # #backend = Agg # diff --git a/setup.py b/setup.py index 84a75b062e68..668bc5b0cf2f 100644 --- a/setup.py +++ b/setup.py @@ -97,10 +97,8 @@ setupext.BackendQt4(), setupext.BackendGtk3Agg(), setupext.BackendGtk3Cairo(), - setupext.BackendGtkAgg(), setupext.BackendTkAgg(), setupext.BackendWxAgg(), - setupext.BackendGtk(), setupext.BackendAgg(), setupext.BackendCairo(), setupext.Windowing(), diff --git a/setupext.py b/setupext.py index da81c3635e2b..58e95459ce5c 100644 --- a/setupext.py +++ b/setupext.py @@ -1431,128 +1431,6 @@ def add_flags(self, ext): ext.libraries.extend(['dl']) -class BackendGtk(OptionalBackendPackage): - name = "gtk" - - def check_requirements(self): - try: - import gtk - except ImportError: - raise CheckFailed("Requires pygtk") - except RuntimeError: - raise CheckFailed('pygtk present, but import failed.') - else: - version = (2, 2, 0) - if gtk.pygtk_version < version: - raise CheckFailed( - "Requires pygtk %d.%d.%d or later. " - "Found %d.%d.%d" % (version + gtk.pygtk_version)) - - ext = self.get_extension() - self.add_flags(ext) - check_include_file(ext.include_dirs, - os.path.join("gtk", "gtk.h"), - 'gtk') - check_include_file(ext.include_dirs, - os.path.join("pygtk", "pygtk.h"), - 'pygtk') - - return 'Gtk: %s pygtk: %s' % ( - ".".join(str(x) for x in gtk.gtk_version), - ".".join(str(x) for x in gtk.pygtk_version)) - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - def get_extension(self): - sources = [ - 'src/_backend_gdk.c' - ] - ext = make_extension('matplotlib.backends._backend_gdk', sources) - self.add_flags(ext) - Numpy().add_flags(ext) - return ext - - def add_flags(self, ext): - if sys.platform == 'win32': - def getoutput(s): - ret = os.popen(s).read().strip() - return ret - - if 'PKG_CONFIG_PATH' not in os.environ: - # If Gtk+ is installed, pkg-config is required to be installed - os.environ['PKG_CONFIG_PATH'] = 'C:\\GTK\\lib\\pkgconfig' - - # popen broken on my win32 platform so I can't use pkgconfig - ext.library_dirs.extend( - ['C:/GTK/bin', 'C:/GTK/lib']) - - ext.include_dirs.extend( - ['win32_static/include/pygtk-2.0', - 'C:/GTK/include', - 'C:/GTK/include/gobject', - 'C:/GTK/include/gext', - 'C:/GTK/include/glib', - 'C:/GTK/include/pango', - 'C:/GTK/include/atk', - 'C:/GTK/include/X11', - 'C:/GTK/include/cairo', - 'C:/GTK/include/gdk', - 'C:/GTK/include/gdk-pixbuf', - 'C:/GTK/include/gtk', - ]) - - pygtkIncludes = getoutput( - 'pkg-config --cflags-only-I pygtk-2.0').split() - gtkIncludes = getoutput( - 'pkg-config --cflags-only-I gtk+-2.0').split() - includes = pygtkIncludes + gtkIncludes - ext.include_dirs.extend([include[2:] for include in includes]) - - pygtkLinker = getoutput('pkg-config --libs pygtk-2.0').split() - gtkLinker = getoutput('pkg-config --libs gtk+-2.0').split() - linkerFlags = pygtkLinker + gtkLinker - - ext.libraries.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-l')]) - - ext.library_dirs.extend( - [flag[2:] for flag in linkerFlags if flag.startswith('-L')]) - - ext.extra_link_args.extend( - [flag for flag in linkerFlags if not - (flag.startswith('-l') or flag.startswith('-L'))]) - - # visual studio doesn't need the math library - if (sys.platform == 'win32' and - win32_compiler == 'msvc' and - 'm' in ext.libraries): - ext.libraries.remove('m') - - elif sys.platform != 'win32': - pkg_config.setup_extension(ext, 'pygtk-2.0') - pkg_config.setup_extension(ext, 'gtk+-2.0') - - -class BackendGtkAgg(BackendGtk): - name = "gtkagg" - - def get_package_data(self): - return {'matplotlib': ['mpl-data/*.glade']} - - def get_extension(self): - sources = [ - 'src/py_converters.cpp', - 'src/_gtkagg.cpp', - 'src/mplutils.cpp' - ] - ext = make_extension('matplotlib.backends._gtkagg', sources) - self.add_flags(ext) - LibAgg().add_flags(ext) - Numpy().add_flags(ext) - return ext - - def backend_gtk3agg_internal_check(x): try: import gi diff --git a/src/_backend_gdk.c b/src/_backend_gdk.c deleted file mode 100644 index 8314219cca22..000000000000 --- a/src/_backend_gdk.c +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- mode: C; c-basic-offset: 4 -*- - * C extensions for backend_gdk - */ - -#include "Python.h" -#include "numpy/arrayobject.h" - -#include - -static PyTypeObject *_PyGdkPixbuf_Type; -#define PyGdkPixbuf_Type (*_PyGdkPixbuf_Type) - -static PyObject *pixbuf_get_pixels_array(PyObject *self, PyObject *args) -{ - /* 1) read in Python pixbuf, get the underlying gdk_pixbuf */ - PyGObject *py_pixbuf; - GdkPixbuf *gdk_pixbuf; - PyArrayObject *array; - npy_intp dims[3] = { 0, 0, 3 }; - npy_intp strides[3]; - - if (!PyArg_ParseTuple(args, "O!:pixbuf_get_pixels_array", &PyGdkPixbuf_Type, &py_pixbuf)) - return NULL; - - gdk_pixbuf = GDK_PIXBUF(py_pixbuf->obj); - - /* 2) same as pygtk/gtk/gdk.c _wrap_gdk_pixbuf_get_pixels_array() - * with 'self' changed to py_pixbuf - */ - - dims[0] = gdk_pixbuf_get_height(gdk_pixbuf); - dims[1] = gdk_pixbuf_get_width(gdk_pixbuf); - if (gdk_pixbuf_get_has_alpha(gdk_pixbuf)) - dims[2] = 4; - - strides[0] = gdk_pixbuf_get_rowstride(gdk_pixbuf); - strides[1] = dims[2]; - strides[2] = 1; - - array = (PyArrayObject*) - PyArray_New(&PyArray_Type, 3, dims, NPY_UBYTE, strides, - (void*)gdk_pixbuf_get_pixels(gdk_pixbuf), 1, - NPY_ARRAY_WRITEABLE, NULL); - - if (array == NULL) - return NULL; - - /* the array holds a ref to the pixbuf pixels through this wrapper*/ - Py_INCREF(py_pixbuf); - if (PyArray_SetBaseObject(array, (PyObject *)py_pixbuf) == -1) { - Py_DECREF(py_pixbuf); - Py_DECREF(array); - return NULL; - } - return PyArray_Return(array); -} - -static PyMethodDef _backend_gdk_functions[] = { - { "pixbuf_get_pixels_array", (PyCFunction)pixbuf_get_pixels_array, METH_VARARGS }, - { NULL, NULL, 0 } -}; - -PyMODINIT_FUNC init_backend_gdk(void) -{ - PyObject *mod; - mod = Py_InitModule("matplotlib.backends._backend_gdk", _backend_gdk_functions); - import_array(); - init_pygtk(); - - mod = PyImport_ImportModule("gtk.gdk"); - _PyGdkPixbuf_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "Pixbuf"); -} diff --git a/src/_gtkagg.cpp b/src/_gtkagg.cpp deleted file mode 100644 index 2d6a1cec13c1..000000000000 --- a/src/_gtkagg.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#include -#include - -#include - -#include "agg_basics.h" -#include "agg_pixfmt_rgba.h" -#include "agg_renderer_base.h" -#include "agg_rendering_buffer.h" - -#include "numpy_cpp.h" -#include "py_converters.h" - -static PyObject *Py_agg_to_gtk_drawable(PyObject *self, PyObject *args, PyObject *kwds) -{ - typedef agg::pixfmt_rgba32_plain pixfmt; - typedef agg::renderer_base renderer_base; - - PyGObject *py_drawable; - numpy::array_view buffer; - agg::rect_d rect; - - // args are gc, renderer, bbox where bbox is a transforms BBox - // (possibly None). If bbox is None, blit the entire agg buffer - // to gtk. If bbox is not None, blit only the region defined by - // the bbox - - if (!PyArg_ParseTuple(args, - "OO&O&:agg_to_gtk_drawable", - &py_drawable, - &buffer.converter, - &buffer, - &convert_rect, - &rect)) { - return NULL; - } - - if (buffer.dim(2) != 4) { - PyErr_SetString(PyExc_ValueError, "Invalid image buffer. Must be NxMx4."); - return NULL; - } - - GdkDrawable *drawable = GDK_DRAWABLE(py_drawable->obj); - GdkGC *gc = gdk_gc_new(drawable); - - int srcstride = buffer.dim(1) * 4; - int srcwidth = buffer.dim(1); - int srcheight = buffer.dim(0); - - // these three will be overridden below - int destx = 0; - int desty = 0; - int destwidth = 1; - int destheight = 1; - int deststride = 1; - - std::vector destbuffer; - agg::int8u *destbufferptr; - - if (rect.x1 == 0.0 && rect.x2 == 0.0 && rect.y1 == 0.0 && rect.y2 == 0.0) { - // bbox is None; copy the entire image - destbufferptr = (agg::int8u *)buffer.data(); - destwidth = srcwidth; - destheight = srcheight; - deststride = srcstride; - } else { - destx = (int)rect.x1; - desty = srcheight - (int)rect.y2; - destwidth = (int)(rect.x2 - rect.x1); - destheight = (int)(rect.y2 - rect.y1); - deststride = destwidth * 4; - destbuffer.resize(destheight * deststride, 0); - destbufferptr = &destbuffer.front(); - - agg::rendering_buffer destrbuf; - destrbuf.attach(destbufferptr, destwidth, destheight, deststride); - pixfmt destpf(destrbuf); - renderer_base destrb(destpf); - - agg::rendering_buffer srcrbuf; - srcrbuf.attach((agg::int8u *)buffer.data(), buffer.dim(1), buffer.dim(0), buffer.dim(1) * 4); - - agg::rect_base region(destx, desty, (int)rect.x2, srcheight - (int)rect.y1); - destrb.copy_from(srcrbuf, ®ion, -destx, -desty); - } - - gdk_draw_rgb_32_image(drawable, - gc, - destx, - desty, - destwidth, - destheight, - GDK_RGB_DITHER_NORMAL, - destbufferptr, - deststride); - - gdk_gc_destroy(gc); - - Py_RETURN_NONE; -} - -static PyMethodDef module_methods[] = { - {"agg_to_gtk_drawable", (PyCFunction)Py_agg_to_gtk_drawable, METH_VARARGS, NULL}, - NULL -}; - -extern "C" { - -#if PY3K - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_gtkagg", - NULL, - 0, - module_methods, - NULL, - NULL, - NULL, - NULL - }; - -#define INITERROR return NULL - - PyMODINIT_FUNC PyInit__gtkagg(void) - -#else -#define INITERROR return - - PyMODINIT_FUNC init_gtkagg(void) -#endif - - { - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_gtkagg", module_methods, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - init_pygobject(); - init_pygtk(); - import_array(); - -#if PY3K - return m; -#endif - } -} diff --git a/tutorials/introductory/usage.py b/tutorials/introductory/usage.py index 185f38d29b65..5d56b9f4a3b6 100644 --- a/tutorials/introductory/usage.py +++ b/tutorials/introductory/usage.py @@ -354,8 +354,8 @@ def my_plotter(ax, data1, data2, param_dict): # :func:`~matplotlib.use` unless absolutely necessary. # # .. note:: -# Backend name specifications are not case-sensitive; e.g., 'GTKAgg' -# and 'gtkagg' are equivalent. +# Backend name specifications are not case-sensitive; e.g., 'GTK3Agg' +# and 'gtk3agg' are equivalent. # # With a typical installation of matplotlib, such as from a # binary installer or a linux distribution package, a good default @@ -373,11 +373,10 @@ def my_plotter(ax, data1, data2, param_dict): # renderer for user interfaces is ``Agg`` which uses the `Anti-Grain # Geometry`_ C++ library to make a raster (pixel) image of the figure. # All of the user interfaces except ``macosx`` can be used with -# agg rendering, e.g., -# ``WXAgg``, ``GTKAgg``, ``QT4Agg``, ``QT5Agg``, ``TkAgg``. In -# addition, some of the user interfaces support other rendering engines. -# For example, with GTK, you can also select GDK rendering (backend -# ``GTK`` deprecated in 2.0) or Cairo rendering (backend ``GTKCairo``). +# agg rendering, e.g., ``WXAgg``, ``GTK3Agg``, ``QT4Agg``, ``QT5Agg``, +# ``TkAgg``. In addition, some of the user interfaces support other rendering +# engines. For example, with GTK+ 3, you can also select Cairo rendering +# (backend ``GTK3Cairo``). # # For the rendering engines, one can also distinguish between `vector # `_ or `raster @@ -438,11 +437,6 @@ def my_plotter(ax, data1, data2, param_dict): # Qt4Agg Agg rendering to a :term:`Qt4` canvas (requires PyQt4_ or # ``pyside``). This backend can be activated in IPython with # ``%matplotlib qt4``. -# GTKAgg Agg rendering to a :term:`GTK` 2.x canvas (requires PyGTK_, and -# pycairo_ or cairocffi_; Python2 only). This backend can be -# activated in IPython with ``%matplotlib gtk``. -# GTKCairo Cairo rendering to a :term:`GTK` 2.x canvas (requires PyGTK_, -# and pycairo_ or cairocffi_; Python2 only). # WXAgg Agg rendering to a :term:`wxWidgets` canvas (requires wxPython_; # v4.0 (in beta) is required for Python3). This backend can be # activated in IPython with ``%matplotlib wx``.# From 56947bdc9638aac2b17492c9ee94c7f103dfd553 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sun, 11 Feb 2018 23:58:20 -0500 Subject: [PATCH 05/10] DOC: Convert remaining GTK2 examples to GTK3. --- .../user_interfaces/gtk_spreadsheet_sgskip.py | 55 +++++++++---------- .../user_interfaces/pylab_with_gtk_sgskip.py | 18 +++--- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/examples/user_interfaces/gtk_spreadsheet_sgskip.py b/examples/user_interfaces/gtk_spreadsheet_sgskip.py index 41d4aca37418..476022db1c44 100644 --- a/examples/user_interfaces/gtk_spreadsheet_sgskip.py +++ b/examples/user_interfaces/gtk_spreadsheet_sgskip.py @@ -8,55 +8,54 @@ data """ -import pygtk -pygtk.require('2.0') -import gtk -from gtk import gdk +import gi +gi.require_version('Gtk', '3.0') +gi.require_version('Gdk', '3.0') +from gi.repository import Gtk, Gdk -import matplotlib -matplotlib.use('GTKAgg') # or 'GTK' -from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas +from matplotlib.backends.backend_gtk3agg import FigureCanvas +# from matplotlib.backends.backend_gtk3cairo import FigureCanvas from numpy.random import random from matplotlib.figure import Figure -class DataManager(gtk.Window): +class DataManager(Gtk.Window): numRows, numCols = 20, 10 data = random((numRows, numCols)) def __init__(self): - gtk.Window.__init__(self) + Gtk.Window.__init__(self) self.set_default_size(600, 600) - self.connect('destroy', lambda win: gtk.main_quit()) + self.connect('destroy', lambda win: Gtk.main_quit()) self.set_title('GtkListStore demo') self.set_border_width(8) - vbox = gtk.VBox(False, 8) + vbox = Gtk.VBox(False, 8) self.add(vbox) - label = gtk.Label('Double click a row to plot the data') + label = Gtk.Label('Double click a row to plot the data') - vbox.pack_start(label, False, False) + vbox.pack_start(label, False, False, 0) - sw = gtk.ScrolledWindow() - sw.set_shadow_type(gtk.SHADOW_ETCHED_IN) - sw.set_policy(gtk.POLICY_NEVER, - gtk.POLICY_AUTOMATIC) - vbox.pack_start(sw, True, True) + sw = Gtk.ScrolledWindow() + sw.set_shadow_type(Gtk.ShadowType.ETCHED_IN) + sw.set_policy(Gtk.PolicyType.NEVER, + Gtk.PolicyType.AUTOMATIC) + vbox.pack_start(sw, True, True, 0) model = self.create_model() - self.treeview = gtk.TreeView(model) + self.treeview = Gtk.TreeView(model) self.treeview.set_rules_hint(True) # matplotlib stuff fig = Figure(figsize=(6, 4)) - self.canvas = FigureCanvas(fig) # a gtk.DrawingArea - vbox.pack_start(self.canvas, True, True) + self.canvas = FigureCanvas(fig) # a Gtk.DrawingArea + vbox.pack_start(self.canvas, True, True, 0) ax = fig.add_subplot(111) self.line, = ax.plot(self.data[0, :], 'go') # plot the first row @@ -65,9 +64,9 @@ def __init__(self): self.add_columns() - self.add_events(gdk.BUTTON_PRESS_MASK | - gdk.KEY_PRESS_MASK | - gdk.KEY_RELEASE_MASK) + self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.KEY_RELEASE_MASK) def plot_row(self, treeview, path, view_column): ind, = path # get the index into data @@ -77,18 +76,18 @@ def plot_row(self, treeview, path, view_column): def add_columns(self): for i in range(self.numCols): - column = gtk.TreeViewColumn('%d' % i, gtk.CellRendererText(), text=i) + column = Gtk.TreeViewColumn(str(i), Gtk.CellRendererText(), text=i) self.treeview.append_column(column) def create_model(self): types = [float]*self.numCols - store = gtk.ListStore(*types) + store = Gtk.ListStore(*types) for row in self.data: - store.append(row) + store.append(tuple(row)) return store manager = DataManager() manager.show_all() -gtk.main() +Gtk.main() diff --git a/examples/user_interfaces/pylab_with_gtk_sgskip.py b/examples/user_interfaces/pylab_with_gtk_sgskip.py index b1abb3f8f73e..c7ea65dda64e 100644 --- a/examples/user_interfaces/pylab_with_gtk_sgskip.py +++ b/examples/user_interfaces/pylab_with_gtk_sgskip.py @@ -7,7 +7,7 @@ modify the GUI by accessing the underlying gtk widgets """ import matplotlib -matplotlib.use('GTKAgg') +matplotlib.use('GTK3Agg') # or 'GTK3Cairo' import matplotlib.pyplot as plt @@ -22,9 +22,11 @@ toolbar = manager.toolbar # now let's add a button to the toolbar -import gtk +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk next = 8 # where to insert this in the mpl toolbar -button = gtk.Button('Click me') +button = Gtk.Button('Click me') button.show() @@ -32,22 +34,20 @@ def clicked(button): print('hi mom') button.connect('clicked', clicked) -toolitem = gtk.ToolItem() +toolitem = Gtk.ToolItem() toolitem.show() -toolitem.set_tooltip( - toolbar.tooltips, - 'Click me for fun and profit') +toolitem.set_tooltip_text('Click me for fun and profit') toolitem.add(button) toolbar.insert(toolitem, next) next += 1 # now let's add a widget to the vbox -label = gtk.Label() +label = Gtk.Label() label.set_markup('Drag mouse over axes for position') label.show() vbox = manager.vbox -vbox.pack_start(label, False, False) +vbox.pack_start(label, False, False, 0) vbox.reorder_child(manager.toolbar, -1) From 962388fa58188bbfe6179b19df9def4082792732 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 14 Feb 2018 23:44:13 -0500 Subject: [PATCH 06/10] Remove unused lineprops glade file. It was part of the GTK2 backends, but not implemented for GTK3. This file doesn't load in current Glade either. --- MANIFEST.in | 1 - .../lineprops_dialog_gtk_sgskip.py | 30 -- lib/matplotlib/mpl-data/lineprops.glade | 285 ------------------ 3 files changed, 316 deletions(-) delete mode 100644 examples/user_interfaces/lineprops_dialog_gtk_sgskip.py delete mode 100644 lib/matplotlib/mpl-data/lineprops.glade diff --git a/MANIFEST.in b/MANIFEST.in index e5aaa106f7ef..fcdff13813cb 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -4,7 +4,6 @@ include pytest.ini include Makefile MANIFEST.in include matplotlibrc.template setup.cfg.template include setupext.py setup.py distribute_setup.py -include lib/matplotlib/mpl-data/lineprops.glade include lib/matplotlib/mpl-data/matplotlibrc include lib/matplotlib/mpl-data/images/* include lib/matplotlib/mpl-data/fonts/ttf/* diff --git a/examples/user_interfaces/lineprops_dialog_gtk_sgskip.py b/examples/user_interfaces/lineprops_dialog_gtk_sgskip.py deleted file mode 100644 index 584fa6d49e80..000000000000 --- a/examples/user_interfaces/lineprops_dialog_gtk_sgskip.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -==================== -Lineprops Dialog GTK -==================== - -""" -import matplotlib -matplotlib.use('GTKAgg') -from matplotlib.backends.backend_gtk import DialogLineprops - -import numpy as np -import matplotlib.pyplot as plt - - -def f(t): - s1 = np.cos(2*np.pi*t) - e1 = np.exp(-t) - return np.multiply(s1, e1) - -t1 = np.arange(0.0, 5.0, 0.1) -t2 = np.arange(0.0, 5.0, 0.02) -t3 = np.arange(0.0, 2.0, 0.01) - -fig, ax = plt.subplots() -l1, = ax.plot(t1, f(t1), 'bo', label='line 1') -l2, = ax.plot(t2, f(t2), 'k--', label='line 2') - -dlg = DialogLineprops([l1, l2]) -dlg.show() -plt.show() diff --git a/lib/matplotlib/mpl-data/lineprops.glade b/lib/matplotlib/mpl-data/lineprops.glade deleted file mode 100644 index d731f3370bb7..000000000000 --- a/lib/matplotlib/mpl-data/lineprops.glade +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - True - Line Properties - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 - - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - False - 0 - - - - True - - - - - 0 - True - True - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 12 - 0 - - - - True - False - 0 - - - - True - 2 - 3 - False - 0 - 0 - - - - True - Marker - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - - - - - 1 - 2 - 0 - 1 - fill - - - - - - True - - - - - 1 - 2 - 1 - 2 - fill - fill - - - - - - True - True - True - Line color - True - - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - True - False - Marker color - True - - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - Line style - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - 0 - True - True - - - - - - - - - - True - <b>Line properties</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - label_item - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - From 5d57a874d897b39b337506286931717a9dd92550 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 16 Feb 2018 22:58:22 -0500 Subject: [PATCH 07/10] Update GTK example in the docs to GTK3. --- doc/users/navigation_toolbar.rst | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/users/navigation_toolbar.rst b/doc/users/navigation_toolbar.rst index 22e6e5bb1a14..162dc6b6e98a 100644 --- a/doc/users/navigation_toolbar.rst +++ b/doc/users/navigation_toolbar.rst @@ -109,31 +109,34 @@ automatically for every figure. If you are writing your own user interface code, you can add the toolbar as a widget. The exact syntax depends on your UI, but we have examples for every supported UI in the ``matplotlib/examples/user_interfaces`` directory. Here is some -example code for GTK:: +example code for GTK+ 3:: - import gtk + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk from matplotlib.figure import Figure - from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar + from matplotlib.backends.backend_gtk3agg import FigureCanvas + from matplotlib.backends.backend_gtk3 import ( + NavigationToolbar2GTK3 as NavigationToolbar) - win = gtk.Window() - win.connect("destroy", lambda x: gtk.main_quit()) + win = Gtk.Window() + win.connect("destroy", lambda x: Gtk.main_quit()) win.set_default_size(400,300) win.set_title("Embedding in GTK") - vbox = gtk.VBox() + vbox = Gtk.VBox() win.add(vbox) fig = Figure(figsize=(5,4), dpi=100) ax = fig.add_subplot(111) ax.plot([1,2,3]) - canvas = FigureCanvas(fig) # a gtk.DrawingArea - vbox.pack_start(canvas) + canvas = FigureCanvas(fig) # a Gtk.DrawingArea + vbox.pack_start(canvas, True, True, 0) toolbar = NavigationToolbar(canvas, win) - vbox.pack_start(toolbar, False, False) + vbox.pack_start(toolbar, False, False, 0) win.show_all() - gtk.main() + Gtk.main() From c4c40d0799baddc6d8601fd0db0fe27fb40b1d9d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 16 Feb 2018 23:36:43 -0500 Subject: [PATCH 08/10] Remove reference to delete gtktools toolkit. --- lib/matplotlib/mlab.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 93c5e16a58ab..90124479f9ec 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -151,14 +151,6 @@ rec2excel(r, 'test.xls', formatd=formatd) rec2csv(r, 'test.csv', formatd=formatd) - scroll = rec2gtk(r, formatd=formatd) - - win = gtk.Window() - win.set_size_request(600,800) - win.add(scroll) - win.show_all() - gtk.main() - """ From 4987e3cf3fa12183470fd2da7e0251146d364087 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Fri, 16 Feb 2018 23:57:27 -0500 Subject: [PATCH 09/10] DOC: Add note that deprecated backends were removed. --- doc/api/next_api_changes/2018-02-16-ES-removals.rst | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 doc/api/next_api_changes/2018-02-16-ES-removals.rst diff --git a/doc/api/next_api_changes/2018-02-16-ES-removals.rst b/doc/api/next_api_changes/2018-02-16-ES-removals.rst new file mode 100644 index 000000000000..a9558b0f3090 --- /dev/null +++ b/doc/api/next_api_changes/2018-02-16-ES-removals.rst @@ -0,0 +1,9 @@ +Removal of deprecated backends +------------------------------ + +Deprecated backends have been removed: + + * GTKAgg + * GTKCairo + * GTK + * GDK From d6e93a393e4ed4863e42d513d4fc06349411bbab Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 17 Feb 2018 02:53:33 -0500 Subject: [PATCH 10/10] Fix review items. --- examples/user_interfaces/pylab_with_gtk_sgskip.py | 6 +++--- examples/widgets/cursor.py | 2 +- examples/widgets/span_selector.py | 2 +- lib/matplotlib/pyplot.py | 3 +-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/examples/user_interfaces/pylab_with_gtk_sgskip.py b/examples/user_interfaces/pylab_with_gtk_sgskip.py index c7ea65dda64e..4308107afc76 100644 --- a/examples/user_interfaces/pylab_with_gtk_sgskip.py +++ b/examples/user_interfaces/pylab_with_gtk_sgskip.py @@ -25,7 +25,7 @@ import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk -next = 8 # where to insert this in the mpl toolbar +pos = 8 # where to insert this in the mpl toolbar button = Gtk.Button('Click me') button.show() @@ -39,8 +39,8 @@ def clicked(button): toolitem.set_tooltip_text('Click me for fun and profit') toolitem.add(button) -toolbar.insert(toolitem, next) -next += 1 +toolbar.insert(toolitem, pos) +pos += 1 # now let's add a widget to the vbox label = Gtk.Label() diff --git a/examples/widgets/cursor.py b/examples/widgets/cursor.py index 0e049b6ff80c..6fa20ca21177 100644 --- a/examples/widgets/cursor.py +++ b/examples/widgets/cursor.py @@ -20,7 +20,7 @@ ax.set_xlim(-2, 2) ax.set_ylim(-2, 2) -# Set useblit=True on some backends for enhanced performance. +# Set useblit=True on most backends for enhanced performance. cursor = Cursor(ax, useblit=True, color='red', linewidth=2) plt.show() diff --git a/examples/widgets/span_selector.py b/examples/widgets/span_selector.py index 0ea8904e3471..e3516b0ef7de 100644 --- a/examples/widgets/span_selector.py +++ b/examples/widgets/span_selector.py @@ -38,7 +38,7 @@ def onselect(xmin, xmax): ax2.set_ylim(thisy.min(), thisy.max()) fig.canvas.draw() -# Set useblit=True on some backends for enhanced performance. +# Set useblit=True on most backends for enhanced performance. span = SpanSelector(ax1, onselect, 'horizontal', useblit=True, rectprops=dict(alpha=0.5, facecolor='red')) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index a4ebe6c36c0a..e8429bc78016 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -97,8 +97,7 @@ def _backend_selection(): rcParams['backend'] = 'qt5Agg' elif 'gtk' in sys.modules and 'gi' in sys.modules: from gi.repository import GObject - ml = GObject.MainLoop - if ml().is_running(): + if GObject.MainLoop().is_running(): rcParams['backend'] = 'GTK3Agg' elif 'Tkinter' in sys.modules and not backend == 'TkAgg': # import Tkinter