|
20 | 20 | from matplotlib.backend_bases import RendererBase, GraphicsContextBase
|
21 | 21 | from matplotlib.backend_bases import FigureManagerBase, FigureCanvasBase
|
22 | 22 | from matplotlib.backend_bases import NavigationToolbar2, cursors, TimerBase
|
23 |
| -from matplotlib.backend_bases import ShowBase |
| 23 | +from matplotlib.backend_bases import ShowBase, ToolbarBase, NavigationBase |
| 24 | +from matplotlib.backend_tools import SaveFigureBase, ConfigureSubplotsBase |
24 | 25 | from matplotlib._pylab_helpers import Gcf
|
25 | 26 |
|
26 | 27 | from matplotlib.figure import Figure
|
@@ -541,9 +542,23 @@ def __init__(self, canvas, num, window):
|
541 | 542 |
|
542 | 543 | def notify_axes_change(fig):
|
543 | 544 | 'this will be called whenever the current axes is changed'
|
544 |
| - if self.toolbar != None: self.toolbar.update() |
| 545 | + if self.navigation is not None: |
| 546 | + self.navigation.update() |
| 547 | + elif self.toolbar is not None: |
| 548 | + self.toolbar.update() |
545 | 549 | self.canvas.figure.add_axobserver(notify_axes_change)
|
546 | 550 |
|
| 551 | + def _get_toolbar(self, canvas): |
| 552 | + if matplotlib.rcParams['toolbar'] == 'toolbar2': |
| 553 | + toolbar = NavigationToolbar2TkAgg(canvas, self.window) |
| 554 | + elif matplotlib.rcParams['toolbar'] == 'navigation': |
| 555 | + self.navigation = NavigationTk(canvas, ToolbarTk) |
| 556 | + toolbar = self.navigation.toolbar |
| 557 | + else: |
| 558 | + self.navigation = NavigationTk(canvas, None) |
| 559 | + toolbar = None |
| 560 | + return toolbar |
| 561 | + |
547 | 562 | def resize(self, width, height=None):
|
548 | 563 | # before 09-12-22, the resize method takes a single *event*
|
549 | 564 | # parameter. On the other hand, the resize method of other
|
@@ -871,5 +886,180 @@ def hidetip(self):
|
871 | 886 | if tw:
|
872 | 887 | tw.destroy()
|
873 | 888 |
|
| 889 | + |
| 890 | +class NavigationTk(NavigationBase): |
| 891 | + def __init__(self, *args, **kwargs): |
| 892 | + NavigationBase.__init__(self, *args, **kwargs) |
| 893 | + |
| 894 | + def set_cursor(self, cursor): |
| 895 | + self.canvas.manager.window.configure(cursor=cursord[cursor]) |
| 896 | + |
| 897 | + def draw_rubberband(self, event, caller, x0, y0, x1, y1): |
| 898 | + if not self.canvas.widgetlock.available(caller): |
| 899 | + return |
| 900 | + height = self.canvas.figure.bbox.height |
| 901 | + y0 = height - y0 |
| 902 | + y1 = height - y1 |
| 903 | + try: |
| 904 | + self.lastrect |
| 905 | + except AttributeError: |
| 906 | + pass |
| 907 | + else: |
| 908 | + self.canvas._tkcanvas.delete(self.lastrect) |
| 909 | + self.lastrect = self.canvas._tkcanvas.create_rectangle(x0, y0, x1, y1) |
| 910 | + |
| 911 | + def remove_rubberband(self, event, caller): |
| 912 | + try: |
| 913 | + self.lastrect |
| 914 | + except AttributeError: |
| 915 | + pass |
| 916 | + else: |
| 917 | + self.canvas._tkcanvas.delete(self.lastrect) |
| 918 | + del self.lastrect |
| 919 | + |
| 920 | + |
| 921 | +class ToolbarTk(ToolbarBase, Tk.Frame): |
| 922 | + def __init__(self, manager): |
| 923 | + ToolbarBase.__init__(self, manager) |
| 924 | + xmin, xmax = self.manager.canvas.figure.bbox.intervalx |
| 925 | + height, width = 50, xmax - xmin |
| 926 | + Tk.Frame.__init__(self, master=self.manager.window, |
| 927 | + width=int(width), height=int(height), |
| 928 | + borderwidth=2) |
| 929 | + self._toolitems = {} |
| 930 | + self._add_message() |
| 931 | + |
| 932 | + def _add_toolitem(self, name, tooltip_text, image_file, position, |
| 933 | + toggle): |
| 934 | + |
| 935 | + button = self._Button(name, image_file, toggle) |
| 936 | + if tooltip_text is not None: |
| 937 | + ToolTip.createToolTip(button, tooltip_text) |
| 938 | + self._toolitems[name] = button |
| 939 | + |
| 940 | + def _Button(self, text, file, toggle): |
| 941 | + if file is not None: |
| 942 | + img_file = os.path.join(rcParams['datapath'], 'images', file) |
| 943 | + im = Tk.PhotoImage(master=self, file=img_file) |
| 944 | + else: |
| 945 | + im = None |
| 946 | + |
| 947 | + if not toggle: |
| 948 | + b = Tk.Button( |
| 949 | + master=self, text=text, padx=2, pady=2, image=im, |
| 950 | + command=lambda: self._button_click(text)) |
| 951 | + else: |
| 952 | + b = Tk.Checkbutton(master=self, text=text, padx=2, pady=2, |
| 953 | + image=im, indicatoron=False, |
| 954 | + command=lambda: self._button_click(text)) |
| 955 | + b._ntimage = im |
| 956 | + b.pack(side=Tk.LEFT) |
| 957 | + return b |
| 958 | + |
| 959 | + def _button_click(self, name): |
| 960 | + self.manager.navigation._toolbar_callback(name) |
| 961 | + |
| 962 | + def _toggle(self, name, callback=False): |
| 963 | + if name not in self._toolitems: |
| 964 | + self.set_message('%s Not in toolbar' % name) |
| 965 | + return |
| 966 | + self._toolitems[name].toggle() |
| 967 | + if callback: |
| 968 | + self._button_click(name) |
| 969 | + |
| 970 | + def _add_message(self): |
| 971 | + self.message = Tk.StringVar(master=self) |
| 972 | + self._message_label = Tk.Label(master=self, textvariable=self.message) |
| 973 | + self._message_label.pack(side=Tk.RIGHT) |
| 974 | + self.pack(side=Tk.BOTTOM, fill=Tk.X) |
| 975 | + |
| 976 | + def set_message(self, s): |
| 977 | + self.message.set(s) |
| 978 | + |
| 979 | + def _remove_toolitem(self, name): |
| 980 | + self._toolitems[name].pack_forget() |
| 981 | + del self._toolitems[name] |
| 982 | + |
| 983 | + def set_toolitem_visibility(self, name, visible): |
| 984 | + pass |
| 985 | + |
| 986 | + |
| 987 | +class SaveFigureTk(SaveFigureBase): |
| 988 | + def trigger(self, *args): |
| 989 | + from six.moves import tkinter_tkfiledialog, tkinter_messagebox |
| 990 | + filetypes = self.figure.canvas.get_supported_filetypes().copy() |
| 991 | + default_filetype = self.figure.canvas.get_default_filetype() |
| 992 | + |
| 993 | + # Tk doesn't provide a way to choose a default filetype, |
| 994 | + # so we just have to put it first |
| 995 | + default_filetype_name = filetypes[default_filetype] |
| 996 | + del filetypes[default_filetype] |
| 997 | + |
| 998 | + sorted_filetypes = list(six.iteritems(filetypes)) |
| 999 | + sorted_filetypes.sort() |
| 1000 | + sorted_filetypes.insert(0, (default_filetype, default_filetype_name)) |
| 1001 | + |
| 1002 | + tk_filetypes = [ |
| 1003 | + (name, '*.%s' % ext) for (ext, name) in sorted_filetypes] |
| 1004 | + |
| 1005 | + # adding a default extension seems to break the |
| 1006 | + # asksaveasfilename dialog when you choose various save types |
| 1007 | + # from the dropdown. Passing in the empty string seems to |
| 1008 | + # work - JDH! |
| 1009 | + #defaultextension = self.figure.canvas.get_default_filetype() |
| 1010 | + defaultextension = '' |
| 1011 | + initialdir = rcParams.get('savefig.directory', '') |
| 1012 | + initialdir = os.path.expanduser(initialdir) |
| 1013 | + initialfile = self.figure.canvas.get_default_filename() |
| 1014 | + fname = tkinter_tkfiledialog.asksaveasfilename( |
| 1015 | + master=self.figure.canvas.manager.window, |
| 1016 | + title='Save the figure', |
| 1017 | + filetypes=tk_filetypes, |
| 1018 | + defaultextension=defaultextension, |
| 1019 | + initialdir=initialdir, |
| 1020 | + initialfile=initialfile, |
| 1021 | + ) |
| 1022 | + |
| 1023 | + if fname == "" or fname == (): |
| 1024 | + return |
| 1025 | + else: |
| 1026 | + if initialdir == '': |
| 1027 | + # explicitly missing key or empty str signals to use cwd |
| 1028 | + rcParams['savefig.directory'] = initialdir |
| 1029 | + else: |
| 1030 | + # save dir for next time |
| 1031 | + rcParams['savefig.directory'] = os.path.dirname( |
| 1032 | + six.text_type(fname)) |
| 1033 | + try: |
| 1034 | + # This method will handle the delegation to the correct type |
| 1035 | + self.figure.canvas.print_figure(fname) |
| 1036 | + except Exception as e: |
| 1037 | + tkinter_messagebox.showerror("Error saving file", str(e)) |
| 1038 | + |
| 1039 | + |
| 1040 | +class ConfigureSubplotsTk(ConfigureSubplotsBase): |
| 1041 | + def __init__(self, *args, **kwargs): |
| 1042 | + ConfigureSubplotsBase.__init__(self, *args, **kwargs) |
| 1043 | + toolfig = Figure(figsize=(6, 3)) |
| 1044 | + self.window = Tk.Tk() |
| 1045 | + |
| 1046 | + canvas = FigureCanvasTkAgg(toolfig, master=self.window) |
| 1047 | + toolfig.subplots_adjust(top=0.9) |
| 1048 | + _tool = SubplotTool(self.figure, toolfig) |
| 1049 | + canvas.show() |
| 1050 | + canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) |
| 1051 | + self.window.protocol("WM_DELETE_WINDOW", self.destroy) |
| 1052 | + |
| 1053 | + def trigger(self, event): |
| 1054 | + self.window.lift() |
| 1055 | + |
| 1056 | + def destroy(self, *args, **kwargs): |
| 1057 | + self.unregister() |
| 1058 | + self.window.destroy() |
| 1059 | + |
| 1060 | + |
| 1061 | +SaveFigure = SaveFigureTk |
| 1062 | +ConfigureSubplots = ConfigureSubplotsTk |
| 1063 | + |
874 | 1064 | FigureCanvas = FigureCanvasTkAgg
|
875 | 1065 | FigureManager = FigureManagerTkAgg
|
0 commit comments