在 python cmd.Cmd 中绘制图表

哦哦

我正在尝试在 CLI 中绘制一些数据。我希望在单独的窗口中绘制多个图表,它不应该阻止 CLI,以便我仍然可以在 CLI 中发出命令。

class CLI(cmd.Cmd):

    def __init__(self):
        super().__init__()

    def do_plot(self):
        # plot here


if __name__ == '__main__':
    CLI().cmdloop()

方法一:使用matplotlib

我开始知道 matplotlib 不是线程安全的。

方法二:pyqtgraph

我在这里问了一个详细问题:https : //forum.qt.io/topic/122033/running-multiple-plots-with-pyside2,仍然没有解决方案。

我现在能想到的唯一解决方案是编写单独的程序并使用套接字将其与 CLI 连接并共享数据。有什么简单有效的方法吗?

埃利亚内斯克

Qt 小部件不是线程安全的,因此通常不能(或应该)在另一个线程中创建和修改小部件(这涉及 matplotlib 和 pyqtgraph 的 Qt 后端)。

考虑到上述情况,一个可能的替代方案是在主线程中 Qt 事件循环存在,在辅助线程中 cmd.Cmd 事件循环,然后通过线程安全的信号发送信息。

import cmd
import signal
import sys
import threading

from PyQt5 import QtCore, QtWidgets

import numpy as np

from matplotlib.backends.backend_qt5agg import (
    FigureCanvas,
    NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure


class QtSignaller(QtCore.QObject):
    commandChanged = QtCore.pyqtSignal(str, object)


class QtShell(cmd.Cmd):
    def __init__(self, qobject):
        super().__init__()
        self._qobject = qobject

    @property
    def qobject(self):
        return self._qobject

    def do_plot(self, arg):
        self.qobject.commandChanged.emit("plot", parse(arg))


class QtManager(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._window = None

    @QtCore.pyqtSlot(str, object)
    def run_command(self, command, parameters):
        x, y = parameters, np.sin(parameters)
        if self._window is None:
            self._window = FigureCanvas(Figure(figsize=(5, 3)))
            self._ax = self._window.figure.add_subplot(111)
            self._ax.plot(x, y)
        else:
            self._ax.clear()
            self._ax.plot(x, y)
            self._ax.figure.canvas.draw()
        self._window.show()


def run_command(signaller):
    shell = QtShell(signaller)
    shell.cmdloop()


def parse(arg):
    return tuple(map(float, arg.split()))


def main():
    signal.signal(signal.SIGINT, signal.SIG_DFL)

    app = QtWidgets.QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(False)
    signaller = QtSignaller()
    manager = QtManager()
    signaller.commandChanged.connect(manager.run_command)
    threading.Thread(target=run_command, args=(signaller,), daemon=True).start()
    app.exec_()


if __name__ == "__main__":
    main()

注意:虽然我的示例使用了 matplotlib,但 pyqtgraph 应该使用相同的逻辑

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章