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中定义自己的导航模式,并将其应用于适当的数据可视化场景。
极客笔记