wxPython - 绘图数据
我在使用wxPython绘制数据时遇到了一些问题。下面的代码可以运行,但并不是完全正确:目前我绘制的是一些随机数字,这些数字是输入框的倍数,每100毫秒更新一次。
我的问题是,所有的数字历史记录都会显示出来,而我其实想要的是一个(比如说)25个样本的动态窗口。我最开始尝试在每次收集100个样本时重绘图表,像这样:if( length(data)%100 ): drawGraph
,但这样看起来也不太对。
欢迎大家提出想法和建议。
我的代码:
print( "\n- Please Wait -- Importing Matplotlib and Related Modules...\n" )
import random
import matplotlib
import numpy
import wx
import u3
import numpy as np
matplotlib.use('WXAgg')
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure
class TemperaturePanel( wx.Panel ) :
def __init__( self, parent, position ) :
wx.Panel.__init__( self, parent, pos=position, size=(800,320) )
# initialize matplotlib
self.figure = matplotlib.figure.Figure( None, facecolor="white" )
self.canvas = matplotlib.backends.backend_wxagg.FigureCanvasWxAgg( self, -1, self.figure )
self.axes = self.figure.add_subplot(111)
self.axes.grid(True, color="gray")
self.axes.set_xbound( (0,5) )
self.axes.set_ybound( (3,80) )
self.axes.set_xlabel( "Minutes" )
self.axes.set_ylabel( "Temperature ($^\circ$C)" )
self.axes = self.figure.add_subplot(111)
self.axes.grid(True, color="gray")
self._SetSize()
self.Bind( wx.EVT_SIZE, self._SetSize )
self.TemperatureData = []
def updateTemperature(self, value):
self.TemperatureData.append( value )
length = len(self.TemperatureData)
x = np.arange( length )
y = np.array(self.TemperatureData)
yMin = round(min(y)) - 2
yMax = round(max(y)) + 2
self.axes.plot(x,y, "-k")
self.axes.set_ybound( (yMin,yMax) )
self.canvas = FigureCanvas(self, -1, self.figure)
#-----------------------------------------------------------------------------------
def _SetSize( self, event=None ):
pixels = self.GetSize()
self.SetSize( pixels )
self.canvas.SetSize( pixels )
dpi = self.figure.get_dpi()
self.figure.set_size_inches( float( pixels[0] ) / dpi,float( pixels[1] ) / dpi )
#------------------------------------------------------------------------------------
class MainWindow(wx.Frame):
def __init__(self, parent):
#wx.Frame.__init__(self, *args, **kwargs)
wx.Frame.__init__(self, parent, title="Graph Issue", size=(1000,600))
self.panel = wx.Panel(self)
self.spin = wx.SpinCtrl(self.panel)
self.button = wx.Button(self.panel, label="Update")
self.stop = wx.Button(self.panel, label="Stop")
self.sizer = wx.BoxSizer()
self.sizer.Add(self.spin)
self.sizer.Add(self.button)
self.sizer.Add(self.stop)
self.TemperatureGraph = TemperaturePanel( self, position=(20, 50) )
self.panel.SetSizerAndFit(self.sizer)
self.Show()
# Use EVT_CHAR_HOOK on Frame insted of wx.EVT_KEY_UP on SpinCtrl
# to disable "on Enter go to next widget" functionality
self.Bind(wx.EVT_CHAR_HOOK, self.OnKey)
self.button.Bind(wx.EVT_BUTTON, self.OnUpdate)
self.stop.Bind(wx.EVT_BUTTON, self.OnStop)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.Bind(wx.EVT_TIMER, self.updateTemperature, self.timer)
self.timer.Start(100)
self.value = 0
def OnKey(self, e):
if e.GetKeyCode() == wx.WXK_RETURN: # Is the key ENTER?
self.value = self.spin.GetValue() # Read SpinCtrl and set internal value
else: # Else let the event out of the handler
e.Skip()
def OnUpdate(self, e):
self.value = self.spin.GetValue() # Read SpinCtrl and set internal value
def OnTimer(self, e):
# Show internal value
print(self.value)
def updateTemperature(self, e):
Temperature = self.value*random.uniform(-1,1) # obtain currnt temperature
self.TemperatureGraph.updateTemperature(Temperature) # add temperature to graph
def OnStop(self, e):
self.timer.Stop()
self.Destroy()
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
1 个回答
1
如果我理解得没错,你的问题是想在图表中只显示最近的25个温度值,而不是所有的历史值。如果是这样的话,在updateTemperature
这个小程序里,只需要绘制最后的25个值就可以了:
if length < 25:
x = np.arange(length)
y = np.array(self.TemperatureData)
else:
x = np.arange(length-25, length)
y = np.array(self.TemperatureData)[-25:]
为了让图表看起来更好,x轴的设置可以和y轴一样调整:
xMin = 0 if length < 25 else length-25
xMax = 25 if length < 25 else length
self.axes.set_xbound( (xMin,xMax) )
如果你觉得图表看起来还不错,但问题是内存泄漏导致图表在大约200次更新后卡住了,那是因为每次更新温度时都会创建一个新的FigureCanvas
。其实,你可以重复使用已经存在的FigureCanvas
,只需要把updateTemperature
最后一行改成:
self.canvas.draw()