I am trying to make an interactive plotting GUI using Tkinter and matplotlib (python 3.7 and matplotlib 3.0.0) I want the user to be able to resize the figure as it is displayed on the screen without resizing the window, and have achieved this by editing the dpi, width, and height properties of the figure. So far, this works, but if the figure is bigger than the display area, I want the user to be able to scroll to see the whole figure. And if the figure is smaller than the display area, I want the scrollbars to be disabled.
I have tried applying scrollbars directly to the FigureCanvasTkAgg object itself as well as embedding the FigureCanvasTkAgg canvas inside a second scrollable canvas, but it seems that the problem is that the drawable area of the FigureCanvasTkAgg widget doesn't change when the figure size changes. Minimal code reproducing the problem is below. Is there some property of the FigureCanvasTkAgg object that I'm missing that makes this work?
import tkinter as tk
from tkinter import ttk
from tkinter.simpledialog import askfloat
from matplotlib.figure import Figure
from matplotlib.axes import Axes
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
class InteractivePlot(tk.Frame):
def __init__(self,master,**kwargs):
super().__init__(master,**kwargs)
self._figure = Figure(dpi=150)
self._canvas = FigureCanvasTkAgg(self._figure, master=self)
self._sizebutton = tk.Button(self,text="Size (in.)", command=self._change_size)
self._axis = self._figure.add_subplot(111)
# Plot some data just to have something to look at.
self._axis.plot([0,1,2,3,4,5],[1,1,3,3,5,5],label='Dummy Data')
self._cwidg = self._canvas.get_tk_widget()
self._scrx = ttk.Scrollbar(self,orient="horizontal", command=self._cwidg.xview)
self._scry = ttk.Scrollbar(self,orient="vertical", command=self._cwidg.yview)
self._cwidg.configure(yscrollcommand=self._scry.set, xscrollcommand=self._scrx.set)
self._cwidg.bind(
"<Configure>",
lambda e: self._cwidg.configure(
scrollregion=self._cwidg.bbox("all")
)
)
self._sizebutton.grid(row=0,column=0,sticky='w')
self._cwidg. grid(row=1,column=0,sticky='news')
self._scrx. grid(row=2,column=0,sticky='ew')
self._scry. grid(row=1,column=1,sticky='ns')
self.rowconfigure(1,weight=1)
self.columnconfigure(0,weight=1)
self._canvas.draw()
def _change_size(self):
newsize = askfloat('Size','Input new size in inches')
if newsize is None:
return
w = newsize
h = newsize/1.8
self._figure.set_figwidth(w)
self._figure.set_figheight(h)
self._canvas.draw()
root = tk.Tk()
plt = InteractivePlot(root,width=400,height=400)
plt.pack(fill=tk.BOTH,expand=True)
root.mainloop()