如何修改此代码,以便我不会每次都重新绘制图表,matplotlib
Posted
技术标签:
【中文标题】如何修改此代码,以便我不会每次都重新绘制图表,matplotlib【英文标题】:How can I modify this code so that I am not replotting my graph everytime, matplotlib 【发布时间】:2017-01-19 05:00:51 【问题描述】:我正在从设备中获取数据并想要绘制它的电压,并将该图嵌入到 UI 中。我在这里使用了示例:http://matplotlib.org/examples/user_interfaces/embedding_in_qt4.html
这个例子运行良好,但是当我添加 2 个或更多图表时,整个 UI 变得非常慢(使用 RPi3)并且 CPU 使用率非常高。我意识到这可能是因为图表不断被清除和重新绘制。
我的代码如下所示:
class MyMplCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=2, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
self.compute_initial_figure()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
class MyDynamicMplCanvas(MyMplCanvas):
def __init__(self, *args, **kwargs):
MyMplCanvas.__init__(self, *args, **kwargs)
def compute_initial_figure(self):
self.axes.cla()
def update_figure(self,voltage):
self.axes.cla()
self.axes.plot(np.linspace(0,len(voltage)-1,num = len(voltage)), voltage, 'b')
self.axes.set_xlabel("Time")
self.draw()
class worker_thread(QThread):
... #worker thread stuff here
class Monitor(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.exit_button.clicked.connect(exit)
self.ui.go_button.clicked.connect(self.start_monitoring)
self.ui.print_button.clicked.connect(self.test_print)
self.ac_graph = QtGui.QWidget(self)
self.ac_1_graph = MyDynamicMplCanvas(self.ac_graph,width = 10, height =3 , dpi = 60)
self.ui.mplvl.addWidget(self.ac_1_graph)
self.ac_1_graph.axes.set_xlabel("Time")
self.dc_graph = QtGui.QWidget(self)
self.dc_2_graph = MyDynamicMplCanvas(self.dc_graph,width = 10, height =3 , dpi = 60)
self.ui.mplvl_2.addWidget(self.dc_2_graph)
self.ac1_voltage_values = []
self.ac1_current_values = []
self.dc2_voltage_values = []
def start_monitoring(self):
self.worker_thread = worker_thread()
self.connect(self.worker_thread,SIGNAL('grid_done'), self.update_ac_dc_info)
def update_plot_values(self, y_value, y_list):
y_list.append(y_value)
if (len(y_list) == 61):
del y_list[0]
return y_list
def update_ac_dc_info(self,grid_info):
self.ac1_voltage_values = self.update_plot_values((grid_info['ac1_voltage']/10),self.ac1_voltage_values)
self.ac_1_graph.update_figure(self.ac1_voltage_values)
基本上,当数据从我的设备返回时,我会从 worker_thread 发出一个信号,触发我的 UI 在主线程和绘图中更新。在这一点上,我如何让 matplotlib 只接受新出现的点而不重新绘制整个事情?我读过的许多示例都使用了我无法使用的 pyplot,因为我需要将其嵌入到现有的 UI 中。
【问题讨论】:
【参考方案1】:您可以重画点线,而不是每次有新数据时清除轴。这样可以节省一些时间。
class MyDynamicMplCanvas(MyMplCanvas):
def __init__(self, *args, **kwargs):
MyMplCanvas.__init__(self, *args, **kwargs)
def compute_initial_figure(self):
# empty plot
self.line, = self.axes.plot([],[], color="b")
self.axes.set_xlabel("Time") # xlabel will not change over time
def update_figure(self,voltage):
self.line.set_data(np.linspace(0,len(voltage)-1,num = len(voltage)), voltage)
# now you need to take care of the axis limits yourself
self.axes.set_xlim([0,len(voltage])
self.draw()
仅更新最后一个新点有点棘手,因为该图由单个 Line2D
对象组成。您可以选择点图,每次新数据到达时都可以在其中绘制一个新点。
【讨论】:
感谢您的回复!我将我的代码修改为您发布的内容,并且效果很好。我可以在我的 Raspberry Pi 上以非常小的 CPU 负载绘制两个图表。在我一直 100% ping 核心之前。现在我可以在我的程序运行时做其他事情。结果我的函数update_plot_values
只负责通过自动删除列表的最后一个值并附加一个新值来绘制最后一个点,然后将整个列表传递给set_data
!。我还解决了轴重新缩放问题(如果有人想知道,请参阅我的答案)【参考方案2】:
ImportanceOfBeingErnest 的方法效果很好。根据数据重新调整坐标轴:
self.axes.relim()
self.axes.autoscale_view(True,True,True)
【讨论】:
以上是关于如何修改此代码,以便我不会每次都重新绘制图表,matplotlib的主要内容,如果未能解决你的问题,请参考以下文章
如何修复此绘图程序,以便在选择另一个像素时,从一条线绘制的最后一个像素不会变为不同的颜色?