Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在定期更新的图表上保留NavigationToolbar所做的更改_Python_Matplotlib_Graph_Pyqt5 - Fatal编程技术网

Python 如何在定期更新的图表上保留NavigationToolbar所做的更改

Python 如何在定期更新的图表上保留NavigationToolbar所做的更改,python,matplotlib,graph,pyqt5,Python,Matplotlib,Graph,Pyqt5,我有一个PyQt5 GUI应用程序。这个应用程序显示了一个每秒更新一次的图形(使用默认的xlim和ylim),基本上是一个实时图形。我有这个功能,但我想添加一个NavigationToolbar,这样可以放大/缩小图表 我将工具栏添加到我的布局中,并显示出来。到现在为止,一直都还不错。现在我放大了,图形被放大了,但是一旦图形被定期更新,xlim和ylim再次被默认,并且缩放消失了。我需要从工具栏调用哪些属性,以便保存它们并将它们传递给我的\u update\u canvas函数?我看了一下,注意

我有一个PyQt5 GUI应用程序。这个应用程序显示了一个每秒更新一次的图形(使用默认的
xlim
ylim
),基本上是一个实时图形。我有这个功能,但我想添加一个
NavigationToolbar
,这样可以放大/缩小图表

我将工具栏添加到我的布局中,并显示出来。到现在为止,一直都还不错。现在我放大了,图形被放大了,但是一旦图形被定期更新,
xlim
ylim
再次被默认,并且缩放消失了。我需要从工具栏调用哪些属性,以便保存它们并将它们传递给我的
\u update\u canvas
函数?我看了一下,注意到函数
get_ylim
。所以我试着如下:

self.\u dynamic\u ax.set\u ylim(self.\u dynamic\u ax.get\u ylim())
self.\u dynamic\u ax.set\u ylim(self.\u dynamic\u ax2.get\u ylim())

以及:
self.\u动态\u ax.set\u导航(True)

然而,这些都不起作用。如何保持由
导航工具栏设置的设置?不仅是缩放,还有平移

最小可运行代码示例:

import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt


buffer_size = 120
t = [t for t in range(buffer_size)]
bitthrough = [t for t in range(buffer_size)]
errors = bitthrough[::-1]


class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PCANbus sniffer")
        self.table_widget = MyTableWidget(self)
        self.setCentralWidget(self.table_widget)
        self.setMinimumSize(QtCore.QSize(640, 400))
        self.show()


class MyTableWidget(QtWidgets.QWidget):
    def __init__(self, parent):
        super(QtWidgets.QWidget, self).__init__(parent)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.tabs = QtWidgets.QTabWidget()
        self.tab_graph = QtWidgets.QWidget()
        self.tab_info = QtWidgets.QWidget()
        self.tabs.addTab(self.tab_graph, "PCANbus occupation")
        self.tabs.addTab(self.tab_info, "PCANbus information")

        self.tab_graph.layout = QtWidgets.QVBoxLayout(self)

        self.dynamic_canvas = FigureCanvas(Figure(figsize=(6, 4)))
        self.tab_graph.layout.addWidget(self.dynamic_canvas)

        self.toolbar = NavigationToolbar(self.dynamic_canvas, self)
        self.tab_graph.layout.addWidget(self.toolbar)

        self._dynamic_ax = self.dynamic_canvas.figure.subplots()
        self._dynamic_ax.set_xlabel("time (s)")
        self._dynamic_ax.set_xlim(-5, 125)
        self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
        self._dynamic_ax.set_ylim(-5, 120)
        self._dynamic_ax.tick_params(axis="y", labelcolor="black")
        # self._dynamic_ax.set_navigate(True)

        self._dynamic_ax2 = self._dynamic_ax.twinx()
        self._dynamic_ax2.set_ylabel("Errors (%)", color="blue")
        self._dynamic_ax2.set_ylim(-4, 100)
        self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
        #self._dynamic_ax2.set_navigate(True)

        self.tab_graph.setLayout(self.tab_graph.layout)

        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._update_canvas)
        self.timer.start(1000)

    def _update_canvas(self):

        self._dynamic_ax.clear()
        self._dynamic_ax.plot(t, bitthrough, color="black")
        self._dynamic_ax.set_xlabel("time (s)")
        self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
        self._dynamic_ax.set_ylim(-5, 120) #self._dynamic_ax.get_ylim())
        self._dynamic_ax.tick_params(axis="y", labelcolor="black")

        self._dynamic_ax2.clear()
        self._dynamic_ax2.plot(t, errors, color="blue")
        self._dynamic_ax2.set_ylabel("Errors", color="blue")
        self._dynamic_ax2.set_ylim(-4, 100) #self._dynamic_ax2.get_ylim())
        self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")

        self._dynamic_ax.figure.canvas.draw_idle()


