Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit afe3e76

Browse filesBrowse files
committed
Deduplicate implementation of per-backend Tools.
... by reusing the old Toolbar-based implementations. If toolmanager ever becomes the default we can move the implementations there and conversely point the old Toolbar-based implementations to use the Tools.
1 parent 4dbbd22 commit afe3e76
Copy full SHA for afe3e76

File tree

Expand file treeCollapse file tree

5 files changed

+47
-164
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+47
-164
lines changed

‎lib/matplotlib/backend_tools.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backend_tools.py
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import re
1515
import time
1616
import logging
17+
from types import SimpleNamespace
1718
from weakref import WeakKeyDictionary
1819

1920
import numpy as np
@@ -102,6 +103,15 @@ def canvas(self):
102103
def toolmanager(self):
103104
return self._toolmanager
104105

106+
def _make_classic_style_pseudo_toolbar(self):
107+
"""
108+
Return a placeholder object with a single `canvas` attribute.
109+
110+
This is useful to reuse the implementations of tools already provided
111+
by the classic Toolbars.
112+
"""
113+
return SimpleNamespace(canvas=self.canvas)
114+
105115
def set_figure(self, figure):
106116
"""
107117
Assign a figure to the tool

‎lib/matplotlib/backends/_backend_tk.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/_backend_tk.py
+11-50Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,9 @@ class NavigationToolbar2Tk(NavigationToolbar2, tk.Frame):
609609
"""
610610
def __init__(self, canvas, window):
611611
self.canvas = canvas
612+
# Avoid using self.window (use e.g.
613+
# self.canvas.get_tk_widget().master), so that Tool implementations can
614+
# reuse the methods.
612615
self.window = window
613616
NavigationToolbar2.__init__(self, canvas)
614617

@@ -627,16 +630,15 @@ def draw_rubberband(self, event, x0, y0, x1, y1):
627630
self.canvas._tkcanvas.delete(self.lastrect)
628631
self.lastrect = self.canvas._tkcanvas.create_rectangle(x0, y0, x1, y1)
629632

630-
#self.canvas.draw()
631-
632633
def release(self, event):
633634
if hasattr(self, "lastrect"):
634635
self.canvas._tkcanvas.delete(self.lastrect)
635636
del self.lastrect
636637

637638
def set_cursor(self, cursor):
638-
self.window.configure(cursor=cursord[cursor])
639-
self.window.update_idletasks()
639+
window = self.canvas.get_tk_widget()
640+
window.configure(cursor=cursord[cursor])
641+
window.update_idletasks()
640642

