【问题标题】:Dynamically update multiple axis in matplotlib在 matplotlib 中动态更新多个轴
【发布时间】:2017-05-04 23:13:51
【问题描述】:

我想用 matplotlib 动画在 PyQT GUI 上显示传感器数据。 我已经有一个工作图,每次我使用以下代码从外部源收到新的传感器值时都会更新:

    def __init__(self):
            self.fig = Figure(figsize=(width, height), dpi=dpi)
            self.axes = self.fig.add_subplot(111)
            self.axes.grid()
            self.xdata = []
            self.ydata = []
            self.entry_limit = 50
            self.line, = self.axes.plot([0], [0], 'r')

    def update_figure_with_new_value(self, xval: float, yval: float):
            self.xdata.append(xval)
            self.ydata.append(yval)

            if len(self.xdata) > self.entry_limit:
                self.xdata.pop(0)
                self.ydata.pop(0)

            self.line.set_data(self.xdata, self.ydata)
            self.axes.relim()
            self.axes.autoscale_view()
            self.fig.canvas.draw()
            self.fig.canvas.flush_events()

我现在想扩展绘图以显示具有相同 x 轴的另一个数据系列。我试图通过在上面的初始化代码中添加以下内容来实现这一点:

            self.axes2 = self.axes.twinx()
            self.y2data = []
            self.line2, = self.axes2.plot([0], [0], 'b')

在 update_figure_with_new_value() 函数中(出于测试目的,我只是尝试将 1 加到 yval,稍后我将扩展该函数的参数):

            self.y2data.append(yval+1)
            if len(self.y2data) > self.entry_limit:
                self.y2data.pop(0)
            self.line2.set_data(self.xdata, self.ydata)
            self.axes2.relim()
            self.axes2.autoscale_view()

但是,我没有在图中得到两条线,它们应该具有完全相同的运动,但只是移动了一条,我得到了第二个绘图轴(蓝色)的垂直线。第一个轴(红色)保持不变,正常。

如何使用 matplotlib 更新多个轴,以便它们显示正确的值?

我正在使用 python 3.4.0 和 matplotlib 2.0.0。

【问题讨论】:

    标签: python matplotlib


    【解决方案1】:

    由于没有可用的最小示例,因此很难说出这种不良行为的原因。原则上ax.relim()ax.autoscale_view() 应该做你需要的。

    所以这里有一个完整的例子,它在使用 python 2.7、matplotlib 2.0 和 PyQt4 运行时可以正常工作并更新两个比例:

    import numpy as np
    import matplotlib.pyplot as plt
    from PyQt4 import QtGui, QtCore
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
    
    class Window(QtGui.QMainWindow):
        def __init__(self):
            QtGui.QMainWindow.__init__(self)
            self.widget = QtGui.QWidget()
            self.setCentralWidget(self.widget)
            self.widget.setLayout(QtGui.QVBoxLayout())
            self.widget.layout().setContentsMargins(0,0,0,0)
            self.widget.layout().setSpacing(0)
    
            self.fig = Figure(figsize=(5,4), dpi=100)
            self.axes = self.fig.add_subplot(111)
            self.axes.grid()
            self.xdata = [0]
            self.ydata = [0]
            self.entry_limit = 50
            self.line, = self.axes.plot([], [], 'r', lw=3)
    
            self.axes2 = self.axes.twinx()
            self.y2data = [0]
            self.line2, = self.axes2.plot([], [], 'b')
    
            self.canvas = FigureCanvas(self.fig)
            self.canvas.draw()
    
            self.nav = NavigationToolbar(self.canvas, self.widget)
            self.widget.layout().addWidget(self.nav)
            self.widget.layout().addWidget(self.canvas)
    
            self.show()
    
            self.ctimer = QtCore.QTimer()
            self.ctimer.timeout.connect(self.update)
            self.ctimer.start(150)
    
    
        def update(self):
            y = np.random.rand(1)
            self.update_figure_with_new_value(self.xdata[-1]+1,y)
    
        def update_figure_with_new_value(self, xval,yval):
            self.xdata.append(xval)
            self.ydata.append(yval)
    
            if len(self.xdata) > self.entry_limit:
                self.xdata.pop(0)
                self.ydata.pop(0)
                self.y2data.pop(0)
    
            self.line.set_data(self.xdata, self.ydata)
            self.axes.relim()
            self.axes.autoscale_view()
    
            self.y2data.append(yval+np.random.rand(1)*0.17)
    
            self.line2.set_data(self.xdata, self.y2data)
            self.axes2.relim()
            self.axes2.autoscale_view()
    
            self.fig.canvas.draw()
            self.fig.canvas.flush_events()
    
    
    if __name__ == "__main__":
        qapp = QtGui.QApplication([])
        a = Window()
        exit(qapp.exec_())
    

    您可能想对此进行测试并报告它是否有效。

    【讨论】:

    • 我把所有东西都按照你的例子中的顺序排列,现在它可以正常工作了。之后,我尝试撤消这些操作以获取有关导致该行为的原因的更多信息,但现在我不再能够重现这一点。感谢您的代码示例。
    • 是的,这就是minimal reproducible examples 的全部意义所在。通过创建一个,您通常已经解决了问题,如果没有,它可以更容易地定位问题。下次你可以记住这一点。 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2012-06-12
    • 1970-01-01
    • 2022-10-25
    • 2020-12-28
    相关资源
    最近更新 更多