在 Tkinter GUI 上嵌入 matplotlib 图
Embedding matplotlib graph on Tkinter GUI
晚上好...我正在学习如何在 Tkinter GUI 上嵌入 matplotlib 图,但没有成功,我附上了一张图片向您展示发生了什么,请帮忙。
我正在从 Arduino 串行端口(ECG 读数)获取数据,使用 matplotlib(嵌入在 Tkinter GUI 上)绘制它,但是当我 运行 我在 matplotlib 图下面的代码是在绘图发生的地方创建的。
请注意,我的目标是直接在 GUI 上的图表上绘制,不要担心已绘制的图表。
[![enter image description here][1]][1]import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import numpy as np
import serial as sr
import time
def start_plot():
data = np.array([])
while True:
a = s.readline()
a.decode()
b = float(a[0:4])
data = np.append(data, b);
plt.cla()
plt.plot(data)
plt.pause(0.01)
s.close()
main_window = Tk()
main_window.configure(background='light blue')
main_window.iconbitmap('lardmon_icon.ico')
main_window.title("ECG-LArdmon")
main_window.geometry('800x700')
main_window.resizable(width=False, height=False)
plotting_frame = LabelFrame(main_window, text='Real Time', bg='white', width=300, height=440, bd=5, relief=SUNKEN)
controls_frame = LabelFrame(main_window, text='Controls', background='light grey', height=150)
controls_frame.pack(fill='both', expand='1', side=TOP, padx=20, pady=10)
plotting_frame.pack(fill='both', expand='yes', side=BOTTOM, padx=20)
start_button = Button(controls_frame, text='Start Monitoring', width=16, height=2, borderwidth=3, command=start_plot)
start_button.pack(side=LEFT, padx=26)
exit_button = Button(controls_frame, text='Close', width=10, height=2, borderwidth=3, command=main_window.destroy)
exit_button.pack(side=RIGHT, padx=26)
s = sr.Serial('COM3', 9600)
fig = Figure()
ax = fig.add_subplot(111)
ax.set_title("Electrocadiogram")
ax.set_xlabel("Time(Sec)")
ax.set_ylabel("Voltage(mV)")
ax.set_xlim(0, 200)
ax.set_ylim(-0.5, 6)
ax.grid(b=True, which='major', color='#666666', linestyle='-')
ax.minorticks_on()
ax.grid(b=True, which='minor', color='#666666', linestyle='-', alpha=0.2)
canvas = FigureCanvasTkAgg(fig, master=plotting_frame)
canvas.get_tk_widget().place(x = 0, y = 0, width = 600, height = 420)
canvas.draw()
main_window.mainloop()
- 您已经创建了一个
Figure
对象和一个 ax
,因此始终在其上绘图并更新您的 canvas
。
- 使用
tkinter.after
方法递归调用您的函数,这样它就不会冻结您的 GUI。
以下是展示如何完成所需的最少更改:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import numpy as np
from tkinter import *
data = []
def start_plot():
data.append(np.random.uniform(0, 5))
ax.plot(data, color="blue")
canvas.draw_idle()
main_window.after(100, start_plot) # in milliseconds, 1000 for 1 second
# no change to the rest
....
请注意,我的目标是直接在 GUI 上的图表上绘制,不要担心已绘制的图表。
[![enter image description here][1]][1]import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import numpy as np
import serial as sr
import time
def start_plot():
data = np.array([])
while True:
a = s.readline()
a.decode()
b = float(a[0:4])
data = np.append(data, b);
plt.cla()
plt.plot(data)
plt.pause(0.01)
s.close()
main_window = Tk()
main_window.configure(background='light blue')
main_window.iconbitmap('lardmon_icon.ico')
main_window.title("ECG-LArdmon")
main_window.geometry('800x700')
main_window.resizable(width=False, height=False)
plotting_frame = LabelFrame(main_window, text='Real Time', bg='white', width=300, height=440, bd=5, relief=SUNKEN)
controls_frame = LabelFrame(main_window, text='Controls', background='light grey', height=150)
controls_frame.pack(fill='both', expand='1', side=TOP, padx=20, pady=10)
plotting_frame.pack(fill='both', expand='yes', side=BOTTOM, padx=20)
start_button = Button(controls_frame, text='Start Monitoring', width=16, height=2, borderwidth=3, command=start_plot)
start_button.pack(side=LEFT, padx=26)
exit_button = Button(controls_frame, text='Close', width=10, height=2, borderwidth=3, command=main_window.destroy)
exit_button.pack(side=RIGHT, padx=26)
s = sr.Serial('COM3', 9600)
fig = Figure()
ax = fig.add_subplot(111)
ax.set_title("Electrocadiogram")
ax.set_xlabel("Time(Sec)")
ax.set_ylabel("Voltage(mV)")
ax.set_xlim(0, 200)
ax.set_ylim(-0.5, 6)
ax.grid(b=True, which='major', color='#666666', linestyle='-')
ax.minorticks_on()
ax.grid(b=True, which='minor', color='#666666', linestyle='-', alpha=0.2)
canvas = FigureCanvasTkAgg(fig, master=plotting_frame)
canvas.get_tk_widget().place(x = 0, y = 0, width = 600, height = 420)
canvas.draw()
main_window.mainloop()
- 您已经创建了一个
Figure
对象和一个ax
,因此始终在其上绘图并更新您的canvas
。 - 使用
tkinter.after
方法递归调用您的函数,这样它就不会冻结您的 GUI。
以下是展示如何完成所需的最少更改:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import numpy as np
from tkinter import *
data = []
def start_plot():
data.append(np.random.uniform(0, 5))
ax.plot(data, color="blue")
canvas.draw_idle()
main_window.after(100, start_plot) # in milliseconds, 1000 for 1 second
# no change to the rest
....