if __name__ == "__main__":

    qapp = QtWidgets.QApplication(sys.argv)
    app = App()
    app.show()
    qapp.exec_()

我的真实
\u更新\u画布
功能:

    def _update_canvas(self):

        wh_green = [a <= b for a, b in zip(bitthrough, llvl)]
        wh_orange = [a > b and a <= c
                     for a, b, c in zip(bitthrough, llvl, lvl)]
        wh_red = [a > b for a, b, in zip(bitthrough, lvl)]

        # self._dynamic_ax.clear()
        # self._dynamic_ax2.clear()

        self._dynamic_ax.fill_between(
            t, 0, bitthrough, where=wh_red, color="red", interpolate=True
        )
        self._dynamic_ax.fill_between(
            t, 0, bitthrough, where=wh_orange, color="orange", interpolate=True
        )
        self._dynamic_ax.fill_between(
            t, 0, bitthrough, where=wh_green, color="green", interpolate=True
        )
        # self._dynamic_ax.plot(t, bitthrough, color="black")
        # self._dynamic_ax.set_xlabel("time (s)")
        # self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
        # #self._dynamic_ax.set_ylim(self._dynamic_ax.get_ylim())
        # self._dynamic_ax.tick_params(axis="y", labelcolor="black")

        # self._dynamic_ax2.plot(t, errors, color="blue")
        # self._dynamic_ax2.set_ylabel("Errors", color="blue")
        # #self._dynamic_ax2.set_ylim(self._dynamic_ax2.get_ylim())
        # self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")

        self._plot1.set_ydata(bitthrough)
        self._plot2.set_ydata(errors)

        # logging.debug("redrawing graph!!")
        self._dynamic_ax.figure.canvas.draw_idle()
def\u更新\u画布(自):
wh_green=[a b和a b表示a,b,在zip中(比特通过,lvl)]
#self.\u dynamic\u ax.clear()
#self.\u dynamic\u ax2.clear()
自。\ u动态\u ax.fill\u之间(
t、 0,位通过,其中=wh\u red,color=“red”,插值=True
)
自。\ u动态\u ax.fill\u之间(
t、 0,位通过,其中=wh_orange,color=“orange”,插值=True
)
自。\ u动态\u ax.fill\u之间(
t、 0,位通过,其中=wh\u绿色,color=“绿色”,插值=True
)
#自动态轴测图(t、bitthrough、color=“黑色”)
#self.\u dynamic\u ax.set\u xlabel(“时间”)
#self.\u dynamic\u ax.set\u ylabel(“吞吐量(%)”,color=“黑色”)
##self._dynamic_ax.set_ylim(self._dynamic_ax.get_ylim())
#自身动态勾选参数(轴=“y”,标签颜色=“黑色”)
#自.\u动态\u ax2.绘图(t、错误、颜色=“蓝色”)
#self.\u dynamic\u ax2.set\u ylabel(“错误”,color=“蓝色”)
##self._dynamic_ax2.set_ylim(self._dynamic_ax2.get_ylim())
#self.\u dynamic\u ax2.勾选参数(axis=“y”,labelcolor=“blue”)
自绘图1.设置数据(位通过)
自绘图2.设置数据(错误)
#debug(“重画图形!!”)
self.\u dynamic\u ax.figure.canvas.draw\u idle()
之间使用
fill\u时,@DizietAsahi的解决方案不起作用。该区域被覆盖而未被清除。因此,它们显示在彼此的顶部


