Matplotlib 在Matplotlib中添加新的导航模式

Matplotlib 在Matplotlib中添加新的导航模式

在本文中,我们将介绍如何在Matplotlib中添加新的导航模式。Matplotlib是用于绘制各种图形的Python库。在默认情况下,Matplotlib提供了很多导航模式,如平移、缩放、框选和菜单。然而,对于特定的数据可视化场景,我们可能需要自定义导航模式来满足我们自己的需求。下面是如何添加自定义导航模式的步骤。

阅读更多:Matplotlib 教程

步骤1:定义新的导航模式

为了定义新的导航模式,我们需要从Navigation类继承一个新的类,并实现相应的导航方法。例如,下面是一个可以旋转图形的自定义导航模式:

from matplotlib.backend_bases import NavigationToolbar2
from matplotlib.backend_bases import MouseEvent

class Rotation(NavigationToolbar2):
    def __init__(self, canvas, parent=None):
        NavigationToolbar2.__init__(self, canvas, parent)
        self.cid = canvas.mpl_connect('button_press_event', self.on_press)
        self.press = None
        self.rotate_base = None

    def on_press(self, event):
        if event.inaxes is None:
            return
        self.press = event.x, event.y
        self.rotate_base = self._get_rotate_base(event)

    def _get_rotate_base(self, event):
        return event.xdata, event.ydata

    def motion_notify_event(self, event):
        if self.press is None or event.inaxes is None:
            return
        x0, y0 = self.press
        x1, y1 = event.x, event.y
        dx, dy = x1 - x0, y1 - y0
        self.press = x1, y1
        if event.button == 1:    # left button
            self._rotate_view(event.inaxes, dx)
            self.canvas.draw_idle()

    def _rotate_view(self, ax, dx):
        rotate_angle = dx*0.01
        cx, cy = self.rotate_base
        transform = ax.transData - ax.transData.inverted()
        ax.transData = (transform
                        + mtransforms.Affine2D().translate(cx, cy)
                        + mtransforms.Affine2D().rotate_deg_around(cx, cy, rotate_angle)
                        + mtransforms.Affine2D().translate(-cx, -cy)
                        )

上面的代码定义了一个名为“Rotation”的类,它是从NavigationToolbar2继承而来的。该类实现了以下方法:

  • init:初始化新的导航模式,并为canvas.mpl_connect()链接一个鼠标事件 (button_press_event);
  • on_press:当用户按下鼠标键时调用。它将“x-y”坐标存储在self. press中,并调用_get_rotate_base()以获取旋转基点;
  • _get_rotate_base:根据事件获取旋转基点,以便旋转坐标系;
  • motion_notify_event:当用户移动鼠标时调用。它获取鼠标移动的距离,并根据所得到的偏移量旋转坐标系。在旋转完成后,我们需要调用canvas.draw_idle()方法来重绘图形;
  • _rotate_view:通过向仿射变换中添加一个旋转变换来旋转坐标系。

现在我们已经定义了一个新的导航模式,接下来我们需要将其添加到Matplotlib导航栏中。

步骤2:添加新的导航模式

我们可以通过向Matplotlib的导航栏添加新的导航按钮来添加自定义导航模式。下面是如何在Matplotlib工具栏中添加旋转按钮的代码:

from matplotlib.backend_bases import NavigationToolbar2

class MyToolbar(NavigationToolbar2):
    toolitems = NavigationToolbar2.toolitems + (
        ('Rotation', 'Rotate the figure', 'rot.png', 'rotate'),
    )

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

    def _init_toolbar(self):
        super()._init_toolbar()
        self._actions['rotate'] = self._actions['pan'].copy()
        self._actions['rotate']['handler'] = self.create_rotate_handler

    def create_rotate_handler(self, toolbar):
        return Rotation(toolbar.canvas, toolbar)


以MyToolbar为例,我们创建一个新的工具栏,并定义了一个名为“Rotation”的按钮。toolitems元组包含原始Matplotlib导航工具栏的所有按钮以及自定义按钮。我们还在新工具栏的_init_toolbar方法中添加了一个名为“rotate”的动作,它的_handler被设置为create_rotate_handler。create_rotate_handler方法是传递给toolbar._actions[‘rotate’]的参数,它返回一个Rotation实例。

最后一步是使用我们自己的工具栏来展示Matplotlib图形。

步骤3:使用新的导航模式

我们可以将自定义工具栏添加到Matplotlib GUI中,以使用新的导航模式。例如,在PyQt5中,我们可以这样实现:

import sys
import matplotlib as mpl
mpl.use('Qt5Agg')
from PyQt5 import QtCore, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar


class ApplicationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Custom Navigation')
        self.setGeometry(0, 0, 800, 600)
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.central_widget = QtWidgets.QWidget(self)
        self.setCentralWidget(self.central_widget)
        layout = QtWidgets.QVBoxLayout(self.central_widget)
        # Create a fig and axes area to draw on and create canvas
        self.fig = mpl.figure.Figure()
        self.canvas = FigureCanvas(self.fig)
        layout.addWidget(self.canvas)
        # Create custom toolbar
        self.toolbar = MyToolbar(self.canvas, self)
        self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar)
        # Assign custom toolbar to canvas
        self.canvas.toolbar = self.toolbar
        # Draw a circle to show the rotation
        self.ax = self.fig.add_subplot(111)
        self.ax.set_xlim(-1, 1)
        self.ax.set_ylim(-1, 1)
        self.circle = mpl.patches.Circle((0, 0), radius=0.5, alpha=0.5)
        self.ax.add_patch(self.circle)
        self.fig.canvas.draw()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    win = ApplicationWindow()
    win.show()
    sys.exit(app.exec_())


在上面的代码中,我们通过重载ApplicationWindow类来创建一个自定义的Matplotlib应用程序。我们使用自定义工具栏MyToolbar和FigureCanvasQTAgg来创建canvas,并将自定义工具栏分配给canvas.toolbar。接下来,我们在Qt应用程序中添加canvas和工具栏。

最后,在图形中绘制一个圆形,以演示如何使用我们的自定义工具栏进行旋转操作。

总结

在本文中,我们介绍了如何在Matplotlib中添加新的导航模式。我们实现了一个简单的导航模式,名为“旋转”,并通过创建一个自定义工具栏将它添加到Matplotlib GUI中。通过此方法,我们可以在Matplotlib中定义自己的导航模式,并将其应用于适当的数据可视化场景。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程