在 Tkinter [.grid 方法] 中嵌入 MatPlotLib 图形,并自定义 MatPlotLib 的导航工具栏
Embedding a MatPlotLib Graph in Tkinter [.grid method], and Customizing MatPlotLib's Navigation Toolbar
我在将我的 MatPlotLib 图嵌入 Tkinter 时遇到了问题,在 Google 和 MatPlotLib 网站上进行了一些搜索后,我能得到的最好的方法是标准方法:
import tkinter
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
fig = Figure(figsize=(5, 4), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
现在,如果我尝试用 .grid 替换包装布局(并删除 .pack() 参数),我会遇到一堆错误,无论我尝试了多少次 Google 搜索,所有在 Tkinter 中嵌入 MatPlotLib 图的方法都只使用 pack 方法。有人可以帮我解决这个问题吗?我想嵌入图形,但使用网格方法,因为我的 GUI 应用程序的其余布局是 .grid 布局。
我在 Tkinter 中的导航工具栏遇到的另一个问题是导航工具栏显然可以自定义(至少根据 SentDex [5:18])。他似乎没有详细说明我如何做到这一点,这对我来说很困难,因为我对 MatPlotLib 的按钮不是很满意(它们看起来非常陈旧和过时)。
有人可以帮我解决这个问题吗?当我只放入图表时,它似乎工作得很好,但是当我尝试将图表放入导航工具栏时我也遇到了问题。对此的任何帮助将不胜感激。谢谢!
这是一个简单的 plot
和 navigation toolbar
inside tkinter window
仅使用 grid
几何管理器。
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
window = tk.Tk()
btn = tk.Label(window, text='A simple plot')
btn.grid(row=0, column=0, padx=20, pady=10)
x = ['Col A', 'Col B', 'Col C']
y = [50, 20, 80]
fig = plt.figure(figsize=(4, 5))
plt.bar(x=x, height=y)
# You can make your x axis labels vertical using the rotation
plt.xticks(x, rotation=90)
# specify the window as master
canvas = FigureCanvasTkAgg(fig, master=window)
canvas.draw()
canvas.get_tk_widget().grid(row=1, column=0, ipadx=40, ipady=20)
# navigation toolbar
toolbarFrame = tk.Frame(master=window)
toolbarFrame.grid(row=2,column=0)
toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)
window.mainloop()
输出GUI
我没有对导航工具栏进行自定义,因此我没有为该部分提供任何解决方案。但我肯定会调查它,如果我发现有用的东西,就会更新你。希望对您有所帮助。
我设法获得了一个简单的应用程序来控制 matplotlib 图形 window 调整大小。
我没有使用过导航栏功能,所以这可能是对这个框架的补充
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from google.cloud import bigquery
import os, json, sys
from time import time
import pandas as pd
class SliderGraph:
def __init__(self, master):
self.master = master
# with open(self.resource_path(config_file)) as fp:
# self.config = json.load(fp)
# os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = self.resource_path(creds_file)
# self.projectID = self.config['projectID']
# self.datasetID = self.config['datasetID']
# last_used_freq = self.config['last_used_frequency']
# last_used_delta = self.config['last_used_delta']
self.bounds = 1
self.frame = tk.Frame(master)
self.fig = Figure()
row = 0
self.ax = self.fig.add_subplot(111)
self.ax.set_xlabel("Run Numbers")
self.ax.set_ylabel("UDD")
self.ax.set_ylim([-self.bounds,self.bounds])
self.canvas = FigureCanvasTkAgg(self.fig, master=master) # , width=win_width, height=(win_height-50))
self.canvas.draw()
self.canvas.get_tk_widget().grid(row=row, columnspan=2, sticky='nsew')
row+=1
self.table_label = tk.Label(master, text="Enter BigQuery Table Name")
self.table_label.grid(row=row, column=0)
# row += 1
self.table_name = tk.Entry(master)
# self.table_name.insert(0,self.config['last_used_table'])
self.table_name.grid(row=row, column=1, sticky='ew')
row += 1
self.get_table_button = tk.Button(master, text="Get Table Data and Plot", command=self.plot_data)
self.get_table_button.grid(row=row, columnspan=2)
row += 1
self.frequency_slider = tk.Scale(master, from_=400, to=4500, orient=tk.HORIZONTAL, command=self.update_plot)
# self.frequency_slider.set(last_used_freq)
self.frequency_slider.grid(row=row,columnspan=2, sticky="nsew")
row += 1
self.frequency_entry = tk.Entry(master)
# self.frequency_entry.insert(0,last_used_freq)
self.frequency_entry.grid(row=row, columnspan=2)
row += 1
self.delta_slider = tk.Scale(master, from_=-500, to=500, orient=tk.HORIZONTAL, command=self.update_plot)
# self.delta_slider.set(last_used_delta)
self.delta_slider.grid(row=row, columnspan=2, sticky="ensw")
row += 1
self.delta_entry = tk.Entry(master)
# self.delta_entry.insert(0, last_used_delta)
self.delta_entry.grid(row=row, columnspan=2)
row += 1
self.get_table_button = tk.Button(master, text="Autoscale", command=self.autoscale)
self.get_table_button.grid(row=row,columnspan=2)
row += 1
tk.Grid.columnconfigure(master, 0, weight=1)
tk.Grid.columnconfigure(master, 1, weight=1)
tk.Grid.rowconfigure(master, 0, weight=5)
for x in range(1,row):
tk.Grid.rowconfigure(master, x, weight=0)
master.protocol('WM_DELETE_WINDOW', self.close)
self.df = None
self.frequency_list = []
self.series = None
self.elapsed = time()*1000
def plot_data(self):
self.ax.clear()
self.client = bigquery.Client(project=self.projectID)
self.tableID = f"`{self.datasetID}.{self.table_name.get()}`"
QUERY = (
f"SELECT * EXCEPT (testCount,elapsed_run_time_ms_,moleculeValue,onboardTemp1,onboardTemp2,temp,tempControl,\
logamp, txrx,timestamp) FROM {self.tableID} ORDER BY runCount ASC;"
)
# query_job = self.client.query(QUERY)
# rows = query_job.result()
self.df = pd.read_gbq(QUERY,self.projectID)
for col in self.df.columns:
if 'runCount' in col:
continue
self.frequency_list.append(int(col.replace('_','')))
self.frequency_slider.configure(from_=min(self.frequency_list),to=max(self.frequency_list))
self.delta_slider.configure(from_=-max(self.frequency_list),to=max(self.frequency_list))
freq = f'_{self.frequency_slider.get()}'
freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
self.series = self.df[freq] - self.df[freq2]
self.series.plot(ax=self.ax)
self.ax.set_ylim([-self.bounds,self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
pass
def update_plot(self, newslider):
try:
self.ax.clear()
freq = f'_{self.frequency_slider.get()}'
freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
self.series = self.df[freq] - self.df[freq2]
self.series.plot(ax=self.ax)
zero = self.series.mean()
self.ax.set_ylim([zero-self.bounds, zero+self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
# self.master.update_idletasks()
if ((time()*1000)-self.elapsed > 100):
self.elapsed = time()*1000
self.frequency_entry.delete(0,'end')
self.frequency_entry.insert(0,freq.replace('_',''))
self.delta_entry.delete(0,'end')
self.delta_entry.insert(0,self.delta_slider.get())
except:
pass
def play_runs(self):
pass
def autoscale(self):
self.ax.clear()
self.series.plot(ax=self.ax)
self.ax.relim()
self.ax.autoscale()
zero = self.series.mean()
self.bounds = self.series.max() - self.series.min()
self.ax.set_ylim([zero-self.bounds,zero+self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def close(self):
self.master.destroy()
if __name__=="__main__":
root = tk.Tk()
slider_fig = SliderGraph(root)
root.mainloop()
我在将我的 MatPlotLib 图嵌入 Tkinter 时遇到了问题,在 Google 和 MatPlotLib 网站上进行了一些搜索后,我能得到的最好的方法是标准方法:
import tkinter
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
fig = Figure(figsize=(5, 4), dpi=100)
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.draw()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
toolbar = NavigationToolbar2Tk(canvas, root) toolbar.update()
canvas.get_tk_widget().pack(side=tkinter.TOP, fill=tkinter.BOTH, expand=1)
现在,如果我尝试用 .grid 替换包装布局(并删除 .pack() 参数),我会遇到一堆错误,无论我尝试了多少次 Google 搜索,所有在 Tkinter 中嵌入 MatPlotLib 图的方法都只使用 pack 方法。有人可以帮我解决这个问题吗?我想嵌入图形,但使用网格方法,因为我的 GUI 应用程序的其余布局是 .grid 布局。
我在 Tkinter 中的导航工具栏遇到的另一个问题是导航工具栏显然可以自定义(至少根据 SentDex [5:18])。他似乎没有详细说明我如何做到这一点,这对我来说很困难,因为我对 MatPlotLib 的按钮不是很满意(它们看起来非常陈旧和过时)。
有人可以帮我解决这个问题吗?当我只放入图表时,它似乎工作得很好,但是当我尝试将图表放入导航工具栏时我也遇到了问题。对此的任何帮助将不胜感激。谢谢!
这是一个简单的 plot
和 navigation toolbar
inside tkinter window
仅使用 grid
几何管理器。
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
window = tk.Tk()
btn = tk.Label(window, text='A simple plot')
btn.grid(row=0, column=0, padx=20, pady=10)
x = ['Col A', 'Col B', 'Col C']
y = [50, 20, 80]
fig = plt.figure(figsize=(4, 5))
plt.bar(x=x, height=y)
# You can make your x axis labels vertical using the rotation
plt.xticks(x, rotation=90)
# specify the window as master
canvas = FigureCanvasTkAgg(fig, master=window)
canvas.draw()
canvas.get_tk_widget().grid(row=1, column=0, ipadx=40, ipady=20)
# navigation toolbar
toolbarFrame = tk.Frame(master=window)
toolbarFrame.grid(row=2,column=0)
toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)
window.mainloop()
输出GUI
我没有对导航工具栏进行自定义,因此我没有为该部分提供任何解决方案。但我肯定会调查它,如果我发现有用的东西,就会更新你。希望对您有所帮助。
我设法获得了一个简单的应用程序来控制 matplotlib 图形 window 调整大小。
我没有使用过导航栏功能,所以这可能是对这个框架的补充
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from google.cloud import bigquery
import os, json, sys
from time import time
import pandas as pd
class SliderGraph:
def __init__(self, master):
self.master = master
# with open(self.resource_path(config_file)) as fp:
# self.config = json.load(fp)
# os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = self.resource_path(creds_file)
# self.projectID = self.config['projectID']
# self.datasetID = self.config['datasetID']
# last_used_freq = self.config['last_used_frequency']
# last_used_delta = self.config['last_used_delta']
self.bounds = 1
self.frame = tk.Frame(master)
self.fig = Figure()
row = 0
self.ax = self.fig.add_subplot(111)
self.ax.set_xlabel("Run Numbers")
self.ax.set_ylabel("UDD")
self.ax.set_ylim([-self.bounds,self.bounds])
self.canvas = FigureCanvasTkAgg(self.fig, master=master) # , width=win_width, height=(win_height-50))
self.canvas.draw()
self.canvas.get_tk_widget().grid(row=row, columnspan=2, sticky='nsew')
row+=1
self.table_label = tk.Label(master, text="Enter BigQuery Table Name")
self.table_label.grid(row=row, column=0)
# row += 1
self.table_name = tk.Entry(master)
# self.table_name.insert(0,self.config['last_used_table'])
self.table_name.grid(row=row, column=1, sticky='ew')
row += 1
self.get_table_button = tk.Button(master, text="Get Table Data and Plot", command=self.plot_data)
self.get_table_button.grid(row=row, columnspan=2)
row += 1
self.frequency_slider = tk.Scale(master, from_=400, to=4500, orient=tk.HORIZONTAL, command=self.update_plot)
# self.frequency_slider.set(last_used_freq)
self.frequency_slider.grid(row=row,columnspan=2, sticky="nsew")
row += 1
self.frequency_entry = tk.Entry(master)
# self.frequency_entry.insert(0,last_used_freq)
self.frequency_entry.grid(row=row, columnspan=2)
row += 1
self.delta_slider = tk.Scale(master, from_=-500, to=500, orient=tk.HORIZONTAL, command=self.update_plot)
# self.delta_slider.set(last_used_delta)
self.delta_slider.grid(row=row, columnspan=2, sticky="ensw")
row += 1
self.delta_entry = tk.Entry(master)
# self.delta_entry.insert(0, last_used_delta)
self.delta_entry.grid(row=row, columnspan=2)
row += 1
self.get_table_button = tk.Button(master, text="Autoscale", command=self.autoscale)
self.get_table_button.grid(row=row,columnspan=2)
row += 1
tk.Grid.columnconfigure(master, 0, weight=1)
tk.Grid.columnconfigure(master, 1, weight=1)
tk.Grid.rowconfigure(master, 0, weight=5)
for x in range(1,row):
tk.Grid.rowconfigure(master, x, weight=0)
master.protocol('WM_DELETE_WINDOW', self.close)
self.df = None
self.frequency_list = []
self.series = None
self.elapsed = time()*1000
def plot_data(self):
self.ax.clear()
self.client = bigquery.Client(project=self.projectID)
self.tableID = f"`{self.datasetID}.{self.table_name.get()}`"
QUERY = (
f"SELECT * EXCEPT (testCount,elapsed_run_time_ms_,moleculeValue,onboardTemp1,onboardTemp2,temp,tempControl,\
logamp, txrx,timestamp) FROM {self.tableID} ORDER BY runCount ASC;"
)
# query_job = self.client.query(QUERY)
# rows = query_job.result()
self.df = pd.read_gbq(QUERY,self.projectID)
for col in self.df.columns:
if 'runCount' in col:
continue
self.frequency_list.append(int(col.replace('_','')))
self.frequency_slider.configure(from_=min(self.frequency_list),to=max(self.frequency_list))
self.delta_slider.configure(from_=-max(self.frequency_list),to=max(self.frequency_list))
freq = f'_{self.frequency_slider.get()}'
freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
self.series = self.df[freq] - self.df[freq2]
self.series.plot(ax=self.ax)
self.ax.set_ylim([-self.bounds,self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
pass
def update_plot(self, newslider):
try:
self.ax.clear()
freq = f'_{self.frequency_slider.get()}'
freq2 = f'_{self.frequency_slider.get() + self.delta_slider.get()}'
self.series = self.df[freq] - self.df[freq2]
self.series.plot(ax=self.ax)
zero = self.series.mean()
self.ax.set_ylim([zero-self.bounds, zero+self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
# self.master.update_idletasks()
if ((time()*1000)-self.elapsed > 100):
self.elapsed = time()*1000
self.frequency_entry.delete(0,'end')
self.frequency_entry.insert(0,freq.replace('_',''))
self.delta_entry.delete(0,'end')
self.delta_entry.insert(0,self.delta_slider.get())
except:
pass
def play_runs(self):
pass
def autoscale(self):
self.ax.clear()
self.series.plot(ax=self.ax)
self.ax.relim()
self.ax.autoscale()
zero = self.series.mean()
self.bounds = self.series.max() - self.series.min()
self.ax.set_ylim([zero-self.bounds,zero+self.bounds])
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def close(self):
self.master.destroy()
if __name__=="__main__":
root = tk.Tk()
slider_fig = SliderGraph(root)
root.mainloop()