python - 当我绘制超过 2 个值时,为什么 Timer 会破坏我的数据?
问题描述
我使用 Timer 同时进行绘图和存储。当我绘制 2 个值时,不会丢失串行端口的数据(每分钟 60 行,我的设备 = 1Hz)。但是当我尝试绘制超过 2 个值时,它会破坏数据(每分钟约 40 行)。
1.我应该尝试thread
还是queue
代替wx.Timer
?
2.为什么会wx.Timer
损坏我的数据?或者有什么问题?
3.我应该使用串口功能吗?里面wx.Timer
??
我在哪里做错了什么?我需要你的帮助。任何帮助,将不胜感激。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import wx
import wxmplot
import serial
import serial.tools.list_ports
import numpy as np
is_wxPhoenix = 'phoenix' in wx.PlatformInfo
if is_wxPhoenix:
PyDeadObjectError = RuntimeError
else:
from wx._core import PyDeadObjectError
class myframe ( wx.Frame ): #Panel ###(reading, saving, plotting as a real-time from serial port)
def __init__( self, parent ):
wx.Frame.__init__ ( self, parent )
self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )
bSizer1 = wx.BoxSizer( wx.VERTICAL )
self.plotframe = None
self.toggleBtn17 = wx.ToggleButton( self, wx.ID_ANY, u"GRAPH", wx.DefaultPosition, wx.DefaultSize, 0 )
bSizer1.Add( self.toggleBtn17, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
self.toggleBtn171 = wx.ToggleButton( self, wx.ID_ANY, u"Store", wx.DefaultPosition, wx.DefaultSize, 0 )
self.toggleBtn171.Hide()
bSizer1.Add( self.toggleBtn171, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
self.toggleBtn4 = wx.ToggleButton( self, wx.ID_ANY, u"Save", wx.DefaultPosition, wx.DefaultSize, 0 )
self.toggleBtn4.Hide()
bSizer1.Add( self.toggleBtn4, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
self.timer1 = wx.Timer()
self.timer1.SetOwner( self, 1 )
self.timer2 = wx.Timer()
self.timer2.SetOwner( self, 2 )
self.timer2.Start( 1000 ) ### running when app begins
self.timer3 = wx.Timer()
self.timer3.SetOwner( self, 3 )
self.timer3.Start( 15000 ) #999 ### running when app begins
self.Centre( wx.BOTH )
self.SetSizer( bSizer1 )
# Connect Events
self.toggleBtn17.Bind( wx.EVT_TOGGLEBUTTON, self.plot_aio )
self.Bind( wx.EVT_TIMER, self.timer1_plot, id=1 )
self.toggleBtn171.Bind( wx.EVT_TOGGLEBUTTON, self.store_f )
self.Bind( wx.EVT_TIMER, self.timer2_store, id=2 )
self.toggleBtn4.Bind( wx.EVT_TOGGLEBUTTON, self.save_f )
self.Bind( wx.EVT_TIMER, self.timer3_save, id=3 )
self.x1 = np.array([]) # coming data from serial port should list. in wxmplot, numpy array is the best choice for appending data
self.y1 = np.array([])
self.y2 = np.array([])
self.y3 = np.array([])
self.store = []
self.store_tempr = []
self.ser = serial.Serial('COM9', 9600)
def ShowPlotFrame(self, do_raise=True, clear=True):
"make sure plot frame is enabled, and visible"
if self.plotframe is None:
self.plotframe = wxmplot.MultiPlotFrame(rows=3, cols=3, panelsize=(350, 275))
self.has_plot = False
try:
self.plotframe.Show()
except PyDeadObjectError:
self.plotframe = wxmplot.MultiPlotFrame(rows=3, cols=3, panelsize=(350, 275))
self.plotframe.Show()
if do_raise:
self.plotframe.Raise()
if clear:
self.plotframe.panel.clear()
#self.plotframe.reset_config()
def plot_aio( self, event ): ### plot button(timer 1)
if self.timer1.IsRunning():
self.timer1.Stop()
print("timer1 stopped")
else:
print("tgl_timer1 starting...")
self.ShowPlotFrame()
self.timer1.Start( 500 )
def store_f( self, event ): ### store in the numpy array button but both Timer activated and Button hidden(timer 2)
event.Skip()
#=======================================================================
# if self.timer2.IsRunning():
# self.timer2.Stop()
# print("saving stopped")
# else:
# print("saving_timer2 is starting...")
# self.timer2.Start( 1000 )
#=======================================================================
def save_f( self, event ): ### del the storing data button for not using more memory (both Timer activated and Button hidden)
event.Skip()
#=======================================================================
# if self.timer3.IsRunning():
# self.timer3.Stop()
# print("timer 3 stopped")
# else:
# print("tgl_timer 3 starting...")
# self.timer3.Start( 10000 ) #501
#=======================================================================
def timer1_plot( self, event ): ### PLOT STORED DATA (not button but entegrated with plot_aio func which is button)
for line in self.store_tempr:
data=line.split(b",")
if data[0] == b"$GNGGA":
tim2=data[1]
timm=float(tim2)
tim=timm+30000
hour = tim//10000
minute = (tim//100)%100
second = tim%100
zaman = hour*3600 + minute*60 + second
self.x1 = np.append(self.x1, zaman)
latitude=data[2]
lat=float(latitude)
lat1=int(lat/100)
lat2=(lat%100)/60
lati=lat1+lat2
self.y2 = np.append(self.y2, lati)
longitude=data[4]
lon=float(longitude)
lon1=int(lon/100)
lon2=(lon%100)/60
longi=lon1+lon2
self.y3 = np.append(self.y3, longi)
altitude=data[9]
self.y1 = np.append(self.y1, float(altitude))
self.ShowPlotFrame()
self.plotframe.plot(self.x1, self.y1, panel=(0, 0), labelfontsize=6)
self.plotframe.plot(self.x1, self.y3, panel=(0, 1), color='red', labelfontsize=6)
self.plotframe.plot(self.y1, self.x1, panel=(1, 0), color='black', labelfontsize=5)
self.plotframe.plot(self.y2, self.y3, panel=(1, 1), fullbox=False)
self.plotframe.plot(self.x1, self.y1, panel=(0, 2), labelfontsize=6)
self.plotframe.plot(self.x1, self.y3, panel=(2, 1), color='red', labelfontsize=6)
self.plotframe.plot(self.y1, self.x1, panel=(2, 0), color='black', labelfontsize=5)
self.plotframe.plot(self.y2, self.y3, panel=(2, 2), fullbox=False)
del self.store_tempr[:]
def timer2_store( self, event ): ### STORE and WRITE TO .TXT FILE AND DELETE FROM THE LIST (not button)
print( "storing and saving")
for line in self.ser:
self.store.append(line)
self.store_tempr.append(line)
def timer3_save( self, event ): ### DELETE STORED DATA IN THE LIST (not button)
with open("C:\\Users\\Desktop\\4n.txt","a") as f:
for line in self.store:
f.writelines(str(line)+ "\n")
del self.store[:]
if __name__ == "__main__":
app = wx.App(False)
frame = myframe(None)
frame.Show(True)
app.MainLoop()
解决方案
我认为您不需要使用线程或队列来代替 wx.Timers。但是,我也认为您实际上只需要 1wx.Timer
来检查并从串行端口(或其他数据源)获取数据。我建议wx.Timer
事件的处理程序(如果您期望数据为 1Hz,可能以 ~2Hz 运行)应该执行以下操作:
检查新数据。如果没有新数据,立即返回,等待下一个
wx.Timer
事件。如果有新数据,请立即解析并根据该数据进行计算,并将其附加到该事件处理程序中的数据数组中。只需删除所有临时数据的存储和以后删除,并在数据事件处理程序结束时让您
self.x1
等self.y1
保持最新状态。代码中的所有这些del XXX
——特别是因为一个事件处理程序删除了在另一个地方创建的数据——看起来它们可能是一个问题。然后更新地块。如果您认为绘图会很慢,您可以使用第二个计时器事件来查看长度是否
self.x1
已更改并重新制作绘图。但是,我相信您不需要使用第二个计时器,只需更新数据事件处理程序中的图即可。
有关如何完成此操作的示例,请参阅https://github.com/newville/wxmplot/blob/master/examples/stripchart.py
它仅使用一个wx.Timer
获取新数据并更新绘图的方法。请注意,它在更新现有绘图时使用比为每个新数据集wxmplot.PlotPanel.update_line()
重做要快得多。wxmplot.PlotPanel.plot()
next_data()
与从串行端口读取数据所需的操作相比,该示例中的函数更简单且更具确定性。但是你已经在做那部分了,你正在做的事情看起来并不太难或太慢。
推荐阅读
- ada - 如何在“-x ada”错误中停止无效值“ada”?
- kubernetes - Kubernetes API 为默认令牌返回 401
- javascript - 奇怪的方式 ES6 类方法,箭头函数,这有效
- javascript - Re-Render component React
- c++ - Gtk::StatusIcon 系统托盘对齐问题
- javascript - 用于对特定建筑物进行颜色编码的 Mapbox
- c# - Razor Pages - 一对多关系
- python - C 程序到 Ctypes Python
- reactjs - 如何使用 Hooks 更新数组状态 onClick()
- git - 有没有办法找到所有引用这个 repo 作为子模块的 repos?