Python matplotlib绘图更改tkinter窗口中的大小
在本例中,可以输入点坐标,然后将其保存在树视图中并打印。很简单。但我发现我可以初始化我的绘图,使其按照我想要的格式进行格式化,但一旦我添加第一个点,绘图似乎会增长,并占用更多的tkinter窗口。我不知道为什么会发生这种情况,也不知道如何控制它,使其保持原来的大小。谢谢Python matplotlib绘图更改tkinter窗口中的大小,python,matplotlib,tkinter-canvas,Python,Matplotlib,Tkinter Canvas,在本例中,可以输入点坐标,然后将其保存在树视图中并打印。很简单。但我发现我可以初始化我的绘图,使其按照我想要的格式进行格式化,但一旦我添加第一个点,绘图似乎会增长,并占用更多的tkinter窗口。我不知道为什么会发生这种情况,也不知道如何控制它,使其保持原来的大小。谢谢 import tkinter as tk from tkinter import ttk import numpy as np from matplotlib.backends.backend_tkagg import Fig
import tkinter as tk
from tkinter import ttk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
from matplotlib.figure import Figure
matplotlib.use("TkAgg")
class MainGUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title('Title')
self.geometry('750x500')
self.nb = ttk.Notebook(self)
self.nb.grid(row=0, column=0, columnspan=5, rowspan=4, sticky='NESW')
self.tab2 = ttk.Frame(self.nb)
self.nb.add(self.tab2, text='Tab2')
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
tab2_r = 8
tab2_c = 4
for i in range(tab2_r):
self.tab2.rowconfigure(i, weight=1)
for i in range(tab2_c):
self.tab2.columnconfigure(i, weight=1)
self.makeTable()
self.makePlot()
self.makeWidgets()
def makeWidgets(self):
self.Labels = []
self.Entries = []
self.labText = [('X Location:'), ('Y Location:')]
self.xGrid = 1
self.yGrid = int(np.ceil(len(self.labText) / self.xGrid))
i = 0
for j in range(0, self.xGrid + 1, 2):
for k in range(self.yGrid):
if(i == len(self.labText)):
break
else:
self.label = tk.Label(self.tab2, text=self.labText[i])
self.label.grid(column=j, row=k + 8, sticky='SW')
self.Labels.append(self.label)
self.entry = tk.Entry(self.tab2)
self.entry.insert(0, '0.0000')
self.entry.grid(column=j + 1, row=k + 8, sticky='NS')
self.Entries.append(self.entry)
i += 1
self.addBtn = tk.Button(self.tab2, text='Add Entry', command=self.addEntry)
self.addBtn.grid(column=self.xGrid + 1, row=self.yGrid + 9, sticky='NSEW')
def makeTable(self):
tab_header = ['Pattern #', 'Description']
self.tree = ttk.Treeview(self.tab2, columns=tab_header, height=5, show="headings")
vsb = ttk.Scrollbar(self.tab2, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=vsb.set)
self.tree.grid(column=0, row=0, columnspan=2, rowspan=5, sticky='NSEW')
vsb.grid(column=1, row=0, rowspan=5, sticky='ENS')
self.tree.heading(tab_header[0], text=tab_header[0].title())
self.tree.column(tab_header[0], width=30, anchor='center')
self.tree.heading(tab_header[1], text=tab_header[1].title())
self.tree.column(tab_header[1], width=170, anchor='center')
self.tree.insert('', 'end', values=("", "(new)"))
self.counter = 1
def addEntry(self):
check = (len(self.tree.get_children()) == 1)
self.description = "Location: " + self.Entries[0].get() + ", " + self.Entries[1].get()
self.tree.insert('', 'end', values=(self.counter, self.description))
newEntry = [float(self.Entries[0].get()), float(self.Entries[1].get())]
if(check == True):
self.points = newEntry
else:
self.points = np.vstack((self.points, newEntry))
self.counter += 1
self.plotstuff()
def makePlot(self):
self.fig = Figure(figsize=(1, 1), dpi=100)
self.ptrnFig = self.fig.add_subplot(111)
self.ptrnFig.plot([1], [1])
self.ptrnFig.axis([-1, 1, -1, 1])
self.ptrnFig.spines['left'].set_position('zero')
self.ptrnFig.spines['bottom'].set_position('zero')
self.ptrnFig.grid(True)
self.canvas = FigureCanvasTkAgg(self.fig, self.tab2)
self.canvas.draw()
self.canvas.get_tk_widget().grid(column=2, row=0, columnspan=2, rowspan=5, sticky='NSEW')
def plotstuff(self):
self.ptrnFig.cla()
if(np.ndim(self.points) == 1):
x = self.points[0]
y = self.points[1]
else:
x = self.points[:, 0]
y = self.points[:, 1]
self.ptrnFig.grid(True)
self.ptrnFig.axis('equal')
self.ptrnFig.scatter(x, y, c="b", marker="o")
self.canvas = FigureCanvasTkAgg(self.fig, self.tab2)
self.canvas.draw()
self.canvas.get_tk_widget().grid(column=2, row=0, columnspan=2, rowspan=5, sticky='NSEW')
def main():
MainGUI().mainloop()
if __name__ == '__main__':
main()
我真的说不出为什么地块面积会增加。不过,我能告诉你的是,你使用了错误的策略。每次添加一个新点时,您都在创建一个新的图形和新的画布,这会浪费大量精力,并给您带来问题。相反,您应该创建一个带有空艺术家的空绘图,并在每次单击按钮时向该艺术家添加新点
考虑一下我修改的代码主要是makePlot和plotstuff:
谢谢@Diziet,这就像我所期望的那样。我在最初的问题中遗漏了一件事,那就是删除或更新表中的点的功能。您可以想象,我发布的示例与我的实际应用程序相比有相当大的减少。在实际应用程序中,我有一个按钮,允许您删除或更新表中的条目。如何删除或更新正在绘制的点列表?我保留每个点或点集,因为实际应用程序允许字典中的点集(如果有帮助的话)。另外,请您解释一下您的解决方案实际上在做什么。据我所知,您首先绘制的是空阵列的散点图。然后,每次添加数据时,都会附加/更新正在绘制的数组,但我不清楚self.canvas.draw\u idle调用是如何工作的,它似乎会在每次添加数据时更新绘制?。出于某种原因,当我在实际用例中运行此程序时,它对第一个输入运行良好,但当我添加下一个输入时,它只绘制最后一组输入点。知道为什么会这样吗?在addEntry中,您将向Nx2数组self.points添加一个新的[x,y]坐标,函数plotstuff只需更新初始调用scatter创建的PathCollection对象中存储的坐标。这与人们创建动画散点图时使用的策略相同。你可以在这里搜索,你会得到很多例子。我猜不出为什么代码与第一个输入一起工作,而不是后续的输入。我会确保self.points的形状保持为Nx2,并且它包含预期的坐标
import tkinter as tk
from tkinter import ttk
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib
from matplotlib.figure import Figure
matplotlib.use("TkAgg")
class MainGUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title('Title')
self.geometry('750x500')
self.nb = ttk.Notebook(self)
self.nb.grid(row=0, column=0, columnspan=5, rowspan=4, sticky='NESW')
self.tab2 = ttk.Frame(self.nb)
self.nb.add(self.tab2, text='Tab2')
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
tab2_r = 8
tab2_c = 4
for i in range(tab2_r):
self.tab2.rowconfigure(i, weight=1)
for i in range(tab2_c):
self.tab2.columnconfigure(i, weight=1)
self.makeTable()
self.makePlot()
self.makeWidgets()
def makeWidgets(self):
self.Labels = []
self.Entries = []
self.labText = [('X Location:'), ('Y Location:')]
self.xGrid = 1
self.yGrid = int(np.ceil(len(self.labText) / self.xGrid))
i = 0
for j in range(0, self.xGrid + 1, 2):
for k in range(self.yGrid):
if(i == len(self.labText)):
break
else:
self.label = tk.Label(self.tab2, text=self.labText[i])
self.label.grid(column=j, row=k + 8, sticky='SW')
self.Labels.append(self.label)
self.entry = tk.Entry(self.tab2)
self.entry.insert(0, '0.0000')
self.entry.grid(column=j + 1, row=k + 8, sticky='NS')
self.Entries.append(self.entry)
i += 1
self.addBtn = tk.Button(self.tab2, text='Add Entry', command=self.addEntry)
self.addBtn.grid(column=self.xGrid + 1, row=self.yGrid + 9, sticky='NSEW')
def makeTable(self):
tab_header = ['Pattern #', 'Description']
self.tree = ttk.Treeview(self.tab2, columns=tab_header, height=5, show="headings")
vsb = ttk.Scrollbar(self.tab2, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=vsb.set)
self.tree.grid(column=0, row=0, columnspan=2, rowspan=5, sticky='NSEW')
vsb.grid(column=1, row=0, rowspan=5, sticky='ENS')
self.tree.heading(tab_header[0], text=tab_header[0].title())
self.tree.column(tab_header[0], width=30, anchor='center')
self.tree.heading(tab_header[1], text=tab_header[1].title())
self.tree.column(tab_header[1], width=170, anchor='center')
self.tree.insert('', 'end', values=("", "(new)"))
self.counter = 1
def addEntry(self):
check = (len(self.tree.get_children()) == 1)
self.description = "Location: " + self.Entries[0].get() + ", " + self.Entries[1].get()
self.tree.insert('', 'end', values=(self.counter, self.description))
newEntry = [float(self.Entries[0].get()), float(self.Entries[1].get())]
if(check == True):
self.points = np.array(newEntry, ndmin=2)
else:
self.points = np.vstack((self.points, newEntry))
self.counter += 1
self.plotstuff()
def makePlot(self):
self.fig = Figure(figsize=(1, 1), dpi=100)
self.ptrnFig = self.fig.add_subplot(111)
self.ptrnFig.axis([-1, 1, -1, 1])
self.ptrnFig.spines['left'].set_position('zero')
self.ptrnFig.spines['bottom'].set_position('zero')
self.ptrnFig.grid(True)
self.canvas = FigureCanvasTkAgg(self.fig, self.tab2)
self.canvas.draw()
self.canvas.get_tk_widget().grid(column=2, row=0, columnspan=2, rowspan=5, sticky='NSEW')
self.scat = self.ptrnFig.scatter([], [], c="b", marker="o")
def plotstuff(self):
self.scat.set_offsets(self.points)
# adjust the limits of the axes
xmin = min(self.points[:, 0])
xmax = max(self.points[:, 0])
ymin = min(self.points[:, 1])
ymax = max(self.points[:, 1])
self.ptrnFig.set_xlim(xmin - 0.1 * (xmax - xmin), xmax + 0.1 * (xmax - xmin))
self.ptrnFig.set_ylim(ymin - 0.1 * (ymax - ymin), ymax + 0.1 * (ymax - ymin))
self.canvas.draw_idle()
def main():
MainGUI().mainloop()
if __name__ == '__main__':
main()