Matplotlib + PyQt5,将自定义工具添加到工具栏

问题描述 投票:0回答:2

我正在开发一个带有嵌入式 matplotlib 画布的 PYQt5 应用程序。这个想法是,呈现图像,然后用户可以在图像中绘制矩形。我想通过向 matplotlib 工具栏添加一个新工具来实现这一点。该工具的工作方式应该与缩放工具类似,用户选择该工具,绘制一个矩形,然后我在 Python 中获取边界框,这样我就可以保存它并为用户绘制它。但是,我目前无法向工具栏添加任何新工具。

我的代码目前如下所示:

import sys

import matplotlib
import numpy as np

matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
from matplotlib.backend_tools import ToolBase
from matplotlib.backends.backend_qtagg import FigureCanvas
from matplotlib.backends.backend_qtagg import \
    NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QAction, QApplication, QMainWindow, QVBoxLayout,
                             QWidget)

plt.rcParams['toolbar'] = 'toolmanager'


class ListTools(ToolBase):
    """List all the tools controlled by the `ToolManager`."""
    # keyboard shortcut
    default_keymap = 'm'
    description = 'List Tools'

    def trigger(self, *args, **kwargs):
        print('_' * 80)
        print("{0:12} {1:45} {2}".format('Name (id)', 'Tool description',
                                         'Keymap'))
        print('-' * 80)
        tools = self.toolmanager.tools
        for name in sorted(tools):
            if not tools[name].description:
                continue
            keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name)))
            print("{0:12} {1:45} {2}".format(name, tools[name].description,
                                             keys))
        print('_' * 80)
        print("Active Toggle tools")
        print("{0:12} {1:45}".format("Group", "Active"))
        print('-' * 80)
        for group, active in self.toolmanager.active_toggle.items():
            print("{0:12} {1:45}".format(str(group), str(active)))


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.sc = FigureCanvas(Figure(figsize=(5, 3), tight_layout=True))
        self.sc.manager.toolmanager.add_tool('List', ListTools)
        self.toolbar = NavigationToolbar(self.sc, self)
        self.addToolBar(self.toolbar)
        print(dir(self.toolbar))

        uniform_data = np.random.rand(10, 12)

        axes = self.sc.figure.subplots()

        axes.imshow(uniform_data)

        widget = QWidget()
        self.setCentralWidget(widget)
        layout = QVBoxLayout(widget)
        layout.addWidget(self.sc)


def main():
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()


if __name__ == "__main__":
    main()

然而,它在第 51 行失败了:

self.sc.manager.toolmanager.add_tool('List', ListTools)

AttributeError:“NoneType”对象没有属性“toolmanager”

我在 Matplotlib 教程中找不到任何其他信息。我在 Stackoverflow 上也找不到有关此问题的任何解决方案,我发现的唯一问题是this,但是没有答案。此外,我只找到了一个关于此问题的GitHub问题,该问题也没有详细说明如何解决这个问题。有人可以向我解释一下我做错了什么吗?

python matplotlib pyqt
2个回答
0
投票

manager.toolmanager.addtool() 方法源自 matplotlib.pyplot.figure(),而不是源自 matplotlib.backends.backend_qtagg.FigureCanvas()。然而对于 NavigationToolbar() 你需要FigureCanvas()。

import sys

import matplotlib
import numpy as np

matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
from matplotlib.backend_tools import ToolBase
from matplotlib.backends.backend_qtagg import     FigureCanvas
from matplotlib.backends.backend_qtagg import \
NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QAction, QApplication, QMainWindow, QVBoxLayout,
                         QWidget)


