在 wxPython 中嵌入 matplotlib FuncAnimation:不需要的图形弹出窗口
Embedding matplotlib FuncAnimation in wxPython: Unwanted figure pop-up
我已尝试修改以下示例以用于实时绘图。
Embedding a matplotlib figure inside a WxPython panel
我正在尝试读取来自 Arduino 的串行数据和 plot/update 收集的数据。问题是图形出现在 wx App 之前,我需要关闭图形才能看到 wx App。
我认为问题与以下几行有关,但我不知道为什么。
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 1000), ylim=(0, 5000))
脚本如下
import wx
from matplotlib.figure import Figure as Fig
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from collections import deque
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mlp
import numpy as np
# Class that inherits wx.Panel. The purpose is to embed it into
# a wxPython App. That part can be seen in main()
class Serial_Plot(wx.Panel):
def __init__(self, parent, strPort, id=-1, dpi=None, **kwargs):
super().__init__(parent, id=id, **kwargs)
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 1000), ylim=(0, 5000))
self.plot_data, = self.ax.plot([], [])
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, 1, wx.EXPAND)
sizer.Add(self.toolbar, 0, wx.RIGHT | wx.EXPAND)
self.SetSizer(sizer)
# Serial communication
self.ser = serial.Serial(strPort, 115200)
# Serial data initialized as deque. The serial readings from arduino
# are set to be one value per line.
self.vals = deque()
# matplotlib function animation
anim = animation.FuncAnimation(self.figure, self.update,
interval=20)
plt.show()
self.close
def update(self, i):
try:
# read serial line
data = float(self.ser.readline().decode('utf-8'))
self.vals.append(data)
# update plot data
self.plot_data.set_data(range(len(self.vals)), self.vals)
except:
pass
return self.plot_data
def close(self):
# close serial
self.ser.flush()
self.ser.close()
def main():
app = wx.App(False)
frame = wx.Frame(None, -1, "WX APP!")
demo_plot = Serial_Plot(frame,'COM3')
frame.Show()
app.MainLoop()
if __name__ == "__main__":
main()
这是GUI前弹出的图
关闭后wx app可见
我试图摆脱弹出的图形,只看到嵌入在 wx 应用程序中的图形。如果有任何帮助,我将不胜感激。
我认为您可能通过使用 animation.FuncAnimation
抓住了错误的一端,因为我认为这是一个 matplotlib 函数,预计将由 matplotlib 的主循环控制,但您是使用它自己的wxpython。 (在这一点上,我保留犯错的权利:))
下面是您的代码,经过修改以使用 random
来避免串行端口并包含 wx.Timer
来执行更新。
import wx
from matplotlib.figure import Figure as Fig
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from collections import deque
#import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mlp
import numpy as np
import random
# Class that inherits wx.Panel. The purpose is to embed it into
# a wxPython App. That part can be seen in main()
class Serial_Plot(wx.Panel):
def __init__(self, parent, strPort, id=-1, dpi=None, **kwargs):
super().__init__(parent, id=id, **kwargs)
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 10), ylim=(0, 50))
self.plot_data, = self.ax.plot([], [])
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()
#
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update, self.timer)
#
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, 1, wx.EXPAND)
sizer.Add(self.toolbar, 0, wx.RIGHT | wx.EXPAND)
self.SetSizer(sizer)
# Serial communication
# self.ser = serial.Serial(strPort, 115200)
# Serial data initialized as deque. The serial readings from arduino
# are set to be one value per line.
self.vals = deque()
# matplotlib function animation
#anim = animation.FuncAnimation(self.figure, self.update,
# interval=2)
#plt.show()
plt.ion() #Turn on interactive plot
#self.close
#
self.timer.Start(1000)
def update(self,event):
#try:
# read serial line
#data = float(self.ser.readline().decode('utf-8'))
data = float(random.randint(1, 50))
self.vals.append(data)
# update plot data
length = len(self.vals)
self.plot_data.set_data(range(length), self.vals)
#Update x axis to follow interactive plot
self.ax.set_xlim(0.0,float(length + 1))
#except:
# pass
#return self.plot_data
plt.plot()
def close(self):
# close serial
self.ser.flush()
self.ser.close()
def main():
app = wx.App(False)
frame = wx.Frame(None, -1, "WX APP!")
demo_plot = Serial_Plot(frame,'COM3')
frame.Show()
app.MainLoop()
if __name__ == "__main__":
main()
N.B.
self.ax.set_xlim(0.0,float(length + 1))
可以调整为 self.ax.set_xlim(float(length - 10), float(length + 1))
之类的东西,它将遵循当前值,而不仅仅是不断地扩展 x 轴。
我已尝试修改以下示例以用于实时绘图。
Embedding a matplotlib figure inside a WxPython panel
我正在尝试读取来自 Arduino 的串行数据和 plot/update 收集的数据。问题是图形出现在 wx App 之前,我需要关闭图形才能看到 wx App。
我认为问题与以下几行有关,但我不知道为什么。
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 1000), ylim=(0, 5000))
脚本如下
import wx
from matplotlib.figure import Figure as Fig
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from collections import deque
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mlp
import numpy as np
# Class that inherits wx.Panel. The purpose is to embed it into
# a wxPython App. That part can be seen in main()
class Serial_Plot(wx.Panel):
def __init__(self, parent, strPort, id=-1, dpi=None, **kwargs):
super().__init__(parent, id=id, **kwargs)
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 1000), ylim=(0, 5000))
self.plot_data, = self.ax.plot([], [])
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, 1, wx.EXPAND)
sizer.Add(self.toolbar, 0, wx.RIGHT | wx.EXPAND)
self.SetSizer(sizer)
# Serial communication
self.ser = serial.Serial(strPort, 115200)
# Serial data initialized as deque. The serial readings from arduino
# are set to be one value per line.
self.vals = deque()
# matplotlib function animation
anim = animation.FuncAnimation(self.figure, self.update,
interval=20)
plt.show()
self.close
def update(self, i):
try:
# read serial line
data = float(self.ser.readline().decode('utf-8'))
self.vals.append(data)
# update plot data
self.plot_data.set_data(range(len(self.vals)), self.vals)
except:
pass
return self.plot_data
def close(self):
# close serial
self.ser.flush()
self.ser.close()
def main():
app = wx.App(False)
frame = wx.Frame(None, -1, "WX APP!")
demo_plot = Serial_Plot(frame,'COM3')
frame.Show()
app.MainLoop()
if __name__ == "__main__":
main()
这是GUI前弹出的图
关闭后wx app可见
我试图摆脱弹出的图形,只看到嵌入在 wx 应用程序中的图形。如果有任何帮助,我将不胜感激。
我认为您可能通过使用 animation.FuncAnimation
抓住了错误的一端,因为我认为这是一个 matplotlib 函数,预计将由 matplotlib 的主循环控制,但您是使用它自己的wxpython。 (在这一点上,我保留犯错的权利:))
下面是您的代码,经过修改以使用 random
来避免串行端口并包含 wx.Timer
来执行更新。
import wx
from matplotlib.figure import Figure as Fig
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar
from collections import deque
#import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib as mlp
import numpy as np
import random
# Class that inherits wx.Panel. The purpose is to embed it into
# a wxPython App. That part can be seen in main()
class Serial_Plot(wx.Panel):
def __init__(self, parent, strPort, id=-1, dpi=None, **kwargs):
super().__init__(parent, id=id, **kwargs)
self.figure = plt.figure(figsize=(20,20))
self.ax = plt.axes(xlim=(0, 10), ylim=(0, 50))
self.plot_data, = self.ax.plot([], [])
self.canvas = FigureCanvas(self, -1, self.figure)
self.toolbar = NavigationToolbar(self.canvas)
self.toolbar.Realize()
#
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update, self.timer)
#
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.canvas, 1, wx.EXPAND)
sizer.Add(self.toolbar, 0, wx.RIGHT | wx.EXPAND)
self.SetSizer(sizer)
# Serial communication
# self.ser = serial.Serial(strPort, 115200)
# Serial data initialized as deque. The serial readings from arduino
# are set to be one value per line.
self.vals = deque()
# matplotlib function animation
#anim = animation.FuncAnimation(self.figure, self.update,
# interval=2)
#plt.show()
plt.ion() #Turn on interactive plot
#self.close
#
self.timer.Start(1000)
def update(self,event):
#try:
# read serial line
#data = float(self.ser.readline().decode('utf-8'))
data = float(random.randint(1, 50))
self.vals.append(data)
# update plot data
length = len(self.vals)
self.plot_data.set_data(range(length), self.vals)
#Update x axis to follow interactive plot
self.ax.set_xlim(0.0,float(length + 1))
#except:
# pass
#return self.plot_data
plt.plot()
def close(self):
# close serial
self.ser.flush()
self.ser.close()
def main():
app = wx.App(False)
frame = wx.Frame(None, -1, "WX APP!")
demo_plot = Serial_Plot(frame,'COM3')
frame.Show()
app.MainLoop()
if __name__ == "__main__":
main()
N.B.
self.ax.set_xlim(0.0,float(length + 1))
可以调整为 self.ax.set_xlim(float(length - 10), float(length + 1))
之类的东西,它将遵循当前值,而不仅仅是不断地扩展 x 轴。