在 tkinter 画布中嵌入来自 Arduino 的 Matplotlib 实时绘图数据 [英] Embedding Matplotlib live plot data from Arduino in tkinter canvas
问题描述
我只用了几周 Python.我用 Matplotlib 绘制来自 Arduino 的数据没有问题.但是,该图显示为弹出窗口,我希望该图仅显示在我使用 tkinter 制作的 GUI 根窗口的画布中.我尝试了多种组合,但无法正常工作.如果我只是将绘图值添加到代码中,让我们说:
I've only been using Python for a couple of weeks. I have no problems plotting the data coming in from the Arduino with Matplotlib. However the plot shows up as a pop-window and I would like that plot to only show up in a canvas in the root window of the GUI I'm making with tkinter. I've tried multiple combinations of things and I can't get it to work. If I just add the plot values to the code, let's say:
a.plot([1, 2, 3, 4, 5], [2, 3, 4, 5, 6, 7])
它工作正常,所以我的主要问题是从 Arduino 获取数据时的 while 循环.我也尝试了 drawow 选项来更新绘图,但我得到了完全相同的结果.无论我做什么,我似乎都无法让情节停止显示为单独的窗口.
it works fine, so my main problem then is with the while loop when getting data from the Arduino. I've also tried the drawnow option to update the plot but I get the same exact result. Whatever I do I can't seem to get the plot from to stop showing up as a separate window.
后面带有主 GUI 窗口的绘图窗口:
Plot window with main GUI window in the back:
这是我正在使用的示例代码:
Here's the sample code that I'm using:
import serial
from tkinter import *
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
root.geometry('1200x700+200+100')
root.title('This is my root window')
root.state('zoomed')
root.config(background='#fafafa')
yar = []
plt.ion()
style.use('ggplot')
fig = plt.figure(figsize=(14, 4.5), dpi=100)
ax1 = fig.add_subplot(1, 1, 1)
ser = serial.Serial('com3', 9600)
def animate(i):
while True:
ser.reset_input_buffer()
data = ser.readline().decode("utf-8")
data_array = data.split(',')
yvalue = float(data_array[1])
yar.append(yvalue)
print(yvalue)
plt.ylim(0, 100)
ax1.plot(yar, 'r', marker='o')
plt.pause(0.0001)
plotcanvas = FigureCanvasTkAgg(fig, root, animate)
plotcanvas.get_tk_widget().grid(column=1, row=1)
ani = animation.FuncAnimation(fig, animate, interval=1000, blit=True)
plotcanvas.show()
root.mainloop()
推荐答案
tk 的主循环会处理动画,因此你不应该使用 plt.ion() 或 plt.pause().
The main loop of tk will take care of the animation, you therefore shouldn't use plt.ion() or plt.pause().
动画函数将每隔 interval
秒调用一次.您不能在此函数中使用 while True
循环.
The animating function will be called every interval
seconds. You cannot use a while True
loop inside this function.
没有任何理由为 FigureCanvasTkAgg
提供动画功能.
There is no reason whatsoever to supply the animating function to the FigureCanvasTkAgg
.
除非您知道自己在做什么,否则不要使用 blit=True
.一秒钟的间隔,这无论如何是没有必要的.
Don't use blit=True
unless you know what you're doing. With an interval of one second this is anyways not necessary.
更新线而不是在每个迭代步骤中重新绘制它.
Update the line instead of replotting it in every iteration step.
#import serial
from Tkinter import *
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = Tk()
root.geometry('1200x700+200+100')
root.title('This is my root window')
root.state('zoomed')
root.config(background='#fafafa')
xar = []
yar = []
style.use('ggplot')
fig = plt.figure(figsize=(14, 4.5), dpi=100)
ax1 = fig.add_subplot(1, 1, 1)
ax1.set_ylim(0, 100)
line, = ax1.plot(xar, yar, 'r', marker='o')
#ser = serial.Serial('com3', 9600)
def animate(i):
#ser.reset_input_buffer()
#data = ser.readline().decode("utf-8")
#data_array = data.split(',')
#yvalue = float(data_array[1])
yar.append(99-i)
xar.append(i)
line.set_data(xar, yar)
ax1.set_xlim(0, i+1)
plotcanvas = FigureCanvasTkAgg(fig, root)
plotcanvas.get_tk_widget().grid(column=1, row=1)
ani = animation.FuncAnimation(fig, animate, interval=1000, blit=False)
root.mainloop()
这篇关于在 tkinter 画布中嵌入来自 Arduino 的 Matplotlib 实时绘图数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!