使用线程时在matplotlib中错误地填充\u-between

2024-10-02 08:20:09 发布

您现在位置:Python中文网/ 问答频道 /正文

这个问题实际上是建立在我上周发布的问题之上的(How to partial fill_between in matplotlib, as in different colors for different values

我试着在CAN总线上记录每秒的数据量,并将其绘制在图表上。我为这么多代码提前道歉,但是我尝试的三种方法有些相似

这是一种静态情况,有效:

import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib import pyplot as plt
import sys
from collections import deque
import logging
import time

logging.basicConfig(level=logging.INFO)

buffer_size = 120
lvl = buffer_size * [100]
llvl = buffer_size * [95]
t = [t for t in range(buffer_size)]

bitthrough = deque(buffer_size*[0], buffer_size)

y = [107, 108, 105, 109, 107, 106, 107, 109, 106, 106, 94, 93, 94, 93, 93, 94, 95, 106, 108, 109, 107, 107, 106, 108, 105, 108, 107, 106, 107, 97, 93, 96, 94, 96, 95, 94, 104, 107, 106, 108, 107, 107, 106, 107, 105, 107, 108, 105, 107, 100, 93, 94, 93, 95, 104, 107, 107, 108, 108, 107, 107, 107, 107, 104, 94, 96, 95, 96, 94, 95, 94, 100, 107, 107, 105, 107, 107, 109, 107, 108, 107, 105, 108, 108, 106, 97, 94, 94, 94, 94, 95, 94, 94, 94, 96, 108, 108, 107, 106, 107, 107, 108, 107, 106, 95, 95, 95, 94, 94, 96, 105, 108, 107, 106, 106, 108, 107, 108, 106, 107]

bitthrough = y

fig, ax = plt.subplots()

ax.set_ylim(0, 120)
ax.set_xlim(0, 120)

ln, = plt.plot([], color='black')
plt.ion()
plt.show()

while True:
    plt.pause(1)

    ln.set_xdata(range(buffer_size))
    ln.set_ydata(bitthrough)

    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)]

    ax.fill_between(t, 0, bitthrough, where=wh_red, color='red', interpolate=True)
    ax.fill_between(t, 0, bitthrough, where=wh_orange, color='orange', interpolate=True)
    ax.fill_between(t, 0, bitthrough, where=wh_green, color='green', interpolate=True)
    fig.canvas.draw_idle()

这将导致下面的图表:(现在对我来说这很好) static situation graph

但是,当我想使用线程实时更新图形时,情况就不一样了。这是我的密码canbus是我用来监视can总线的模块PCAN.throughput()是一个asyncio协程函数,它统计一秒钟内的消息数。在传递第二个之后,它返回它在总线上接收到的千字节数。终端显示bitthrough的内容,该内容被填充到一个单独的线程中

from canbus import PCAN
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib import pyplot as plt
import sys
import asyncio
from collections import deque
import logging
import time
import threading
from matplotlib.figure import Figure

logging.basicConfig(level=logging.INFO)

buffer_size = 120
lvl = buffer_size * [100]
llvl = buffer_size * [95]
t = [t for t in range(buffer_size)]

loop = asyncio.get_event_loop()

cn = PCAN()
loop.run_until_complete(cn.poll_ids())
loop.run_until_complete(cn.get_names())
print(cn.names)

bitthrough = deque(buffer_size*[0], buffer_size)


def get_bt(loop):
    asyncio.set_event_loop(loop)
    while True:
        task = loop.run_until_complete(cn.throughput())
        bitthrough.append(task[0] / 33. * 100.)
        print(bitthrough)


thread = threading.Thread(target=get_bt, args=(loop,))
thread.daemon = True
thread.start()

fig, ax = plt.subplots()

ax.set_ylim(0, 120)
ax.set_xlim(0, 120)

ln, = plt.plot([], color='black')
plt.ion()
plt.show()

while True:
    plt.pause(1)
    ln.set_xdata(range(buffer_size))
    ln.set_ydata(bitthrough)

    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)]

    ax.fill_between(t, 0, bitthrough, where=wh_red, color='red', interpolate=True)
    ax.fill_between(t, 0, bitthrough, where=wh_orange, color='orange', interpolate=True)
    ax.fill_between(t, 0, bitthrough, where=wh_green, color='green', interpolate=True)
    fig.canvas.draw_idle()

此代码产生以下结果:

threading case graph

注意红色是如何保持在以前的最高水平的

我还尝试用matplotlib的Qt后端实现它。然而,我只是得到了一个无法更新的空图(如果没有线程,这个方法是有效的,但它使我的计算机陷入困境,使我无法做其他事情)

from canbus import PCAN
# import numpy as np
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import sys
import asyncio
from collections import deque
import logging
import time
import threading
import datetime
from matplotlib.backends.qt_compat import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import (
        FigureCanvas, NavigationToolbar2QT as NavigationToolbar)

from matplotlib.figure import Figure

logging.basicConfig(level=logging.INFO)

buffer_size = 120
lvl = buffer_size * [100]
llvl = buffer_size * [95]
t = [t for t in range(buffer_size)]

loop = asyncio.get_event_loop()

cn = PCAN()
loop.run_until_complete(cn.poll_ids())
loop.run_until_complete(cn.get_names())
print(cn.names)

bitthrough = deque(buffer_size*[0], buffer_size)


def get_bt(loop):
    asyncio.set_event_loop(loop)
    while True:
        task = loop.run_until_complete(cn.throughput())
        bitthrough.append(task[0] / 33. * 100.)
        print(bitthrough)


thread = threading.Thread(target=get_bt, args=(loop,))
thread.daemon = True
thread.start()

class ApplicationWindow(QtWidgets.QMainWindow):

    def __init__(self):

        super().__init__()

        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main)
        layout = QtWidgets.QVBoxLayout(self._main)

        dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
        layout.addWidget(dynamic_canvas)

        self._dynamic_ax = dynamic_canvas.figure.subplots()

        self._update_canvas()

    def _update_canvas(self):

        # p = loop.run_until_complete(cn.throughput())[0] / 500. * 100.
        # bitthrough.append(p)

        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_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_ylim(0, 120)
        logging.info("redrawing graph")
        self._dynamic_ax.figure.canvas.draw()


if __name__ == "__main__":

    qapp = QtWidgets.QApplication(sys.argv)
    app = ApplicationWindow()
    app.show()
    qapp.exec_()
    while True:
        app._update_canvas()
        time.sleep(1)

给了我这个: qt matplotlib backend

也不太好,我现在有点迷路了


Tags: infromimportselflooptrueforsize
1条回答
网友
1楼 · 发布于 2024-10-02 08:20:09

我发现这个问题是我的最后一个解决方案(使用matplotlib的Qt后端)。我打电话来了

while True:
    app._update_canvas()
    time.sleep(1)

在Qt应用程序之外。所以这个图没有被更新,因此,一个空的图。将app._update_canvas()移动到类内部并使用QTimer周期性地调用它,可以正确地绘制图形

添加到ApplicationWindow__init__函数:

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

相关问题 更多 >

    热门问题