在 PyQt4 的嵌入式 matplotlib 图中使用 ginput

Posted

技术标签:

【中文标题】在 PyQt4 的嵌入式 matplotlib 图中使用 ginput【英文标题】:using ginput in embedded matplotlib figure in PyQt4 【发布时间】:2015-11-12 01:02:06 【问题描述】:

我正在尝试使用“ginput”通过允许用户单击位置来测量 matplotlib 图中的距离。我可以在 matplotlib 图中独立执行此操作,但是当我尝试将图设置到 matplotlib 画布上然后将其嵌入 PyQt4 小部件时遇到问题。下面是我的代码,其中大部分取自 matplotlib 示例。我的解决方案是单击一组位置,并将 (x,y) 坐标传递给“dist_calc”函数以获取距离。

import sys
from PyQt4 import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
import random
import numpy as np

class Window(QtGui.QWidget):
def __init__(self, parent=None):
    super(Window, self).__init__(parent)
    self.fig = Figure((6.5, 5.0), tight_layout=True)
    self.ax = self.fig.add_subplot(111)
    self.canvas = FigureCanvas(self.fig)
    self.toolbar = NavigationToolbar(self.canvas, self)

    self.button = QtGui.QPushButton('Plot')
    self.button.clicked.connect(self.plot)

    self.ndist = QtGui.QPushButton('Measure')
    self.ndist.clicked.connect(self.draw_line)

    self.toolbar.addWidget(self.button)
    self.toolbar.addWidget(self.ndist)
    self.fig.tight_layout()
    layout = QtGui.QVBoxLayout()
    layout.addWidget(self.toolbar)
    layout.addWidget(self.canvas)
    self.setLayout(layout)

def plot(self):
    data = [random.random() for i in range(20)]
    self.ax.hold(False)                          
    self.ax.plot(data, '*-')                     
    self.canvas.draw()                      

def draw_line(self):
    self.xy = plt.ginput(0)
    x = [p[0] for p in self.xy]
    y = [p[1] for p in self.xy]
    self.ax.plot(x,y)
    self.ax.figure.canvas.draw()
    self.get_dist(x, y)

def get_dist(self, xpts, ypts):
    npts = len(xpts)
    distArr = []
    for i in range(npts-1):
        apt = [xpts[i], ypts[i]]
        bpt = [xpts[i+1], ypts[i+1]]
        dist =self.calc_dist(apt,bpt)
        distArr.append(dist)

    tdist = np.sum(distArr)
    print(tdist)

def calc_dist(self,apt, bpt):
    apt = np.asarray(apt)
    dist = np.sum((apt - bpt)**2)
    dist = np.sqrt(dist)
    return dist

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Window()
    main.show()
    sys.exit(app.exec_())

【问题讨论】:

【参考方案1】:

根据一位主要 Matplotlib 开发人员的 this comment,在 Qt 中嵌入 Matplotlib 时,您必须导入 pyplot。 Pyplot 设置了自己的 gui、mainloop 和 canvas,它们会干扰 Qt 事件循环。

将行 self.xy = plt.ginput(0) 更改为 self.xy = self.fig.ginput(0) 并没有帮助但给出了一个有见地的错误:

AttributeError: 'FigureCanvasQTAgg' object has no attribute 'manager'
Figure.show works only for figures managed by pyplot, normally created by pyplot.figure().

简而言之,我认为这是不可能的。 ginput 是一个阻塞函数,似乎只为 Matplotlib 事件循环实现。恐怕您将不得不使用Matplotlib mouse events 构建您想要的功能,当嵌入到 PyQt 中时确实工作。请确保不要使用 pyplot!

编辑:我才想起来,也许LassoSelector 是你需要的。

【讨论】:

以上是关于在 PyQt4 的嵌入式 matplotlib 图中使用 ginput的主要内容,如果未能解决你的问题,请参考以下文章

在 PyQt4 中向 MPL 图添加工具栏

如何在 PyQt4 小部件中嵌入的 Axes3D (matplotlib) 中启用旋转?

Matplotlib在PyQt4的应用

Matplotlib.savefig 忽略轴并在图像周围绘制黑色边框

如何在 pyqt 中嵌入 matplotlib - For Dummies

如何在 pyqt 中嵌入 matplotlib - For Dummies