641643
def _Button(self, text, file, command, extension='.gif'):
642644
img_file = os.path.join(
@@ -709,7 +711,7 @@ def save_figure(self, *args):
709711
initialdir = os.path.expanduser(rcParams['savefig.directory'])
710712
initialfile = self.canvas.get_default_filename()
711713
fname = tkinter.filedialog.asksaveasfilename(
712-
master=self.window,
714+
master=self.canvas.get_tk_widget(),
713715
title='Save the figure',
714716
filetypes=tk_filetypes,
715717
defaultextension=defaultextension,
@@ -790,9 +792,6 @@ def hidetip(self):
790792

791793

792794
class RubberbandTk(backend_tools.RubberbandBase):
793-
def __init__(self, *args, **kwargs):
794-
backend_tools.RubberbandBase.__init__(self, *args, **kwargs)
795-
796795
def draw_rubberband(self, x0, y0, x1, y1):
797796
height = self.figure.canvas.figure.bbox.height
798797
y0 = height - y0
@@ -810,7 +809,8 @@ def remove_rubberband(self):
810809

811810
class SetCursorTk(backend_tools.SetCursorBase):
812811
def set_cursor(self, cursor):
813-
self.figure.canvas.manager.window.configure(cursor=cursord[cursor])
812+
NavigationToolbar2Tk.set_cursor(
813+
self._make_classic_style_pseudo_toolbar(), cursor)
814814

815815

816816
class ToolbarTk(ToolContainerBase, tk.Frame):
@@ -910,47 +910,8 @@ def set_message(self, s):
910910

911911
class SaveFigureTk(backend_tools.SaveFigureBase):
912912
def trigger(self, *args):
913-
filetypes = self.figure.canvas.get_supported_filetypes().copy()
914-
default_filetype = self.figure.canvas.get_default_filetype()
915-
916-
# Tk doesn't provide a way to choose a default filetype,
917-
# so we just have to put it first
918-
default_filetype_name = filetypes.pop(default_filetype)
919-
sorted_filetypes = ([(default_filetype, default_filetype_name)]
920-
+ sorted(filetypes.items()))
921-
tk_filetypes = [(name, '*.%s' % ext) for ext, name in sorted_filetypes]
922-
923-
# adding a default extension seems to break the
924-
# asksaveasfilename dialog when you choose various save types
925-
# from the dropdown. Passing in the empty string seems to
926-
# work - JDH!
927-
# defaultextension = self.figure.canvas.get_default_filetype()
928-
defaultextension = ''
929-
initialdir = os.path.expanduser(rcParams['savefig.directory'])
930-
initialfile = self.figure.canvas.get_default_filename()
931-
fname = tkinter.filedialog.asksaveasfilename(
932-
master=self.figure.canvas.manager.window,
933-
title='Save the figure',
934-
filetypes=tk_filetypes,
935-
defaultextension=defaultextension,
936-
initialdir=initialdir,
937-
initialfile=initialfile,
938-
)
939-
940-
if fname == "" or fname == ():
941-
return
942-
else:
943-
if initialdir == '':
944-
# explicitly missing key or empty str signals to use cwd
945-
rcParams['savefig.directory'] = initialdir
946-
else:
947-
# save dir for next time
948-
rcParams['savefig.directory'] = os.path.dirname(str(fname))
949-
try:
950-
# This method will handle the delegation to the correct type
951-
self.figure.savefig(fname)
952-
except Exception as e:
953-
tkinter.messagebox.showerror("Error saving file", str(e))
913+
NavigationToolbar2Tk.save_figure(
914+
self._make_classic_style_pseudo_toolbar())
954915

955916

956917
class ConfigureSubplotsTk(backend_tools.ConfigureSubplotsBase):

‎lib/matplotlib/backends/backend_gtk3.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_gtk3.py
+8-29Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -649,34 +649,6 @@ def get_filename_from_user(self):
649649
return None, self.ext
650650

651651

652-
class RubberbandGTK3(backend_tools.RubberbandBase):
653-
def __init__(self, *args, **kwargs):
654-
backend_tools.RubberbandBase.__init__(self, *args, **kwargs)
655-
self.ctx = None
656-
657-
def draw_rubberband(self, x0, y0, x1, y1):
658-
# 'adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/
659-
# Recipe/189744'
660-
self.ctx = self.figure.canvas.get_property("window").cairo_create()
661-
662-
# todo: instead of redrawing the entire figure, copy the part of
663-
# the figure that was covered by the previous rubberband rectangle
664-
self.figure.canvas.draw()
665-
666-
height = self.figure.bbox.height
667-
y1 = height - y1
668-
y0 = height - y0
669-
w = abs(x1 - x0)
670-
h = abs(y1 - y0)
671-
rect = [int(val) for val in (min(x0, x1), min(y0, y1), w, h)]
672-
673-
self.ctx.new_path()
674-
self.ctx.set_line_width(0.5)
675-
self.ctx.rectangle(rect[0], rect[1], rect[2], rect[3])
676-
self.ctx.set_source_rgb(0, 0, 0)
677-
self.ctx.stroke()
678-
679-
680652
class ToolbarGTK3(ToolContainerBase, Gtk.Box):
681653
_icon_extension = '.png'
682654

@@ -766,6 +738,12 @@ def set_message(self, s):
766738
self.push(self._context, s)
767739

768740

741+
class RubberbandGTK3(backend_tools.RubberbandBase):
742+
def draw_rubberband(self, x0, y0, x1, y1):
743+
NavigationToolbar2GTK3.draw_rubberband(
744+
self._make_classic_style_pseudo_toolbar(), None, x0, y0, x1, y1)
745+
746+
769747
class SaveFigureGTK3(backend_tools.SaveFigureBase):
770748

771749
def get_filechooser(self):
@@ -798,7 +776,8 @@ def trigger(self, *args, **kwargs):
798776

799777
class SetCursorGTK3(backend_tools.SetCursorBase):
800778
def set_cursor(self, cursor):
801-
self.figure.canvas.get_property("window").set_cursor(cursord[cursor])
779+
NavigationToolbar2GTK3.set_cursor(
780+
self._make_classic_style_pseudo_toolbar(), cursor)
802781

803782

804783
class ConfigureSubplotsGTK3(backend_tools.ConfigureSubplotsBase, Gtk.Window):

‎lib/matplotlib/backends/backend_qt5.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_qt5.py
+12-47Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ def remove_rubberband(self):
819819
def configure_subplots(self):
820820
image = os.path.join(matplotlib.rcParams['datapath'],
821821
'images', 'matplotlib.png')
822-
dia = SubplotToolQt(self.canvas.figure, self.parent)
822+
dia = SubplotToolQt(self.canvas.figure, self.canvas.parent())
823823
dia.setWindowIcon(QtGui.QIcon(image))
824824
dia.exec_()
825825

@@ -841,7 +841,7 @@ def save_figure(self, *args):
841841
filters.append(filter)
842842
filters = ';;'.join(filters)
843843

844-
fname, filter = _getSaveFileName(self.parent,
844+
fname, filter = _getSaveFileName(self.canvas.parent(),
845845
"Choose a filename to save to",
846846
start, filters, selectedFilter)
847847
if fname:
@@ -1001,65 +1001,30 @@ def set_message(self, s):
10011001

10021002
class ConfigureSubplotsQt(backend_tools.ConfigureSubplotsBase):
10031003
def trigger(self, *args):
1004-
image = os.path.join(matplotlib.rcParams['datapath'],
1005-
'images', 'matplotlib.png')
1006-
parent = self.canvas.manager.window
1007-
dia = SubplotToolQt(self.figure, parent)
1008-
dia.setWindowIcon(QtGui.QIcon(image))
1009-
dia.exec_()
1004+
NavigationToolbar2QT.configure_subplots(
1005+
self._make_classic_style_pseudo_toolbar())
10101006

10111007

10121008
class SaveFigureQt(backend_tools.SaveFigureBase):
10131009
def trigger(self, *args):
1014-
filetypes = self.canvas.get_supported_filetypes_grouped()
1015-
sorted_filetypes = sorted(filetypes.items())
1016-
default_filetype = self.canvas.get_default_filetype()
1017-
1018-
startpath = os.path.expanduser(
1019-
matplotlib.rcParams['savefig.directory'])
1020-
start = os.path.join(startpath, self.canvas.get_default_filename())
1021-
filters = []
1022-
selectedFilter = None
1023-
for name, exts in sorted_filetypes:
1024-
exts_list = " ".join(['*.%s' % ext for ext in exts])
1025-
filter = '%s (%s)' % (name, exts_list)
1026-
if default_filetype in exts:
1027-
selectedFilter = filter
1028-
filters.append(filter)
1029-
filters = ';;'.join(filters)
1030-
1031-
parent = self.canvas.manager.window
1032-
fname, filter = _getSaveFileName(parent,
1033-
"Choose a filename to save to",
1034-
start, filters, selectedFilter)
1035-
if fname:
1036-
# Save dir for next time, unless empty str (i.e., use cwd).
1037-
if startpath != "":
1038-
matplotlib.rcParams['savefig.directory'] = (
1039-
os.path.dirname(fname))
1040-
try:
1041-
self.canvas.figure.savefig(fname)
1042-
except Exception as e:
1043-
QtWidgets.QMessageBox.critical(
1044-
self, "Error saving file", str(e),
1045-
QtWidgets.QMessageBox.Ok, QtWidgets.QMessageBox.NoButton)
1010+
NavigationToolbar2QT.save_figure(
1011+
self._make_classic_style_pseudo_toolbar())
10461012

10471013

10481014
class SetCursorQt(backend_tools.SetCursorBase):
10491015
def set_cursor(self, cursor):
1050-
self.canvas.setCursor(cursord[cursor])
1016+
NavigationToolbar2QT.set_cursor(
1017+
self._make_classic_style_pseudo_toolbar(), cursor)
10511018

10521019

10531020
class RubberbandQt(backend_tools.RubberbandBase):
10541021
def draw_rubberband(self, x0, y0, x1, y1):
1055-
height = self.canvas.figure.bbox.height
1056-
y1 = height - y1
1057-
y0 = height - y0
1058-
rect = [int(val) for val in (x0, y0, x1 - x0, y1 - y0)]
1059-
self.canvas.drawRectangle(rect)
1022+
NavigationToolbar2QT.draw_rubberband(
1023+
self._make_classic_style_pseudo_toolbar(), None, x0, y0, x1, y1)
10601024

10611025
def remove_rubberband(self):
1062-
self.canvas.drawRectangle(None)
1026+
NavigationToolbar2QT.remove_rubberband(
1027+
self._make_classic_style_pseudo_toolbar())
10631028

10641029

10651030
class HelpQt(backend_tools.ToolHelpBase):

‎lib/matplotlib/backends/backend_wx.py

Copy file name to clipboardExpand all lines: lib/matplotlib/backends/backend_wx.py
+6-38Lines changed: 6 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,8 +1558,8 @@ def save_figure(self, *args):
15581558
# Fetch the required filename and file type.
15591559
filetypes, exts, filter_index = self.canvas._get_imagesave_wildcards()
15601560
default_file = self.canvas.get_default_filename()
1561-
dlg = wx.FileDialog(self._parent, "Save to file", "", default_file,
1562-
filetypes,
1561+
dlg = wx.FileDialog(self.canvas.GetParent(),
1562+
"Save to file", "", default_file, filetypes,
15631563
wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
15641564
dlg.SetFilterIndex(filter_index)
15651565
if dlg.ShowModal() == wx.ID_OK:
@@ -1816,46 +1816,14 @@ def get_canvas(self, frame, fig):
18161816

18171817
class SaveFigureWx(backend_tools.SaveFigureBase):
18181818
def trigger(self, *args):
1819-
# Fetch the required filename and file type.
1820-
filetypes, exts, filter_index = self.canvas._get_imagesave_wildcards()
1821-
default_dir = os.path.expanduser(
1822-
matplotlib.rcParams['savefig.directory'])
1823-
default_file = self.canvas.get_default_filename()
1824-
dlg = wx.FileDialog(self.canvas.GetTopLevelParent(), "Save to file",
1825-
default_dir, default_file, filetypes,
1826-
wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
1827-
dlg.SetFilterIndex(filter_index)
1828-
if dlg.ShowModal() != wx.ID_OK:
1829-
return
1830-
1831-
dirname = dlg.GetDirectory()
1832-
filename = dlg.GetFilename()
1833-
DEBUG_MSG('Save file dir:%s name:%s' % (dirname, filename), 3, self)
1834-
format = exts[dlg.GetFilterIndex()]
1835-
basename, ext = os.path.splitext(filename)
1836-
if ext.startswith('.'):
1837-
ext = ext[1:]
1838-
if ext in ('svg', 'pdf', 'ps', 'eps', 'png') and format != ext:
1839-
# looks like they forgot to set the image type drop
1840-
# down, going with the extension.
1841-
_log.warning('extension %s did not match the selected '
1842-
'image type %s; going with %s',
1843-
ext, format, ext)
1844-
format = ext
1845-
if default_dir != "":
1846-
matplotlib.rcParams['savefig.directory'] = dirname
1847-
try:
1848-
self.canvas.figure.savefig(
1849-
os.path.join(dirname, filename), format=format)
1850-
except Exception as e:
1851-
error_msg_wx(str(e))
1819+
NavigationToolbar2Wx.save_figure(
1820+
self._make_classic_style_pseudo_toolbar())
18521821

18531822

18541823
class SetCursorWx(backend_tools.SetCursorBase):
18551824
def set_cursor(self, cursor):
1856-
cursor = wx.Cursor(cursord[cursor])
1857-
self.canvas.SetCursor(cursor)
1858-
self.canvas.Update()
1825+
NavigationToolbar2Wx.set_cursor(
1826+
self._make_classic_style_pseudo_toolbar(), cursor)
18591827

18601828

18611829
if 'wxMac' not in wx.PlatformInfo:

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.