我的建议是不要在每次更新时清除该图。相反,存储对由
plot()
创建的Line2D美工师的引用,并在更新函数中更新{x | y}数据(使用
set_data()
set_ydata()

import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np


buffer_size = 120
t = np.linspace(0, 100, buffer_size)
bitthrough = 120*np.random.random(size=(buffer_size,))
errors = bitthrough[::-1]


class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PCANbus sniffer")
        self.table_widget = MyTableWidget(self)
        self.setCentralWidget(self.table_widget)
        self.setMinimumSize(QtCore.QSize(640, 400))
        self.show()


class MyTableWidget(QtWidgets.QWidget):
    def __init__(self, parent):
        super(QtWidgets.QWidget, self).__init__(parent)
        self.layout = QtWidgets.QVBoxLayout(self)
        self.tabs = QtWidgets.QTabWidget()
        self.tab_graph = QtWidgets.QWidget()
        self.tab_info = QtWidgets.QWidget()
        self.tabs.addTab(self.tab_graph, "PCANbus occupation")
        self.tabs.addTab(self.tab_info, "PCANbus information")

        self.tab_graph.layout = QtWidgets.QVBoxLayout(self)

        self.dynamic_canvas = FigureCanvas(Figure(figsize=(6, 4)))
        self.tab_graph.layout.addWidget(self.dynamic_canvas)

        self.toolbar = NavigationToolbar(self.dynamic_canvas, self)
        self.tab_graph.layout.addWidget(self.toolbar)

        self._dynamic_ax = self.dynamic_canvas.figure.subplots()
        self._dynamic_ax.set_xlabel("time (s)")
        self._dynamic_ax.set_xlim(-5, 125)
        self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
        self._dynamic_ax.set_ylim(-5, 120)
        self._dynamic_ax.tick_params(axis="y", labelcolor="black")
        # self._dynamic_ax.set_navigate(True)

        self._dynamic_ax2 = self._dynamic_ax.twinx()
        self._dynamic_ax2.set_ylabel("Errors (%)", color="blue")
        self._dynamic_ax2.set_ylim(-4, 100)
        self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
        #self._dynamic_ax2.set_navigate(True)


        ##
        ## Create plots here (initially empty)
        ##
        self._plot1, = self._dynamic_ax.plot(t, np.empty(shape=(buffer_size,)), color="black")
        self._plot2, = self._dynamic_ax2.plot(t, np.empty(shape=(buffer_size,)), color="blue")
        self._fill1 = self._dynamic_ax.fill_between(t, 0, bitthrough, color="orange")

        self.tab_graph.setLayout(self.tab_graph.layout)

        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._update_canvas)
        self.timer.start(1000)

    def _update_canvas(self):
        bitthrough = 120*np.random.random(size=(buffer_size, ))
        errors = bitthrough[::-1]

        ##
        ## update the content of the plots here, without clearing the figure
        ##
        self._plot1.set_ydata(bitthrough)
        self._plot2.set_ydata(errors)
        self._fill1.remove()
        self._fill1 = self._dynamic_ax.fill_between(t, 0, bitthrough, color="orange")

        self._dynamic_ax.figure.canvas.draw_idle()


if __name__ == "__main__":

    qapp = QtWidgets.QApplication(sys.argv)
    app = App()
    app.show()
    qapp.exec_()
编辑 我添加了一些代码来处理
fill\u between()

fill\u between()
返回一个
PolyCollection
,这是一个很难更新的问题,因此最好的选择是删除
PolyCollection
,并在每次更新时重新创建它(但不清除整个图)

谢谢!非常喜欢这个解决方案,优雅而简单。这不是我真正的
update
功能。我在我的作品中添加了我现在在评论中使用的旧代码。我真的认为
fill\u-between
不起作用。原来它是由magicOk交织在一起的,所以我想我没有做足够的测试。这在使用
之间填充时不起作用。有什么建议吗?我添加了更多处理
fill\u between()
的代码,感谢您的快速回复。这很好用。添加了我自己的
\u fill\u red
\u fill\u green