class ListTools(ToolBase):
    """List all the tools controlled by the `ToolManager`."""
    # keyboard shortcut
    default_keymap = 'm'
    description = 'List Tools'

    def trigger(self, *args, **kwargs):
        print('_' * 80)
        print("{0:12} {1:45} {2}".format('Name (id)', 'Tool description',
                                         'Keymap'))
        print('-' * 80)
        tools = self.toolmanager.tools
        for name in sorted(tools):
            if not tools[name].description:
                continue
            keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name)))
            print("{0:12} {1:45} {2}".format(name, tools[name].description,
                                             keys))
        print('_' * 80)
        print("Active Toggle tools")
        print("{0:12} {1:45}".format("Group", "Active"))
        print('-' * 80)
        for group, active in self.toolmanager.active_toggle.items():
            print("{0:12} {1:45}".format(str(group), str(active)))


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)


        # https://matplotlib.org/2.0.2/examples/user_interfaces/toolmanager.html
        self.sc = FigureCanvas(Figure(figsize=(5, 3), tight_layout=True))
        #self.sc.canvas.manager.toolmanager.add_tool('List', ListTools)

        fig = plt.figure()
        fig.canvas.manager.toolmanager.add_tool('List', ListTools)

        self.toolbar = NavigationToolbar(self.sc, self)
        self.addToolBar(self.toolbar)
        print(dir(self.toolbar))
        uniform_data = np.random.rand(10, 12)
        axes = self.sc.figure.subplots()
        axes.imshow(uniform_data)
        widget = QWidget()
        self.setCentralWidget(widget)
        layout = QVBoxLayout(widget)
        layout.addWidget(self.sc)


def main():
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()


if __name__ == "__main__":
    main()

0
投票

我设法通过手动创建“工具管理器”来强制解决方案。似乎 FigureCanvas 作为函数不会创建管理器。因此,可以使用“matplotlib.backends.backend_qt.FigureManagerQT”创建管理器。

import sys

import matplotlib
import numpy as np

matplotlib.use("Qt5Agg")
import matplotlib.pyplot as plt
from matplotlib.backend_tools import ToolBase
from matplotlib.backends.backend_qtagg import FigureCanvas
from matplotlib.backends.backend_qtagg import \
    NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QAction, QApplication, QMainWindow, QVBoxLayout,
                             QWidget)

plt.rcParams['toolbar'] = 'toolmanager'


class ListTools(ToolBase):
    """List all the tools controlled by the `ToolManager`."""
    # keyboard shortcut
    default_keymap = 'm'
    description = 'List Tools'

    def trigger(self, *args, **kwargs):
        print('_' * 80)
        print("{0:12} {1:45} {2}".format('Name (id)', 'Tool description',
                                         'Keymap'))
        print('-' * 80)
        tools = self.toolmanager.tools
        for name in sorted(tools):
            if not tools[name].description:
                continue
            keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name)))
            print("{0:12} {1:45} {2}".format(name, tools[name].description,
                                             keys))
        print('_' * 80)
        print("Active Toggle tools")
        print("{0:12} {1:45}".format("Group", "Active"))
        print('-' * 80)
        for group, active in self.toolmanager.active_toggle.items():
            print("{0:12} {1:45}".format(str(group), str(active)))


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.sc = FigureCanvas(Figure(figsize=(5, 3), tight_layout=True))
        self.sc.manager = matplotlib.backends.backend_qt.FigureManagerQT(self.sc, 1)
        self.sc.manager.toolmanager.add_tool('List', ListTools)
        self.sc.manager.toolbar.add_tool("List", "navigation", 1)
        self.addToolBar(self.sc.manager.toolbar)
        #print(dir(self.toolbar))

        uniform_data = np.random.rand(10, 12)

        axes = self.sc.figure.subplots()

        axes.imshow(uniform_data)

        widget = QWidget()
        self.setCentralWidget(widget)
        layout = QVBoxLayout(widget)
        layout.addWidget(self.sc)


def main():
    app = QApplication(sys.argv)
    w = MainWindow()
    w.show()
    app.exec_()


if __name__ == "__main__":
    main()
© www.soinside.com 2019 - 2024. All rights reserved.