我正在尝试使用Tkinter和matplotlib(python 3.7和matplotlib 3.0.0)制作一个交互式绘图GUI。我希望用户能够在不调整窗口大小的情况下调整图形在屏幕上的显示大小,并通过编辑图形的dpi、宽度和高度属性实现了这一点。到目前为止,这是可行的,但是如果图形大于显示区域,我希望用户能够滚动查看整个图形。如果图形小于显示区域,我希望禁用滚动条
我曾尝试将滚动条直接应用于FigureCastKagg对象本身,并将FigureCastKagg画布嵌入到第二个可滚动画布中,但问题似乎是FigureCastKagg小部件的可绘制区域在图形大小改变时不会改变。下面是再现问题的最小代码。FigureCastKagg对象中是否有我所缺少的一些属性使其工作
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()
多亏了j_4321的回答,在深入研究了
FigureCanvasTk
对象的源代码之后,我想出了下面的解决方案,它完成了我所需要的一切看起来canvas对象所做的就是在每次调整canvas小部件的大小时使用
tkinter.Canvas.create_image
生成图形的新图像,保持图形的DPI不变,并设置图形的宽度和高度以保持其与canvas小部件相同的大小。由于我希望画布小部件根据图形大小调整大小,因此我从图形属性计算宽度和高度,然后将自定义事件对象传递给FigureCanvasTk.resize
,即画布小部件的<Configure>
事件的回调函数最后一个技巧是将画布的滚动区域设置为仅创建的最后一个画布项的大小。看起来没有从画布中删除图形的先前迭代(似乎是内存泄漏?),因此,如果尝试将scrollregion设置为
Canvas.bbox('all')
,它会将scrollregion设置为图形最大版本的大小,而不是图形的当前版本以下是完整的示例代码:
这里的主要问题是matplotlib图的大小是用
self._cwidg
调整的。由于假定地物始终与self._cwidg
具有相同的大小,matplotlib仅重新绘制在self._cwidg
中可见的地物部分,并且在地物大小更改时,后者不会调整大小解决方法是使用额外的画布
self._scroll_canvas
,并将self._cwidg
嵌入其中作为窗口。然后我用以下方式修改了_change_size()
:我直接调整
self._cwidg
的大小,然后调整图形的大小,确保它的每个部分都被重新绘制。然后我更新滚动区域。以下是完整的代码:相关问题 更多 >
编程相关推荐