You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter集成Matplotlib子图坐标轴更新但折线不显示问题

Tkinter嵌入Matplotlib动态绘图折线不显示问题修复

核心错误点

  • 每次刷新绘图时重复新建FigureCanvasTkAgg画布实例,绘图操作绑定在旧画布的子图对象上,新创建的画布没有同步最新绘制的折线内容,导致折线无法渲染。
  • 未保存历史采集的x、y数据序列,每次调用plot仅传入单个数值点,Matplotlib无法基于孤立单点生成连续折线,同时坐标轴自动缩放逻辑也无法正常适配数据范围。
  • 在Tkinter主事件循环中错误调用plt.show(),该方法仅适用于Matplotlib原生弹出窗口,嵌入Tkinter的画布调用该方法会阻塞事件循环,干扰正常渲染流程。
  • 重复对同位置的画布控件调用grid布局,会造成控件堆叠、内存泄漏,程序运行时间越长卡顿越明显。

修复步骤

  • 初始化阶段创建的8个画布实例全程复用,不要在刷新函数里重复新建。
  • 为每个子图维护独立的x、y数据列表,每次采集到新数据就追加到对应列表中,再将完整序列传入plot方法。
  • 每次绘制新数据后直接调用对应画布的draw_idle()方法触发刷新,不需要调用plt.show()。
  • 可根据数据长度动态调整x轴显示范围,实现滚动绘图效果,避免大量数据挤在同一画布上。

修正后完整可运行代码

from tkinter import *
from tkinter import ttk 
import time 
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import random

root = Tk()
root.title("ktu")
root.state('zoomed')
root.configure(bg="#0059aa")
plt.style.use('ggplot')

# 数据存储区
packageNum = 0
datas = []
# 为每个图初始化x、y数据存储列表
plot_datas = {
    "plot1": {"xs": [], "ys": []},
    "plot2": {"xs": [], "ys": []},
    "plot3": {"xs": [], "ys": []},
    "plot4": {"xs": [], "ys": []},
    "plot5": {"xs": [], "ys": []},
    "plot6": {"xs": [], "ys": []},
    "plot7": {"xs": [], "ys": []},
    "plot8": {"xs": [], "ys": []},
}

def randomData():
    global packageNum
    randData = []
    randData.append(356356)
    packageNum += 1
    randData.append(packageNum)
    randData.append(time.strftime("%H:%M:%S, %d/%m/%Y"))
    randData.append(random.randint(0,10000)) # yindex 3
    randData.append(random.randint(0,10000)) # yindex 4
    randData.append(random.randint(0,700))   # yindex 5
    randData.append(random.randint(0,700))   # yindex 6
    randData.append(randData[6]-randData[5]) 
    randData.append(random.randint(10,20))   # yindex 8
    randData.append(random.randint(20,25))   # yindex 9
    randData.append(random.randint(39,50))   # yindex 10
    randData.append(random.randint(1,6))     # yindex 11
    randData.extend([0.0,0.0,random.randint(0,700),0.0,0.0,random.randint(0,700)])
    randData.extend(["durum",random.randint(0,100),random.randint(0,100),random.randint(0,100),random.randint(0,50),"hayır"," "])
    return randData 

# 串口面板区
seriPortOuter = LabelFrame(root,text="SERIAL PORT",border=3, width=170,height=210)
seriPortOuter.place(x=5,y=305)

text1= Label(seriPortOuter,text="get connection", width=14, font=("Helvetica",10), fg="white", bg="red")
text1.place(x=3,y=5)

text2= Label(seriPortOuter,text="COM Port", width=8, font=("Helvetica",10))
text2.place(x=1,y=30)
portList = [f"Option{i}" for i in range(1,7)]
portCombo = ttk.Combobox(seriPortOuter, values = portList, width=8)
portCombo.set("")
portCombo.place(x=68,y=30)

text3= Label(seriPortOuter,text="Speed", width=4, font=("Helvetica",10))
text3.place(x=1,y=55)
speedList = [f"Option{i}" for i in range(1,7)]
speedCombo = ttk.Combobox(seriPortOuter, values = speedList, width=8)
speedCombo.set("") 
speedCombo.place(x=68,y=55)

x = 0
def StartListing():
    global x, datas
    root.after(2000,StartListing)
    datas = randomData()
    GraphIt(plot1, x, 3, plot1Canvas, plot_datas["plot1"])
    GraphIt(plot2, x, 4, plot2Canvas, plot_datas["plot2"]) 
    GraphIt(plot3, x, 5, plot3Canvas, plot_datas["plot3"])
    GraphIt(plot4, x, 6, plot4Canvas, plot_datas["plot4"])
    GraphIt(plot5, x, 10, plot5Canvas, plot_datas["plot5"])
    GraphIt(plot6, x, 9, plot6Canvas, plot_datas["plot6"])
    GraphIt(plot7, x, 11, plot7Canvas, plot_datas["plot7"])
    GraphIt(plot8, x, 8, plot8Canvas, plot_datas["plot8"])
    x += 1

