【问题标题】:Constricting mouse to canvas area in a matplotlib plot将鼠标限制在matplotlib图中的画布区域
【发布时间】:2015-08-17 14:38:12
【问题描述】:

我正在尝试编写自己的裁剪功能,以便可以从较大的图像中选择一个区域,然后对其执行一些其他操作。我使用matplotlib导入和显示图片:self.img=plt.imread("someimage.png")

如果我留在画布区域,这可以正常工作:

 def __onclick__(self, event):

    self.point=[]
    if event.xdata is not None:
        xholder=event.xdata
    else:
        xholder = 0
    if event.ydata is not None:
        yholder = event.ydata
    else:
        yholder = 0 
    self.point.append([int(xholder),int(yholder)])
def __onrelease__(self,event):
    if event.xdata is not None:
        xholder=event.xdata
    else:
        xholder = self.img.shape[0]
    if event.ydata is not None:
        yholder = event.ydata
    else:
        yholder = self.img.shape[1]
    self.point.append([int(xholder),int(yholder)])
    self.plotcanvas.axes.imshow(self.img[self.point[0][1]:self.point[1][1],self.point[0][0]:self.point[1][0]])
    self.plotcanvas.draw()

但是,一旦我超出画布边界 event.xdataevent.ydata 就会返回(无,无)。一旦在画布区域中注册了鼠标单击,是否仍将鼠标移动限制在画布区域?

使用允许导入 .png 文件然后对其进行裁剪的代码进行编辑

import sys
from PyQt4 import QtGui, QtCore
from matplotlib import pyplot as plt
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import numpy as np


class Example(QtGui.QMainWindow):

    def __init__(self):
        super(Example, self).__init__()
        self.initUI()

    def initUI(self):           
        self.statusBar()
        self.form_widget=FormWidget(self)
        self.setCentralWidget(self.form_widget)
        openFile = QtGui.QAction('Open', self)
        openFile.setShortcut('Ctrl+O')
        openFile.setStatusTip('Open new File')
        openFile.triggered.connect(self.showDialog)
        toolbar = self.addToolBar('Exit')
        toolbar.addAction(openFile)
        self.show()

    def showDialog(self):

        fname = QtGui.QFileDialog.getOpenFileName(self, 'Open file', 
                '/home')

        self.form_widget.redraw(fname)

class FormWidget(QtGui.QWidget):
    def __init__(self,parent):        
        super(FormWidget,self).__init__() 
        self.layout=QtGui.QVBoxLayout(self)
        self.mpcanvas=MyMplCanvas(self)
        self.plotcanvas=MyMplCanvas(self)
        self.layout.addWidget(self.plotcanvas)
        self.layout.addWidget(self.mpcanvas)
        self.setLayout(self.layout)
        self.cidpresscsv=self.mpcanvas.fig.canvas.mpl_connect('button_press_event', self.__onclick__)
        self.cidreleasecsv=self.mpcanvas.fig.canvas.mpl_connect('button_release_event', self.__onrelease__)
    def redraw(self,fname):
        self.mpcanvas.axes=self.mpcanvas.fig.add_subplot(111)
        self.img=plt.imread(fname)
        self.mpcanvas.axes.imshow(self.img)
        self.mpcanvas.draw()
    def __onclick__(self, event):
        self.point=[]
        if event.xdata is not None:
            xholder=event.xdata
        else:
            xholder = 0
        if event.ydata is not None:
            yholder = event.ydata
        else:
            yholder = 0
        self.point.append([int(xholder),int(yholder)])
    def __onrelease__(self,event):
        if event.xdata is not None:
            xholder=event.xdata
        else:
            xholder = self.img.shape[0]
        if event.ydata is not None:
            yholder = event.ydata
        else:
            yholder = self.img.shape[1]
        self.point.append([int(xholder),int(yholder)])
        self.plotcanvas.axes.imshow(self.img[self.point[0][1]:self.point[1][1],self.point[0][0]:self.point[1][0]])
        self.plotcanvas.draw()




class MyMplCanvas(FigureCanvas):
    def __init__(self, parent=None, width=5, height=4, dpi=100):
        self.fig = plt.figure(figsize=(width, height), dpi=dpi)
        self.axes = self.fig.add_subplot(111)
        self.fig.tight_layout()
        self.axes.hold(False)
        self.compute_initial_figure()
        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)
        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

    def compute_initial_figure(self):
        pass



def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

这是在删除所有不必要的东西后出现的结果,并且仍然制作了一个功能性程序,可以让您导入 .png 文件,然后从中挖出一个区域。我确信 Ed Smith 提出的 Rectangle 选择器可能会起作用,但是我无法让示例代码正常工作,并且对值的存储位置以及 eclick 和 erelease 如何在其他事件处理程序的上下文中工作感到困惑。恐怕我一般对matplotlib和python不太熟悉。

【问题讨论】:

  • 只是一个想法 - 如果鼠标离开画布,您也可以处理 figure_leave_event 并将矩形的角设置为那个。您可能需要引入角落的临时存储,而不是简单地将其附加到self.point。然后,如果鼠标重新进入,您可能需要恢复到当前功能。如果您提供更多上下文(即您的函数所在类的准系统视图)并且我的建议听起来很有用,我会写下来作为答案。

标签: python matplotlib event-handling pyqt pyqt4


【解决方案1】:

框选择器 matplotlib widget 可能是最简单的方法。您可以将代码与您拥有的图像一起使用:

from matplotlib.widgets import  RectangleSelector
from pylab import *

def onselect(eclick, erelease):
  'eclick and erelease are matplotlib events at press and release'
  print ' startposition : (%f, %f)' % (eclick.xdata, eclick.ydata)
  print ' endposition   : (%f, %f)' % (erelease.xdata, erelease.ydata)
  print ' used button   : ', eclick.button

def toggle_selector(event):
    print ' Key pressed.'
    if event.key in ['Q', 'q'] and toggle_selector.RS.active:
        print ' RectangleSelector deactivated.'
        toggle_selector.RS.set_active(False)
    if event.key in ['A', 'a'] and not toggle_selector.RS.active:
        print ' RectangleSelector activated.'
        toggle_selector.RS.set_active(True)

fig = figure
ax = subplot(111)

A = np.random.random((30,30))
ax.imshow(A)
toggle_selector.RS = RectangleSelector(ax, onselect, drawtype='box')
connect('key_press_event', toggle_selector)
show()

虽然鼠标不限于框,但minspanxminspanyNone 时的默认行为是将返回的坐标限制在框内。我认为您不能轻易地将鼠标移动限制在画布上。

【讨论】:

    猜你喜欢
    • 2016-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    相关资源
    最近更新 更多