Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python interactive selection tools like in MATLAB

I am trying to switch from MATLAB to python but now I have some issues that I cannot solve by myself. I did a GUI in pyqt designed with Qt designer (to analyze some neurons), all visualizations are done in a matplotlib widget for Qt (it is included in pythonxy) but now I need some tools like in MATLAB for interactive selections (not only on image but also on a plot) that work with matplotlib integrated in Qt GUI:

  • imline
  • impoly
  • imellipse
  • imfreehand
  • imrect (doesn't work in pyqt GUI imrect for python);
  • ginput (I am able to call ginput directly on myMatplotlibWidget.figure.ginput() after I commented the command self.fig.show() in matplotlib\blocking_input.py file from matplotlib library).

I found this http://matplotlib.org/users/event_handling.html please, don't tell me that I must implement the above tools by myself with this python module xD

And I found this http://www.pyqtgraph.org/ but it isn't integrated with matplotlib and the final render is not so nice like in matplotlib.

Is there a good interactive selection tools for pyqt? On Google, I cannot find anything useful but I cannot believe that there aren't good interactive tools for python... if so I will switch back to MATLAB.

Thanks for any help

like image 480
opensw Avatar asked Oct 05 '22 22:10

opensw


1 Answers

OK, I have implemented by myself imline for matplotlib integrated in Qt GUI... now, imrect and so on are simple to implement. If someone needs imrect and so on, I will update the code. Below it is my code for imline:

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import time
import matplotlib as mpl
import matplotlib.pyplot as plt

import numpy as np
import scipy.optimize as opt


class Imline(QObject):
    '''
    Plot interactive line
    '''

    def __init__(self, plt, image = None, scale = 1, *args, **kwargs):
        '''
        Initialize imline
        '''
        super(Imline, self).__init__(None)

        # set plot        
        self.__plt = plt
        self.scale = scale        

        # initialize start and end points        
        self.startX = None
        self.startY = None
        self.endX = None
        self.endY = None  

        # initialize line2d        
        self.__line2d = None
        self.mask = None

        # store information to generate mask
        if(image is not None):        
            height, width = image.shape

        else:
            height = None
            width = None            

        self.__width = width
        self.__height = height

        # set signals and slots        
        self.__c1 = self.__plt.figure.canvas.mpl_connect('button_press_event', self.__mousePressEvent)
        self.__c2 = self.__plt.figure.canvas.mpl_connect('motion_notify_event', self.__mouseMoveEvent)
        self.__c3 = self.__plt.figure.canvas.mpl_connect('button_release_event', self.__mouseReleaseEvent)       

        self.imlineEventFinished = SIGNAL('imlineEventFinished')        


    def __mousePressEvent(self, event):
        '''
        Starting point
        '''

        # get xy data        
        xdata = event.xdata
        ydata = event.ydata

        # check if mouse is outside the figure        
        if((xdata is None) | (ydata is None) | (self.startX is not None) | (self.startY is not None) | (self.endX is not None) | (self.endY is not None)):
            return       

        # start point        
        self.startX = xdata
        self.startY = ydata


    def __mouseMoveEvent(self, event):
        '''
        Draw interactive line
        '''

        # get xy data        
        xdata = event.xdata
        ydata = event.ydata

        # check if mouse is outside the figure        
        if((xdata is None) | (ydata is None) | (self.startX is None) | (self.startY is None) | (self.endX is not None) | (self.endY is not None)):
            return      

        # remove line        
        if(self.__line2d is not None):
            self.__line2d[0].remove()

        # set x, t
        x = [self.startX, xdata]
        y = [self.startY, ydata]        

        # plot line
        self.__plt.axes.hold(True)
        xlim = self.__plt.axes.get_xlim()
        ylim = self.__plt.axes.get_ylim()
        self.__line2d = self.__plt.axes.plot(x, y, color = [1, 0, 0])
        self.__plt.axes.set_xlim(xlim)
        self.__plt.axes.set_ylim(ylim)

        # update plot        
        self.__plt.draw()
        self.__plt.show()


    def __mouseReleaseEvent(self, event):
        '''
        End point
        '''     

        # get xy data        
        xdata = event.xdata
        ydata = event.ydata

        # check if mouse is outside the figure        
        if((xdata is None) | (ydata is None) | (self.endX is not None) | (self.endY is not None)):
            return             

        # remove line        
        if(self.__line2d is not None):
            self.__line2d[0].remove()

        self.endX = xdata
        self.endY = ydata   

        P = np.polyfit([self.startX, self.endX], [self.startY, self.endY],1 )
        self.__m = P[0]
        self.__q = P[1]

        # update plot        
        self.__plt.draw()
        self.__plt.show()

        # disconnect the vents        
        self.__plt.figure.canvas.mpl_disconnect(self.__c1)
        self.__plt.figure.canvas.mpl_disconnect(self.__c2)
        self.__plt.figure.canvas.mpl_disconnect(self.__c3)

        # emit SIGNAL        
        self.emit(SIGNAL('imlineEventFinished'))


    def createMask(self):
        '''
        Create mask from painted line
        '''

        # check height width        
        if((self.__height is None) | (self.__width is None)):
            return None

        # initialize mask        
        mask = np.zeros((self.__height, self.__width))        

        # get m q        
        m = self.__m
        q = self.__q        

        print m, q

        # get points        
        startX = np.int(self.startX)   
        startY = np.int(self.startY) 
        endX = np.int(self.endX) 
        endY = np.int(self.endY)

        # ensure startX < endX
        tempStartX = startX
        if(startX > endX):
            startX = endX
            endX = tempStartX

        # ensure startY < endY
        tempStartY = startY
        if(startY > endY):
            startY = endY
            endY = tempStartY

        # save points
        self.startX = startX
        self.endX = endX
        self.startY = startY
        self.endY = endY

        # intialize data        
        xData = np.arange(startX, endX)
        yData = np.arange(startY, endY)

        # scan on x        
        for x in xData:
            row = round(m*x + q)
            if(row < startY):
                row = startY
            if(row > endY):
                row = endY
            mask[row, x] = 1

        # scan on y
        for y in yData:
            col = round((y - q) / m)
            if(col < startX):
                col = startX
            if(col > endX):
                col = endX
            mask[y, col] = 1

        # get boolean mask        
        mask = mask == 1        

        # return boolean mask
        return mask
like image 199
opensw Avatar answered Oct 09 '22 23:10

opensw