StartListingButton = Button(seriPortOuter, text="Start Listing Datas", command=StartListing, width=19)
StartListingButton.place(x=10,y=125)

# 图表面板区
graph_canvas = Canvas(root, width=842,height=575, bg="#0059aa" )
graph_canvas.place(x=585,y=30)

# 初始化8个子图和对应画布
fig_plot1= Figure(figsize=(2.33,2.5), dpi=100)
plot1= fig_plot1.add_subplot(111)
plot1.set_title('Pressure1 (Pa)',fontsize=8)
plot1Canvas = FigureCanvasTkAgg(fig_plot1, master=graph_canvas)
plot1Canvas.get_tk_widget().grid(row=0,column=0,pady=5, padx=3)
plot1Canvas.draw()

fig_plot2= Figure(figsize=(2.33,2.5), dpi=100)
plot2= fig_plot2.add_subplot(111)
plot2.set_title('Pressure2 (Pa)',fontsize=8)
plot2Canvas = FigureCanvasTkAgg(fig_plot2, master=graph_canvas)
plot2Canvas.get_tk_widget().grid(row=1,column=0,pady=5, padx=3)
plot2Canvas.draw()

fig_plot3= Figure(figsize=(2.33,2.5), dpi=100)
plot3= fig_plot3.add_subplot(111)
plot3.set_title('altitude1 (m)',fontsize=8)
plot3Canvas = FigureCanvasTkAgg(fig_plot3, master=graph_canvas)
plot3Canvas.get_tk_widget().grid(row=0,column=1,pady=5, padx=2)
plot3Canvas.draw()

fig_plot4= Figure(figsize=(2.33,2.5), dpi=100)
plot4= fig_plot4.add_subplot(111)
plot4.set_title('altitude2 (m)',fontsize=8)
plot4Canvas = FigureCanvasTkAgg(fig_plot4, master=graph_canvas)
plot4Canvas.get_tk_widget().grid(row=1,column=1,pady=5, padx=2)
plot4Canvas.draw()

fig_plot5= Figure(figsize=(2.33,2.5), dpi=100)
plot5= fig_plot5.add_subplot(111)
plot5.set_title('temperature (°C)',fontsize=8)
plot5Canvas = FigureCanvasTkAgg(fig_plot5, master=graph_canvas)
plot5Canvas.get_tk_widget().grid(row=0,column=2,pady=5, padx=2)
plot5Canvas.draw()

fig_plot6= Figure(figsize=(2.33,2.5), dpi=100)
plot6= fig_plot6.add_subplot(111)
plot6.set_title('temperature (°C)',fontsize=8)
plot6Canvas = FigureCanvasTkAgg(fig_plot6, master=graph_canvas)
plot6Canvas.get_tk_widget().grid(row=1,column=2,pady=5, padx=2)
plot6Canvas.draw()

fig_plot7= Figure(figsize=(2.33,2.5), dpi=100)
plot7= fig_plot7.add_subplot(111)
plot7.set_title('voltage (V)',fontsize=8)
plot7Canvas = FigureCanvasTkAgg(fig_plot7, master=graph_canvas)
plot7Canvas.get_tk_widget().grid(row=0,column=3,pady=5, padx=2)
plot7Canvas.draw()

fig_plot8= Figure(figsize=(2.33,2.5), dpi=100)
plot8= fig_plot8.add_subplot(111)
plot8.set_title('descent velocity (m/sn)',fontsize=8)
plot8Canvas = FigureCanvasTkAgg(fig_plot8, master=graph_canvas)
plot8Canvas.get_tk_widget().grid(row=1,column=3,pady=5, padx=2)
plot8Canvas.draw()

def GraphIt(myplot, xindex, yindex, canvas, data_store):
    # 追加新数据到存储列表
    data_store["xs"].append(xindex)
    data_store["ys"].append(datas[yindex])
    # 清空上次绘制内容,重绘全量数据
    myplot.clear()
    myplot.plot(data_store["xs"], data_store["ys"])
    # 自动适配坐标轴范围,保留最近20个点做滚动显示
    if len(data_store["xs"]) > 20:
        myplot.set_xlim(left=data_store["xs"][-20], right=data_store["xs"][-1])
    # 复用已有画布刷新
    canvas.draw_idle()

root.mainloop()

内容的提问来源于stack exchange,提问作者ayse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:33:13