예제 #1
0
    def __init__(self, transactions, max_price, marker):
        QtGui.QWidget.__init__(self)

        layout = QtGui.QVBoxLayout()
        self.setLayout(layout)

        figure = plt.Figure(figsize=(6, 3), facecolor="white")
        canvas = FigureCanvas(figure)
        canvas.setFixedSize(550, 300)
        layout.addWidget(canvas)

        graph = figure.add_subplot(111)
        if transactions:
            graph.plot([t["seconds_from_start"] for t in transactions],
                       [t["prix"] for t in transactions],
                       color="k",
                       ls="",
                       marker=marker)
        graph.set_xlabel("Temps (secondes)")
        graph.set_xlim(
            -5, pms.MARKET_TIME.minute * 60 + pms.MARKET_TIME.second + 5)
        graph.set_xticks(
            range(0, pms.MARKET_TIME.minute * 60 + pms.MARKET_TIME.second + 1,
                  10))
        graph.set_xticklabels([
            "{}".format(i) if i % 30 == 0 else "" for i in range(
                0, pms.MARKET_TIME.minute * 60 + pms.MARKET_TIME.second +
                1, 10)
        ])
        graph.set_ylabel("Prix")
        graph.set_ylim(-0.25, max_price + 0.25)
        graph.set_yticks(np.arange(0, max_price + 0.1, 0.25))
        graph.grid(ls="--")

        figure.tight_layout()
예제 #2
0
파일: form.py 프로젝트: yajuan2016/PyGator
    def __init__(self, streamline, parent=None, width=5, height=4, dpi=50, subs=1):
        self.fig = Figure(figsize=(width - 50, height), dpi=dpi)

        pos = 0

        self.sl = streamline
        self.subs = subs
        self.cpunum = self.sl.mDevice.cpu_num

        self.gpu_pos = 0
        self.fps_pos = 0
        self.temp_pos = 0

        self.axes = []
        for i in range(self.cpunum):
            self.axes.append(self.fig.add_subplot(self.subs, 1, i + 1))  # For CPU CORES
            # We want the axes cleared every time plot() is called
            self.axes[i].set_title("CPU" + str(i))
            # self.axes[i].set_xticks([])   # not show x
            self.axes[i].set_xlim(0, 20000)
            self.axes[i].set_ylim(0, 2500)

        if self.sl.mDevice.show_gpu == 1:
            self.gpu_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + pos + 1))  # FOR GPU
            self.axes[self.cpunum + self.gpu_pos].set_title("GPU")
            self.axes[self.cpunum + self.gpu_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.gpu_pos].set_ylim(0, 850)
            pos += 1

        if self.sl.mDevice.show_fps == 1:
            self.fps_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.fps_pos + 1))  # FOR FPS
            self.axes[self.cpunum + self.fps_pos].set_title("FPS")
            self.axes[self.cpunum + self.fps_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.fps_pos].set_ylim(0, 100)
            pos += 1

        if self.sl.mDevice.show_temp == 1:
            self.temp_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.temp_pos + 1))  # FOR CPU TEMP
            self.axes[self.cpunum + self.temp_pos].set_title("CPU Temperature")
            self.axes[self.cpunum + self.temp_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.temp_pos].set_ylim(0, 100)
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.temp_pos + 2))  # FOR BOARD TEMP
            self.axes[self.cpunum + self.temp_pos + 1].set_title("Board Temperature")
            self.axes[self.cpunum + self.temp_pos + 1].set_xlim(0, 20000)
            self.axes[self.cpunum + self.temp_pos + 1].set_ylim(0, 100)

        self.fig.set_tight_layout(True)
        self.compute_initial_figure()

        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        FigureCanvas.setFixedSize(self, width - 50, subs * 100)

        FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
예제 #3
0
    def _create_plot(self):
        dpi = plt.rcParams['figure.dpi']
        figsize = (self._plot_width / dpi, self._plot_height / dpi)

        figure = plt.figure(frameon=False, figsize=figsize)
        axes = figure.add_subplot(111)

        canvas = FigureCanvas(figure)
        canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        canvas.setFixedSize(self._plot_width, self._plot_height)
        canvas.setStyleSheet("background: transparent")

        return axes, canvas
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Mark Gonad')
        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):

        # SET THE GEOMETRY
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        fNameLbl = QtGui.QLabel('File name:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMinimum(-100000)
        self.tp.setMaximum(100000)

        directionLbl = QtGui.QLabel('Time direction:')
        self.tDirection = QtGui.QComboBox(self)
        self.tDirection.addItem('Forward')
        self.tDirection.addItem('Backward')

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(directionLbl, 1, 0)
        Col1.addWidget(self.tDirection, 1, 1)
        Col1.addWidget(fNameLbl, 2, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.fName, 2, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 3, 0)
        Col1.addWidget(self._561nmBtn, 4, 0)
        Col1.addWidget(self.CoolLEDBtn, 5, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        self.setFocus()

        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.updateCanvas1)
        self.sld1.valueChanged.connect(self.updateCanvas1)
        self.sld2.valueChanged.connect(self.updateCanvas1)

        self._488nmBtn.toggled.connect(self.radio488Clicked)
        self._561nmBtn.toggled.connect(self.radio561Clicked)
        self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

        self.fig1.canvas.mpl_connect('button_press_event',
                                     self.onMouseClickOnCanvas1)
        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):

        return width

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder',
            'C:\\Users\\Nicola\\Dropbox\\PhD\\Codes\\test')  #Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Mark gonad - ' + self.pathDial.split("\\")[-2] +
                            ' - ' + self.pathDial.split("\\")[-1][:3])

        ### give error message if there is no CoolLED movie in the selected folder
        flist = glob.glob(self.pathDial + '\\*_movie.tif')
        if len(
                flist
        ) == 0:  #not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        ### load all movies (without timestamps, we will add it later on)
        self.channels = {}

        if os.path.isfile(os.path.join(self.pathDial, '488nm_movie.tif')):
            self.channels['488nm'] = load_stack(
                os.path.join(self.pathDial, '488nm_movie.tif'))

        if os.path.isfile(os.path.join(self.pathDial, '561nm_movie.tif')):
            self.channels['561nm'] = load_stack(
                os.path.join(self.pathDial, '561nm_movie.tif'))

        if os.path.isfile(os.path.join(self.pathDial, 'CoolLED_movie.tif')):
            self.channels['CoolLED'] = load_stack(
                os.path.join(self.pathDial, 'CoolLED_movie.tif'))
        print(list(self.channels.keys())[0])

        if 'CoolLED' in self.channels.keys():
            self.currentChannel = 'CoolLED'
        else:
            self.currentChannel = list(self.channels.keys())[0]

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame(self.path,
                                        self.worm + '_01params.pickle')
        self.timesDF = load_data_frame(self.path,
                                       self.worm + '_01times.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the gonadPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_02gonadPos.pickle')):
            self.gpDF = load_data_frame(self.path,
                                        self.worm + '_02gonadPos.pickle')

        else:
            self.gpDF = create_gonad_pos(self.timesDF)

        tp = 0

        ### update the text of the fileName
        self.fName.setText(self.timesDF.ix[self.timesDF.tidxRel == 0,
                                           'fName'].values[0])

        ### initialize the figure.astype(np.uint8)
        self.initializeCanvas1()

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))

        if tp != self.tp.value():
            self.tp.setValue(0)

        self.setBCslidersMinMax()  # this updates the canvas, only once!
        self.CoolLEDBtn.setChecked(
            True)  # this also updates the canvas, only once!

        self.setFocus()

    def saveData(self):

        save_data_frame(self.gpDF, self.path, self.worm + '_02gonadPos.pickle')

    def radio488Clicked(self, enabled):
        # print('radio 488 clicked')

        if enabled:
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

    def radio561Clicked(self, enabled):
        # print('radio 561 clicked')

        if enabled:
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

    def radioCoolLEDClicked(self, enabled):
        # print('radio LED clicked')

        if enabled:
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def wheelEvent(self, event):

        if self.canvas1.underMouse():
            step = event.step

        else:
            step = event.delta() / abs(event.delta())

        self.tp.setValue(self.tp.value() + step)
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):

        # print(event.button,event.xdata,event.ydata)

        x = event.xdata
        y = event.ydata

        if event.button == 1:

            # left button: add a point to the outline
            gonadPos = (np.array([x, y]) * self.compression).astype(np.uint16)

        if event.button == 3:

            gonadPos = [np.nan, np.nan]

        # update the dataframe with the new gonadPos
        self.gpDF.ix[self.gpDF.tidx == self.tp.value(), 'X'] = gonadPos[0]
        self.gpDF.ix[self.gpDF.tidx == self.tp.value(), 'Y'] = gonadPos[1]

        # move to next or previous timepoint depending on tDirection chosen
        if event.button == 1:
            if self.tDirection.currentText() == 'Forward':
                tStep = +1
            else:
                tStep = -1
            self.tp.setValue(self.tp.value() + tStep)
            self.fName.setText(
                self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                                'fName'].values[0])
        if event.button == 3:
            self.updateCanvas1()

        # print( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ] )
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(
            np.max(
                [np.max(self.channels[key]) for key in self.channels.keys()]))
        self.sld1.setMinimum(0)
        self.sld2.setMaximum(
            np.max(
                [np.max(self.channels[key]) for key in self.channels.keys()]))
        self.sld2.setMinimum(0)

    def initializeCanvas1(self):
        print('initializing canvas1... ')

        # plot the image
        self.ax1.cla()
        size = 2048 / self.compression
        self.imgplot = self.ax1.imshow(np.zeros((size, size)), cmap='gray')

        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = [np.nan, np.nan]
        self.pointsplot, = self.ax1.plot(gonadPos[0],
                                         gonadPos[1],
                                         'o',
                                         color='w',
                                         ms=10,
                                         mew=0,
                                         alpha=.8,
                                         lw=0)

        # print gonad position
        gonadBox = np.array([[np.nan, np.nan, np.nan, np.nan],
                             [np.nan, np.nan, np.nan, np.nan]])
        self.boxplot, = self.ax1.plot(gonadPos[0],
                                      gonadPos[1],
                                      '--',
                                      color='w',
                                      alpha=.8,
                                      lw=2)

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.textplot = self.ax1.text(5,
                                      20,
                                      '--.--',
                                      color='white',
                                      fontsize=20)

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas1(self):
        # print('updating canvas1... ')
        size = 2048 / self.compression

        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        # plot the image
        self.imgplot.set_data(
            self.channels[self.currentChannel][self.tp.value() +
                                               self.hatchingtidx])

        # change brightness and contrast
        self.imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # print gonad position
        gonadPos = extract_pos(self.gpDF.ix[
            self.gpDF.tidx == self.tp.value()].squeeze()) / self.compression
        if len(gonadPos.shape) > 0:
            self.pointsplot.set_xdata(gonadPos[0])
            self.pointsplot.set_ydata(gonadPos[1])

            self.boxplot.set_xdata([
                gonadPos[0] - size / 8., gonadPos[0] + size / 8.,
                gonadPos[0] + size / 8., gonadPos[0] - size / 8.,
                gonadPos[0] - size / 8.
            ])
            self.boxplot.set_ydata([
                gonadPos[1] - size / 8., gonadPos[1] - size / 8.,
                gonadPos[1] + size / 8., gonadPos[1] + size / 8.,
                gonadPos[1] - size / 8.
            ])
            plt.draw()

        # plot box

        # print time
        ### find ecdysis timepoint
        ecd = np.loadtxt(open(os.path.join(self.path, 'skin.txt'), 'rb'))
        # load ecdysis data
        index = np.where(ecd[:, 0] == float(self.worm[1:]))
        mintp = np.min([i for i in ecd[index, 1:6][0][0] if i >= 0])
        lethtidx = ecd[index, 1:6][0][0]
        lethtidx = lethtidx[lethtidx >= 0]
        tpL2 = self.timesDF.ix[self.timesDF.tidxRel == (lethtidx[1] - mintp),
                               'timesRel'].values[0]

        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.textplot.set_text(
            '%.2f' % (self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                                      'timesRel'].values[0] - tpL2))

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
예제 #5
0
class GUI(QtGui.QWidget):
    
	def __init__(self):

		super(GUI, self).__init__()

		self.setWindowTitle( 'Outline Cells' )
		self.cellNames = ['1.p','4.a','1.pp','4.aa','1.ppa','1.ppp','4.aaa','4.aap','b_1','b_4']
		self.initUI()
    
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

	def initUI(self):
		# SET THE GEOMETRY

		mainWindow = QtGui.QVBoxLayout()
		mainWindow.setSpacing(15)

		fileBox = QtGui.QHBoxLayout()
		spaceBox1 = QtGui.QHBoxLayout()
		rawDataBox = QtGui.QHBoxLayout()

		mainWindow.addLayout(fileBox)
		mainWindow.addLayout(spaceBox1)
		mainWindow.addLayout(rawDataBox)

		Col1 = QtGui.QGridLayout()
		Col2 = QtGui.QHBoxLayout()
		Col3 = QtGui.QVBoxLayout()

		rawDataBox.addLayout(Col1)
		rawDataBox.addLayout(Col2)
		rawDataBox.addLayout(Col3)

		self.setLayout(mainWindow)

		# DEFINE ALL WIDGETS AND BUTTONS

		loadBtn = QtGui.QPushButton('Load DataSet')
		saveBtn = QtGui.QPushButton('Save data (F12)')

		tpLbl = QtGui.QLabel('Relative Tp:')
		slLbl = QtGui.QLabel('Slice:')
		fNameLbl = QtGui.QLabel('File name:')
		zoomLbl = QtGui.QLabel('Zoom (imgPxl):')

		self.tp = QtGui.QSpinBox(self)
		self.tp.setValue(-5)
		self.tp.setMaximum(100000)

		self.sl = QtGui.QSpinBox(self)
		self.sl.setValue(0)
		self.sl.setMaximum(100000)

		self.fName = QtGui.QLabel('')

		self.zoom = QtGui.QSpinBox(self)
		self.zoom.setValue(50)
		self.zoom.setMinimum(10)
		self.zoom.setMaximum(150)
		self.zoom.setSingleStep(10)

		self._488nmBtn = QtGui.QRadioButton('488nm')
		self._561nmBtn = QtGui.QRadioButton('561nm')
		self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

		self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
		self.sld1.setMaximum(2**16-1)
		self.sld1.setValue(0)
		self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
		self.sld2.setMaximum(2**16)
		self.sld2.setValue(2**16-1)

		self.fig1 = Figure((8.0, 8.0), dpi=100)
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax1 = self.fig1.add_subplot(111)
		self.canvas1 = FigureCanvas(self.fig1)
		self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
		self.canvas1.setFocus()
		self.canvas1.setFixedSize(QtCore.QSize(600,600))
		self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

		self.fig2 = Figure((4.0, 4.0), dpi=100)
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax2 = self.fig2.add_subplot(111)
		self.canvas2 = FigureCanvas(self.fig2)
		self.canvas2.setFixedSize(QtCore.QSize(300,300))
		self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

		# PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

		fileBox.addWidget(loadBtn)
		fileBox.addWidget(saveBtn)

		spaceBox1.addWidget(self.HLine())

		Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(fNameLbl, 2, 0)
		Col1.addWidget(self.fName, 2, 1)
		Col1.addWidget(zoomLbl, 3, 0)
		Col1.addWidget(self.zoom, 3, 1)
		Col1.addWidget(self._488nmBtn, 4, 0 )
		Col1.addWidget(self._561nmBtn, 5, 0 )
		Col1.addWidget(self.CoolLEDBtn, 6, 0 )

		Col2.addWidget(self.sld1)
		Col2.addWidget(self.sld2)
		Col2.addWidget(self.canvas1)

		Col3.addWidget(self.canvas2)

		self.setFocus()
		self.show()

		# BIND BUTTONS TO FUNCTIONS

		loadBtn.clicked.connect(self.selectWorm)
		saveBtn.clicked.connect(self.saveData)

		self.tp.valueChanged.connect(self.loadNewStack)
		self.sl.valueChanged.connect(self.updateAllCanvas)
		self.zoom.valueChanged.connect(self.changeZoom)
		self.sld1.valueChanged.connect(self.updateBC)
		self.sld2.valueChanged.connect(self.updateBC)

		self._488nmBtn.toggled.connect(self.radio488Clicked)
		self._561nmBtn.toggled.connect(self.radio561Clicked)
		self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

		self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
		self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        

	#-----------------------------------------------------------------------------------------------
	# FORMATTING THE WINDOW
	#-----------------------------------------------------------------------------------------------

	def center(self):
        
		qr = self.frameGeometry()
		cp = QtGui.QDesktopWidget().availableGeometry().center()
		qr.moveCenter(cp)
		self.move(qr.topLeft())
        
	def HLine(self):

		toto = QtGui.QFrame()
		toto.setFrameShape(QtGui.QFrame.HLine)
		toto.setFrameShadow(QtGui.QFrame.Sunken)
		return toto

	def VLine(self):
	    
	    toto = QtGui.QFrame()
	    toto.setFrameShape(QtGui.QFrame.VLine)
	    toto.setFrameShadow(QtGui.QFrame.Sunken)
	    return toto

	def heightForWidth(self, width):

		return width

	#-----------------------------------------------------------------------------------------------
	# BUTTON FUNCTIONS
	#-----------------------------------------------------------------------------------------------

	def selectWorm(self):

		### store the folders
		self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101')#'Y:\\Images')
		self.worm = self.pathDial.split("\\")[-1].split('_')[0]
		self.path = os.path.dirname( self.pathDial )
		self.setWindowTitle('Outline Cells - ' + self.pathDial)

		### give error message if there is no CoolLED movie in the selected folder
		flist = glob.glob( self.pathDial + '\\*_movie.tif' )
		if len(flist)==0:#not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
			QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
			return

		### load parameters and times dataframes
		self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
		self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
		self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )
		self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )

		# extract some info
		self.compression = self.paramsDF.compression
		self.hatchingtidx = int( self.paramsDF.tidxHatch )

		### if the cellOutline pickle file already exists, load it, otherwise create a blank one
		if os.path.isfile( os.path.join(self.path, self.worm + '_05cellOut.pickle' ) ):
			self.cellOutDF = load_data_frame( self.path, self.worm + '_05cellOut.pickle' )

		else:
			self.cellOutDF = create_cell_out( self.timesDF, self.cellNames )

		# detect available channels
		self.channels = []
		chns = ['CoolLED','488nm','561nm']
		for c in chns:

			if os.path.isfile( os.path.join( self.pathDial, c + '_movie.tif' ) ):

				self.channels.append(c)
		print(self.channels)
		self.currentChannel = self.channels[0]

		### detect size of the cropped images
		tp = first_tidx_pos_all_cells( self.cellPosDF )
		self.prevtp = tp-1
		tRow = self.timesDF.ix[ self.timesDF.tidxRel == tp ].squeeze()
		fileName = os.path.join( self.pathDial, tRow.fName + self.currentChannel + '.tif')
		firststack = load_stack( fileName )
		self.cropsize = firststack.shape[1]
		self.nslices = firststack.shape[0]

		### intialize canvases
		self.initializeCanvas1()
		self.initializeCanvas2()

		### extract current cells already labeled
		self.currentCells = extract_current_cell_out( self.cellPosDF, self.cellOutDF, self.tp.value(), self.zoom.value() )
		self.analyzedCell = '---'

		### update the text of the fileName
		self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == tp, 'fName' ].values[0])

		### set the timepoint to the hatching time
		self.tp.setMinimum(np.min(self.timesDF.tidxRel))
		self.tp.setMaximum(np.max(self.timesDF.tidxRel))

		### set the max slice number
		self.sl.setMaximum( self.nslices-1 )

		self.tp.setValue( tp )

		if self.currentChannel == 'CoolLED':
			self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
		elif self.currentChannel == '561nm':
			self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
		elif self.currentChannel == '488nm':
			self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more

		# self.pathDial.show()
		self.setFocus()

	def loadNewStack(self):

		# update the cell outline data frame before updating the images and retrireving new cells
		newCellOutDF = update_cell_out_DF( self.currentCells, self.cellOutDF, self.prevtp )
		self.cellOutDF = newCellOutDF
		self.prevtp = self.tp.value()

		# before changing timepoint, print labeled cells and check if they are OK
		# print( 'cells labeled:\n ', self.currentCells )

		# print(self.fList['gfp'][self.tp.value()])
		tRow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

		### update the text of the fileName
		self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

		print( 'Loading... ', self.pathDial, tRow.fName )

		# calculate the max value of the previous stack
		try:
			prevmax = np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] )
		# if it's the first time a stack is to be loaded (so if there is no previous stack), set it to zero
		except:
			prevmax = 0

		# load all the available stacks - this is the slowest part of the code!!!
		self.stacks = {}
		for ch in self.channels:
			fileName = os.path.join( self.pathDial, tRow.fName + ch + '.tif')
			if os.path.isfile( fileName ):
				# print(MultiImage('X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101\\C02_analyzedImages\\Z003_488nm.tif'))
				# print(fileName, MultiImage( fileName ))
				# self.stacks[ch] = MultiImage( fileName )
				self.stacks[ch] = load_stack( fileName )
			# if there are no files for the timepoint, create a blank image
			else:
				self.stacks[ch] = prevmax * np.ones((self.nslices,self.cropsize,self.cropsize))

		### extract current cells already labeled
		self.currentCells = extract_current_cell_out( self.cellPosDF, self.cellOutDF, self.tp.value(), self.zoom.value() )
		# print(self.currentCells)

		# if there are cells labeled and if the previously currently analyzed cell is present, set it as the currently labeled cell and select the right slice
		if len(self.currentCells) > 0:
			print(self.currentCells)
			print('cells detected')

			### update currently analyzed cell
			if self.analyzedCell not in list( self.currentCells.cname ):
				self.analyzedCell = self.currentCells.cname[0]

			### update slice, if it's the same slice number, manually replot the images
			newslice = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ].values[0]
			if newslice != self.sl.value():
				self.sl.setValue( newslice )

			else:
				self.updateAllCanvas()
		# if no cells are found, manually plot the blank images
		elif len(self.currentCells) == 0:
			self.updateAllCanvas()

		# update the BC
		self.setBCslidersMinMax()            

	def saveData(self):
	    
		save_data_frame( self.cellOutDF, self.path, self.worm + '_05cellOut.pickle' )       
		self.setFocus()
	    
	def updateAllCanvas(self):
		self.updateCanvas1()
		self.updateCanvas2()
	    
	def radio488Clicked(self, enabled):
		# print('radio 488 clicked')

		if enabled:
			if '488nm' in self.channels:
				self.currentChannel = '488nm'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == 'CoolLED':
					self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '561nm':
					self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

	def radio561Clicked(self, enabled):
	    # print('radio 561 clicked')

		if enabled:
			if '561nm' in self.channels:
				self.currentChannel = '561nm'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == 'CoolLED':
					self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '488nm':
					self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

	def radioCoolLEDClicked(self, enabled):
	    # print('radio LED clicked')

		if enabled:
			if 'CoolLED' in self.channels:
				self.currentChannel = 'CoolLED'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == '561nm':
					self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '488nm':
					self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

	def updateBC(self):
		# change brightness and contrast
		self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  
		self.imgplot2.set_clim( self.sld1.value(), self.sld2.value() )  
		self.canvas1.draw()
		self.canvas2.draw()

	#-----------------------------------------------------------------------------------------------
	# DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
	#-----------------------------------------------------------------------------------------------

	def keyPressEvent(self, event):

		# print(event.key())

		# change timepoint
		if event.key() == QtCore.Qt.Key_Right:
			self.changeSpaceTime( 'time', +1 )

		elif event.key() == QtCore.Qt.Key_Left:
			self.changeSpaceTime( 'time', -1 )

		# change slice
		elif event.key() == QtCore.Qt.Key_Up:
			self.changeSpaceTime( 'space', +1 )
		    
		elif event.key() == QtCore.Qt.Key_Down:
			self.changeSpaceTime( 'space', -1 )

		elif event.key() == QtCore.Qt.Key_Space:

			if len( self.currentCells ) > 0:
				idx = np.mod( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].index + 1, len(self.currentCells) )
				self.analyzedCell = self.currentCells.cname.values[idx][0]
				self.sl.setValue( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ] )

				self.updateAllCanvas()

		self.setFocus()

	def wheelEvent(self,event):
		if self.canvas1.underMouse():
			step = event.step
		else:          
			step = event.delta()/abs(event.delta())
		self.sl.setValue( self.sl.value() + step) 

	#-----------------------------------------------------------------------------------------------
	# ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
	#-----------------------------------------------------------------------------------------------

	def onMouseClickOnCanvas1(self, event):

		pos = np.array( [ int(np.round(event.xdata)), int(np.round(event.ydata)) ] )

		outline = extract_out( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

		if event.button == 1:

			if np.isnan( outline[0,0] ):
				outline = np.array( [ pos ] )
			else:
				outline = np.vstack( [ outline, pos ] )

		elif event.button == 3:

			if len( outline[ :, 0 ] ) == 1:
				outline = np.array( [ [ np.nan, np.nan ] ] )
			else:
				outline = outline[:-1,:]

		idx = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].index

		self.currentCells.Xout.values[ idx ] = [ outline[:,0] ]
		self.currentCells.Yout.values[ idx ] = [ outline[:,1] ]

		self.updateCanvas1()
		self.setFocus()
		# print(event.button,event.xdata,event.ydata)

	#-----------------------------------------------------------------------------------------------
	# UTILS
	#-----------------------------------------------------------------------------------------------

	def changeZoom( self ):
		imgpxl = self.zoom.value()
		self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'imgPxl' ] = imgpxl
		self.updateCanvas1()

	def setBCslidersMinMax(self):
		self.sld1.setMaximum( np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
		self.sld1.setMinimum(0)
		self.sld2.setMaximum (np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
		self.sld2.setMinimum(0)

	def initializeCanvas1(self):
		# print('initializing canvas1')

		self.fig1.clf()
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax1 = self.fig1.add_subplot(111)
		self.canvas1.draw()

		# plot the first blank image with the right size
		self.ax1.cla()
		self.imgplot1 = self.ax1.imshow( np.zeros((1000,1000)), cmap = 'gray', interpolation = 'nearest' )

		# remove the white borders
		self.ax1.autoscale(False)
		self.ax1.axis('Off')
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

		# plot cell pos and name
		self.text_c1 = []
		self.plot_c1 = []

		# redraw the canvas
		self.canvas1.draw()
		self.setFocus()

	def updateCanvas1(self):
		# print('updating canvas1')

		# clear cell text and points
		# print(self.text1,self.points1)
		for text in self.text_c1:
			text.remove()
		self.text_c1 = []

		for points in self.plot_c1:
			self.ax1.lines.remove(points)
		self.plot_c1 = []


		# if no cells labeled, leave the image blank
		if len( self.currentCells ) == 0:
			self.imgplot1.set_data( np.ones((self.zoom.value(),self.zoom.value())) )
			self.canvas1.draw()
			return

		# detect and update zoom size
		imgpxl = self.zoom.value()
		if not np.isnan( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'imgPxl' ].values[0] ):
			imgpxl = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'imgPxl' ].values[0]
			self.zoom.setValue( imgpxl )
		else:
			self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'imgPxl' ] = imgpxl

		# extract current cell data
		pos = extract_3Dpos( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

		# plot the image
		self.imgplot1.set_data( self.stacks[self.currentChannel][self.sl.value(),pos[1]-imgpxl/2:pos[1]+imgpxl/2+1,pos[0]-imgpxl/2:pos[0]+imgpxl/2+1] )

		# change brightness and contrast
		self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  

		# print cell name
		if pos[2] == self.sl.value():
			self.text_c1.append( self.ax1.text( 10, 50, self.analyzedCell, color='yellow', size='medium', alpha=.8,
					rotation=0, fontsize = 20 ) )

		### draw outline
		outline = extract_out( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

		# print(self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze())

		if len( outline ) > 1:
			outline = np.vstack( [ outline, outline[0] ] )

		self.plot_c1.append( self.ax1.plot( outline[:,0], outline[:,1], '-x', color='yellow', ms=2, alpha=1., lw = .5 )[0] )

		# # redraw the canvas
		self.canvas1.draw()
		self.setFocus()

	def initializeCanvas2(self):
		# print('initializing canvas2')

		self.fig2.clf()
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax2 = self.fig2.add_subplot(111)
		self.canvas2.draw()

		# plot the first blank image with the right size
		self.ax2.cla()
		self.imgplot2 = self.ax2.imshow( np.zeros((self.cropsize,self.cropsize)), cmap = 'gray' )

		# remove the white borders
		self.ax2.autoscale(False)
		self.ax2.axis('Off')
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

		# plot cell pos and name
		self.text_c2 = []
		self.plot_c2 = []

		# redraw the canvas
		self.canvas2.draw()
		self.setFocus()

	def updateCanvas2(self):
		# print('updating canvas2')

		# plot the image
		self.imgplot2.set_data( self.stacks[self.currentChannel][self.sl.value()] )

		# change brightness and contrast
		self.imgplot2.set_clim( self.sld1.value(), self.sld2.value() )  

		# clear cell text and points
		# print(self.text1,self.points1)
		for text in self.text_c2:
			text.remove()
		self.text_c2 = []

		for points in self.plot_c2:
			self.ax2.lines.remove(points)
		self.plot_c2 = []

		# extract current cell data
		for idx, cell in self.currentCells.iterrows():

			if cell.Z == self.sl.value():

				color = 'red'
				if cell.cname == self.analyzedCell:
					color = 'yellow'

				self.text_c2.append( self.ax2.text( cell.X, cell.Y + 18, cell.cname, color=color, size='medium', alpha=.8,
						rotation=0 ) )
				self.plot_c2.append( self.ax2.plot( cell.X, cell.Y, 'o', color=color, alpha = .8, mew = 0 )[0] )


		# redraw the canvas
		self.canvas2.draw()
		self.setFocus()

	def changeSpaceTime(self, whatToChange, increment):

		if whatToChange == 'time':
			# if they are OK (and not going to negative times), change timepoint
			self.tp.setValue( self.tp.value() + increment )

		if whatToChange == 'space':
			self.sl.setValue( self.sl.value() + increment )
예제 #6
0
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Body Length Analysis')
        self.side = 'L'
        self.lbltxt = '"wheel" press: change side, currently %s\n"i" or "u" press: change cell sides'
        self.seamCellNames = ['a', 'b', 'c', '1', '2', '3', '4', '5', '6', 't']
        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):

        # SET THE GEOMETRY

        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        fNameLbl = QtGui.QLabel('File name:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMinimum(-100000)
        self.tp.setMaximum(100000)

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 1, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.fName, 1, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 2, 0)
        Col1.addWidget(self._561nmBtn, 3, 0)
        Col1.addWidget(self.CoolLEDBtn, 4, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        self.setFocus()
        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',
                                     self.onMouseClickOnCanvas1)
        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):

        return width

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Body Length Analysis - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile(os.path.join(self.pathDial,
                                           'CoolLED_movie.tif')):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        ### load all movies (without timestamps, we will add it later on)
        self.channels = {}

        if os.path.isfile(os.path.join(self.pathDial, '488nm_movie.tif')):
            self.channels['488nm'] = load_stack(
                os.path.join(self.pathDial, '488nm_movie.tif'))

        if os.path.isfile(os.path.join(self.pathDial, '561nm_movie.tif')):
            self.channels['561nm'] = load_stack(
                os.path.join(self.pathDial, '561nm_movie.tif'))

        if os.path.isfile(os.path.join(self.pathDial, 'CoolLED_movie.tif')):
            self.channels['CoolLED'] = load_stack(
                os.path.join(self.pathDial, 'CoolLED_movie.tif'))

        self.currentChannel = list(self.channels.keys())[0]

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame(self.path,
                                        self.worm + '_01params.pickle')
        self.timesDF = load_data_frame(self.path,
                                       self.worm + '_01times.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the gonadPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_02gonadPos.pickle')):
            self.gpDF = load_data_frame(self.path,
                                        self.worm + '_02gonadPos.pickle')

        else:
            self.gpDF = create_gonad_pos(self.timesDF)

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue(0)

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        ### update canvases for the first time
        self.updateAllCanvas()
        self.setFocus()

    def saveData(self):

        save_data_frame(self.gpDF, self.path, self.worm + '_02gonadPos.pickle')

    def updateAllCanvas(self):

        self.updateRadioBtn()
        self.updateCanvas1()

    def radioClicked(self):

        if self._488nmBtn.isChecked():
            if '488nm' in self.channels.keys():
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels.keys():
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels.keys():
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def wheelEvent(self, event):

        if self.canvas1.underMouse():
            step = event.step

        else:
            step = event.delta() / abs(event.delta())

        self.tp.setValue(self.tp.value() + step)
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):

        # print(event.button,event.xdata,event.ydata)

        x = event.xdata
        y = event.ydata

        if event.button == 1:

            # left button: add a point to the outline
            gonadPos = (np.array([x, y]) * self.compression).astype(np.uint16)

        if event.button == 3:

            gonadPos = [np.nan, np.nan]

        # update the dataframe with the new gonadPos
        self.gpDF.ix[self.gpDF.tidx == self.tp.value(), 'X'] = gonadPos[0]
        self.gpDF.ix[self.gpDF.tidx == self.tp.value(), 'Y'] = gonadPos[1]

        # print( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ] )
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.channels[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.channels[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.channels[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.channels[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.channels[self.currentChannel]))
        self.sld2.setValue(np.max(self.channels[self.currentChannel]))

    def updateCanvas1(self):

        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow(
            self.channels[self.currentChannel][self.tp.value() +
                                               self.hatchingtidx],
            cmap='gray')

        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(), self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(), self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # print gonad position
        gonadPos = extract_pos(self.gpDF.ix[
            self.gpDF.tidx == self.tp.value()].squeeze()) / self.compression
        if len(gonadPos.shape) > 0:
            self.ax1.plot(gonadPos[0],
                          gonadPos[1],
                          'o',
                          color='red',
                          ms=10,
                          mew=0,
                          alpha=.5,
                          lw=0)

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.ax1.text(5,
                      15,
                      '%.2f' %
                      self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                                      'timesRel'].values[0],
                      color='red')

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
예제 #7
0
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'AP-DV Analaysis' )
        self.lbltxt = '"wheel" press: change side, currently %s\n"i" or "u" press: change cell sides'
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Relative Tp:')
        fNameLbl = QtGui.QLabel('File name:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMinimum(-100000)
        self.tp.setMaximum(100000)

        self.fName = QtGui.QLabel('')
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.fName, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 2, 0 )
        Col1.addWidget(self._561nmBtn, 3, 0 )
        Col1.addWidget(self.CoolLEDBtn, 4, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)
        
        self.setFocus()
        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'X:\\Simone\\160226_lag2YFP_histmCherry')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname( self.pathDial )
        self.setWindowTitle('Body Length Analysis - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) ):
            QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
            return

        ### load all movies (without timestamps, we will add it later on)
        self.channels = {}
        
        if os.path.isfile( os.path.join( self.pathDial, '488nm_movie.tif' ) ):
            self.channels['488nm'] = load_stack( os.path.join( self.pathDial, '488nm_movie.tif') )
        
        if os.path.isfile( os.path.join( self.pathDial, '561nm_movie.tif') ):
            self.channels['561nm'] = load_stack( os.path.join( self.pathDial, '561nm_movie.tif') )
        
        if os.path.isfile( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) ):
            self.channels['CoolLED'] = load_stack( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) )

        self.currentChannel = 'CoolLED'
        
        ### load parameters and times dataframes
        self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
        self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
        self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )
        self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )
        
        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int( self.paramsDF.tidxHatch )

        ### if the AP pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile( os.path.join(self.path, self.worm + '_08apdvPos.pickle' ) ):
            self.apdvPosDF = load_data_frame( self.path, self.worm + '_08apdvPos.pickle' )
        
        else:
            self.apdvPosDF = create_apdv_pos( self.timesDF )

        ### extract current cells already labeled
        self.currentPos = extract_current_apdv_pos( self.apdvPosDF, first_tidx_pos_all_cells( self.cellPosDF ) )
        print(self.currentPos)

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue( first_tidx_pos_all_cells( self.cellPosDF ) )

        ### update the text of the fileName
        self.fName.setText(self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(), 'fName'].values[0])

        self.setFocus()

    def saveData(self):

        save_data_frame( self.apdvPosDF, self.path, self.worm + '_08apdvPos.pickle' )
        
    def updateAllCanvas(self):

        self.updateRadioBtn()
        self.updateCanvas1()
        
    def radioClicked(self):

        if self._488nmBtn.isChecked():
            if '488nm' in self.channels.keys():
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels.keys():
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels.keys():
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    def keyPressEvent(self, event):
        
        # key press on cropped image
        if self.canvas1.underMouse():
            self.onKeyPressOnCanvas1(event)
            
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def wheelEvent(self,event):

        if self.canvas1.underMouse():
            step = event.step
        
        else:          
            step = event.delta()/abs(event.delta())

        ### update daytaframe with previously labeled cells
        newapdvDF = update_apdv_pos_DF( self.currentPos, self.apdvPosDF, self.tp.value() )
        self.apdvPosDF = newapdvDF
        print(self.currentPos) # print previously labeled positions

        ### extract current cells already labeled
        self.currentPos = extract_current_apdv_pos( self.apdvPosDF, self.tp.value() + step )

        self.tp.setValue( self.tp.value() + step ) 

        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0] )

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas1(self, event):
        
        posNameList = [ QtCore.Qt.Key_A, QtCore.Qt.Key_P, QtCore.Qt.Key_D ]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.channels[self.currentChannel][0].shape
        canshape = self.canvas1.size()
        cf = imgshape[0]/canshape.width()
        refpos = self.canvas1.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([ int( refpos.x() * cf ), int( refpos.y() * cf )]) * self.compression

        ### find the closest cell to the cursor
        idx = closer_2Dpos( refpos.astype( np.uint16 ), self.currentPos )

        ### assign the name to the cell
        if any( [ event.key() == cn for cn in posNameList ] ):

            self.currentPos.ix[ idx, 'pname' ] = QtGui.QKeySequence(event.key()).toString().lower()

        self.updateCanvas1()
        self.setFocus()

    def onMouseClickOnCanvas1(self, event):
        
        refpos = np.array( [ event.xdata, event.ydata ] ) * self.compression 

        if event.button == 1:

            # create an empty cell in the currentCells df: the only entries are tidx, xyzpos and cname
            newpos = create_single_apdv_pos( refpos.astype(np.uint16), self.tp.value() )
            self.currentPos = pd.concat( [ self.currentPos, newpos ] )
            
        elif event.button == 3:

            # remove a cell (the closest to the cursor at the moment of right-click)
            idx = closer_2Dpos( refpos.astype(np.uint16), self.currentPos )
            self.currentPos = self.currentPos.drop( [ idx ] )

        self.currentPos = self.currentPos.reset_index(drop=True)
        
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.channels[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.channels[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.channels[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.channels[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.channels[self.currentChannel]))
        self.sld2.setValue(np.max(self.channels[self.currentChannel]))
        
    def updateCanvas1(self):
        
        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow( self.channels[self.currentChannel][self.tp.value() + self.hatchingtidx], cmap = 'gray' )
        
        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(),self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(),self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())  

        # print gonad position
        gonadPos = extract_pos( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ].squeeze() ) / self.compression
        if len( gonadPos.shape ) > 0:
            self.ax1.plot( gonadPos[0], gonadPos[1], 'o', color='red', ms=10, mew=0, alpha=.5, lw = 0 ) 

        # pritn apdv pos
        for idx, pos in self.currentPos.iterrows():
            p = extract_pos( pos ) / self.compression

            self.ax1.plot( p[0], p[1], 'o', color='red', ms=10, mew=0, alpha=.8, lw = 0 ) 
            self.ax1.text( p[0], p[1] + 20, pos.pname, color='red', size='medium', alpha=.8,
                    rotation=0 )

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.ax1.text( 5, 15, '%.2f' % self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ].values[0], color = 'red' )     

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Compute Cell Fluorescence')
        self.cellNames = [
            '1.p', '4.a', '1.pp', '4.aa', '1.ppa', '1.ppp', '4.aaa', '4.aap',
            'b_1', 'b_4'
        ]
        self.imgpxl = 80
        self.initUI()

#-----------------------------------------------------------------------------------------------
# INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
#-----------------------------------------------------------------------------------------------

    def initUI(self):
        # SET THE GEOMETRY

        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        computeBtn = QtGui.QPushButton('Compute current image')
        computeBtn.setFixedWidth(200)
        self.computeAllBtn = QtGui.QPushButton(
            'Compute %s signal for all the images' % '???')
        self.computeAllBtn.setFixedWidth(200)
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')
        gridLbl = QtGui.QLabel('Grid size:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(-5)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.gridsize = QtGui.QSpinBox(self)
        self.gridsize.setValue(5)
        self.gridsize.setMaximum(20)

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300, 300))
        self.canvas2.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0)
        Col1.addWidget(self._561nmBtn, 4, 0)
        Col1.addWidget(self.CoolLEDBtn, 5, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        Col3.addWidget(self.canvas2)
        Col1.addWidget(gridLbl, 6, 0)
        Col1.addWidget(self.gridsize, 6, 1)
        Col1.addWidget(computeBtn, 7, 0)
        Col1.addWidget(self.computeAllBtn, 8, 0)

        self.setFocus()
        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateBC)
        self.sld2.valueChanged.connect(self.updateBC)

        self._488nmBtn.toggled.connect(self.radio488Clicked)
        self._561nmBtn.toggled.connect(self.radio561Clicked)
        self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

        computeBtn.clicked.connect(self.computeFluo)
        self.computeAllBtn.clicked.connect(self.computeAllFluo)

        self.fig1.canvas.mpl_connect('button_press_event',
                                     self.onMouseClickOnCanvas1)
        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):

        return width

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder',
            'X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101')  #'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Outline Cells - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        flist = glob.glob(self.pathDial + '\\*_movie.tif')
        if len(
                flist
        ) == 0:  #not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame(self.path,
                                        self.worm + '_01params.pickle')
        self.timesDF = load_data_frame(self.path,
                                       self.worm + '_01times.pickle')
        self.gpDF = load_data_frame(self.path,
                                    self.worm + '_02gonadPos.pickle')
        self.cellPosDF = load_data_frame(self.path,
                                         self.worm + '_04cellPos.pickle')
        self.cellOutDF = load_data_frame(self.path,
                                         self.worm + '_05cellOut.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the cellOutline pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_06cellFluo.pickle')):
            self.cellFluoDF = load_data_frame(self.path,
                                              self.worm + '_06cellFluo.pickle')

        else:
            self.cellFluoDF = create_cell_fluo(self.timesDF, self.cellNames)

        # detect available channels
        self.channels = []
        chns = ['CoolLED', '488nm', '561nm']
        for c in chns:

            if os.path.isfile(os.path.join(self.pathDial, c + '_movie.tif')):

                self.channels.append(c)
        self.currentChannel = self.channels[0]

        ### detect size of the cropped images
        tp = first_tidx_pos_all_cells(self.cellPosDF)
        self.prevtp = tp - 1
        tRow = self.timesDF.ix[self.timesDF.tidxRel == tp].squeeze()
        fileName = os.path.join(self.pathDial,
                                tRow.fName + self.currentChannel + '.tif')
        firststack = load_stack(fileName)
        self.cropsize = firststack.shape[1]
        self.nslices = firststack.shape[0]

        ### intialize canvases
        self.initializeCanvas1()
        self.initializeCanvas2()

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_fluo(self.cellPosDF,
                                                      self.cellOutDF,
                                                      self.cellFluoDF,
                                                      self.tp.value())
        self.analyzedCell = '---'

        ### update the text of the fileName
        self.fName.setText(self.timesDF.ix[self.timesDF.tidxRel == tp,
                                           'fName'].values[0])

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))

        ### set the max slice number
        self.sl.setMaximum(self.nslices - 1)

        if tp != self.tp.value():
            self.tp.setValue(tp)
        else:
            self.loadNewStack()

        if self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(
                True)  # this uppdates the canvas1 once more
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(
                True)  # this uppdates the canvas1 once more
        elif self.currentChannel == '488nm':
            self._488nmBtn.setChecked(
                True)  # this uppdates the canvas1 once more

        # self.pathDial.show()
        self.setFocus()

    def loadNewStack(self):

        # update the cell outline data frame before updating the images and retrireving new cells
        newCellFluoDF = update_cell_fluo_DF(self.currentCells, self.cellFluoDF,
                                            self.prevtp)
        self.cellFluoDF = newCellFluoDF
        self.prevtp = self.tp.value()

        # before changing timepoint, print labeled cells and check if they are OK
        tRow = self.timesDF.ix[self.timesDF.tidxRel ==
                               self.tp.value()].squeeze()

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        print('Loading... ', self.pathDial, tRow.fName)

        # calculate the max value of the previous stack
        try:
            prevmax = np.max([np.max(self.stacks[ch]) for ch in self.channels])
        # if it's the first time a stack is to be loaded (so if there is no previous stack), set it to zero
        except:
            prevmax = 0

        # load all the available stacks - this is the slowest part of the code!!!
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join(self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile(fileName):
                # print(MultiImage('X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101\\C02_analyzedImages\\Z003_488nm.tif'))
                # print(fileName, MultiImage( fileName ))
                # self.stacks[ch] = MultiImage( fileName )
                self.stacks[ch] = load_stack(fileName)
            # if there are no files for the timepoint, create a blank image
            else:
                self.stacks[ch] = prevmax * np.ones(
                    (self.nslices, self.cropsize, self.cropsize))

        ### extract current cells already labeled
        print('Cells in previous tp:', self.currentCells)
        self.currentCells = extract_current_cell_fluo(self.cellPosDF,
                                                      self.cellOutDF,
                                                      self.cellFluoDF,
                                                      self.tp.value())
        print('Cells in new tp:', self.currentCells)

        # if there are cells labeled and if the previously currently analyzed cell is present, set it as the currently labeled cell and select the right slice
        if len(self.currentCells) > 0:
            print('cells detected')

            ### update currently analyzed cell
            if self.analyzedCell not in list(self.currentCells.cname):
                self.analyzedCell = self.currentCells.cname[0]

            ### update slice, if it's the same slice number, manually replot the images
            newslice = self.currentCells.ix[self.currentCells.cname ==
                                            self.analyzedCell, 'Z'].values[0]
            if newslice != self.sl.value():
                self.sl.setValue(newslice)

            else:
                self.updateAllCanvas()
        # if no cells are found, manually plot the blank images
        elif len(self.currentCells) == 0:
            self.updateAllCanvas()

        # update the BC
        self.setBCslidersMinMax()

    def saveData(self):

        save_data_frame(self.cellFluoDF, self.path,
                        self.worm + '_06cellFluo.pickle')
        self.setFocus()

    def updateAllCanvas(self):
        self.updateCanvas1()
        self.updateCanvas2()

    def radio488Clicked(self, enabled):
        # print('radio 488 clicked')

        if enabled:
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

    def radio561Clicked(self, enabled):
        # print('radio 561 clicked')

        if enabled:
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

    def radioCoolLEDClicked(self, enabled):
        # print('radio LED clicked')

        if enabled:
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

    def updateBC(self):
        # change brightness and contrast
        self.imgplot1.set_clim(self.sld1.value(), self.sld2.value())
        self.imgplot2.set_clim(self.sld1.value(), self.sld2.value())
        self.canvas1.draw()
        self.canvas2.draw()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):

        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime('time', +1)

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime('time', -1)

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime('space', +1)

        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime('space', -1)

        elif event.key() == QtCore.Qt.Key_Space:

            if len(self.currentCells) > 0:
                idx = np.mod(
                    self.currentCells.ix[self.currentCells.cname ==
                                         self.analyzedCell].index + 1,
                    len(self.currentCells))
                self.analyzedCell = self.currentCells.cname.values[idx][0]
                self.sl.setValue(self.currentCells.ix[
                    self.currentCells.cname == self.analyzedCell, 'Z'])

                self.updateAllCanvas()

        self.setFocus()

    def wheelEvent(self, event):
        if self.canvas1.underMouse():
            step = event.step
        else:
            step = event.delta() / abs(event.delta())
        self.sl.setValue(self.sl.value() + step)

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):
        if self._488nmBtn.isChecked():
            channel = '488nm'
        elif self._561nmBtn.isChecked():
            channel = '561nm'
        else:
            QtGui.QMessageBox.about(self, 'Warning',
                                    'Select a proper fluorescence channel!')
            return

        currentCell = self.currentCells.ix[self.currentCells.cname ==
                                           self.analyzedCell].squeeze()
        imgpxl = currentCell.imgPxl
        cell = self.currentCells.ix[self.currentCells.cname ==
                                    self.analyzedCell].squeeze()
        cellPos = extract_3Dpos(cell)
        cellOut = extract_out(cell) * imgpxl / 1000.

        # calculate new drift
        pos = np.array(
            [int(np.round(event.xdata)),
             int(np.round(event.ydata))])
        drift = np.array([pos[0] - 500, pos[1] - 500]) * self.imgpxl / 1000.

        ### perform flat field correction
        # find gonadpos
        gonadPos = extract_pos(
            self.gpDF.ix[self.gpDF.tidx == self.tp.value()].squeeze())
        # load darkField
        darkField = load_stack('W:\\Orca_calibration\\AVG_darkField.tif')
        # load flatField
        flatField = load_stack(
            os.path.join(self.path, 'AVG_flatField_' + channel + '.tif'))
        medianCorrection = np.median((flatField - darkField))
        #correct image
        imgs = self.stacks[self.currentChannel]
        imgsCorr = flat_field_correction(imgs, darkField, flatField, gonadPos)
        imgCorr = imgsCorr[cellPos[2],
                           cellPos[1] - imgpxl / 2:cellPos[1] + imgpxl / 2 + 1,
                           cellPos[0] - imgpxl / 2:cellPos[0] + imgpxl / 2 + 1]

        ### find the new signal
        signal = calculate_fluo_intensity(imgCorr, drift, cellOut)

        # update the current cells
        newCurrentCells = update_current_cell_fluo(self.currentCells, cell,
                                                   channel, drift, signal)
        self.currentCells = newCurrentCells

        # update the cell outline data frame before updating the images and retrireving new cells
        newCellFluoDF = update_cell_fluo_DF(self.currentCells, self.cellFluoDF,
                                            self.tp.value())
        self.cellFluoDF = newCellFluoDF.copy()

        # update canvas
        self.updateCanvas1()
        self.setFocus()
        # print(event.button,event.xdata,event.ydata)

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(
            np.max([np.max(self.stacks[ch]) for ch in self.channels]))
        self.sld1.setMinimum(0)
        self.sld2.setMaximum(
            np.max([np.max(self.stacks[ch]) for ch in self.channels]))
        self.sld2.setMinimum(0)

    def initializeCanvas1(self):
        # print('initializing canvas1')

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        # plot the first blank image with the right size
        self.ax1.cla()
        self.imgplot1 = self.ax1.imshow(np.zeros((1000, 1000)),
                                        cmap='gray',
                                        interpolation='nearest')

        # remove the white borders
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # plot cell pos and name
        self.text_c1 = []
        self.out_c1 = []
        self.center_c1 = []
        self.outDrift_c1 = []
        self.centerDrift_c1 = []

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas1(self):
        # print('updating canvas1')

        # clear cell text and points
        # print(self.text1,self.points1)
        for text in self.text_c1:
            text.remove()
        self.text_c1 = []

        for points in self.out_c1:
            self.ax1.lines.remove(points)
        self.out_c1 = []

        for points in self.outDrift_c1:
            self.ax1.lines.remove(points)
        self.outDrift_c1 = []

        for points in self.centerDrift_c1:
            self.ax1.lines.remove(points)
        self.centerDrift_c1 = []

        # if no cells labeled, leave the image blank
        if len(self.currentCells) == 0:
            self.imgplot1.set_data(np.ones((10, 10)))
            self.canvas1.draw()
            return

        # current cell
        currentCell = self.currentCells.ix[self.currentCells.cname ==
                                           self.analyzedCell].squeeze()

        # extract the zoom
        self.imgpxl = currentCell.imgPxl
        imgpxl = self.imgpxl

        # extract current cell data
        pos = extract_3Dpos(currentCell)

        # plot the image
        self.imgplot1.set_data(
            self.stacks[self.currentChannel][self.sl.value(),
                                             pos[1] - imgpxl / 2:pos[1] +
                                             imgpxl / 2 + 1,
                                             pos[0] - imgpxl / 2:pos[0] +
                                             imgpxl / 2 + 1])

        # change brightness and contrast
        self.imgplot1.set_clim(self.sld1.value(), self.sld2.value())

        # print cell name
        if pos[2] == self.sl.value():
            self.text_c1.append(
                self.ax1.text(10,
                              50,
                              self.analyzedCell,
                              color='yellow',
                              size='medium',
                              alpha=.8,
                              rotation=0,
                              fontsize=20))

        ### draw outline
        outline = extract_out(currentCell)

        # print(self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze())

        if len(outline) > 1:
            outline = np.vstack([outline, outline[0]])

        self.out_c1.append(
            self.ax1.plot(outline[:, 0],
                          outline[:, 1],
                          '-x',
                          color='yellow',
                          ms=2,
                          alpha=1.,
                          lw=.5)[0])
        self.center_c1.append(
            self.ax1.plot(500, 500, 'o', color='yellow', mew=0.)[0])

        # draw drifted outline
        if self._488nmBtn.isChecked():
            drift = (extract_pos488(currentCell) -
                     extract_pos(currentCell)) * 1000 / imgpxl
        elif self._561nmBtn.isChecked():
            drift = (extract_pos561(currentCell) -
                     extract_pos(currentCell)) * 1000 / imgpxl
        else:
            drift = np.array([np.nan, np.nan])
        self.outDrift_c1.append(
            self.ax1.plot(drift[0] + outline[:, 0],
                          drift[1] + outline[:, 1],
                          '-x',
                          color='red',
                          ms=2,
                          alpha=1.,
                          lw=.5)[0])
        self.centerDrift_c1.append(
            self.ax1.plot(500 + drift[0],
                          500 + drift[1],
                          'o',
                          color='red',
                          mew=0.)[0])

        # # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def initializeCanvas2(self):
        # print('initializing canvas2')

        self.fig2.clf()
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2.draw()

        # plot the first blank image with the right size
        self.ax2.cla()
        self.imgplot2 = self.ax2.imshow(np.zeros(
            (self.cropsize, self.cropsize)),
                                        cmap='gray')

        # remove the white borders
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # plot cell pos and name
        self.text_c2 = []
        self.plot_c2 = []

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def updateCanvas2(self):
        # print('updating canvas2')

        # plot the image
        self.imgplot2.set_data(
            self.stacks[self.currentChannel][self.sl.value()])

        # change brightness and contrast
        self.imgplot2.set_clim(self.sld1.value(), self.sld2.value())

        # clear cell text and points
        # print(self.text1,self.points1)
        for text in self.text_c2:
            text.remove()
        self.text_c2 = []

        for points in self.plot_c2:
            self.ax2.lines.remove(points)
        self.plot_c2 = []

        # extract current cell data
        for idx, cell in self.currentCells.iterrows():

            if cell.Z == self.sl.value():

                color = 'red'
                if cell.cname == self.analyzedCell:
                    color = 'yellow'

                self.text_c2.append(
                    self.ax2.text(cell.X,
                                  cell.Y + 18,
                                  cell.cname,
                                  color=color,
                                  size='medium',
                                  alpha=.8,
                                  rotation=0))
                self.plot_c2.append(
                    self.ax2.plot(cell.X,
                                  cell.Y,
                                  'o',
                                  color=color,
                                  alpha=.8,
                                  mew=0)[0])

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def changeSpaceTime(self, whatToChange, increment):

        if whatToChange == 'time':
            self.tp.setValue(self.tp.value() + increment)

        if whatToChange == 'space':
            self.sl.setValue(self.sl.value() + increment)

    def computeFluo(self):

        if self._488nmBtn.isChecked():
            channel = '488nm'
        elif self._561nmBtn.isChecked():
            channel = '561nm'
        else:
            QtGui.QMessageBox.about(self, 'Warning',
                                    'Select a proper fluorescence channel!')
            return

        path = self.path
        worm = self.worm

        rawImgsPath = os.path.join(path, worm + '_analyzedImages')

        # load pickle files
        paramsDF = self.paramsDF
        timesDF = self.timesDF
        gpDF = self.gpDF
        currentCells = self.currentCells

        # load darkField
        darkField = load_stack('W:\\Orca_calibration\\AVG_darkField.tif')

        # load flatField
        flatField = load_stack(
            os.path.join(path, 'AVG_flatField_' + channel + '.tif'))
        medianCorrection = np.median((flatField - darkField))

        # for idx, trow in timesDF.ix[ timesDF.tidxRel == 58 ].iterrows(): ### THIS IS TO TEST A PARTICULAR TIMEPOINT!!!
        trow = self.timesDF.ix[self.timesDF.tidxRel ==
                               self.tp.value()].squeeze()

        # if there is the cropped image
        if not os.path.isfile(
                os.path.join(rawImgsPath, trow.fName + channel + '.tif')):
            QtGui.QMessageBox.about(self, 'Warning', 'No croped image found!')

        else:

            # find all cells labeled in the timepoint
            gonadPos = extract_pos(
                gpDF.ix[gpDF.tidx == trow.tidxRel].squeeze())

            # load the stack and perform FF correction
            imgs = self.stacks[self.currentChannel]
            imgsCorr = flat_field_correction(imgs, darkField, flatField,
                                             gonadPos)

            ### for each labeled cell, calculate the signal
            cell = self.currentCells.ix[self.currentCells.cname ==
                                        self.analyzedCell].squeeze()
            cellPos = extract_3Dpos(cell)

            # extract the zoom
            self.imgpxl = cell.imgPxl
            imgpxl = self.imgpxl

            ### find the XYpos with maximum intensity
            imgCorr = imgsCorr[cellPos[2], cellPos[1] - imgpxl / 2:cellPos[1] +
                               imgpxl / 2 + 1, cellPos[0] -
                               imgpxl / 2:cellPos[0] + imgpxl / 2 + 1]

            ### if there is an outline
            if is_outline_cell(cell):

                print('detected cell/background with outline: ', cell.cname)

                cellOut = extract_out(cell) * self.imgpxl / 1000.

                if not cell.cname[:2] == 'b_':

                    ## this is for the cells - WITH DRIFT CORRECTION
                    _range = self.gridsize.value()
                    signals = np.zeros((2 * _range + 1, 2 * _range + 1))

                    for i in np.arange(2 * _range + 1):
                        for j in np.arange(2 * _range + 1):
                            signals[i, j] = calculate_fluo_intensity(
                                imgCorr, np.array([i - _range, j - _range]),
                                cellOut)

                    drift = np.array([
                        np.where(signals == np.max(signals))[0][0],
                        np.where(signals == np.max(signals))[1][0]
                    ]) - _range
                    # print(drift)
                    signal = np.max(signals)

                else:

                    ### this is for backgrounds in which an outline has been drawn
                    signal = calculate_fluo_intensity(imgCorr, np.array([0,
                                                                         0]),
                                                      cellOut)
                    drift = [0, 0]

            else:

                ### if the outline of the background has not been drawn, just take a small area arund its center
                # if cell.cname[:2] == 'b_':

                print('detected background/cell without outline: ', cell.cname)

                signal = calculate_fluo_intensity_bckg(
                    imgsCorr[cellPos[2], :, :], 6, cellPos)

                drift = [0, 0]

            ### update the currentCells dataframe
            newCurrentCells = update_current_cell_fluo(currentCells, cell,
                                                       channel, drift, signal)
            self.currentCells = newCurrentCells

            # update the cell outline data frame before updating the images and retrireving new cells
            newCellFluoDF = update_cell_fluo_DF(self.currentCells,
                                                self.cellFluoDF,
                                                self.tp.value())
            self.cellFluoDF = newCellFluoDF

        self.updateCanvas1()

    def computeAllFluo(self):

        if self.CoolLEDBtn.isChecked():
            QtGui.QMessageBox.about(self, 'Warning',
                                    'Select a proper fluorescence channel!')
            return

        firsttp = first_tidx_pos_all_cells(self.cellPosDF)
        lasttp = last_tidx_pos_all_cells(self.cellPosDF)

        for idx, trow in self.timesDF.ix[(self.timesDF.tidxRel <= lasttp) & (
                self.timesDF.tidxRel >= firsttp)].iterrows():
            self.tp.setValue(trow.tidxRel)

            for jdx, cell in self.currentCells.iterrows():
                self.analyzedCell = cell.cname
                self.computeFluo()

        self.tp.setValue(firsttp)
예제 #9
0
class GraphUI(QtGui.QDialog):

    window = None
    tweetsSum = None
    scriptsSum = None
    prediction = None
    prediction_size = 0

    def __init__(self, parent=None):
        super(GraphUI, self).__init__(parent)

        #self.ui = Graph_UI.Ui_Form()
        #self.ui.setupUi(self)

        # a figure instance to plot on
        #self.figure = Figure()S
        self.figure = plt.figure()
        self.setWindowTitle("Analysis Result")
        # this is the Canvas Widget that displays the `figure`
        # it takes the `figure` instance as a parameter to __init__
        self.canvas = FigureCanvas(self.figure)

        # this is the Navigation widget
        # it takes the Canvas widget and a parent
        self.toolbar = NavigationToolbar(self.canvas, self)

        # O u r  - C o d e :
        userSymbol = "@"

        # If there are no analysis results
        if GraphUI.scriptsSum is None:
            GraphUI.scriptsSum = list()
            for i in range(0, 4):
                GraphUI.scriptsSum.insert(i, "")
            GraphUI.scriptsSum.insert(3, 0)
            GraphUI.scriptsSum[0] = list()
            for i in range(0, 8):
                GraphUI.scriptsSum[0].insert(i, 0)

        if GraphUI.prediction is None:
            GraphUI.prediction = list()
            for i in range(0, 8):
                GraphUI.prediction.insert(i, 0)

        if GraphUI.tweetsSum is None:
            GraphUI.tweetsSum = list()
            for i in range(0, 6):
                GraphUI.tweetsSum.insert(i, "")
            GraphUI.tweetsSum.insert(5, 0)
            GraphUI.tweetsSum[0] = list()
            for i in range(0, 8):
                GraphUI.tweetsSum[0].insert(i, 0)
            userSymbol = ""

        # Set the window
        self.setStyleSheet("background-color: rgb(255, 255, 255);")
        #self.window.setGeometry(self.window.x(), self.window.y() , 1000, 200)

        # Set the headline
        labelText = ""
        if self.window.character_text is not None:
            labelText = str(self.window.character_text)
        elif self.window.location_text is not None:
            labelText = str(self.window.location_text)
        elif self.window.house is not None:
            labelText = "House " + str(self.window.house)
        # Capitalize the name
        labelText = labelText[0].upper() + labelText[1:]
        lastNameIndex = labelText.find(" ") + 1
        labelText = labelText[:lastNameIndex] + labelText[lastNameIndex].upper(
        ) + labelText[lastNameIndex + 1:]
        q = '"'
        labelText += " in episode " + str(self.window.episode) + " - " + str(
            self.window.episode_text)

        self.label = QtGui.QLabel(labelText)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setStyleSheet(
            "background-color: rgb(255, 255, 255);"
            "color: rgb(0, 0, 0);"
            "margin-top: 0px; margin-bottom: 10px; margin-right: 15px; margin-left: 15px;"
            "padding: 0px;"
            "font-size: 35px;")

        # Set secondary headline
        self.second_label = QtGui.QLabel(
            "Produced from " + str(GraphUI.tweetsSum[5]) + " tweets and " +
            str(GraphUI.scriptsSum[3]) + " script lines. " +
            str(round(0.8 * GraphUI.prediction_size)) +
            " tweets used as a training-set and " +
            str(round(0.2 * GraphUI.prediction_size)) +
            " tweets used as a testing-set.")
        if GraphUI.prediction_size == 0:
            self.second_label = QtGui.QLabel(
                "Produced from " + str(GraphUI.tweetsSum[5]) + " tweets and " +
                str(GraphUI.scriptsSum[3]) +
                " script lines. No prediction was done, "
                "due to lack of relevant data.")
        self.second_label.setAlignment(QtCore.Qt.AlignCenter)
        self.second_label.setStyleSheet(
            "background-color: rgb(255, 255, 255);"
            "color: rgb(0, 0, 0);"
            "margin-top: 0px; margin-bottom: 10px; margin-right: 15px; margin-left: 15px;"
            "padding: 0px;"
            "font-size: 18px;")

        # Set the graph's size
        self.canvas.setFixedSize(QtCore.QSize(500, 500))
        #self.canvas.setMaximumWidth(1200)

        # Set the representative tweets

        self.tweet1 = QtGui.QLabel(
            str(GraphUI.tweetsSum[1]) + "\n\n" + userSymbol +
            str(GraphUI.tweetsSum[2]))
        self.tweet1.setWordWrap(True)
        self.tweet1.setMaximumWidth(350)
        self.tweet1.setStyleSheet(
            "background-color: rgb(29, 202, 255);"
            "color: rgb(0, 0, 0);"
            "margin-top: 5px; margin-bottom: 15px; margin-right: 15px; margin-left: 15px;"
            "padding: 15px;"
            "font-size: 18px;")

        self.tweet2 = QtGui.QLabel(
            str(GraphUI.tweetsSum[3]) + "\n\n" + userSymbol +
            str(GraphUI.tweetsSum[4]))
        self.tweet2.setWordWrap(True)
        self.tweet2.setMaximumWidth(350)
        self.tweet2.setStyleSheet(
            "background-color: rgb(29, 202, 255);"
            "color: rgb(0, 0, 0);"
            "margin-top: 15px; margin-bottom: 5px; margin-right: 15px; margin-left: 15px;"
            "padding: 15px;"
            "font-size: 18px;")

        # abort if there are no analysis results
        if userSymbol == "":
            self.tweet1.setStyleSheet("background-color: rgb(255, 255, 255);")
            self.tweet2.setStyleSheet("background-color: rgb(255, 255, 255);")

        # Set the restart and quit buttons

        #self.restart_button = QtGui.QPushButton('Restart')
        self.restart_button = QtGui.QPushButton()
        self.restart_button.clicked.connect(GraphUI.window.startMainPageUI)
        #self.restart_button.setMaximumWidth(91)
        #self.restart_button.setMaximumHeight(91)
        self.restart_button.setIcon(
            QtGui.QIcon(
                QtGui.QPixmap('./buttons/icons8-reboot-filled-100.png')))
        self.restart_button.setFixedSize(QtCore.QSize(90, 90))
        self.restart_button.setIconSize(QtCore.QSize(80, 80))

        #self.restart_button.setGeometry(self.restart_button.x(), self.restart_button.y(), 91, 91)
        #self.restart_button.setStyleSheet("background-color: #000000; color: black; border: 4.5px solid #111111; margin: 4px; border-radius: 40px;")

        #self.quit_button = QtGui.QPushButton('Quit')
        self.quit_button = QtGui.QPushButton()
        self.quit_button.clicked.connect(exit)
        self.quit_button.setIcon(
            QtGui.QIcon(QtGui.QPixmap('./buttons/icons8-shutdown-100.png')))
        self.quit_button.setFixedSize(QtCore.QSize(90, 90))
        self.quit_button.setIconSize(QtCore.QSize(80, 80))

        # set the layout

        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.second_label)

        # Set an inner layout for the graph and the tweets
        middle_layout = QtGui.QHBoxLayout()

        # Set an inner-inner layout for the quit button
        leftbtn_layout = QtGui.QVBoxLayout()
        leftbtn_layout.addStretch()
        leftbtn_layout.addWidget(self.quit_button)
        middle_layout.addLayout(leftbtn_layout)

        middle_layout.addStretch()

        # Set an inner-inner layout for the graph and its toolbar
        graph_layout = QtGui.QVBoxLayout()
        graph_layout.addWidget(self.toolbar)
        graph_layout.addWidget(self.canvas)
        middle_layout.addLayout(graph_layout)

        # Set an inner-inner layout for the tweets
        tweets_layout = QtGui.QVBoxLayout()
        tweets_layout.addWidget(self.tweet1)
        tweets_layout.addWidget(self.tweet2)
        middle_layout.addLayout(tweets_layout)

        middle_layout.addStretch()

        # Set an inner-inner layout for the restart button
        rightbtn_layout = QtGui.QVBoxLayout()
        rightbtn_layout.addStretch()
        rightbtn_layout.addWidget(self.restart_button)
        middle_layout.addLayout(rightbtn_layout)

        layout.addLayout(middle_layout)

        # Set an inner layout for the buttons
        #down_layout = QtGui.QHBoxLayout()
        #down_layout.addWidget(self.quit_button)
        #down_layout.addStretch()
        #down_layout.addWidget(self.restart_button)
        #layout.addLayout(down_layout)

        self.setLayout(layout)

        # Clean the chosen parameters for the next round
        self.window.parameters = None
        self.window.episode = None
        self.window.episode_text = None
        self.window.category = None
        self.window.character = None
        self.window.character_text = None
        self.window.location = None
        self.window.location_text = None
        self.window.house = None

        # Show graph
        self.plot()

    def plot(self):
        # Set data
        df = pd.DataFrame({
            'group': ['Tweets', 'Scripts', 'Prediction'],
            'Joy': [
                GraphUI.tweetsSum[0][5], GraphUI.scriptsSum[0][5],
                GraphUI.prediction[5]
            ],
            'Trust': [
                GraphUI.tweetsSum[0][7], GraphUI.scriptsSum[0][7],
                GraphUI.prediction[7]
            ],
            'Fear': [
                GraphUI.tweetsSum[0][2], GraphUI.scriptsSum[0][2],
                GraphUI.prediction[2]
            ],
            'Surprise': [
                GraphUI.tweetsSum[0][4], GraphUI.scriptsSum[0][4],
                GraphUI.prediction[4]
            ],
            'Sadness': [
                GraphUI.tweetsSum[0][3], GraphUI.scriptsSum[0][3],
                GraphUI.prediction[3]
            ],
            'Disgust': [
                GraphUI.tweetsSum[0][1], GraphUI.scriptsSum[0][1],
                GraphUI.prediction[1]
            ],
            'Anger': [
                GraphUI.tweetsSum[0][0], GraphUI.scriptsSum[0][0],
                GraphUI.prediction[0]
            ],
            'Anticipation': [
                GraphUI.tweetsSum[0][6], GraphUI.scriptsSum[0][6],
                GraphUI.prediction[6]
            ]
        })

        #initialize the figure
        #my_dpi = 96
        #plt.figure(figsize=(1000 / my_dpi, 1000 / my_dpi), dpi=my_dpi)

        # ------- PART 1: Create background

        # number of variable
        categories = list(df)[1:]
        N = len(categories)

        # What will be the angle of each axis in the plot? (we divide the plot / number of variable)
        angles = [n / float(N) * 2 * pi for n in range(N)]
        angles += angles[:1]

        # Initialise the spider plot
        ax = plt.subplot(111, polar=True)

        # discards the old graph
        #ax.clear()

        # If you want the first axis to be on top:
        ax.set_theta_offset(pi / 2)
        ax.set_theta_direction(-1)

        # Draw one axe per variable + add labels labels yet
        plt.xticks(angles[:-1], categories, size=9)
        # Set the distance of x-axe labels from the graph
        ax.tick_params(axis='x', which='major', pad=14)

        # Draw ylabels
        ax.set_rlabel_position(0)
        plt.yticks([10, 20, 30, 40, 50, 60, 70, 80, 90, 100],
                   ["", "20", "", "40", "", "60", "", "80", "", "100"],
                   color="grey",
                   size=7)
        plt.ylim(0, 100)

        # ------- PART 2: Add plots

        # Plot each individual = each line of the data
        # I don't do a loop, because plotting more than 3 groups makes the chart unreadable

        # Ind1
        values = df.loc[0].drop('group').values.flatten().tolist()
        values += values[:1]
        ax.plot(angles, values, linewidth=1, linestyle='solid', label="Tweets")
        ax.fill(angles, values, 'b', alpha=0.1)

        # Ind2
        values = df.loc[1].drop('group').values.flatten().tolist()
        values += values[:1]
        ax.plot(angles,
                values,
                linewidth=1,
                linestyle='solid',
                label="Scripts")
        ax.fill(angles, values, 'r', alpha=0.1)

        # Ind3
        values = df.loc[2].drop('group').values.flatten().tolist()
        values += values[:1]
        ax.plot(angles,
                values,
                linewidth=1,
                linestyle='solid',
                label="Prediction")
        ax.fill(angles, values, 'g', alpha=0.1)

        # Add legend
        plt.legend(loc='upper right', bbox_to_anchor=(0.2, 0.05))

        # create an axis
        #ax = self.figure.add_subplot(111)

        # refresh canvas
        self.canvas.draw()
예제 #10
0
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'Label Cells' )
        self.cellNames = ['1.p','4.a','1.pp','4.aa','1.ppa','1.ppp','4.aaa','4.aap','b_1','b_4']
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300,300))
        self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0 )
        Col1.addWidget(self._561nmBtn, 4, 0 )
        Col1.addWidget(self.CoolLEDBtn, 5, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        # Col3.addWidget(self.cellTbl)
        Col3.addWidget(self.canvas2)
        
        self.setFocus()

        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.checkNames = True
        self.tp.valueChanged.connect(self.changeTp)
        self.sl.valueChanged.connect(self.updateCanvas1)
        self.sld1.valueChanged.connect(self.updateBC)
        self.sld2.valueChanged.connect(self.updateBC)

        self._488nmBtn.toggled.connect(self.radio488Clicked)
        self._561nmBtn.toggled.connect(self.radio561Clicked)
        self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101')#'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname( self.pathDial )
        self.setWindowTitle('Mark Cells - ' + self.pathDial)
        
        ### give error message if there is no CoolLED movie in the selected folder
        flist = glob.glob( self.pathDial + '\\*_movie.tif' )
        if len(flist)==0:#not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
            QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
            return

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
        self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
        self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int( self.paramsDF.tidxHatch )

        ### find ecdysis timepoint

        ecd = np.loadtxt( open( os.path.join( self.path, 'skin.txt'), 'rb' ) )
        # load ecdysis data
        index = np.where( ecd[:,0] == float(self.worm[1:]) )
        mintp = np.min( [ i for i in ecd[index, 1:6][0][0] if i >= 0 ] )
        lethtidx = ecd[ index, 2:6 ][0][0] - 1
        tpL2 = self.timesDF.ix[ self.timesDF.tidxRel == lethtidx[0], 'timesRel' ].values[0]
        tpL1 = self.timesDF.ix[ self.timesDF.tidxRel == mintp, 'timesRel' ].values[0]

        # relative to hatching time
        self.tpHatch=tpL1

        ### if the cellPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile( os.path.join(self.path, self.worm + '_04cellPos.pickle' ) ):
            self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )
        
        else:
            self.cellPosDF = create_cell_pos( self.timesDF, self.cellNames )

        # detect available channels
        self.channels = []
        chns = ['CoolLED','488nm','561nm']
        for c in chns:

            if os.path.isfile( os.path.join( self.pathDial, c + '_movie.tif' ) ):

                self.channels.append(c)
        self.currentChannel = self.channels[0]

        ### detect size of the cropped images
        tp = np.min( self.gpDF.ix[ pd.notnull( self.gpDF.X ), 'tidx' ] )
        self.prevtp = tp-1
        tRow = self.timesDF.ix[ self.timesDF.tidxRel == tp ].squeeze()
        fileName = os.path.join( self.pathDial, tRow.fName + self.currentChannel + '.tif')
        firststack = load_stack( fileName )
        self.cropsize = firststack.shape[1]
        self.nslices = firststack.shape[0]

        ### load CoolLED movie
        if 'CoolLED' in self.channels:
            self.LEDmovie = load_stack( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) )
        else:
            self.LEDmovie = load_stack( os.path.join( self.pathDial, self.currentChannel + '_movie.tif' ) )
        self.initializeCanvas1()
        self.initializeCanvas2()

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos( self.cellPosDF, self.tp.value() )

        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == tp, 'fName' ].values[0])

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))

        ### set the max slice number
        self.sl.setMaximum( self.nslices-1 )

        self.tp.setValue( tp )

        if self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
        elif self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more

        # self.pathDial.show()
        self.setFocus()

    def loadNewStack(self):

        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

        print( 'Loading... ', self.pathDial, tRow.fName )

        # calculate the max value of the previous stack
        try:
            prevmax = np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] )
        # if it's the first time a stack is to be loaded (so if there is no previous stack), set it to zero
        except:
            prevmax = 0

        # load all the available stacks - this is the slowest part of the code!!!
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join( self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile( fileName ):
                # print(MultiImage('X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101\\C02_analyzedImages\\Z003_488nm.tif'))
                # print(fileName, MultiImage( fileName ))
                # self.stacks[ch] = MultiImage( fileName )
                self.stacks[ch] = load_stack( fileName )
            # if there are no files for the timepoint, create a blank image
            else:
                self.stacks[ch] = prevmax*np.ones((self.nslices,self.cropsize,self.cropsize))
                
        # if the BC bound are different, the BCsliderMinMax will automatically update canvas1. Otherwise, manually update it!
        self.setBCslidersMinMax()            

        self.updateCanvas1()    
        self.updateCanvas2()

    def changeTp( self ):

        # if it's the second time you are checking the same tp, don't do anything
        if self.checkNames:
            cellFine = self.checkConsistencyCellNames()
        else:
            return

        # before changing timepoint, print labeled cells and check if they are OK
        print( 'cells labeled:\n ', self.currentCells )

        ### extract current cells already labeled
        self.newCells = extract_current_cell_pos( self.cellPosDF, self.tp.value() )

        if cellFine:
            # if everything fine, load the new stack
            self.currentCells = self.newCells
            self.loadNewStack()
        else:
            # otherwise, go back to prev tp
            self.checkNames = False
            self.tp.setValue( self.prevtp )
            self.checkNames = True

        self.prevtp = self.tp.value()


    def saveData(self):
        
        if self.checkConsistencyCellNames():
            save_data_frame( self.cellPosDF, self.path, self.worm + '_04cellPos.pickle' )        
        else:
            QtGui.QMessageBox.about(self,'Warning!','There is a mistake in the cell labels!')
        self.setFocus()
        
    def radio488Clicked(self, enabled):
        # print('radio 488 clicked')

        if enabled:
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

    def radio561Clicked(self, enabled):
        # print('radio 561 clicked')

        if enabled:
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

    def radioCoolLEDClicked(self, enabled):
        # print('radio LED clicked')

        if enabled:
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

    def updateBC(self):
        # change brightness and contrast
        self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  
        self.canvas1.draw()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):
        
        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime( 'time', +1 )

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime( 'time', -1 )

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime( 'space', +1 )
            
        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime( 'space', -1 )

        elif event.key() == QtCore.Qt.Key_Space:
            idx = self.channels.index(self.currentChannel)
            if self.channels[ (idx+1)%len(self.channels) ] == 'CoolLED':
                self.CoolLEDBtn.setChecked(True)
            if self.channels[ (idx+1)%len(self.channels) ] == '488nm':
                self._488nmBtn.setChecked(True)
            if self.channels[ (idx+1)%len(self.channels) ] == '561nm':
                self._561nmBtn.setChecked(True)

        # key press on cropped image
        if self.canvas1.underMouse():
            self.onKeyPressOnCanvas1(event)
            
        self.setFocus()

    def wheelEvent(self,event):
        if self.canvas1.underMouse():
            step = event.step
        else:          
            step = event.delta()/abs(event.delta())
        self.sl.setValue( self.sl.value() + step) 

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas1(self, event):
        
        motherCells = [ QtCore.Qt.Key_1, QtCore.Qt.Key_4, QtCore.Qt.Key_B ]
        daughterCells = [ QtCore.Qt.Key_A, QtCore.Qt.Key_P ]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.stacks[self.currentChannel][self.sl.value()].shape
        canshape = self.canvas1.size()
        cf = imgshape[0]/canshape.width()
        refpos = self.canvas1.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([ int( refpos.x() * cf ), int( refpos.y() * cf )])
        refpos = np.append(refpos,self.sl.value())

        ### find the closest cell to the cursor
        idx = closer_cell( refpos.astype( np.uint16 ), self.currentCells )

        ### assign the name to the cell
        if any( [ event.key() == cn for cn in motherCells ] ):
            # if labeling bckg, add the 1 or 2 to the name
            if self.currentCells.ix[ idx, 'cname' ] == 'b_':
                self.currentCells.ix[ idx, 'cname' ] += QtGui.QKeySequence(event.key()).toString().lower()
            else:
                # if not, rename the cell from scratch
                if event.key() == QtCore.Qt.Key_B:
                    self.currentCells.ix[ idx, 'cname' ] = QtGui.QKeySequence(event.key()).toString().lower() + '_'
                else:
                    self.currentCells.ix[ idx, 'cname' ] = QtGui.QKeySequence(event.key()).toString().lower() + '.'

        # add the anterior/posterior to the cell name
        elif any( [ event.key() == cp for cp in daughterCells ] ):
            # don't do it if labeling background (bckg doesn't have a/p!)
            if self.currentCells.ix[ idx, 'cname' ] == 'b_':
                return
            else:
                self.currentCells.ix[ idx, 'cname' ] += QtGui.QKeySequence(event.key()).toString().lower()
        
        # remove the last entry of the name with backspace                
        elif event.key() == QtCore.Qt.Key_Backspace:
            self.currentCells.ix[ idx, 'cname' ] = self.currentCells.ix[ idx, 'cname' ][:-1]

        if ( event.key() != QtCore.Qt.Key_Left ) and ( event.key() != QtCore.Qt.Key_Right ) and ( event.key() != QtCore.Qt.Key_Up ) and ( event.key() != QtCore.Qt.Key_Down ):
            self.updateCanvas1()
        self.setFocus()

    def onMouseClickOnCanvas1(self, event):

        refpos = np.array( [ event.xdata, event.ydata, self.sl.value() ] )  

        if event.button == 1:

            # create an empty cell in the currentCells df: the only entries are tidx, xyzpos and cname
            newcell = create_single_cell_pos( refpos.astype(np.uint16), self.tp.value() )
            self.currentCells = pd.concat( [ self.currentCells, newcell ] )
            
        elif event.button == 3:

            if len( self.currentCells ) == 0:
                self.setFocus()
                return

            # remove a cell (the closest to the cursor at the moment of right-click)
            idx = closer_cell( refpos.astype(np.uint16), self.currentCells )
            self.currentCells = self.currentCells.drop( [ idx ] )

        self.currentCells = self.currentCells.reset_index(drop=True)
        
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def setBCslidersMinMax(self):
        self.sld1.setMaximum( np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
        self.sld1.setMinimum(0)
        self.sld2.setMaximum (np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
        self.sld2.setMinimum(0)

    def initializeCanvas1(self):
        # print('initializing canvas1')

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        # plot the first blank image with the right size
        self.ax1.cla()
        self.imgplot1 = self.ax1.imshow( np.zeros((self.cropsize,self.cropsize)), cmap = 'gray' )
        
        # remove the white borders
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # plot cell pos and name
        self.text1 = []
        self.points1 = []

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
        
    def updateCanvas1(self):
        # print('updating canvas1')

        # plot the image
        self.imgplot1.set_data( self.stacks[self.currentChannel][self.sl.value()] )

        # change brightness and contrast
        self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  
        
        # clear cell text and points
        # print(self.text1,self.points1)
        for text in self.text1:
            text.remove()
        self.text1 = []

        for points in self.points1:
            self.ax1.lines.remove(points)
        self.points1 = []

        # draw cell text and point
        for idx, cell in self.currentCells.iterrows():

            if cell.Z == self.sl.value():

                self.text1.append( self.ax1.text( cell.X, cell.Y + 18, cell.cname, color='red', size='medium', alpha=.8,
                        rotation=0 ) )
                self.points1.append( self.ax1.plot( cell.X, cell.Y, 'o', color='red', alpha = .8, mew = 0 )[0] )

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def initializeCanvas2(self):
        # print('initializing canvas2')

        # plot the image
        self.ax2.cla()
        self.imgplot2 = self.ax2.imshow( np.zeros((512,512)), cmap = 'gray' )
        self.imgplot2.set_clim( np.min(self.LEDmovie), np.max(self.LEDmovie) )

        # remove the white borders and plot outline and spline
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = [np.nan,np.nan]
        self.points2, = self.ax2.plot( gonadPos[0], gonadPos[1], 'o', color='red', ms=10, mew=0, alpha=.5, lw = 0 ) 

        # print time
        self.text2 = self.ax2.text( 5, 25, '--.--', color = 'red' )     

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def updateCanvas2(self):
        # print('updating canvas2')
        # plot the image
        self.imgplot2.set_data( self.LEDmovie[ self.tp.value() + self.hatchingtidx ] )

        # print gonad position
        gonadPos = extract_pos( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ].squeeze() ) / self.compression
        if len( gonadPos.shape ) > 0:
            self.points2.set_xdata( gonadPos[0] ) 
            self.points2.set_ydata( gonadPos[1] ) 
            plt.draw()

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.text2.set_text( '%.2f' % ( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ].values[0] - self.tpHatch ) )

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def checkConsistencyCellNames( self ):
        ### check consistency of cell names
        tp = self.prevtp

        # if no cells are labeled (currentCells df is empty), remove all labeled cells in the cellPosDF and return
        if len( self.currentCells ) == 0:
            newCellPosDF = update_cell_pos_DF( self.currentCells, self.cellPosDF, tp )
            correctCellNames = True

        if len( self.currentCells ) > 0:

            correctCellNames = check_cell_names( self.currentCells, self.cellNames )

            # if cells are not properly labeled, give a Warning
            if not correctCellNames:
                QtGui.QMessageBox.about(self,'Warning!','There is a mistake in the cell labels!')

            # else, update final cellPosDF and return OK
            else:
                newCellPosDF = update_cell_pos_DF( self.currentCells, self.cellPosDF, tp )
                self.cellPosDF = newCellPosDF

        return correctCellNames

    def changeSpaceTime(self, whatToChange, increment):

        if whatToChange == 'time':
            # if they are OK (and not going to negative times), change timepoint
            self.tp.setValue( self.tp.value() + increment )

        if whatToChange == 'space':
            self.sl.setValue( self.sl.value() + increment )
예제 #11
0
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Outline Cells')
        self.cellNames = [
            '1.p', '4.a', '1.pp', '4.aa', '1.ppa', '1.ppp', '4.aaa', '4.aap',
            'b_1', 'b_4'
        ]
        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        # SET THE GEOMETRY

        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(-5)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300, 300))
        self.canvas2.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0)
        Col1.addWidget(self._561nmBtn, 4, 0)
        Col1.addWidget(self.CoolLEDBtn, 5, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        Col3.addWidget(self.cellTbl)
        Col3.addWidget(self.canvas2)

        self.setFocus()
        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',
                                     self.onMouseClickOnCanvas1)
        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):

        return width

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Outline Cells - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile(os.path.join(self.pathDial,
                                           'CoolLED_movie.tif')):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        # detect available channels
        self.channels = []
        chns = ['CoolLED', '488nm', '561nm']
        for c in chns:

            if os.path.isfile(os.path.join(self.pathDial, c + '_movie.tif')):

                self.channels.append(c)

        self.currentChannel = self.channels[0]

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame(self.path,
                                        self.worm + '_01params.pickle')
        self.timesDF = load_data_frame(self.path,
                                       self.worm + '_01times.pickle')
        self.gpDF = load_data_frame(self.path,
                                    self.worm + '_02gonadPos.pickle')
        self.cellPosDF = load_data_frame(self.path,
                                         self.worm + '_04cellPos.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the cellOutline pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_05cellOut.pickle')):
            self.cellOutDF = load_data_frame(self.path,
                                             self.worm + '_05cellOut.pickle')

        else:
            self.cellOutDF = create_cell_out(self.timesDF, self.cellNames)

        self.analyzedCell = '---'

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue(first_tidx_pos_all_cells(self.cellPosDF))

        # self.pathDial.show()
        self.updateAllCanvas()
        self.setFocus()

    def loadNewStack(self):

        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[self.timesDF.tidxRel ==
                               self.tp.value()].squeeze()

        print('Loading... ', self.pathDial, tRow.fName)

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_out(self.cellPosDF,
                                                     self.cellOutDF,
                                                     self.tp.value())

        if len(self.currentCells) > 0:
            ### update current analyzed cell
            if self.analyzedCell not in list(self.currentCells.cname):
                self.analyzedCell = self.currentCells.cname[0]

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        # load all the available stacks
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join(self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile(fileName):
                self.stacks[ch] = load_stack(fileName)

        if len(self.stacks.keys()) > 0:
            # print(self.stacks.keys(), self.stacksStraight)
            self.sl.setMaximum(self.stacks[self.currentChannel].shape[0] - 1)

            self.setBCslidersMinMax()

        if len(self.currentCells) > 0:
            ### update slice
            self.sl.setValue(self.currentCells.ix[self.currentCells.cname ==
                                                  self.analyzedCell, 'Z'])

        # self.updateTable()
        self.updateAllCanvas()

    def saveData(self):

        save_data_frame(self.cellOutDF, self.path,
                        self.worm + '_05cellOut.pickle')
        self.setFocus()

    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        self.updateCanvas2()

    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):

        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime('time', +1)

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime('time', -1)

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime('space', +1)

        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime('space', -1)

        elif event.key() == QtCore.Qt.Key_Space:

            if len(self.currentCells) > 0:
                idx = np.mod(
                    self.currentCells.ix[self.currentCells.cname ==
                                         self.analyzedCell].index + 1,
                    len(self.currentCells))
                self.analyzedCell = self.currentCells.cname.values[idx][0]
                self.sl.setValue(self.currentCells.ix[
                    self.currentCells.cname == self.analyzedCell, 'Z'])

                self.updateAllCanvas()

        self.setFocus()

    def wheelEvent(self, event):
        if self.canvas1.underMouse():
            step = event.step
        else:
            step = event.delta() / abs(event.delta())
        self.sl.setValue(self.sl.value() + step)

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):

        pos = np.array([int(event.xdata), int(event.ydata)])

        outline = extract_out(self.currentCells.ix[
            self.currentCells.cname == self.analyzedCell].squeeze())

        if event.button == 1:

            if np.isnan(outline[0, 0]):
                outline = np.array([pos])
            else:
                outline = np.vstack([outline, pos])

        elif event.button == 3:

            if len(outline[:, 0]) == 1:
                outline = np.array([[np.nan, np.nan]])
            else:
                outline = outline[:-1, :]

        idx = self.currentCells.ix[self.currentCells.cname ==
                                   self.analyzedCell].index

        self.currentCells.Xout.values[idx] = [outline[:, 0]]
        self.currentCells.Yout.values[idx] = [outline[:, 1]]

        self.updateCanvas1()
        self.setFocus()
        # print(event.button,event.xdata,event.ydata)

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.stacks[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.stacks[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.currentChannel]))
        self.sld2.setValue(np.max(self.stacks[self.currentChannel]))

    def updateCanvas1(self):

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        if (len(self.stacks.keys()) == 0) or (len(self.currentCells) == 0):
            # if no images are found, leave the canvas empty
            return

        # extract current cell data
        pos = extract_3Dpos(self.currentCells.ix[self.currentCells.cname ==
                                                 self.analyzedCell].squeeze())

        # plot the image
        imgpxl = 50
        self.ax1.cla()
        imgplot = self.ax1.imshow(
            self.stacks[self.currentChannel][self.sl.value(),
                                             pos[1] - imgpxl / 2:pos[1] +
                                             imgpxl / 2 + 1,
                                             pos[0] - imgpxl / 2:pos[0] +
                                             imgpxl / 2 + 1],
            cmap='gray',
            interpolation='nearest')

        # remove the white borders
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print cell name
        if pos[2] == self.sl.value():
            self.ax1.text(1,
                          2,
                          self.analyzedCell,
                          color='yellow',
                          size='medium',
                          alpha=.8,
                          rotation=0,
                          fontsize=20)
            self.ax1.plot(imgpxl / 2,
                          imgpxl / 2,
                          'x',
                          color='yellow',
                          alpha=.8,
                          ms=5)

        ### draw outline
        outline = extract_out(self.currentCells.ix[
            self.currentCells.cname == self.analyzedCell].squeeze())

        # print(self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze())

        if len(outline) > 1:
            outline = np.vstack([outline, outline[0]])

        self.ax1.plot(outline[:, 0],
                      outline[:, 1],
                      '-x',
                      color='yellow',
                      ms=2,
                      alpha=1.,
                      lw=.5)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(), self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(), self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas2(self):

        # plot the image
        self.ax2.cla()
        imgplot = self.ax2.imshow(
            self.stacks[self.currentChannel][self.sl.value()], cmap='gray')

        # remove the white borders
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # extract current cell data
        if len(self.currentCells) > 0:
            pos = extract_3Dpos(self.currentCells.ix[
                self.currentCells.cname == self.analyzedCell].squeeze())

            for idx, cell in self.currentCells.iterrows():

                if cell.Z == self.sl.value():

                    color = 'red'
                    if cell.cname == self.analyzedCell:
                        color = 'yellow'

                    self.ax2.text(cell.X + 10,
                                  cell.Y + 10,
                                  cell.cname,
                                  color=color,
                                  size='medium',
                                  alpha=.8,
                                  rotation=0)
                    self.ax2.plot(cell.X,
                                  cell.Y,
                                  'o',
                                  color=color,
                                  alpha=.8,
                                  ms=5,
                                  mew=0)

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def changeSpaceTime(self, whatToChange, increment):

        if whatToChange == 'time':

            newCellOutDF = update_cell_out_DF(self.currentCells,
                                              self.cellOutDF, self.tp.value())
            self.cellOutDF = newCellOutDF

            # if they are OK (and not going to negative times), change timepoint
            self.tp.setValue(self.tp.value() + increment)

        if whatToChange == 'space':
            self.sl.setValue(self.sl.value() + increment)
class GUI(QtGui.QWidget):
    
	def __init__(self):

		super(GUI, self).__init__()

		self.setWindowTitle( 'Compute Cell Fluorescence' )
		self.cellNames = ['1.p','4.a','1.pp','4.aa','1.ppa','1.ppp','4.aaa','4.aap','b_1','b_4']
		self.imgpxl = 80
		self.initUI()
    
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

	def initUI(self):
		# SET THE GEOMETRY

		mainWindow = QtGui.QVBoxLayout()
		mainWindow.setSpacing(15)

		fileBox = QtGui.QHBoxLayout()
		spaceBox1 = QtGui.QHBoxLayout()
		rawDataBox = QtGui.QHBoxLayout()

		mainWindow.addLayout(fileBox)
		mainWindow.addLayout(spaceBox1)
		mainWindow.addLayout(rawDataBox)

		Col1 = QtGui.QGridLayout()
		Col2 = QtGui.QHBoxLayout()
		Col3 = QtGui.QVBoxLayout()

		rawDataBox.addLayout(Col1)
		rawDataBox.addLayout(Col2)
		rawDataBox.addLayout(Col3)

		self.setLayout(mainWindow)

		# DEFINE ALL WIDGETS AND BUTTONS

		loadBtn = QtGui.QPushButton('Load DataSet')
		computeBtn = QtGui.QPushButton('Compute current image')
		computeBtn.setFixedWidth(200)
		self.computeAllBtn = QtGui.QPushButton('Compute %s signal for all the images' %'???')
		self.computeAllBtn.setFixedWidth(200)
		saveBtn = QtGui.QPushButton('Save data (F12)')

		tpLbl = QtGui.QLabel('Relative Tp:')
		slLbl = QtGui.QLabel('Slice:')
		fNameLbl = QtGui.QLabel('File name:')
		gridLbl = QtGui.QLabel('Grid size:')

		self.tp = QtGui.QSpinBox(self)
		self.tp.setValue(-5)
		self.tp.setMaximum(100000)

		self.sl = QtGui.QSpinBox(self)
		self.sl.setValue(0)
		self.sl.setMaximum(100000)

		self.gridsize = QtGui.QSpinBox(self)
		self.gridsize.setValue(5)
		self.gridsize.setMaximum(20)

		self.fName = QtGui.QLabel('')

		self._488nmBtn = QtGui.QRadioButton('488nm')
		self._561nmBtn = QtGui.QRadioButton('561nm')
		self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

		self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
		self.sld1.setMaximum(2**16-1)
		self.sld1.setValue(0)
		self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
		self.sld2.setMaximum(2**16)
		self.sld2.setValue(2**16-1)

		self.fig1 = Figure((8.0, 8.0), dpi=100)
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax1 = self.fig1.add_subplot(111)
		self.canvas1 = FigureCanvas(self.fig1)
		self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
		self.canvas1.setFocus()
		self.canvas1.setFixedSize(QtCore.QSize(600,600))
		self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

		self.fig2 = Figure((4.0, 4.0), dpi=100)
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax2 = self.fig2.add_subplot(111)
		self.canvas2 = FigureCanvas(self.fig2)
		self.canvas2.setFixedSize(QtCore.QSize(300,300))
		self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

		# PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

		fileBox.addWidget(loadBtn)
		fileBox.addWidget(saveBtn)

		spaceBox1.addWidget(self.HLine())

		Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
		Col1.addWidget(fNameLbl, 2, 0)
		Col1.addWidget(self.fName, 2, 1)
		Col1.addWidget(self._488nmBtn, 3, 0 )
		Col1.addWidget(self._561nmBtn, 4, 0 )
		Col1.addWidget(self.CoolLEDBtn, 5, 0 )

		Col2.addWidget(self.sld1)
		Col2.addWidget(self.sld2)
		Col2.addWidget(self.canvas1)

		Col3.addWidget(self.canvas2)
		Col1.addWidget(gridLbl,6,0)
		Col1.addWidget(self.gridsize,6,1)
		Col1.addWidget(computeBtn,7,0)
		Col1.addWidget(self.computeAllBtn,8,0)

		self.setFocus()
		self.show()

		# BIND BUTTONS TO FUNCTIONS

		loadBtn.clicked.connect(self.selectWorm)
		saveBtn.clicked.connect(self.saveData)

		self.tp.valueChanged.connect(self.loadNewStack)
		self.sl.valueChanged.connect(self.updateAllCanvas)
		self.sld1.valueChanged.connect(self.updateBC)
		self.sld2.valueChanged.connect(self.updateBC)

		self._488nmBtn.toggled.connect(self.radio488Clicked)
		self._561nmBtn.toggled.connect(self.radio561Clicked)
		self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

		computeBtn.clicked.connect(self.computeFluo)
		self.computeAllBtn.clicked.connect(self.computeAllFluo)

		self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
		self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        

	#-----------------------------------------------------------------------------------------------
	# FORMATTING THE WINDOW
	#-----------------------------------------------------------------------------------------------

	def center(self):
        
		qr = self.frameGeometry()
		cp = QtGui.QDesktopWidget().availableGeometry().center()
		qr.moveCenter(cp)
		self.move(qr.topLeft())
        
	def HLine(self):

		toto = QtGui.QFrame()
		toto.setFrameShape(QtGui.QFrame.HLine)
		toto.setFrameShadow(QtGui.QFrame.Sunken)
		return toto

	def VLine(self):
	    
	    toto = QtGui.QFrame()
	    toto.setFrameShape(QtGui.QFrame.VLine)
	    toto.setFrameShadow(QtGui.QFrame.Sunken)
	    return toto

	def heightForWidth(self, width):

		return width

	#-----------------------------------------------------------------------------------------------
	# BUTTON FUNCTIONS
	#-----------------------------------------------------------------------------------------------

	def selectWorm(self):

		### store the folders
		self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101')#'Y:\\Images')
		self.worm = self.pathDial.split("\\")[-1].split('_')[0]
		self.path = os.path.dirname( self.pathDial )
		self.setWindowTitle('Outline Cells - ' + self.pathDial)

		### give error message if there is no CoolLED movie in the selected folder
		flist = glob.glob( self.pathDial + '\\*_movie.tif' )
		if len(flist)==0:#not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
			QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
			return

		### load parameters and times dataframes
		self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
		self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
		self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )
		self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )
		self.cellOutDF = load_data_frame( self.path, self.worm + '_05cellOut.pickle' )

		# extract some info
		self.compression = self.paramsDF.compression
		self.hatchingtidx = int( self.paramsDF.tidxHatch )

		### if the cellOutline pickle file already exists, load it, otherwise create a blank one
		if os.path.isfile( os.path.join(self.path, self.worm + '_06cellFluo.pickle' ) ):
			self.cellFluoDF = load_data_frame( self.path, self.worm + '_06cellFluo.pickle' )

		else:
			self.cellFluoDF = create_cell_fluo( self.timesDF, self.cellNames )

		# detect available channels
		self.channels = []
		chns = ['CoolLED','488nm','561nm']
		for c in chns:

			if os.path.isfile( os.path.join( self.pathDial, c + '_movie.tif' ) ):

				self.channels.append(c)
		self.currentChannel = self.channels[0]

		### detect size of the cropped images
		tp = first_tidx_pos_all_cells( self.cellPosDF )
		self.prevtp = tp-1
		tRow = self.timesDF.ix[ self.timesDF.tidxRel == tp ].squeeze()
		fileName = os.path.join( self.pathDial, tRow.fName + self.currentChannel + '.tif')
		firststack = load_stack( fileName )
		self.cropsize = firststack.shape[1]
		self.nslices = firststack.shape[0]

		### intialize canvases
		self.initializeCanvas1()
		self.initializeCanvas2()

		### extract current cells already labeled
		self.currentCells = extract_current_cell_fluo( self.cellPosDF, self.cellOutDF, self.cellFluoDF, self.tp.value() )
		self.analyzedCell = '---'

		### update the text of the fileName
		self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == tp, 'fName' ].values[0])

		### set the timepoint to the hatching time
		self.tp.setMinimum(np.min(self.timesDF.tidxRel))
		self.tp.setMaximum(np.max(self.timesDF.tidxRel))

		### set the max slice number
		self.sl.setMaximum( self.nslices-1 )

		if tp != self.tp.value():
			self.tp.setValue( tp )
		else:
			self.loadNewStack()

		if self.currentChannel == 'CoolLED':
			self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
		elif self.currentChannel == '561nm':
			self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
		elif self.currentChannel == '488nm':
			self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more

		# self.pathDial.show()
		self.setFocus()

	def loadNewStack(self):

		# update the cell outline data frame before updating the images and retrireving new cells
		newCellFluoDF = update_cell_fluo_DF( self.currentCells, self.cellFluoDF, self.prevtp )
		self.cellFluoDF = newCellFluoDF
		self.prevtp = self.tp.value()

		# before changing timepoint, print labeled cells and check if they are OK
		tRow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

		### update the text of the fileName
		self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

		print( 'Loading... ', self.pathDial, tRow.fName )

		# calculate the max value of the previous stack
		try:
			prevmax = np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] )
		# if it's the first time a stack is to be loaded (so if there is no previous stack), set it to zero
		except:
			prevmax = 0

		# load all the available stacks - this is the slowest part of the code!!!
		self.stacks = {}
		for ch in self.channels:
			fileName = os.path.join( self.pathDial, tRow.fName + ch + '.tif')
			if os.path.isfile( fileName ):
				# print(MultiImage('X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101\\C02_analyzedImages\\Z003_488nm.tif'))
				# print(fileName, MultiImage( fileName ))
				# self.stacks[ch] = MultiImage( fileName )
				self.stacks[ch] = load_stack( fileName )
			# if there are no files for the timepoint, create a blank image
			else:
				self.stacks[ch] = prevmax*np.ones((self.nslices,self.cropsize,self.cropsize))

		### extract current cells already labeled
		print('Cells in previous tp:', self.currentCells)
		self.currentCells = extract_current_cell_fluo( self.cellPosDF, self.cellOutDF, self.cellFluoDF, self.tp.value() )
		print('Cells in new tp:', self.currentCells)

		# if there are cells labeled and if the previously currently analyzed cell is present, set it as the currently labeled cell and select the right slice
		if len(self.currentCells) > 0:
			print('cells detected')

			### update currently analyzed cell
			if self.analyzedCell not in list( self.currentCells.cname ):
				self.analyzedCell = self.currentCells.cname[0]

			### update slice, if it's the same slice number, manually replot the images
			newslice = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ].values[0]
			if newslice != self.sl.value():
				self.sl.setValue( newslice )

			else:
				self.updateAllCanvas()
		# if no cells are found, manually plot the blank images
		elif len(self.currentCells) == 0:
			self.updateAllCanvas()

		# update the BC
		self.setBCslidersMinMax()            

	def saveData(self):

		save_data_frame( self.cellFluoDF, self.path, self.worm + '_06cellFluo.pickle' )
		self.setFocus()
	    
	def updateAllCanvas(self):
		self.updateCanvas1()
		self.updateCanvas2()
        
	def radio488Clicked(self, enabled):
		# print('radio 488 clicked')

		if enabled:
			if '488nm' in self.channels:
				self.currentChannel = '488nm'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == 'CoolLED':
					self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '561nm':
					self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

	def radio561Clicked(self, enabled):
	    # print('radio 561 clicked')

		if enabled:
			if '561nm' in self.channels:
				self.currentChannel = '561nm'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == 'CoolLED':
					self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '488nm':
					self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

	def radioCoolLEDClicked(self, enabled):
	    # print('radio LED clicked')

		if enabled:
			if 'CoolLED' in self.channels:
				self.currentChannel = 'CoolLED'
				self.setFocus()
				self.updateCanvas1()
			else:
				if self.currentChannel == '561nm':
					self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				elif self.currentChannel == '488nm':
					self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
				QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

	def updateBC(self):
		# change brightness and contrast
		self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  
		self.imgplot2.set_clim( self.sld1.value(), self.sld2.value() )  
		self.canvas1.draw()
		self.canvas2.draw()

	#-----------------------------------------------------------------------------------------------
	# DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
	#-----------------------------------------------------------------------------------------------

	def keyPressEvent(self, event):

		# print(event.key())

		# change timepoint
		if event.key() == QtCore.Qt.Key_Right:
			self.changeSpaceTime( 'time', +1 )

		elif event.key() == QtCore.Qt.Key_Left:
			self.changeSpaceTime( 'time', -1 )

		# change slice
		elif event.key() == QtCore.Qt.Key_Up:
			self.changeSpaceTime( 'space', +1 )
		    
		elif event.key() == QtCore.Qt.Key_Down:
			self.changeSpaceTime( 'space', -1 )

		elif event.key() == QtCore.Qt.Key_Space:

			if len( self.currentCells ) > 0:
				idx = np.mod( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].index + 1, len(self.currentCells) )
				self.analyzedCell = self.currentCells.cname.values[idx][0]
				self.sl.setValue( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ] )

				self.updateAllCanvas()

		self.setFocus()

	def wheelEvent(self,event):
		if self.canvas1.underMouse():
			step = event.step
		else:          
			step = event.delta()/abs(event.delta())
		self.sl.setValue( self.sl.value() + step) 

	#-----------------------------------------------------------------------------------------------
	# ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
	#-----------------------------------------------------------------------------------------------

	def onMouseClickOnCanvas1(self, event):
		if self._488nmBtn.isChecked():
			channel = '488nm'
		elif self._561nmBtn.isChecked():
			channel = '561nm'
		else:
			QtGui.QMessageBox.about(self, 'Warning', 'Select a proper fluorescence channel!')
			return		

		currentCell = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze()
		imgpxl = currentCell.imgPxl
		cell = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze()
		cellPos = extract_3Dpos( cell )
		cellOut = extract_out( cell ) * imgpxl / 1000.

		# calculate new drift
		pos = np.array( [ int(np.round(event.xdata)), int(np.round(event.ydata)) ] )
		drift = np.array([pos[0]-500,pos[1]-500]) * self.imgpxl / 1000.

		### perform flat field correction
		# find gonadpos
		gonadPos = extract_pos( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ].squeeze() )
		# load darkField
		darkField = load_stack( 'X:\\Orca_calibration\\AVG_darkField.tif' )
		# load flatField
		flatField = load_stack( os.path.join( self.path, 'AVG_flatField_'+channel+'.tif' ) )
		medianCorrection = np.median( ( flatField - darkField ) )
		#correct image	
		imgs = self.stacks[self.currentChannel]
		imgsCorr = flat_field_correction( imgs, darkField, flatField, gonadPos )
		imgCorr = imgsCorr[cellPos[2],cellPos[1]-imgpxl/2:cellPos[1]+imgpxl/2+1,cellPos[0]-imgpxl/2:cellPos[0]+imgpxl/2+1]

		### find the new signal
		signal = calculate_fluo_intensity( imgCorr, drift, cellOut )

		# update the current cells
		newCurrentCells = update_current_cell_fluo( self.currentCells, cell, channel, drift, signal )
		self.currentCells = newCurrentCells

		# update the cell outline data frame before updating the images and retrireving new cells
		newCellFluoDF = update_cell_fluo_DF( self.currentCells, self.cellFluoDF, self.tp.value() )
		self.cellFluoDF = newCellFluoDF.copy()

		# update canvas
		self.updateCanvas1()
		self.setFocus()
		# print(event.button,event.xdata,event.ydata)

	#-----------------------------------------------------------------------------------------------
	# UTILS
	#-----------------------------------------------------------------------------------------------

	def setBCslidersMinMax(self):
		self.sld1.setMaximum( np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
		self.sld1.setMinimum(0)
		self.sld2.setMaximum (np.max( [ np.max(self.stacks[ch]) for ch in self.channels ] ) )
		self.sld2.setMinimum(0)

	def initializeCanvas1(self):
		# print('initializing canvas1')

		self.fig1.clf()
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax1 = self.fig1.add_subplot(111)
		self.canvas1.draw()

		# plot the first blank image with the right size
		self.ax1.cla()
		self.imgplot1 = self.ax1.imshow( np.zeros((1000,1000)), cmap = 'gray', interpolation = 'nearest' )

		# remove the white borders
		self.ax1.autoscale(False)
		self.ax1.axis('Off')
		self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

		# plot cell pos and name
		self.text_c1 = []
		self.out_c1 = []
		self.center_c1 = []
		self.outDrift_c1 = []
		self.centerDrift_c1 = []

		# redraw the canvas
		self.canvas1.draw()
		self.setFocus()

	def updateCanvas1(self):
		# print('updating canvas1')

		# clear cell text and points
		# print(self.text1,self.points1)
		for text in self.text_c1:
			text.remove()
		self.text_c1 = []

		for points in self.out_c1:
			self.ax1.lines.remove(points)
		self.out_c1 = []

		for points in self.outDrift_c1:
			self.ax1.lines.remove(points)
		self.outDrift_c1 = []

		for points in self.centerDrift_c1:
			self.ax1.lines.remove(points)
		self.centerDrift_c1 = []

		# if no cells labeled, leave the image blank
		if len( self.currentCells ) == 0:
			self.imgplot1.set_data( np.ones((10,10)) )
			self.canvas1.draw()
			return

		# current cell
		currentCell = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze()

		# extract the zoom
		self.imgpxl = currentCell.imgPxl
		imgpxl = self.imgpxl

		# extract current cell data
		pos = extract_3Dpos( currentCell )

		# plot the image
		self.imgplot1.set_data( self.stacks[self.currentChannel][self.sl.value(),pos[1]-imgpxl/2:pos[1]+imgpxl/2+1,pos[0]-imgpxl/2:pos[0]+imgpxl/2+1] )

		# change brightness and contrast
		self.imgplot1.set_clim( self.sld1.value(), self.sld2.value() )  

		# print cell name
		if pos[2] == self.sl.value():
			self.text_c1.append( self.ax1.text( 10, 50, self.analyzedCell, color='yellow', size='medium', alpha=.8,
					rotation=0, fontsize = 20 ) )

		### draw outline
		outline = extract_out( currentCell )

		# print(self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze())

		if len( outline ) > 1:
			outline = np.vstack( [ outline, outline[0] ] )

		self.out_c1.append( self.ax1.plot( outline[:,0], outline[:,1], '-x', color='yellow', ms=2, alpha=1., lw = .5 )[0] )
		self.center_c1.append( self.ax1.plot( 500, 500, 'o', color = 'yellow', mew = 0. )[0] )

		# draw drifted outline
		if self._488nmBtn.isChecked():
			drift = ( extract_pos488(currentCell) - extract_pos(currentCell) ) * 1000 / imgpxl
		elif self._561nmBtn.isChecked():
			drift = ( extract_pos561(currentCell) - extract_pos(currentCell) ) * 1000 / imgpxl
		else:
			drift = np.array([np.nan,np.nan])
		self.outDrift_c1.append( self.ax1.plot( drift[0] + outline[:,0], drift[1] + outline[:,1], '-x', color='red', ms=2, alpha=1., lw = .5 )[0] )
		self.centerDrift_c1.append( self.ax1.plot( 500 + drift[0], 500 + drift[1], 'o', color = 'red', mew = 0. )[0] )

		# # redraw the canvas
		self.canvas1.draw()
		self.setFocus()

	def initializeCanvas2(self):
		# print('initializing canvas2')

		self.fig2.clf()
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
		self.ax2 = self.fig2.add_subplot(111)
		self.canvas2.draw()

		# plot the first blank image with the right size
		self.ax2.cla()
		self.imgplot2 = self.ax2.imshow( np.zeros((self.cropsize,self.cropsize)), cmap = 'gray' )

		# remove the white borders
		self.ax2.autoscale(False)
		self.ax2.axis('Off')
		self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

		# plot cell pos and name
		self.text_c2 = []
		self.plot_c2 = []

		# redraw the canvas
		self.canvas2.draw()
		self.setFocus()

	def updateCanvas2(self):
		# print('updating canvas2')

		# plot the image
		self.imgplot2.set_data( self.stacks[self.currentChannel][self.sl.value()] )

		# change brightness and contrast
		self.imgplot2.set_clim( self.sld1.value(), self.sld2.value() )  

		# clear cell text and points
		# print(self.text1,self.points1)
		for text in self.text_c2:
			text.remove()
		self.text_c2 = []

		for points in self.plot_c2:
			self.ax2.lines.remove(points)
		self.plot_c2 = []

		# extract current cell data
		for idx, cell in self.currentCells.iterrows():

			if cell.Z == self.sl.value():

				color = 'red'
				if cell.cname == self.analyzedCell:
					color = 'yellow'

				self.text_c2.append( self.ax2.text( cell.X, cell.Y + 18, cell.cname, color=color, size='medium', alpha=.8,
						rotation=0 ) )
				self.plot_c2.append( self.ax2.plot( cell.X, cell.Y, 'o', color=color, alpha = .8, mew = 0 )[0] )


		# redraw the canvas
		self.canvas2.draw()
		self.setFocus()

	def changeSpaceTime(self, whatToChange, increment):

		if whatToChange == 'time':
			self.tp.setValue( self.tp.value() + increment )

		if whatToChange == 'space':
			self.sl.setValue( self.sl.value() + increment )

	def computeFluo( self ):

		if self._488nmBtn.isChecked():
			channel = '488nm'
		elif self._561nmBtn.isChecked():
			channel = '561nm'
		else:
			QtGui.QMessageBox.about(self, 'Warning', 'Select a proper fluorescence channel!')
			return

		path = self.path
		worm = self.worm

		rawImgsPath = os.path.join( path, worm + '_analyzedImages' )

		# load pickle files
		paramsDF = self.paramsDF
		timesDF = self.timesDF
		gpDF = self.gpDF
		currentCells = self.currentCells

		# load darkField
		darkField = load_stack( 'X:\\Orca_calibration\\AVG_darkField.tif' )

		# load flatField
		flatField = load_stack( os.path.join( path, 'AVG_flatField_'+channel+'.tif' ) )
		medianCorrection = np.median( ( flatField - darkField ) )

		# for idx, trow in timesDF.ix[ timesDF.tidxRel == 58 ].iterrows(): ### THIS IS TO TEST A PARTICULAR TIMEPOINT!!!
		trow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

		# if there is the cropped image
		if not os.path.isfile( os.path.join( rawImgsPath, trow.fName + channel + '.tif' ) ):
			QtGui.QMessageBox.about(self, 'Warning', 'No croped image found!')

		else:

			# find all cells labeled in the timepoint
			gonadPos = extract_pos( gpDF.ix[ gpDF.tidx == trow.tidxRel ].squeeze() )

			# load the stack and perform FF correction
			imgs = self.stacks[self.currentChannel]
			imgsCorr = flat_field_correction( imgs, darkField, flatField, gonadPos )

			### for each labeled cell, calculate the signal
			cell = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze()
			cellPos = extract_3Dpos( cell )

			# extract the zoom
			self.imgpxl = cell.imgPxl
			imgpxl = self.imgpxl

			### find the XYpos with maximum intensity
			imgCorr = imgsCorr[cellPos[2],cellPos[1]-imgpxl/2:cellPos[1]+imgpxl/2+1,cellPos[0]-imgpxl/2:cellPos[0]+imgpxl/2+1]

			### if there is an outline
			if is_outline_cell( cell ):

				print('detected cell/background with outline: ', cell.cname)

				cellOut = extract_out( cell ) * self.imgpxl / 1000.

				if not cell.cname[:2] == 'b_':

					## this is for the cells - WITH DRIFT CORRECTION
					_range = self.gridsize.value()
					signals = np.zeros((2*_range+1,2*_range+1))

					for i in np.arange(2*_range+1):
						for j in np.arange(2*_range+1):
							signals[i,j] = calculate_fluo_intensity( imgCorr, np.array([i-_range,j-_range]), cellOut )

					drift = np.array( [ np.where(signals == np.max(signals))[0][0], np.where(signals == np.max(signals))[1][0] ] ) - _range
					# print(drift)
					signal = np.max( signals )

				else:

					### this is for backgrounds in which an outline has been drawn
					signal = calculate_fluo_intensity( imgCorr, np.array([0,0]), cellOut )
					drift = [ 0, 0 ]

			else:

				### if the outline of the background has not been drawn, just take a small area arund its center
				# if cell.cname[:2] == 'b_':

				print('detected background/cell without outline: ', cell.cname)

				signal = calculate_fluo_intensity_bckg( imgsCorr[cellPos[2],:,:], 6, cellPos )

				drift = [ 0, 0 ]

			### update the currentCells dataframe
			newCurrentCells = update_current_cell_fluo( currentCells, cell, channel, drift, signal )
			self.currentCells = newCurrentCells

			# update the cell outline data frame before updating the images and retrireving new cells
			newCellFluoDF = update_cell_fluo_DF( self.currentCells, self.cellFluoDF, self.tp.value() )
			self.cellFluoDF = newCellFluoDF

		self.updateCanvas1()

	def computeAllFluo( self ):

		if self.CoolLEDBtn.isChecked():
			QtGui.QMessageBox.about(self, 'Warning', 'Select a proper fluorescence channel!')
			return

		firsttp = first_tidx_pos_all_cells( self.cellPosDF )
		lasttp = last_tidx_pos_all_cells( self.cellPosDF )

		for idx, trow in self.timesDF.ix[ ( self.timesDF.tidxRel <= lasttp ) & ( self.timesDF.tidxRel >= firsttp ) ].iterrows():
			self.tp.setValue(trow.tidxRel)

			for jdx, cell in self.currentCells.iterrows():
				self.analyzedCell = cell.cname
				self.computeFluo()

		self.tp.setValue( firsttp )
예제 #13
0
파일: ui.py 프로젝트: qristin/qface
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):


        # self._fig = figure(facecolor="white")
        # self._ax = self._fig.add_subplot(111)


        screen = QtGui.QDesktopWidget().screenGeometry() 

        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(screen.width(), screen.height())
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        MainWindow.setCentralWidget(self.centralwidget)

        # self.frame = QtGui.QFrame(self.centralwidget)
        # self.frame.setGeometry(QtCore.QRect(200, 0, 4*320, 4*240))
        # self.frame.setFrameShape(QtGui.QFrame.Box)
        # self.frame.setFrameShadow(QtGui.QFrame.Plain)
        # self.frame.setObjectName(_fromUtf8("frame"))

        # self.gridLayout = QtGui.QGridLayout(self.frame)
        # self.gridLayout.setSpacing(10)
        # self.gridLayout.setObjectName(_fromUtf8("gridLayout"))


        self.videoFrame = QtGui.QLabel(self.centralwidget)
        self.videoFrame.setGeometry(QtCore.QRect(500, 0, 2*320, 2*240))
        self.videoFrame.setObjectName(_fromUtf8("videoFrame"))
        #self.gridLayout.addWidget(self.videoFrame,0,0)
        
        layout = QtGui.QVBoxLayout(self.centralwidget)
        layout.setAlignment(QtCore.Qt.AlignTop)

        self.figure = matplot.figure(figsize=(5, 4), dpi=100)
        matplot.ylim(0,0.5)
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setFixedSize(440, 470)
        self.axes = self.figure.add_subplot(111)
        self.axes.hold(False)
        layout.addWidget(self.canvas)

        self.label1 = QtGui.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        font.setPointSize(70)
        self.label1.setFont(font)
        self.label1.setGeometry(QtCore.QRect(700,600, 800, 200))
        self.label1.setText('')

        # self.histogram = QtGui.QLabel(self.can)
        # self.histogram.setGeometry(QtCore.QRect(500, 400, 2*320, 2*240))
        # self.histogram.setObjectName(_fromUtf8("histogram"))

        # self.label1 = QtGui.QLabel(self.centralwidget)
        # self.label1.setGeometry(QtCore.QRect(1300,100, 200, 10))
        # self.label1.setText('TEST')

        # self.label2 = QtGui.QLabel(self.centralwidget)
        # self.label2.setGeometry(QtCore.QRect(1300,200, 200, 10))
        # self.label2.setText('TEST')

        # self.label3 = QtGui.QLabel(self.centralwidget)
        # self.label3.setGeometry(QtCore.QRect(1300,300, 200, 10))
        # self.label3.setText('TEST')

        # self.label4 = QtGui.QLabel(self.centralwidget)
        # self.label4.setGeometry(QtCore.QRect(1300,400, 200, 10))
        # self.label4.setText('TEST')

        # self.label5 = QtGui.QLabel(self.centralwidget)
        # self.label5.setGeometry(QtCore.QRect(1300,500, 200, 10))
        # self.label5.setText('TEST')

        

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.videoFrame.setText(QtGui.QApplication.translate("MainWindow", "TextLabel", None, QtGui.QApplication.UnicodeUTF8))
예제 #14
0
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'Mark Gonad' )
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Relative Tp:')
        fNameLbl = QtGui.QLabel('File name:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMinimum(-100000)
        self.tp.setMaximum(100000)

        self.fName = QtGui.QLabel('')
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.fName, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 2, 0 )
        Col1.addWidget(self._561nmBtn, 3, 0 )
        Col1.addWidget(self.CoolLEDBtn, 4, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)
        
        self.setFocus()

        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.updateCanvas1)
        self.sld1.valueChanged.connect(self.updateCanvas1)
        self.sld2.valueChanged.connect(self.updateCanvas1)

        self._488nmBtn.toggled.connect(self.radio488Clicked)
        self._561nmBtn.toggled.connect(self.radio561Clicked)
        self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'C:\\Users\\Nicola\\Dropbox\\PhD\\Codes\\test')#Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname( self.pathDial )
        self.setWindowTitle('Body Length Analysis - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        flist = glob.glob( self.pathDial + '\\*_movie.tif' )
        if len(flist)==0:#not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
            QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
            return

        ### load all movies (without timestamps, we will add it later on)
        self.channels = {}
        
        if os.path.isfile( os.path.join( self.pathDial, '488nm_movie.tif' ) ):
            self.channels['488nm'] = load_stack( os.path.join( self.pathDial, '488nm_movie.tif') )
        
        if os.path.isfile( os.path.join( self.pathDial, '561nm_movie.tif') ):
            self.channels['561nm'] = load_stack( os.path.join( self.pathDial, '561nm_movie.tif') )
        
        if os.path.isfile( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) ):
            self.channels['CoolLED'] = load_stack( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) )
        print(list(self.channels.keys())[0])
        if 'CoolLED' in self.channels.keys():
            self.currentChannel = 'CoolLED'
        else:
            self.currentChannel = list(self.channels.keys())[0]

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
        self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
        
        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int( self.paramsDF.tidxHatch )

        ### if the gonadPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile( os.path.join(self.path, self.worm + '_02gonadPos.pickle' ) ):
            self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )
        
        else:
            self.gpDF = create_gonad_pos( self.timesDF )
        
        tp = 0

        ### update the text of the fileName
        self.fName.setText(self.timesDF.ix[self.timesDF.tidxRel == 0, 'fName'].values[0])

        ### initialize the figure.astype(np.uint8)
        self.initializeCanvas1()

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))

        if tp != self.tp.value():
            self.tp.setValue( 0 )

        self.setBCslidersMinMax()   # this updates the canvas, only once!
        self.CoolLEDBtn.setChecked(True) # this also updates the canvas, only once!

        self.setFocus()

    def saveData(self):

        save_data_frame( self.gpDF, self.path, self.worm + '_02gonadPos.pickle' )
        
    def radio488Clicked(self, enabled):
        # print('radio 488 clicked')

        if enabled:
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

    def radio561Clicked(self, enabled):
        # print('radio 561 clicked')

        if enabled:
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

    def radioCoolLEDClicked(self, enabled):
        # print('radio LED clicked')

        if enabled:
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(True)    # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def wheelEvent(self,event):

        if self.canvas1.underMouse():
            step = event.step
        
        else:          
            step = event.delta()/abs(event.delta())
        
        self.tp.setValue( self.tp.value() + step ) 
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0] )

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):
        
        # print(event.button,event.xdata,event.ydata)
        
        x = event.xdata
        y = event.ydata

        if event.button == 1:

            # left button: add a point to the outline
            gonadPos = ( np.array( [ x, y ] ) * self.compression ).astype( np.uint16 )

        if event.button == 3:

            gonadPos = [ np.nan, np.nan ]

        # update the dataframe with the new gonadPos
        self.gpDF.ix[ self.gpDF.tidx == self.tp.value(), 'X' ] = gonadPos[0]
        self.gpDF.ix[ self.gpDF.tidx == self.tp.value(), 'Y' ] = gonadPos[1]

        # print( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ] )
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def setBCslidersMinMax(self):
        self.sld1.setMaximum( np.max( [ np.max(self.channels[key]) for key in self.channels.keys() ] ) )
        self.sld1.setMinimum(0)
        self.sld2.setMaximum( np.max( [ np.max(self.channels[key]) for key in self.channels.keys() ] ) )
        self.sld2.setMinimum(0)

    def initializeCanvas1(self):
        print('initializing canvas1... ')
        
        # plot the image
        self.ax1.cla()
        size = 2048 / self.compression
        self.imgplot = self.ax1.imshow( np.zeros((size,size)), cmap = 'gray' )
        
        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = [np.nan,np.nan]
        self.pointsplot, = self.ax1.plot( gonadPos[0], gonadPos[1], 'o', color='red', ms=10, mew=0, alpha=.5, lw = 0 ) 

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.textplot = self.ax1.text( 5, 15, '--.--', color = 'red' )     

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
        
    def updateCanvas1(self):
        # print('updating canvas1... ')
        
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0] )

        # plot the image
        self.imgplot.set_data( self.channels[self.currentChannel][self.tp.value() + self.hatchingtidx] )
        
        # change brightness and contrast
        self.imgplot.set_clim( self.sld1.value(), self.sld2.value() )  

        # print gonad position
        gonadPos = extract_pos( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ].squeeze() ) / self.compression
        if len( gonadPos.shape ) > 0:
            self.pointsplot.set_xdata( gonadPos[0] ) 
            self.pointsplot.set_ydata( gonadPos[1] ) 
            plt.draw()

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.textplot.set_text( '%.2f' % self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ].values[0] )

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()
예제 #15
0
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'Label Cells' )
        self.cellNames = ['1.p','4.a','1.pp','4.aa','1.ppa','1.ppp','4.aaa','4.aap','b_1','b_4']
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300,300))
        self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0 )
        Col1.addWidget(self._561nmBtn, 4, 0 )
        Col1.addWidget(self.CoolLEDBtn, 5, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        Col3.addWidget(self.cellTbl)
        Col3.addWidget(self.canvas2)
        
        self.setFocus()
        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname( self.pathDial )
        self.setWindowTitle('Mark Cells - ' + self.pathDial)
        
        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) ):
            QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
            return

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
        self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
        self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int( self.paramsDF.tidxHatch )

        ### if the cellPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile( os.path.join(self.path, self.worm + '_04cellPos.pickle' ) ):
            self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )
        
        else:
            self.cellPosDF = create_cell_pos( self.timesDF, self.cellNames )

        ### load all movies (without timestamps, we will add it later on)
        self.LEDmovie = load_stack( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) )

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue( 0 )

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos( self.cellPosDF, self.tp.value() )

        # detect available channels
        self.channels = []
        chns = ['CoolLED','488nm','561nm']
        for c in chns:

            if os.path.isfile( os.path.join( self.pathDial, c + '_movie.tif' ) ):

                self.channels.append(c)
        self.currentChannel = self.channels[0]

        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])
        
        self.loadNewStack()

        # self.pathDial.show()
        self.updateAllCanvas()
        self.setFocus()

    def loadNewStack(self):

        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

        print( 'Loading... ', self.pathDial, tRow.fName )

        # load all the available stacks
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join( self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile( fileName ):
                self.stacks[ch] = load_stack( fileName )

        if len( self.stacks.keys() ) > 0:
            # print(self.stacks.keys(), self.stacksStraight)
            self.sl.setMaximum(self.stacks[self.currentChannel].shape[0]-1)

            self.setBCslidersMinMax()
        
        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos( self.cellPosDF, self.tp.value() )

        # self.updateTable()
        self.updateAllCanvas()

    def saveData(self):
        
        if self.checkConsistencyCellNames():
            save_data_frame( self.cellPosDF, self.path, self.worm + '_04cellPos.pickle' )        
        else:
            QtGui.QMessageBox.about(self,'Warning!','There is a mistake in the cell labels!')
        self.setFocus()
        
    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        self.updateCanvas2()
        
    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):
        
        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime( 'time', +1 )

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime( 'time', -1 )

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime( 'space', +1 )
            
        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime( 'space', -1 )

        # key press on cropped image
        if self.canvas1.underMouse():
            self.onKeyPressOnCanvas1(event)
            
        self.setFocus()

    def wheelEvent(self,event):
        if self.canvas1.underMouse():
            step = event.step
        else:          
            step = event.delta()/abs(event.delta())
        self.sl.setValue( self.sl.value() + step) 

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas1(self, event):
        
        motherCells = [ QtCore.Qt.Key_1, QtCore.Qt.Key_4, QtCore.Qt.Key_B ]
        daughterCells = [ QtCore.Qt.Key_A, QtCore.Qt.Key_P ]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.stacks[self.currentChannel][self.sl.value()].shape
        canshape = self.canvas1.size()
        cf = imgshape[0]/canshape.width()
        refpos = self.canvas1.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([ int( refpos.x() * cf ), int( refpos.y() * cf )])
        refpos = np.append(refpos,self.sl.value())

        ### find the closest cell to the cursor
        idx = closer_cell( refpos.astype( np.uint16 ), self.currentCells )

        ### assign the name to the cell
        if any( [ event.key() == cn for cn in motherCells ] ):
            # if labeling bckg, add the 1 or 2 to the name
            if self.currentCells.ix[ idx, 'cname' ] == 'b_':
                self.currentCells.ix[ idx, 'cname' ] += QtGui.QKeySequence(event.key()).toString().lower()
            else:
                # if not, rename the cell from scratch
                if event.key() == QtCore.Qt.Key_B:
                    self.currentCells.ix[ idx, 'cname' ] = QtGui.QKeySequence(event.key()).toString().lower() + '_'
                else:
                    self.currentCells.ix[ idx, 'cname' ] = QtGui.QKeySequence(event.key()).toString().lower() + '.'

        # add the anterior/posterior to the cell name
        elif any( [ event.key() == cp for cp in daughterCells ] ):
            # don't do it if labeling background (bckg doesn't have a/p!)
            if self.currentCells.ix[ idx, 'cname' ] == 'b_':
                return
            else:
                self.currentCells.ix[ idx, 'cname' ] += QtGui.QKeySequence(event.key()).toString().lower()
        
        # remove the last entry of the name with backspace                
        elif event.key() == QtCore.Qt.Key_Backspace:
            self.currentCells.ix[ idx, 'cname' ] = self.currentCells.ix[ idx, 'cname' ][:-1]

        self.updateCanvas1()
        self.setFocus()

    def onMouseClickOnCanvas1(self, event):

        refpos = np.array( [ event.xdata, event.ydata, self.sl.value() ] )  

        if event.button == 1:

            # create an empty cell in the currentCells df: the only entries are tidx, xyzpos and cname
            newcell = create_single_cell_pos( refpos.astype(np.uint16), self.tp.value() )
            self.currentCells = pd.concat( [ self.currentCells, newcell ] )
            
        elif event.button == 3:

            # remove a cell (the closest to the cursor at the moment of right-click)
            idx = closer_cell( refpos.astype(np.uint16), self.currentCells )
            self.currentCells = self.currentCells.drop( [ idx ] )

        self.currentCells = self.currentCells.reset_index(drop=True)
        
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.stacks[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.stacks[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.currentChannel]))
        self.sld2.setValue(np.max(self.stacks[self.currentChannel]))
        
    def updateCanvas1(self):

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        if len( self.stacks.keys() ) == 0:
            # if no images are found, leave the canvas empty
            return

        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow( self.stacks[self.currentChannel][self.sl.value()], cmap = 'gray' )
        
        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # cell text on the image
        for idx, cell in self.currentCells.iterrows():

            if cell.Z == self.sl.value():

                self.ax1.text( cell.X, cell.Y + 18, cell.cname, color='red', size='medium', alpha=.8,
                        rotation=0 )
                self.ax1.plot( cell.X, cell.Y, 'o', color='red', alpha = .8, mew = 0 )

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(),self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(),self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())  

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas2(self):
        
        # plot the image
        self.ax2.cla()
        imgplot = self.ax2.imshow( self.LEDmovie[ self.tp.value() + self.hatchingtidx ], cmap = 'gray' )
        
        # remove the white borders and plot outline and spline
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = extract_pos( self.gpDF.ix[ self.gpDF.tidx == self.tp.value() ].squeeze() ) / self.compression
        self.ax2.plot( gonadPos[0], gonadPos[1], 'o', color='red', ms=10, mew=0, alpha=.5, lw = 0 )      

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.ax2.text( 5, 25, '%.2f' % self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ].values[0], color = 'red' )     

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def checkConsistencyCellNames( self ):
        ### check consistency of cell names
        tp = self.tp.value()

        # if no cells are labeled (currentCells df is empty), remove all labeled cells in the cellPosDF and return
        if len( self.currentCells ) == 0:
            newCellPosDF = update_cell_pos_DF( self.currentCells, self.cellPosDF, tp )
            correctCellNames = True

        if len( self.currentCells ) > 0:

            correctCellNames = check_cell_names( self.currentCells, self.cellNames )

            # if cells are not properly labeled, give a Warning
            if not correctCellNames:
                QtGui.QMessageBox.about(self,'Warning!','There is a mistake in the cell labels!')

            # else, update final cellPosDF and return OK
            else:
                newCellPosDF = update_cell_pos_DF( self.currentCells, self.cellPosDF, tp )
                self.cellPosDF = newCellPosDF

        return correctCellNames

    def changeSpaceTime(self, whatToChange, increment):


        if whatToChange == 'time':

            # before changinf timepoint, print labeled cells and check if they are OK
            print( self.currentCells )

            # if they are OK (and not going to negative times), change timepoint
            if self.checkConsistencyCellNames() and ( self.tp.value() + increment ) >= 0 :
                self.tp.setValue( self.tp.value() + increment )

        if whatToChange == 'space':
            self.sl.setValue( self.sl.value() + increment )
예제 #16
0
class Window(QtGui.QMainWindow):
	
	win_ry = 900
	win_cx = 1600
	saved = 0
	
	circTick = 0
	gateNames = ("X","Y","Z","H","S","T","Rx","Ry","Rz","CX","CZ","Tf",u"\u23F2",u"\U0001F441")
	gateCodes = ("x","y","z","h","s","t","rx","ry","rz","cnot","cphase","toffoli","measure","display")
	gateSets = ("All","Universal {H, Tf}","Universal {1Qb, CX}")
	gateMasks = ("11111111111111","00010000000111","11111100010011")
	drawGateQ = []
	drawMaxQ = 0
	delGateLno = 0
		
	def __init__(self):

		super(Window,self).__init__()
		self.setGeometry(150,50,self.win_cx,self.win_ry)	# window placement and size (TBD: variable/fullscreen)
		self.setWindowTitle("Quantum Integrated Development Environment")
		self.setWindowIcon(QtGui.QIcon('icons/app.png'))	# (TBD: decide logo)

		self.menu()
		self.quickaccess()
		self.stsmsg = self.statusBar()
		self.stsmsg.showMessage('Create new project or Open existing project')
		self.show()
	
	########################## MAIN MENUS ##########################

	def menu(self):

		self.mainMenu = self.menuBar()
		self.menuFile = self.mainMenu.addMenu('&File')
		self.fileMenu()
		self.menuView = self.mainMenu.addMenu('&View')
		self.viewMenu()
		self.menuHelp = self.mainMenu.addMenu('&Help')
		self.helpMenu()

	#~~~~~~~~~~~~~~~~~~~~~~~~~ file menu ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def fileMenu(self):

		self.menuFileNewProj = QtGui.QAction("&New Project",self)
		self.menuFileNewProj.setShortcut("Ctrl+N")
		self.menuFileNewProj.triggered.connect(self.newProject)
		self.menuFile.addAction(self.menuFileNewProj)

		self.menuFile.addSeparator()

		self.menuFileOpenProj = QtGui.QAction("&Open Project",self)
		self.menuFileOpenProj.setShortcut("Ctrl+O")
		self.menuFileOpenProj.triggered.connect(self.openProject)
		self.menuFile.addAction(self.menuFileOpenProj)

		self.menuFileOpenO = QtGui.QAction("&Import OpenQL",self)
		self.menuFileOpenO.triggered.connect(self.importOpenql)
		self.menuFile.addAction(self.menuFileOpenO)
		self.menuFileOpenO.setEnabled(False)

		self.menuFileOpenQ = QtGui.QAction("&Import QASM",self)
		self.menuFileOpenQ.triggered.connect(self.importQasm)
		self.menuFile.addAction(self.menuFileOpenQ)
		self.menuFileOpenQ.setEnabled(False)

		self.menuFileOpenC = QtGui.QAction("&Import QCircuit",self)
		self.menuFileOpenC.triggered.connect(self.TBD)
		self.menuFile.addAction(self.menuFileOpenC)
		self.menuFileOpenC.setEnabled(False)							# (TBD)

		self.menuFile.addSeparator()

		self.menuFileSaveP = QtGui.QAction("&Save Project",self)
		self.menuFileSaveP.setShortcut("Ctrl+S")
		self.menuFileSaveP.triggered.connect(self.saveProject)
		self.menuFile.addAction(self.menuFileSaveP)
		self.menuFileSaveP.setEnabled(False)

		self.menuFileSaveO = QtGui.QAction("&Export OpenQL",self)
		self.menuFileSaveO.triggered.connect(self.exportOpenql)
		self.menuFile.addAction(self.menuFileSaveO)
		self.menuFileSaveO.setEnabled(False)

		self.menuFileSaveQ = QtGui.QAction("&Export QASM",self)
		self.menuFileSaveQ.triggered.connect(self.exportQasm)
		self.menuFile.addAction(self.menuFileSaveQ)
		self.menuFileSaveQ.setEnabled(False)

		self.menuFileSaveC = QtGui.QAction("&Export QCircuit",self)
		self.menuFileSaveC.triggered.connect(self.TBD)
		self.menuFile.addAction(self.menuFileSaveC)
		self.menuFileSaveC.setEnabled(False)							# (TBD)

		self.menuFileExport = QtGui.QAction("&Export QCircuit Image",self)
		self.menuFileExport.triggered.connect(self.exportQCircImg)
		self.menuFile.addAction(self.menuFileExport)
		self.menuFileExport.setEnabled(False)

		self.menuFile.addSeparator()

		self.menuFileExit = QtGui.QAction("&Exit",self)
		self.menuFileExit.setShortcut("Ctrl+Q")
		self.menuFileExit.triggered.connect(self.closeApp)
		self.menuFile.addAction(self.menuFileExit)

	def closeApp(self):
		if self.saved == 0:
			choice = QtGui.QMessageBox.question(self,'sanity check',"Quit?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
			if choice == QtGui.QMessageBox.Yes:
				sys.exit()
			else:
				pass

	def newProject(self):

		self.dirProj = str(QtGui.QFileDialog.getExistingDirectory(self,'New Project Directory'))
		self.nameProj = self.dirProj[self.dirProj.rindex('/')+1:]
		self.configProj = {'name':self.nameProj}
		self.configProj.update({'path':self.dirProj})
		self.centerLayout()
		file = open(self.fileQCirc,'w')
		file.write("")
		file.close()

	def saveProject(self):

		self.configProjJson = self.dirProj+'/'+self.nameProj+'.qide'
		with open(self.configProjJson,'w') as file:
			json.dump(self.configProj,file,indent=2)
		file.close()

		self.saveOpenql()
		self.saveQasm()

	def saveOpenql(self):

		file = open(self.fileOpenql,'w')
		text = self.textOpenql.toPlainText()
		file.write(text)
		file.close()

	def saveQasm(self):

		file = open(self.fileQasm,'w')
		text = self.textQasm.toPlainText()
		file.write(text)
		file.close()

	def openProject(self):

		self.configProjJson = QtGui.QFileDialog.getOpenFileName(self,'Open QuIDE Project File','',"*.qide")
		print(self.configProjJson)
		pathCnfg = str(self.configProjJson)
		self.dirProj = pathCnfg[:pathCnfg.rindex('/')]
		nameCnfg = pathCnfg[pathCnfg.rindex('/')+1:]
		self.nameProj = nameCnfg[:nameCnfg.rindex('.')]	
		self.configProj = {'name':self.nameProj}
		self.configProj.update({'path':self.dirProj})
		self.centerLayout()
		self.openOpenql()
		self.openQasm()
		self.openQcirc()

	def openOpenql(self):
		
		file = open(self.fileOpenql,'r')
		with file:
			text = file.read()
			self.textOpenql.setText(text)

	def openQasm(self):

		file = open(self.fileQasm,'r')
		with file:
			text = file.read()
			self.textQasm.setText(text)

	def openQcirc(self):

		self.circReset()
		gates = len(self.gateNames)
		file = open(self.fileQCirc,'r')
		self.drawMaxQ = 1	# For drawing measure and display, if circuit was not executed before
		for line in iter(file):

			# Qubits
			ptrn = re.compile('^qubits\s(\d+)',re.IGNORECASE)
			mtch = ptrn.search(line)
			if mtch != None:
				self.drawMaxQ = int(mtch.group(1))

			# Single Qubit Gates
			for g in range(0,9):
				ptrn = re.compile('^\s*'+self.gateNames[g]+'\sq(\d+)',re.IGNORECASE)
				mtch = ptrn.search(line)
				if mtch != None:
					self.circGate(g,[int(mtch.group(1))])
			# Two Qubit Gates
			ptrn = re.compile("cnot"+'\sq(\d+),q(\d+)',re.IGNORECASE)
			mtch = ptrn.search(line)
			if mtch != None:
				self.circGate(9,[int(mtch.group(1)),int(mtch.group(2))])
			# Three Qubit Gates
			ptrn = re.compile("toffoli"+'\sq(\d+),q(\d+),q(\d+)',re.IGNORECASE)
			mtch = ptrn.search(line)
			if mtch != None:
				self.circGate(11,[int(mtch.group(1)),int(mtch.group(2)),int(mtch.group(3))])
			# Measure
			ptrn = re.compile("measure")
			mtch = ptrn.search(line)
			if mtch != None:
				self.circGate(12,[0])
			# Display
			ptrn = re.compile("display")
			mtch = ptrn.search(line)
			if mtch != None:
				self.circGate(13,[0])
		# self.circuit.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)

	def importOpenql(self):

		name = QtGui.QFileDialog.getOpenFileName(self,'Import OpenQL File','',"*.py")
		file = open(name,'r')
		with file:
			text = file.read()
			self.textOpenql.setText(text)			

	def importQasm(self):

		name = QtGui.QFileDialog.getOpenFileName(self,'Import QASM File','',"*.qasm")
		file = open(name,'r')
		with file:
			text = file.read()
			self.textQasm.setText(text)

	def exportOpenql(self):
		
		name = QtGui.QFileDialog.getSaveFileName(self,'Export OpenQL File','',"*.py")
		file = open(name,'w')
		text = self.textOpenql.toPlainText()
		file.write(text)
		file.close()
		
	def exportQasm(self):
		
		name = QtGui.QFileDialog.getSaveFileName(self,'Export QASM File','',"*.qasm")
		file = open(name,'w')
		text = self.textQasm.toPlainText()
		file.write(text)
		file.close()

	def exportQCircImg(self):
		
		name = QtGui.QFileDialog.getSaveFileName(self,'Export Circuit Image','',"*.png")
		pixmap = QtGui.QPixmap(self.qcircuit.sceneRect().width(),self.qcircuit.sceneRect().height())
		painter = QtGui.QPainter(pixmap)
		painter.setRenderHint(QtGui.QPainter.Antialiasing)
		self.qcircuit.render(painter)
		painter.end()
		pixmap.save(name)

	#~~~~~~~~~~~~~~~~~~~~~~~~~ view menu ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def viewMenu(self):
	
		self.menuViewThemes = QtGui.QMenu("&Themes",self)
		self.menuView.addMenu(self.menuViewThemes)

		qtactn = QtGui.QAction("gtk+",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("gtk+")))
		self.menuViewThemes.addAction(qtactn)

		qtactn = QtGui.QAction("motif",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("motif")))
		self.menuViewThemes.addAction(qtactn)
		
		qtactn = QtGui.QAction("plastique",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("plastique")))
		self.menuViewThemes.addAction(qtactn)
		
		qtactn = QtGui.QAction("windows",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("windows")))
		self.menuViewThemes.addAction(qtactn)
		
		qtactn = QtGui.QAction("cleanlooks",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("cleanlooks")))
		self.menuViewThemes.addAction(qtactn)
		
		qtactn = QtGui.QAction("cde",self.menuViewThemes)
		qtactn.triggered.connect(lambda: QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("cde")))
		self.menuViewThemes.addAction(qtactn)

	#~~~~~~~~~~~~~~~~~~~~~~~~~ help menu ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def helpMenu(self):

		self.menuHelpTutorial = QtGui.QMenu("&Learn",self)
		self.menuHelp.addMenu(self.menuHelpTutorial)

		qtactn = QtGui.QAction("&QuIDE and QCirc",self.menuViewThemes)
		qtactn.triggered.connect(self.learnQuide)
		self.menuHelpTutorial.addAction(qtactn)

		qtactn = QtGui.QAction("&OpenQL",self.menuViewThemes)
		qtactn.triggered.connect(self.learnOpenql)
		self.menuHelpTutorial.addAction(qtactn)

		qtactn = QtGui.QAction("&QX-Sim",self.menuViewThemes)
		qtactn.triggered.connect(self.learnQxsim)
		self.menuHelpTutorial.addAction(qtactn)

		self.menuHelp.addSeparator()
		
		self.menuHelpRelease = QtGui.QAction("&Release Notes",self)
		self.menuHelpRelease.triggered.connect(self.TBD)
		self.menuHelp.addAction(self.menuHelpRelease)
		self.menuHelpRelease.setEnabled(False)				# (TBD)
		
		self.menuHelpUpdate = QtGui.QAction("&Update",self)
		self.menuHelpUpdate.triggered.connect(self.TBD)
		self.menuHelp.addAction(self.menuHelpUpdate)
		self.menuHelpUpdate.setEnabled(False)				# (TBD)
		
		self.menuHelp.addSeparator()
		
		self.menuHelpLicense = QtGui.QAction("&License",self)
		self.menuHelpLicense.triggered.connect(self.license)
		self.menuHelp.addAction(self.menuHelpLicense)
		
		self.menuHelpAbout = QtGui.QAction("&About",self)
		self.menuHelpAbout.triggered.connect(self.about)
		self.menuHelp.addAction(self.menuHelpAbout)

	def learnQuide(self):

		QtGui.QMessageBox.about(self,"Learn QuIDE & QCirc","Visit : https://gitlab.com/prince-ph0en1x/QIDE")

	def learnOpenql(self):

		QtGui.QMessageBox.about(self,"Learn OpenQL","Visit : https://gitlab.com/qutech-ce/openql")

	def learnQxsim(self):

		QtGui.QMessageBox.about(self,"Learn OpenQL","Visit : https://gitlab.com/qutech-ce/qx-simulator")

	def license(self):

		QtGui.QMessageBox.about(self,"License",open("license.txt",'r').read())

	def about(self):

		QtGui.QMessageBox.about(self,"About",open("about.txt",'r').read())

	#~~~~~~~~~~~~~~~~~~~~~~~~~ shortcuts ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def quickaccess(self):

		self.toolBar = self.addToolBar("QuickAccess")

		extractAction = QtGui.QAction(QtGui.QIcon('icons/plot5.png'),'Custom Plot',self)
		extractAction.triggered.connect(self.TBD)
		self.toolBar.addAction(extractAction)
		extractAction.setEnabled(False)

		extractAction = QtGui.QAction(QtGui.QIcon('icons/layout3.png'),'Custom Layout',self)
		extractAction.triggered.connect(self.TBD)
		self.toolBar.addAction(extractAction)
		extractAction.setEnabled(False)
		
		extractAction = QtGui.QAction(QtGui.QIcon('icons/uc3.png'),'View Microcode',self)
		extractAction.triggered.connect(self.TBD)
		self.toolBar.addAction(extractAction)
		extractAction.setEnabled(False)
		
	########################## MAIN LAYOUT ##########################

	def centerLayout(self):

		self.menuFileSaveP.setEnabled(True)
		self.stsmsg.showMessage('Current Project Directory : '+self.dirProj)
		self.fileOpenql = self.dirProj+"/"+self.nameProj+".py"
		self.fileQasm = self.dirProj+"/"+self.nameProj+".qasm"
		self.fileQCirc = self.dirProj+"/"+self.nameProj+".qcir"
		
		self.centralWidget = QtGui.QWidget(self)
		self.setCentralWidget(self.centralWidget)
		self.topLayoutV = QtGui.QVBoxLayout(self.centralWidget)
		
		self.topLayoutH1 = QtGui.QHBoxLayout()
		self.openqlEditor()
		self.qasmEditor()
		self.topLayoutV.addLayout(self.topLayoutH1,QtCore.Qt.AlignBottom)
		
		self.topLayoutH2 = QtGui.QHBoxLayout()
		self.gateset()
		self.circuitEditor()
		self.resultTabs()     
		self.topLayoutV.addLayout(self.topLayoutH2,QtCore.Qt.AlignBottom)

		self.menuFileOpenO.setEnabled(True)
		self.menuFileOpenQ.setEnabled(True)
		# self.menuFileOpenC.setEnabled(True)
		self.menuFileSaveO.setEnabled(True)
		self.menuFileSaveQ.setEnabled(True)
		# self.menuFileSaveC.setEnabled(True)
		self.menuFileExport.setEnabled(True)

	#~~~~~~~~~~~~~~~~~~~~~~~~~ openql ed ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def openqlEditor(self):

		self.topLayoutH1.addSpacing(90) 
		
		self.textOpenql = QtGui.QTextEdit(self)
		self.textOpenql.setFixedSize(990,415)
		self.textOpenql.setText("OpenQL Editor")
		self.topLayoutH1.addWidget(self.textOpenql,QtCore.Qt.AlignRight)

		self.btnLayoutOQ = QtGui.QVBoxLayout()
		
		self.btnO2Q = QtGui.QPushButton(u"\u2192",self)
		self.btnO2Q.clicked.connect(self.convO2Q)
		self.btnO2Q.setFixedSize(30,30)
		self.btnLayoutOQ.addWidget(self.btnO2Q,0,QtCore.Qt.AlignBottom)

		self.btnQ2O = QtGui.QPushButton(u"\u2190",self)
		self.btnQ2O.clicked.connect(self.TBD)
		self.btnQ2O.setFixedSize(30,30)
		self.btnLayoutOQ.addWidget(self.btnQ2O,QtCore.Qt.AlignBottom)
		self.btnQ2O.setEnabled(False)

		self.btnLayoutOQ.addSpacing(40) 

		self.topLayoutH1.addLayout(self.btnLayoutOQ,QtCore.Qt.AlignCenter)
		self.editorConfig()

	def editorConfig(self):

		# (TBD : Load from project json)
		self.textOpenql.setLineWrapMode(0)
		self.highlight = syntax.PythonHighlighter(self.textOpenql.document())
		self.textOpenql.setTabStopWidth(40)
		self.textOpenql.setFontFamily("Monospace")

	def convO2Q(self):   

		self.saveOpenql()
		self.saveQasm()		# current QASM backup
		os.system("python3 "+self.fileOpenql+" > "+self.dirProj+"/"+"logO2Q.txt 2>&1")
		name = "test_output/qg.qasm"       # (TBD: get output file name from openql)
		file = open(name,'r')
		with file:
			text = file.read()
			self.textQasm.setText(text)
		file.close()
		text = open(self.dirProj+"/"+"logO2Q.txt",'r').read()
		self.textLog.setText(text)
		self.tabLayout.setCurrentWidget(self.textLog)

	#~~~~~~~~~~~~~~~~~~~~~~~~~ qasm ed ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def qasmEditor(self):

		self.qasmLayout = QtGui.QVBoxLayout()
		
		self.textQasm = QtGui.QTextEdit(self)
		self.textQasm.setFixedSize(460,380)
		self.textQasm.setText("QASM Editor")
		self.textQasm.setLineWrapMode(0)
		self.qasmLayout.addWidget(self.textQasm,0,QtCore.Qt.AlignRight)

		self.btnLayoutQ = QtGui.QHBoxLayout()

		self.btnQ2C = QtGui.QPushButton(u"\u2193",self)
		self.btnQ2C.clicked.connect(self.convQ2C)
		self.btnQ2C.setFixedSize(30,30)
		self.btnLayoutQ.addWidget(self.btnQ2C,QtCore.Qt.AlignLeft)
		
		self.btnC2Q = QtGui.QPushButton(u"\u2191",self)
		self.btnC2Q.clicked.connect(self.convC2Q)
		self.btnC2Q.setFixedSize(30,30)
		self.btnLayoutQ.addWidget(self.btnC2Q,QtCore.Qt.AlignLeft)
		
		self.btnLayoutQ.addSpacing(40) 

		self.btnQ2G = QtGui.QPushButton(u"\u2193",self)
		self.btnQ2G.clicked.connect(self.convQ2G)
		self.btnQ2G.setFixedSize(30,30)
		self.btnLayoutQ.addWidget(self.btnQ2G,0,QtCore.Qt.AlignLeft)
		
		self.qasmLayout.addLayout(self.btnLayoutQ,QtCore.Qt.AlignRight)

		self.topLayoutH1.addLayout(self.qasmLayout,QtCore.Qt.AlignRight)

	def convQ2G(self):

		self.saveQasm()
		os.system("./qx_simulator_1.0.beta_linux_x86_64 "+self.fileQasm+" > "+self.dirProj+"/"+"logQ2G.txt")
		file = open(self.dirProj+"/"+"logQ2G.txt",'r')
		self.plotOutput(file)
		file.close()
		text = open(self.dirProj+"/"+"logQ2G.txt",'r').read()
		self.textLog.setText(text)
		self.tabLayout.setCurrentWidget(self.textLog)

	def convQ2C(self):
		
		self.saveQasm()
		file = open(self.fileQasm,'r')
		with file:
			text = file.read()
		file.close()
		file = open(self.fileQCirc,'w')
		file.write(text)
		file.close()
		self.openQcirc()
		
	#~~~~~~~~~~~~~~~~~~~~~~~~~ qcircuit ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def circuitEditor(self):

		penG = QtGui.QPen(QtCore.Qt.blue)
		fill = QtGui.QBrush(QtCore.Qt.cyan)

		self.qcircuit = QtGui.QGraphicsScene()
		self.qcircuit.setBackgroundBrush(QtCore.Qt.white)

		self.btnLayoutC = QtGui.QHBoxLayout()

		self.circuit = QtGui.QGraphicsView(self.qcircuit)
		self.circuit.setFixedSize(1100,420)
		# self.circuit.mousePressEvent = self.pixelSelect
		self.btnLayoutC.addWidget(self.circuit,QtCore.Qt.AlignLeft)
		self.circReset()
		
		self.btnC2G = QtGui.QPushButton(u"\u2192",self)
		self.btnC2G.clicked.connect(self.convC2G)
		self.btnC2G.setFixedSize(30,30)
		self.btnLayoutC.addWidget(self.btnC2G,0,QtCore.Qt.AlignTop)

		self.topLayoutH2.addLayout(self.btnLayoutC,QtCore.Qt.AlignLeft)

	def circReset(self):

		for item in self.qcircuit.items():
			self.qcircuit.removeItem(item)
		pen = QtGui.QPen(QtCore.Qt.black)
		qubits = 50
		for i in range(0,qubits):
			t = self.qcircuit.addText("q["+str(i)+"]")
			t.setPos(0,i*40)
			self.qcircuit.addLine(QtCore.QLineF(50,i*40+12,80,i*40+12),pen)
		self.circTick = 0 
		self.circuit.centerOn(QtCore.QPointF(0,0))
		# self.qcircuit.addEllipse(QtCore.QRectF(0,0,10,10),QtCore.Qt.black,QtCore.Qt.black)

	def gateset(self):
		
		gsz = 39
		bsz = gsz - 0
		gsr = self.win_ry/2 + gsz/2 + 5
		gsc = 10 
		self.btn_g = {}
		self.btnLayoutGates = QtGui.QGridLayout()
		comboBox = QtGui.QComboBox(self)
		for gs in range(0,len(self.gateSets)):
			comboBox.addItem(self.gateSets[gs])      
		comboBox.setFixedSize(2*gsz+5,gsz)
		comboBox.activated[str].connect(self.gateEnbl)
		self.btnLayoutGates.addWidget(comboBox,0,0,1,2,QtCore.Qt.AlignTop)
		gsr = gsr+gsz  
		gr = 0
		gc = 0
		gates = len(self.gateNames)
		for g in range(0,gates):
			self.btn_g[g] = QtGui.QPushButton(self.gateNames[g],self)
			self.btn_g[g].setFixedSize(bsz,bsz-15)
			self.btnLayoutGates.addWidget(self.btn_g[g],g/2+1,g%2,QtCore.Qt.AlignTop)
			gc = (gc + 1)%2
			if gc == 0:
				gr = gr + 1
		self.btn_g[0].clicked.connect(lambda: self.circSelGate(0))
		self.btn_g[1].clicked.connect(lambda: self.circSelGate(1))
		self.btn_g[2].clicked.connect(lambda: self.circSelGate(2))
		self.btn_g[3].clicked.connect(lambda: self.circSelGate(3))
		self.btn_g[4].clicked.connect(lambda: self.circSelGate(4))
		self.btn_g[5].clicked.connect(lambda: self.circSelGate(5))
		self.btn_g[6].clicked.connect(lambda: self.circSelGate(6))
		self.btn_g[7].clicked.connect(lambda: self.circSelGate(7))
		self.btn_g[8].clicked.connect(lambda: self.circSelGate(8))
		self.btn_g[9].clicked.connect(lambda: self.circSelGate(9))
		self.btn_g[10].clicked.connect(lambda: self.circSelGate(10))
		self.btn_g[11].clicked.connect(lambda: self.circSelGate(11))
		self.btn_g[12].clicked.connect(lambda: self.circSelGate(12))
		self.btn_g[13].clicked.connect(lambda: self.circSelGate(13))
		
		g = gates 
		self.btnGDel = QtGui.QPushButton(u"\u2700",self)
		#self.btnGDel = QtGui.QPushButton(QtGui.QIcon("icons/del1.png"),'',self)
		self.btnGDel.setFixedSize(bsz,bsz)
		self.btnLayoutGates.addWidget(self.btnGDel,g/2+1,g%2,QtCore.Qt.AlignTop)
		self.btnGDel.clicked.connect(self.delGate)

		g = g+1 
		#self.btnGNew = QtGui.QPushButton(u"\U0001F441",self)
		self.btnGNew = QtGui.QPushButton(QtGui.QIcon("icons/cg.png"),'',self)
		self.btnGNew.setFixedSize(bsz,bsz)
		self.btnLayoutGates.addWidget(self.btnGNew,g/2+1,g%2,QtCore.Qt.AlignTop)
		self.btnGNew.clicked.connect(self.makeGate)

		g = g+1
		comboBox = QtGui.QComboBox(self)
		for gs in range(0,5):
			comboBox.addItem("Cust. G"+str(gs))      
		comboBox.setFixedSize(2*gsz+5,gsz)
		comboBox.activated[str].connect(self.TBD)
		self.btnLayoutGates.addWidget(comboBox,g/2+1,g%2,1,2,QtCore.Qt.AlignTop)

		self.topLayoutH2.addLayout(self.btnLayoutGates,QtCore.Qt.AlignLeft)
	
	def delGate(self):

		self.qcircuit.mousePressEvent = self.getDelGate
		return

	def getDelGate(self,event):

		beg = 80
		xsp = 50
		ysp = 40
		pos = QtCore.QPointF(event.scenePos())
		
		#qb = round((pos.y()-12)/ysp)
		tk = round((pos.x() - beg - xsp/4)/xsp)

		file = open(self.fileQCirc,'r+')
		lines = file.readlines()
		file.close()
		
		file = open(self.fileQCirc,'w')
		lno = 0
		for line in lines:
			if lno != int(tk)+1:
				file.write(line)
			lno = lno + 1
		file.close()
		self.openQcirc()

	def makeGate(self):

		# enable drag box
		# self.circuit.dropEvent = self.lol
		# print("hi")
		# print(self.circuit.QGraphicsSceneDragDropEvent.pos())

		self.makeGateBound = []
		self.qcircuit.mousePressEvent = self.getGateBound
		return

	def getGateBound(self,event):

		beg = 80
		xsp = 50
		ysp = 40
		pos = QtCore.QPointF(event.scenePos())
		
		qb = round((pos.y()-12)/ysp)
		tk = round((pos.x() - beg - xsp/4)/xsp)

		self.delGateLno = tk
		print([qb,tk])

	def gateEnbl(self,set):

		gs = 0
		for i in range(0,len(self.gateSets)):
			if set == self.gateSets[i]:
				gs = i
				break
		for g in range(0,len(self.gateMasks[0])):
			if self.gateMasks[gs][g] == '1':
				self.btn_g[g].setEnabled(True)
			else:
				self.btn_g[g].setEnabled(False)

	def circSelGate(self,gateId):

		self.drawGate = gateId
		self.drawGateQ = []
		# self.circuit.setDragMode(QtGui.QGraphicsView.NoDrag)
		self.qcircuit.mousePressEvent = self.pixelSelect
	
# LOGIC RESIDES WHERE WE THINK IT RESIDES
# UNIVERSE EVOLVED INTELLIGENCE TO REDISCOVER ITSELF

# IF WE ARE THE CENTRE OF OUR FRAME OF REFERENCE, WHY DO WE NEED TO USE ENERGY
# DREAM IS THE ILLUSION (MAYA) AND THE URGE TO BE IN IT IS THE DESIRE (MOH)
# THE INFORMATIONAL DIFFERENCE BETWEEN A SARCASTIC AND NORMAL ANSWER IS 0, YET IT CAN TRANSMIT 1 SHANNON BIT OF INFORMATION TO THE RECEIVER


	def pixelSelect(self, event):

		# undo/redo gate button
		# drag toggle button
		# make new kernel button
		# make new unitary button
		# insert custom kernel/unitary button

		
		file = open(self.fileQCirc,'r+')
		content = file.read()
		ptrn = re.compile('qubits')
		mtch = ptrn.search(content)
		if mtch == None:
			file.seek(0, 0)
			file.write("qubits "+str(int(self.drawMaxQ))+"\n" + content)
		file.close()

		file = open(self.fileQCirc,'a')
		ysp = 40
		qb = math.floor(event.scenePos().y()/ysp)
		self.drawGateQ.append(qb)
		if self.drawGate < 9:
			if len(self.drawGateQ) == 1:
				self.circGate(self.drawGate,self.drawGateQ)
				file.write(self.gateCodes[self.drawGate]+" q"+str(int(self.drawGateQ[0]))+"\n")
				# self.circuit.mousePressEvent = None
				# self.circuit.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
		elif self.drawGate == 9:	# CNOT
			if len(self.drawGateQ) == 2:
				self.circGate(self.drawGate,self.drawGateQ)
				file.write(self.gateCodes[self.drawGate]+" q"+str(int(self.drawGateQ[0]))+",q"+str(int(self.drawGateQ[1]))+"\n")
		elif self.drawGate == 11:	# Toffoli
			if len(self.drawGateQ) == 3:
				self.circGate(self.drawGate,self.drawGateQ)
				file.write(self.gateCodes[self.drawGate]+" q"+str(int(self.drawGateQ[0]))+",q"+str(int(self.drawGateQ[1]))+",q"+str(int(self.drawGateQ[2]))+"\n")
		elif self.drawGate >= 12:
			if len(self.drawGateQ) == 1:
				self.circGate(self.drawGate,self.drawGateQ)
				file.write(self.gateCodes[self.drawGate]+"\n")
		file.close()

	def circGate(self,gateId,qbset):

		beg = 80
		xsp = 50
		ysp = 40

		for i in range (0,len(qbset)):
		 	if qbset[i]+1 > self.drawMaxQ:
			    self.drawMaxQ = qbset[i]+1

		pen = QtGui.QPen(QtCore.Qt.black)
		qubits = 50
		for i in range(0,qubits):
			self.qcircuit.addLine(QtCore.QLineF(beg+xsp*self.circTick,i*40+12,beg+xsp*(self.circTick+1),i*40+12),pen)
		
		penG = QtGui.QPen(QtCore.Qt.gray)
		fill = QtGui.QBrush(QtCore.Qt.cyan)
		rsz = 24
		csz = 14
		if gateId < 9:
			qbt = qbset[0]
			self.qcircuit.addRect(QtCore.QRectF(beg+xsp*self.circTick,ysp*qbt,rsz,rsz),penG,fill)
			t = self.qcircuit.addText(self.gateNames[gateId])
			t.setPos(beg+xsp*self.circTick+4,ysp*qbt)
		elif gateId == 9:
			qbc1 = qbset[0]
			qbt = qbset[1]
			self.qcircuit.addLine(QtCore.QLineF(beg+xsp*self.circTick+5+7,ysp*qbc1+5+7,beg+xsp*self.circTick+12,ysp*qbt+12),penG)
			self.qcircuit.addEllipse(QtCore.QRectF(beg+xsp*self.circTick+(rsz-csz)/2,ysp*qbc1+(rsz-csz)/2,csz,csz),penG,QtCore.Qt.black)
			self.qcircuit.addRect(QtCore.QRectF(beg+xsp*self.circTick,ysp*qbt,rsz,rsz),penG,fill)
			t = self.qcircuit.addText("X")
			t.setPos(beg+xsp*self.circTick+4,ysp*qbt)
		elif gateId == 11:
			qbc2 = qbset[0]
			qbc1 = qbset[1]
			qbt = qbset[2]
			self.qcircuit.addLine(QtCore.QLineF(beg+xsp*self.circTick+5+7,ysp*qbc1+5+7,beg+xsp*self.circTick+12,ysp*qbt+12),penG)
			self.qcircuit.addLine(QtCore.QLineF(beg+xsp*self.circTick+5+7,ysp*qbc2+5+7,beg+xsp*self.circTick+12,ysp*qbt+12),penG)
			self.qcircuit.addEllipse(QtCore.QRectF(beg+xsp*self.circTick+(rsz-csz)/2,ysp*qbc1+(rsz-csz)/2,csz,csz),penG,QtCore.Qt.black)
			self.qcircuit.addEllipse(QtCore.QRectF(beg+xsp*self.circTick+(rsz-csz)/2,ysp*qbc2+(rsz-csz)/2,csz,csz),penG,QtCore.Qt.black)
			self.qcircuit.addRect(QtCore.QRectF(beg+xsp*self.circTick,ysp*qbt,rsz,rsz),penG,fill)
			t = self.qcircuit.addText("X")
			t.setPos(beg+xsp*self.circTick+4,ysp*qbt)
		elif gateId >= 12:		# Display
			if gateId == 13:
				fill = QtGui.QBrush(QtCore.Qt.green)
			self.qcircuit.addRect(QtCore.QRectF(beg+xsp*self.circTick,ysp*0,rsz,ysp*int(self.drawMaxQ-1)+rsz),penG,fill)
			for qbt in range(0,int(self.drawMaxQ)):
				t = self.qcircuit.addText(self.gateNames[gateId])
				t.setPos(beg+xsp*self.circTick+1,ysp*qbt)
		pen.setStyle(QtCore.Qt.DotLine)
		self.qcircuit.addLine(QtCore.QLineF(beg+xsp*self.circTick-xsp/4,0,beg+xsp*self.circTick-xsp/4,ysp*qubits-ysp/4),pen)
		self.circTick = self.circTick + 1   # allow parallel scheduling
	
	def convC2Q(self):

		file = open(self.fileQCirc,'r')
		with file:
			text = file.read()
			self.textQasm.setText(text)
		file.close()

	def convC2G(self):

		file = open(self.fileQCirc,'r+')
		content = file.read()
		file.close()
		ptrn = re.compile('^qubits\s(\d+)',re.IGNORECASE)
		mtch = ptrn.search(content)
		if mtch == None:
			file = open(self.fileQCirc,'r+')
			file.seek(0, 0)
			file.write("qubits "+str(int(self.drawMaxQ))+"\n" + content)
			file.close()
		else:
			file = open(self.fileQCirc,'r+')
			lines = file.readlines()
			file.close()
			file = open(self.fileQCirc,'w')
			for line in lines:
				mtch = ptrn.search(line)
				if mtch == None:
					file.write(line)
			file.close()
			file = open(self.fileQCirc,'r+')
			content = file.read()
			file.seek(0, 0)
			file.write("qubits "+str(int(self.drawMaxQ))+"\n" + content)
			file.close()
		os.system("./qx_simulator_1.0.beta_linux_x86_64 "+self.fileQCirc+" > "+self.dirProj+"/"+"logC2G.txt")
		file = open(self.dirProj+"/"+"logC2G.txt",'r')
		self.plotOutput(file)
		file.close()
		text = open(self.dirProj+"/"+"logC2G.txt",'r').read()
		self.textLog.setText(text)
		self.tabLayout.setCurrentWidget(self.textLog)

	#~~~~~~~~~~~~~~~~~~~~~~~~~ results ~~~~~~~~~~~~~~~~~~~~~~~~~#

	def resultTabs(self):

		tsz = 325

		self.figure = Figure()
		self.graphres = FigureCanvas(self.figure)
		self.graphres.setFixedSize(tsz,tsz)

		self.toolbar = NavigationToolbar(self.graphres, self)
		self.toolbar.setFixedSize(tsz,25)

		self.qcoutputw = QtGui.QWidget() 
		
		self.qcoutput = QtGui.QVBoxLayout(self.qcoutputw)
		self.qcoutput.addWidget(self.toolbar)
		self.qcoutput.addWidget(self.graphres)
		
		self.textLog = QtGui.QTextEdit(self)
		self.textLog.setFixedSize(343,388)
		self.textLog.setText("Run Logs")
		self.textLog.setLineWrapMode(0)
		self.textLog.setFontFamily("Monospace")

		# self.scene1 = QtGui.QGraphicsScene()
		# self.qclayout = QtGui.QGraphicsView(self.scene1)
		# self.qclayout.setFixedSize(tsz,tsz)
		# self.pixmap_item = QtGui.QGraphicsPixmapItem(QtGui.QPixmap('topologies/surface17a.png').scaled(tsz,tsz), None, self.scene1)

		self.tabLayout = QtGui.QTabWidget(self)
		self.tabLayout.addTab(self.qcoutputw,"Output")
		self.tabLayout.addTab(self.textLog,"Logs")
		
		self.topLayoutH2.addWidget(self.tabLayout,0,QtCore.Qt.AlignRight)

	def plotOutput(self,file):

		qbno = 0
		ptrn = re.compile('(\d*)\squbits')
		for line in iter(file):
			mtch = ptrn.search(line)
			if mtch != None:
				qbno = int(mtch.group(1))
				break
		ploty = [0]*(2**qbno)
		ptrn = re.compile('\(([+-]\d+.\d*),([+-]\d+.\d*)\)\s[|]([0-1]*)>')
		for line in iter(file):
			mtch = ptrn.search(line)
			if mtch != None:
				x = float(mtch.group(1))
				y = float(mtch.group(2))
				state = int(mtch.group(3),2) 
				ploty[state] = x #x**2 + y**2      # check, sqrt reqd? OR z.z'
		cstmPloty = customPlot(ploty)
		#return
		ax = self.figure.add_subplot(1,1,1)   
		ax.clear()
		#ax.plot(cstmPloty, '*-r')
		ax.bar(range(len(cstmPloty)),cstmPloty)
		ax.set_xlim([0,len(cstmPloty)])
		ax.tick_params(axis='x',labelbottom='off')
		ax.set_ylim([-1,1])
		self.graphres.draw()

	########################## LEGACIES ##########################

	def color_picker(self):

		color = QtGui.QColorDialog.getColor()
		self.penColor = color
		# self.styleChoice.setStyleSheet("QWidget { background-color: %s}" % color.name())

	def TBD(self):

		print("TBD")
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'Body Length Analysis' )
        self.scaleFactor = 4
        self.side = 'L'
        self.lbltxt = '"wheel" press: change side, currently %s\n"i" or "u" press: change cell sides'
        self.seamCellNames = ['a','b','c','1','2','3','4','5','6','t']
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        spaceBox2 = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        mainWindow.addLayout(spaceBox2)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()
        Col4 = QtGui.QVBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)
        rawDataBox.addLayout(Col4)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Timepoint:')
        slLbl = QtGui.QLabel('Slice:')
        hatchLbl = QtGui.QLabel('Hatching Time:')
        widthLbl = QtGui.QLabel('Straightening Width:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)
        
        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)
        
        self.hatch = QtGui.QSpinBox(self)
        self.hatch.setValue(0)
        self.hatch.setMaximum(100000)

        self.straightWidth = QtGui.QSpinBox(self)
        self.straightWidth.setMaximum(1000)
        self.straightWidth.setValue(100)
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        automaticOutlineBtn = QtGui.QPushButton('Automatic Outline')
        straightenBtn = QtGui.QPushButton('Straighten images')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.cellTbl = QtGui.QTableWidget()

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(hatchLbl, 2, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.hatch, 2, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 3, 0 )
        Col1.addWidget(self._561nmBtn, 4, 0 )
        Col1.addWidget(self.CoolLEDBtn, 5, 0 )
        Col1.addWidget(automaticOutlineBtn, 6, 0 )        
        Col1.addWidget(widthLbl, 7, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.straightWidth, 7, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(straightenBtn, 8, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)
        
        Col3.addWidget(self.VLine())
        
        Col4.addWidget(self.cellTbl)

        spaceBox2.addWidget(self.HLine())

        # Raw3.addWidget(QtGui.QDockWidget())

        self.setFocus()
        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)
        self.hatch.valueChanged.connect(self.updateTidxDataFrame)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        automaticOutlineBtn.clicked.connect(self.automaticOutline)
        straightenBtn.clicked.connect(self.straightenWorm)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1]
        self.path = self.pathDial[:-len(self.worm)]
        
        if 'downsized' not in self.worm:
            QtGui.QMessageBox.about(self,'Warning!','These are not downsized (512x512) images! Convert the images first!')
            return

        # print(path + worm + '\\z*.txt')
        self.fList = {}
        if os.path.isfile(self.path + self.worm + '\\z001_488nm.tif'):
            self.fList['488nm'] = glob.glob(self.path + self.worm + '\\z*488nm.tif')
            self.fList['488nm'].sort()
        if os.path.isfile(self.path + self.worm + '\\z001_561nm.tif'):
            self.fList['561nm'] = glob.glob(self.path + self.worm + '\\z*561nm.tif')
            self.fList['561nm'].sort()
        if os.path.isfile(self.path + self.worm + '\\z001_CoolLED.tif'):
            self.fList['CoolLED'] = glob.glob(self.path + self.worm + '\\z*CoolLED.tif')
            self.fList['CoolLED'].sort()

        self.fMetaList = glob.glob(self.path + self.worm + '\\z*.txt')
        
        self.channel = list(self.fList.keys())[0]
        self.tp.setMaximum(len(self.fList[self.channel])-1)
        
        if not os.path.isfile( self.path + '\\worm' + self.worm.split('_')[0] + '.pickle' ):

            create_worm( self.path, self.worm.split('_')[0], 40, len(self.fList[self.channel]) - self.hatch.value(), self.hatch.value()+1 )

        self.df = pickle.load( open(self.path + '\\worm' + self.worm.split('_')[0] + '.pickle','rb') )

        # if there are more timepoints, add the body rows to the dataframe
        if np.max(self.df.tidx)-np.min(self.df.tidx) < len(self.fMetaList):

            times = extract_times( self.path+'\\'+self.worm, -np.min(self.df.tidx) )[int(np.max(self.df.tidx)-np.min(self.df.tidx)+1):]
            df1 = pd.DataFrame( { 'rowtype': 'body',
                          'tidx': np.arange(np.max(self.df.tidx)+1,len(self.fMetaList)+np.min(self.df.tidx)),
                          'times': times,
                          'outline': np.nan,
                          'spline': np.nan} )

            df1.outline = df1.outline.astype(object)
            df1.spline = df1.spline.astype(object)
            for idx, row in df1.iterrows():    
                df1.outline.values[idx] = np.array([[np.nan,np.nan,np.nan]])
                df1.spline.values[idx] = np.array([[np.nan,np.nan,np.nan]])

            self.df = pd.concat([self.df,df1]).sort(['tidx','rowtype','cside','cXpos']).reset_index(drop=True)

        self.hatch.setValue(-np.min(self.df.tidx))
        self.tp.setValue( self.hatch.value() )
        self.setWindowTitle('Body Length Analysis - ' + self.pathDial)

        self.loadNewStack()

        # self.pathDial.show()
        self.setFocus()

    def saveData(self):
        
        pickle.dump( self.df, open(self.path+'\\worm'+self.worm.split('_')[0]+'.pickle','wb'), protocol=2 )        
        
    def loadNewStack(self):
        
        # print(self.fList['gfp'][self.tp.value()])
        
        self.stacks = {}
        for key in self.fList.keys():
            self.stacks[key] = loadstack(self.fList[key][self.tp.value()])
        self.scaleFactor = 2048 / self.stacks[self.channel][0].shape[0]

        self.stacksStraight = {}
        self.straightFile = self.path+self.worm.split('_')[0]+'_straighten\\straight%.3d_%s.tif'%(self.tp.value()+1,self.channel)

        if os.path.isfile(self.straightFile):

            for key in self.fList.keys():
                self.stacksStraight[key] = loadstack(self.path+self.worm.split('_')[0]+'_straighten\\straight%.3d_%s.tif'%(self.tp.value()+1,key))
        # print(self.stacks.keys(), self.stacksStraight)
        self.sl.setMaximum(self.stacks[self.channel].shape[0]-1)

        self.setBCslidersMinMax()
        
        self.updateTable()
        self.updateAllCanvas()

    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        
    def updateTidxDataFrame(self):
        
        times = extract_times(self.path+self.worm, self.hatch.value()+1)
        self.df.ix[self.df.rowtype=='body','tidx'] = np.arange(len(times))-self.hatch.value()
        self.df.ix[self.df.rowtype=='body','times'] = times

    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.fList.keys():
                self.channel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.fList.keys():
                self.channel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.fList.keys():
                self.channel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    def automaticOutline(self):
        
        tp = self.tp.value()
        sl = self.sl.value()
        
        rowmask = self.df['rowtype']=='body'
        outline = self.df.ix[ rowmask, 'outline' ].values
        spline = self.df.ix[ rowmask, 'spline' ].values
        
        for idx, o in enumerate( outline ):

            if len(o) == 2:

                stack = loadstack( self.fList['488nm'][idx] )
                
                # automatically create the outline
                outline[idx] = automatic_outline_michalis( stack, o, sl, idx )

                # create the spline interpolation
                spline[idx] = interp_spline( outline[idx] )

        # update the dataframe with the new outline and spline
        self.df.ix[ rowmask, 'outline' ] = outline
        self.df.ix[ rowmask, 'spline' ] = spline
        self.updateCanvas1()
    
    def straightenWorm(self):

        raw_worm = self.worm.split('_')[0]
        path = self.path+raw_worm
        if not os.path.exists(path):
            QtGui.QMessageBox.about(self, 'Warning! No raw data found in the standard directory. No straightening will be performed', 'Y:\\Images')
            return
        
        spline = []
        for idx in self.df.ix[ pd.notnull(self.df.spline)].index:
            spline.append( np.array( [ self.df.spline.values[idx][:,0]*self.scaleFactor,
                                    self.df.spline.values[idx][:,1]*self.scaleFactor,
                                    self.df.spline.values[idx][:,2] ] ).T )

        fList = {}
        if os.path.isfile(path + '\\z001_488nm.tif'):
            fList['488nm'] = glob.glob(path + '\\z*488nm.tif')
            fList['488nm'].sort()
        if os.path.isfile(path+'\\z001_561nm.tif'):
            fList['561nm'] = glob.glob(path + '\\z*561nm.tif')
            fList['561nm'].sort()
        if os.path.isfile(path + '\\z001_CoolLED.tif'):
            fList['CoolLED'] = glob.glob(path + '\\z*CoolLED.tif')
            fList['CoolLED'].sort()

        # print(25*self.scaleFactor)
        for key in list( fList.keys() ):
            straighten( path, fList[str(key)], spline, width = self.straightWidth.value() )

        self.loadNewStack()
        self.canvas1.setFocus()
         

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):
        
        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime( self.tp, +1 )

        if event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime( self.tp, -1 )

        # change slice
        if event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime( self.sl, +1 )
            
        if event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime( self.sl, -1 )

        # change channel
        if event.key() == QtCore.Qt.Key_Space:
            currentidx = list(self.fList.keys()).index(self.channel) 
            nextidx = np.mod(currentidx+1,len(self.fList.keys()))
            self.channel = list(self.fList.keys())[nextidx]
            self.setBCslidersMinMax()
            self.resetBC()
            self.updateAllCanvas()
            
        self.setFocus()
        
    def wheelEvent(self,event):
        if self.canvas1.underMouse():
            step = event.step
        else:          
            step = event.delta()/abs(event.delta())
        self.sl.setValue( self.sl.value() + step) 

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):
        
        # print(event.button,event.xdata,event.ydata)
        
        tp = self.tp.value()
        sl = self.sl.value()
        
        rowmask = self.df['rowtype']=='body'
        outline = self.df.ix[ rowmask, 'outline' ].values
        spline = self.df.ix[ rowmask, 'spline' ].values

        x = event.xdata
        y = event.ydata

        # left button: add a point to the outline
        if event.button == 1:   
            
            if not np.all(np.isnan(outline[tp])):
                idx = find_closest_point( [ x, y ], outline[tp] )
            else:
                idx = 0                
            outline[tp] = np.insert( outline[tp], idx+1, [ x, y, sl ], axis=0 )
            
            # if the first line is still full of nan, remove it
            if np.all(np.isnan(outline[tp][0])):
                outline[tp] = np.delete(outline[tp],0,axis=0)
                                
        # right button: remove the closest point from the outline
        elif event.button == 3 and len(outline[tp]) > 0:
            
            idx = find_closest_point([x,y],outline[tp])
            if outline[tp].shape[0]!=1:
                outline[tp] = np.delete( outline[tp], idx, axis=0 )
            else:
                outline[tp] = np.array([[np.nan,np.nan,np.nan]])
                
        # update the dataframe with the new outline and spline
        spline[tp] = interp_spline( outline[tp] )
        self.df.ix[ rowmask, 'outline' ] = outline
        self.df.ix[ rowmask, 'spline' ] = spline
        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.channel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.channel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.channel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.channel]))
        self.sld1.setMinimum(np.min(self.stacks[self.channel]))
        self.sld2.setMaximum(np.max(self.stacks[self.channel]))
        self.sld2.setMinimum(np.min(self.stacks[self.channel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.channel]))
        self.sld2.setValue(np.max(self.stacks[self.channel]))
        
    def updateCanvas1(self):
        
        rowmask = self.df['rowtype']=='body'
        tidxmask = self.df['tidx']==(self.tp.value()-self.hatch.value())
        
        # extract and rescale the outline and spline
        outline = np.copy( self.df.ix[ rowmask & tidxmask, 'outline' ].values[0] )
        spline = np.copy( self.df.ix[ rowmask & tidxmask, 'spline' ].values[0] )

        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow(self.stacks[self.channel][self.sl.value()], cmap = 'gray')
        
        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(),self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(),self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())        

        # print(outline, spline)
        self.ax1.plot( outline[:,0], outline[:,1], 'o', color='red', ms=6, mew=1, alpha=.5, lw = 1 )
        self.ax1.plot( spline[:,0], spline[:,1], '-', color='yellow', lw = 1 )
        
        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def changeSpaceTime(self, whatToChange, increment):

        whatToChange.setValue( whatToChange.value() + increment )
        
    def rescaledImage(self, img):
        
        Nbig = img.shape[0]
        Nsmall = img.shape[0]/self.scaleFactor
        return img.reshape([Nsmall, Nbig/Nsmall, Nsmall, Nbig/Nsmall]).mean(3).mean(1)

    def updateTable(self):
        self.cellTbl.clear()
        cellsNow = self.df[(self.df.rowtype=='cell')&(self.df.tidx==self.tp.value()-self.hatch.value())]
        
        horHeaders = ['tidx','times','cell name','cell side','cellXpos','cellYpos','cellZpos']
        self.cellTbl.setColumnCount(len(horHeaders))
        self.cellTbl.setRowCount(len(cellsNow))        
        self.cellTbl.setHorizontalHeaderLabels(horHeaders)
        self.cellTbl.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents)

        for idx, cell in cellsNow.iterrows():
            row = idx-np.min(cellsNow.index.values)
            self.cellTbl.setItem(row,0,QtGui.QTableWidgetItem(str(int(cell.tidx))))
            self.cellTbl.setItem(row,1,QtGui.QTableWidgetItem(str('%.2f'%cell.times)))
            self.cellTbl.setItem(row,2,QtGui.QTableWidgetItem(str(cell.cname)))
            self.cellTbl.setItem(row,3,QtGui.QTableWidgetItem(cell.cside))
            self.cellTbl.setItem(row,4,QtGui.QTableWidgetItem(str(int(cell.cXpos))))
            self.cellTbl.setItem(row,5,QtGui.QTableWidgetItem(str(int(cell.cYpos))))
            self.cellTbl.setItem(row,6,QtGui.QTableWidgetItem(str(int(cell.cZpos))))
       
        self.setFocus()
예제 #18
0
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Label Cells')
        self.cellNames = [
            '1.p', '4.a', '1.pp', '4.aa', '1.ppa', '1.ppp', '4.aaa', '4.aap',
            'b_1', 'b_4'
        ]
        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):

        # SET THE GEOMETRY

        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300, 300))
        self.canvas2.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0)
        Col1.addWidget(self._561nmBtn, 4, 0)
        Col1.addWidget(self.CoolLEDBtn, 5, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        Col3.addWidget(self.cellTbl)
        Col3.addWidget(self.canvas2)

        self.setFocus()
        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',
                                     self.onMouseClickOnCanvas1)
        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):

        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):

        return width

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Mark Cells - ' + self.pathDial)

        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile(os.path.join(self.pathDial,
                                           'CoolLED_movie.tif')):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame(self.path,
                                        self.worm + '_01params.pickle')
        self.timesDF = load_data_frame(self.path,
                                       self.worm + '_01times.pickle')
        self.gpDF = load_data_frame(self.path,
                                    self.worm + '_02gonadPos.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the cellPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_04cellPos.pickle')):
            self.cellPosDF = load_data_frame(self.path,
                                             self.worm + '_04cellPos.pickle')

        else:
            self.cellPosDF = create_cell_pos(self.timesDF, self.cellNames)

        ### load all movies (without timestamps, we will add it later on)
        self.LEDmovie = load_stack(
            os.path.join(self.pathDial, 'CoolLED_movie.tif'))

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue(0)

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos(self.cellPosDF,
                                                     self.tp.value())

        # detect available channels
        self.channels = []
        chns = ['CoolLED', '488nm', '561nm']
        for c in chns:

            if os.path.isfile(os.path.join(self.pathDial, c + '_movie.tif')):

                self.channels.append(c)
        self.currentChannel = self.channels[0]

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        self.loadNewStack()

        # self.pathDial.show()
        self.updateAllCanvas()
        self.setFocus()

    def loadNewStack(self):

        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[self.timesDF.tidxRel ==
                               self.tp.value()].squeeze()

        print('Loading... ', self.pathDial, tRow.fName)

        # load all the available stacks
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join(self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile(fileName):
                self.stacks[ch] = load_stack(fileName)

        if len(self.stacks.keys()) > 0:
            # print(self.stacks.keys(), self.stacksStraight)
            self.sl.setMaximum(self.stacks[self.currentChannel].shape[0] - 1)

            self.setBCslidersMinMax()

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos(self.cellPosDF,
                                                     self.tp.value())

        # self.updateTable()
        self.updateAllCanvas()

    def saveData(self):

        if self.checkConsistencyCellNames():
            save_data_frame(self.cellPosDF, self.path,
                            self.worm + '_04cellPos.pickle')
        else:
            QtGui.QMessageBox.about(self, 'Warning!',
                                    'There is a mistake in the cell labels!')
        self.setFocus()

    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        self.updateCanvas2()

    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):

        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime('time', +1)

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime('time', -1)

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime('space', +1)

        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime('space', -1)

        # key press on cropped image
        if self.canvas1.underMouse():
            self.onKeyPressOnCanvas1(event)

        self.setFocus()

    def wheelEvent(self, event):
        if self.canvas1.underMouse():
            step = event.step
        else:
            step = event.delta() / abs(event.delta())
        self.sl.setValue(self.sl.value() + step)

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas1(self, event):

        motherCells = [QtCore.Qt.Key_1, QtCore.Qt.Key_4, QtCore.Qt.Key_B]
        daughterCells = [QtCore.Qt.Key_A, QtCore.Qt.Key_P]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.stacks[self.currentChannel][self.sl.value()].shape
        canshape = self.canvas1.size()
        cf = imgshape[0] / canshape.width()
        refpos = self.canvas1.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([int(refpos.x() * cf), int(refpos.y() * cf)])
        refpos = np.append(refpos, self.sl.value())

        ### find the closest cell to the cursor
        idx = closer_cell(refpos.astype(np.uint16), self.currentCells)

        ### assign the name to the cell
        if any([event.key() == cn for cn in motherCells]):
            # if labeling bckg, add the 1 or 2 to the name
            if self.currentCells.ix[idx, 'cname'] == 'b_':
                self.currentCells.ix[idx, 'cname'] += QtGui.QKeySequence(
                    event.key()).toString().lower()
            else:
                # if not, rename the cell from scratch
                if event.key() == QtCore.Qt.Key_B:
                    self.currentCells.ix[idx, 'cname'] = QtGui.QKeySequence(
                        event.key()).toString().lower() + '_'
                else:
                    self.currentCells.ix[idx, 'cname'] = QtGui.QKeySequence(
                        event.key()).toString().lower() + '.'

        # add the anterior/posterior to the cell name
        elif any([event.key() == cp for cp in daughterCells]):
            # don't do it if labeling background (bckg doesn't have a/p!)
            if self.currentCells.ix[idx, 'cname'] == 'b_':
                return
            else:
                self.currentCells.ix[idx, 'cname'] += QtGui.QKeySequence(
                    event.key()).toString().lower()

        # remove the last entry of the name with backspace
        elif event.key() == QtCore.Qt.Key_Backspace:
            self.currentCells.ix[idx,
                                 'cname'] = self.currentCells.ix[idx,
                                                                 'cname'][:-1]

        self.updateCanvas1()
        self.setFocus()

    def onMouseClickOnCanvas1(self, event):

        refpos = np.array([event.xdata, event.ydata, self.sl.value()])

        if event.button == 1:

            # create an empty cell in the currentCells df: the only entries are tidx, xyzpos and cname
            newcell = create_single_cell_pos(refpos.astype(np.uint16),
                                             self.tp.value())
            self.currentCells = pd.concat([self.currentCells, newcell])

        elif event.button == 3:

            # remove a cell (the closest to the cursor at the moment of right-click)
            idx = closer_cell(refpos.astype(np.uint16), self.currentCells)
            self.currentCells = self.currentCells.drop([idx])

        self.currentCells = self.currentCells.reset_index(drop=True)

        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.stacks[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.stacks[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.currentChannel]))
        self.sld2.setValue(np.max(self.stacks[self.currentChannel]))

    def updateCanvas1(self):

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        if len(self.stacks.keys()) == 0:
            # if no images are found, leave the canvas empty
            return

        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow(
            self.stacks[self.currentChannel][self.sl.value()], cmap='gray')

        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # cell text on the image
        for idx, cell in self.currentCells.iterrows():

            if cell.Z == self.sl.value():

                self.ax1.text(cell.X,
                              cell.Y + 18,
                              cell.cname,
                              color='red',
                              size='medium',
                              alpha=.8,
                              rotation=0)
                self.ax1.plot(cell.X,
                              cell.Y,
                              'o',
                              color='red',
                              alpha=.8,
                              mew=0)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(), self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(), self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas2(self):

        # plot the image
        self.ax2.cla()
        imgplot = self.ax2.imshow(self.LEDmovie[self.tp.value() +
                                                self.hatchingtidx],
                                  cmap='gray')

        # remove the white borders and plot outline and spline
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = extract_pos(self.gpDF.ix[
            self.gpDF.tidx == self.tp.value()].squeeze()) / self.compression
        self.ax2.plot(gonadPos[0],
                      gonadPos[1],
                      'o',
                      color='red',
                      ms=10,
                      mew=0,
                      alpha=.5,
                      lw=0)

        # print time
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.ax2.text(5,
                      25,
                      '%.2f' %
                      self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                                      'timesRel'].values[0],
                      color='red')

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def checkConsistencyCellNames(self):
        ### check consistency of cell names
        tp = self.tp.value()

        # if no cells are labeled (currentCells df is empty), remove all labeled cells in the cellPosDF and return
        if len(self.currentCells) == 0:
            newCellPosDF = update_cell_pos_DF(self.currentCells,
                                              self.cellPosDF, tp)
            correctCellNames = True

        if len(self.currentCells) > 0:

            correctCellNames = check_cell_names(self.currentCells,
                                                self.cellNames)

            # if cells are not properly labeled, give a Warning
            if not correctCellNames:
                QtGui.QMessageBox.about(
                    self, 'Warning!', 'There is a mistake in the cell labels!')

            # else, update final cellPosDF and return OK
            else:
                newCellPosDF = update_cell_pos_DF(self.currentCells,
                                                  self.cellPosDF, tp)
                self.cellPosDF = newCellPosDF

        return correctCellNames

    def changeSpaceTime(self, whatToChange, increment):

        if whatToChange == 'time':

            # before changinf timepoint, print labeled cells and check if they are OK
            print(self.currentCells)

            # if they are OK (and not going to negative times), change timepoint
            if self.checkConsistencyCellNames() and (self.tp.value() +
                                                     increment) >= 0:
                self.tp.setValue(self.tp.value() + increment)

        if whatToChange == 'space':
            self.sl.setValue(self.sl.value() + increment)
class GUI(QtGui.QWidget):
    
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle('Seam Cells Analysis')
        self.scaleFactor = 4
        self.side = 'L'
        self.lbltxt = '"wheel" press: change side, currently %s\n"i" or "u" press: change cell sides'
        self.initUI()
        
    def initUI(self):
        
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        spaceBox2 = QtGui.QHBoxLayout()
        straightBox = QtGui.QVBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        mainWindow.addLayout(spaceBox2)
        mainWindow.addLayout(straightBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()
        Col4 = QtGui.QVBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)
        rawDataBox.addLayout(Col4)
        
        Raw1 = QtGui.QHBoxLayout()
        Raw2 = QtGui.QHBoxLayout()
        Raw3 = QtGui.QHBoxLayout()

        straightBox.addLayout(Raw1)
        straightBox.addLayout(Raw2)
        straightBox.addLayout(Raw3)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Timepoint:')
        slLbl = QtGui.QLabel('Slice:')
        hatchLbl = QtGui.QLabel('Hatching Time:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)
        
        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)
        
        self.hatch = QtGui.QSpinBox(self)
        self.hatch.setValue(0)
        self.hatch.setMaximum(100000)
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        automaticOutlineBtn = QtGui.QPushButton('Automatic Outline')
        straightenBtn = QtGui.QPushButton('Straighten images')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(500,500)) ############################# change this value to set the figure size
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.cellTbl = QtGui.QTableWidget()

        self.sideLbl = QtGui.QLabel(self.lbltxt % self.side)
        autonameBtn = QtGui.QPushButton('Restore Automatic Cell Names')
        wrt2Btn = QtGui.QPushButton('Compute wrt-2 Expression')
        wrt2FullBtn = QtGui.QPushButton('Compute wrt-2 Expression on the raw data (SLOW!)')        
        
        self.fig2 = Figure((4.0, 2.0))        
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFocusPolicy( QtCore.Qt.StrongFocus )
        self.canvas2.setFocus()
        self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.fig3 = Figure((4.0, 2.0), dpi=100)
        self.fig3.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax3 = self.fig3.add_subplot(111)
        self.canvas3 = FigureCanvas(self.fig3)
        self.canvas3.setFocusPolicy( QtCore.Qt.ClickFocus )

        self.canvas3.setFocus()
        self.canvas3.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )
        
        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(hatchLbl, 2, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.hatch, 2, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self._488nmBtn, 3, 0 )
        Col1.addWidget(self._561nmBtn, 4, 0 )
        Col1.addWidget(self.CoolLEDBtn, 5, 0 )
        Col1.addWidget(automaticOutlineBtn, 6, 0 )        
        Col1.addWidget(straightenBtn, 7, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)
        
        Col3.addWidget(self.VLine())
        
        Col4.addWidget(self.cellTbl)

        spaceBox2.addWidget(self.HLine())

        Raw1.addWidget(self.sideLbl)
        Raw1.addWidget(autonameBtn)
        Raw1.addWidget(wrt2Btn)
        Raw1.addWidget(wrt2FullBtn)

        Raw2.addWidget(self.canvas2)
        
        Raw3.addWidget(self.canvas3)
        # Raw3.addWidget(QtGui.QDockWidget())

        self.setFocus()
        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)
        self.hatch.valueChanged.connect(self.updateTidxDataFrame)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        automaticOutlineBtn.clicked.connect(self.automaticOutline)
        straightenBtn.clicked.connect(self.straightenWorm)
        autonameBtn.clicked.connect(self.automaticCellNames)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig2.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas2)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        self.fig2.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        self.fig3.canvas.mpl_connect('scroll_event',self.wheelEvent)        
        
    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1]
        self.path = self.pathDial[:-len(self.worm)]
        
        self.setWindowTitle('Seam Cells Analysis - ' + self.pathDial)
        
        if 'downsized' not in self.worm:
            QtGui.QMessageBox.about(self,'Warning!','These are not downsized (512x512) images! Convert the images first!')
            return

        # print(path + worm + '\\z*.txt')
        self.fList = {}
        if os.path.isfile(self.path + self.worm + '\\z001_488nm.tif'):
            self.fList['488nm'] = glob.glob(self.path + self.worm + '\\z*488nm.tif')
            self.fList['488nm'].sort()
        if os.path.isfile(self.path + self.worm + '\\z001_561nm.tif'):
            self.fList['561nm'] = glob.glob(self.path + self.worm + '\\z*561nm.tif')
            self.fList['561nm'].sort()
        if os.path.isfile(self.path + self.worm + '\\z001_CoolLED.tif'):
            self.fList['CoolLED'] = glob.glob(self.path + self.worm + '\\z*CoolLED.tif')
            self.fList['CoolLED'].sort()

        self.fMetaList = glob.glob(self.path + self.worm + '\\z*.txt')
        
        self.channel = list(self.fList.keys())[0]
        self.tp.setMaximum(len(self.fList[self.channel])-1)
        
        if not os.path.isfile( self.path + '\\worm' + self.worm.split('_')[0] + '.pickle' ):

            create_worm( self.path, self.worm.split('_')[0], 40, len(self.fList[self.channel]) - self.hatch.value(), self.hatch.value()+1 )

        self.df = pickle.load( open(self.path + '\\worm' + self.worm.split('_')[0] + '.pickle','rb') )

        # if there are more timepoints, add the body rows to the dataframe
        if np.max(self.df.tidx)-np.min(self.df.tidx) < len(self.fMetaList):

            times = extract_times( self.path+'\\'+self.worm, -np.min(self.df.tidx) )[int(np.max(self.df.tidx)-np.min(self.df.tidx)+1):]
            df1 = pd.DataFrame( { 'rowtype': 'body',
                          'tidx': np.arange(np.max(self.df.tidx)+1,len(self.fMetaList)+np.min(self.df.tidx)),
                          'times': times,
                          'outline': np.nan,
                          'spline': np.nan} )

            df1.outline = df1.outline.astype(object)
            df1.spline = df1.spline.astype(object)
            for idx, row in df1.iterrows():    
                df1.outline.values[idx] = np.array([[np.nan,np.nan,np.nan]])
                df1.spline.values[idx] = np.array([[np.nan,np.nan,np.nan]])

            self.df = pd.concat([self.df,df1]).sort(['tidx','rowtype','cside','cXpos']).reset_index(drop=True)

        self.hatch.setValue(-np.min(self.df.tidx))
        self.tp.setValue( self.hatch.value() )

        self.loadNewStack()

        # self.pathDial.show()
        self.setFocus()

    def saveData(self):
        
        pickle.dump( self.df, open(self.path+'\\worm'+self.worm.split('_')[0]+'.pickle','wb'), protocol=2 )        
        
    def loadNewStack(self):
        
        # print(self.fList['gfp'][self.tp.value()])
        
        self.stacks = {}
        for key in self.fList.keys():
            self.stacks[key] = loadstack(self.fList[key][self.tp.value()])
        self.scaleFactor = 2048 / self.stacks[self.channel][0].shape[0]

        self.stacksStraight = {}
        self.straightFile = self.path+self.worm.split('_')[0]+'_straighten\\straight%.3d_%s.tif'%(self.tp.value()+1,self.channel)

        if os.path.isfile(self.straightFile):

            for key in self.fList.keys():
                self.stacksStraight[key] = loadstack(self.path+self.worm.split('_')[0]+'_straighten\\straight%.3d_%s.tif'%(self.tp.value()+1,key))
        # print(self.stacks.keys(), self.stacksStraight)
        self.sl.setMaximum(self.stacks[self.channel].shape[0]-1)

        self.setBCslidersMinMax()
        
        self.updateTable()
        self.updateAllCanvas()

    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        self.updateCanvas2()
        self.updateCanvas3()
        
    def updateTidxDataFrame(self):
        
        times = extract_times(self.path+self.worm, self.hatch.value()+1)
        self.df.ix[self.df.rowtype=='body','tidx'] = np.arange(len(times))-self.hatch.value()
        self.df.ix[self.df.rowtype=='body','times'] = times

    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.fList.keys():
                self.channel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.fList.keys():
                self.channel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.fList.keys():
                self.channel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    def automaticOutline(self):
        
        tp = self.tp.value()
        sl = self.sl.value()
        
        rowmask = self.df['rowtype']=='body'
        outline = self.df.ix[ rowmask, 'outline' ].values
        spline = self.df.ix[ rowmask, 'spline' ].values
        
        for idx, o in enumerate( outline ):

            if len(o) == 2:
                
                stack = loadstack( self.fList['488nm'][idx] )
                
                # automatically create the outline
                outline[idx] = automatic_outline_michalis( stack, o, sl, idx )

                # create the spline interpolation
                spline[idx] = interp_spline( outline[idx] )

        # update the dataframe with the new outline and spline
        self.df.ix[ rowmask, 'outline' ] = outline
        self.df.ix[ rowmask, 'spline' ] = spline
        self.updateCanvas1()
    
    def straightenWorm(self):

        raw_worm = self.worm.split('_')[0]
        path = self.path+raw_worm
        if not os.path.exists(path):
            QtGui.QMessageBox.about(self, 'Warning! No raw data found in the standard directory. No straightening will be performed', 'Y:\\Images')
            return
        
        spline = []
        for idx in self.df.ix[ pd.notnull(self.df.spline)].index:
            spline.append( np.array( [ self.df.spline.values[idx][:,0]*self.scaleFactor,
                                    self.df.spline.values[idx][:,1]*self.scaleFactor,
                                    self.df.spline.values[idx][:,2] ] ).T )

        fList = {}
        if os.path.isfile(path + '\\z001_488nm.tif'):
            fList['488nm'] = glob.glob(path + '\\z*488nm.tif')
            fList['488nm'].sort()
        if os.path.isfile(path+'\\z001_561nm.tif'):
            fList['561nm'] = glob.glob(path + '\\z*561nm.tif')
            fList['561nm'].sort()
        if os.path.isfile(path + '\\z001_CoolLED.tif'):
            fList['CoolLED'] = glob.glob(path + '\\z*CoolLED.tif')
            fList['CoolLED'].sort()

#        print(25*self.scaleFactor)
        for key in list( fList.keys() ):
            straighten( path, fList[str(key)], spline )

        self.loadNewStack()
        self.updateCanvas2()
        self.canvas1.setFocus()
         
    def automaticCellNames(self):

        tidxNow = self.tp.value() - self.hatch.value()

        tidxNowMask = self.df.tidx == tidxNow
        cellMask = self.df.rowtype == 'cell'
        sideMask = self.df.cside == self.side

        # find the previous timepoint with labeled cells
        if np.sum( sideMask & (self.df.tidx < tidxNow) ) == 0:
            QtGui.QMessageBox.about(self, 'Warning', 'No cells are labeled in the %s side yet!' % self.side)
            return   
        else:
            tidxPrev = np.max( self.df.ix[ sideMask & ( self.df.tidx<tidxNow ), 'tidx' ] )
            # print(self.side, tidxPrev)
            tidxPrevMask = self.df['tidx'] == tidxPrev

        # filter the cells from the dataframe
        cellsNow = self.df[cellMask&tidxNowMask&sideMask]
        cellsPrev = self.df[cellMask&tidxPrevMask&sideMask]

        # find the relative positions and sort the cells
        wNowLen = np.max(cellsNow.cXpos)-np.min(cellsNow.cXpos)
        wPrevLen = np.max(cellsPrev.cXpos)-np.min(cellsPrev.cXpos)

        for idx in cellsNow.index:
            cellsNow.ix[idx,'relPos'] = ( cellsNow.ix[idx,'cXpos'] - np.min(cellsNow.cXpos) )/wNowLen
        for idx in cellsPrev.index:
            cellsPrev.ix[idx,'relPos'] = ( cellsPrev.ix[idx,'cXpos'] - np.min(cellsPrev.cXpos) )/wPrevLen

        cellsNow = cellsNow.sort(['relPos'])
        cellsPrev = cellsPrev.sort(['relPos'])

        # assign all the names according to closest cell in previous timepoint
        # if there are more cells now, two cells will have the same name
        for idx, cell in cellsNow.iterrows():
            closestCell = self.closestCell( cell, cellsPrev )
            cellsNow.ix[idx,'cname'] = closestCell.cname.values[0]

        # if more cells, a division happened.
        if len(cellsNow) > len(cellsPrev):
            # print('I am f****d...')

            # for each cell (but first the most left one), find the first one to the left
            for idx, cell in cellsNow.drop( np.min(cellsNow.index.values) ).iterrows():
                cellToTheLeft = cellsNow.ix[ idx - 1 ]

                # if it has the same name, a division happened
                if cellsNow.ix[idx,'cname'] == cellToTheLeft.cname:
                    cellsNow.ix[idx-1,'cname'] += 'a'
                    cellsNow.ix[idx,'cname'] += 'p'

        # update dataframe
        for idx, cell in cellsNow.iterrows():
            self.df.ix[idx,'cname'] = cell.cname

        # update canvas
        self.updateTable()
        self.updateCanvas2()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):
        
        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime( self.tp, +1 )

        if event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime( self.tp, -1 )

        # change slice
        if event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime( self.sl, +1 )
            
        if event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime( self.sl, -1 )

        # change channel
        if event.key() == QtCore.Qt.Key_Space:
            currentidx = list(self.fList.keys()).index(self.channel) 
            nextidx = np.mod(currentidx+1,len(self.fList.keys()))
            self.channel = list(self.fList.keys())[nextidx]
            self.setBCslidersMinMax()
            self.resetBC()
            self.updateAllCanvas()
            
        # key press on straighten worm
        if self.canvas2.underMouse():
            self.onKeyPressOnCanvas2(event)
            
        self.setFocus()
        
    def wheelEvent(self,event):
        if any([ self.canvas1.underMouse(), self.canvas2.underMouse(), self.canvas3.underMouse() ]):
            step = event.step
        else:          
            step = event.delta()/abs(event.delta())
        self.sl.setValue( self.sl.value() + step) 

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas2(self, event):

        # print(event.key())
        
        cellsname = [ QtCore.Qt.Key_A, QtCore.Qt.Key_B, QtCore.Qt.Key_C, QtCore.Qt.Key_1,
                      QtCore.Qt.Key_2, QtCore.Qt.Key_3, QtCore.Qt.Key_4, QtCore.Qt.Key_5,
                      QtCore.Qt.Key_6, QtCore.Qt.Key_T ]
        cellspos = [ QtCore.Qt.Key_Q, QtCore.Qt.Key_W ]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.stacksStraight[self.channel][self.sl.value()].shape
        arimg = imgshape[1]/imgshape[0]
        canshape = self.canvas2.size()
        arcan = canshape.width()/canshape.height()
        cf = 1
        if arimg>arcan:
            cf = imgshape[1]/canshape.width()
            origin = ( canshape.height()*cf - imgshape[0] ) / 2.
            origin = np.array( [ 0, ( canshape.width()*cf - imgshape[1] ) / 2. ] )
        else:
            cf = imgshape[0]/canshape.height()
            origin = np.array( [ ( canshape.width()*cf - imgshape[1] ) / 2., 0 ] )
        refpos = self.canvas2.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([refpos.x(),refpos.y()])*cf - origin
        refpos = np.append(refpos,self.sl.value())

        # find the closest cell to the cursor
        bodymask = self.df['rowtype']=='body'
        cellmask = self.df['rowtype']=='cell'
        tpmask = self.df['tidx'] == (self.tp.value()-self.hatch.value())
        
        idx, cell = closer_cell( refpos, self.df[ cellmask & tpmask ], self.fMetaList[self.tp.value()] )

        if any( [ event.key() == cn for cn in cellsname ] ):
            self.df.ix[ idx, 'cname' ] = QtGui.QKeySequence(event.key()).toString().lower() + '.'

        elif any( [ event.key() == cp for cp in cellspos ] ):

            if event.key() == cellspos[0]:      self.df.ix[ idx, 'cname' ] += 'a'
            elif event.key() == cellspos[1]:    self.df.ix[ idx, 'cname' ] += 'p'
                
        elif event.key() == QtCore.Qt.Key_Backspace:
            
            self.df.ix[ idx, 'cname' ] = self.df.ix[ idx, 'cname' ][:-1]

        elif event.key() == QtCore.Qt.Key_I:
            
            sideLmask = self.df['cside']=='L'
            self.df.ix[ tpmask & cellmask & sideLmask,'cside'] = 'R'
            sideRmask = self.df['cside']=='R'
            self.df.ix[ tpmask & cellmask & sideRmask,'cside'] = 'L'

        elif event.key() == QtCore.Qt.Key_U:
            
            if self.df.ix[idx,'cside']=='L':    self.df.ix[ idx,'cside'] = 'R'
            elif self.df.ix[idx,'cside']=='R':  self.df.ix[ idx,'cside'] = 'L'
        
        self.df = self.df.sort(['tidx','rowtype','cside','cXpos']).reset_index(drop=True)
        self.updateTable()
        self.updateAllCanvas()
        
    def onMouseClickOnCanvas1(self, event):
        
        # print(event.button,event.xdata,event.ydata)
        
        tp = self.tp.value()
        sl = self.sl.value()
        
        rowmask = self.df['rowtype']=='body'
        outline = self.df.ix[ rowmask, 'outline' ].values
        spline = self.df.ix[ rowmask, 'spline' ].values

        x = event.xdata
        y = event.ydata

        # left button: add a point to the outline
        if event.button == 1:   
            
            if not np.all(np.isnan(outline[tp])):
                idx = find_closest_point( [ x, y ], outline[tp] )
            else:
                idx = 0                
            outline[tp] = np.insert( outline[tp], idx+1, [ x, y, sl ], axis=0 )
            
            # if the first line is still full of nan, remove it
            if np.all(np.isnan(outline[tp][0])):
                outline[tp] = np.delete(outline[tp],0,axis=0)
                                
        # right button: remove the closest point from the outline
        elif event.button == 3 and len(outline[tp]) > 0:
            
            idx = find_closest_point([x,y],outline[tp])
            if outline[tp].shape[0]!=1:
                outline[tp] = np.delete( outline[tp], idx, axis=0 )
            else:
                outline[tp] = np.array([[np.nan,np.nan,np.nan]])
                
        # update the dataframe with the new outline and spline
        spline[tp] = interp_spline( outline[tp] )
        self.df.ix[ rowmask, 'outline' ] = outline
        self.df.ix[ rowmask, 'spline' ] = spline
        self.updateCanvas1()
        self.setFocus()

    def onMouseClickOnCanvas2(self, event):
        
        refpos = np.array( [ event.xdata, event.ydata, self.sl.value() ] )  
        # print(refpos)
        bodymask = self.df['rowtype']=='body'
        cellmask = self.df['rowtype']=='cell'
        tpmask = self.df['tidx'] == (self.tp.value()-self.hatch.value())
        # print( 'mouse button pressed:', event.button, 'at pos:', refpos )
        if all( refpos[:-1] ) > 0:
            if event.button == 1:
    
                # create an empty cell: the only entries are tidx, times, xyzpos, side
                newcell = create_cell( refpos, self.df[ bodymask & tpmask ], self.side  )
                self.df = pd.concat( [ self.df, newcell ] )
                
            elif event.button == 3:

                if any( self.df[tpmask].rowtype == 'cell' ):
                    idx, cell = closer_cell( refpos, self.df[ cellmask & tpmask ], self.fMetaList[self.tp.value()] )
                    self.df = self.df.drop([idx])
            
            elif event.button == 2:
    
                if self.side == 'L': self.side = 'R'
                elif self.side == 'R': self.side = 'L'
                self.sideLbl.setText(self.lbltxt % self.side)

        self.df = self.df.sort(['tidx','rowtype','cside','cXpos']).reset_index(drop=True)
        self.updateCanvas2()
        self.updateTable()
        self.setFocus()
                
    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.channel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.channel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.channel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.channel]))
        self.sld1.setMinimum(np.min(self.stacks[self.channel]))
        self.sld2.setMaximum(np.max(self.stacks[self.channel]))
        self.sld2.setMinimum(np.min(self.stacks[self.channel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.channel]))
        self.sld2.setValue(np.max(self.stacks[self.channel]))
        
    def updateCanvas1(self):
        
        rowmask = self.df['rowtype']=='body'
        tidxmask = self.df['tidx']==(self.tp.value()-self.hatch.value())
        
        # extract and rescale the outline and spline
        outline = np.copy( self.df.ix[ rowmask & tidxmask, 'outline' ].values[0] )
        spline = np.copy( self.df.ix[ rowmask & tidxmask, 'spline' ].values[0] )

        # plot the image
        self.ax1.cla()
        imgplot = self.ax1.imshow(self.stacks[self.channel][self.sl.value()], cmap = 'gray')
        
        # remove the white borders and plot outline and spline
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(),self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(),self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())        

        # print(outline, spline)
        self.ax1.plot( outline[:,0], outline[:,1], 'o', color='red', ms=6, mew=1, alpha=.5, lw = 1 )
        self.ax1.plot( spline[:,0], spline[:,1], '-', color='yellow', lw = 1 )
        
        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas2(self):
        
        # plot the image
        self.ax2.cla()

        if not os.path.isfile(self.straightFile):
            self.fig2.clf()
            self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
            self.ax2 = self.fig2.add_subplot(111)
            self.canvas2.draw()
            return
            
        imgplot = self.ax2.imshow(self.stacksStraight[self.channel][self.sl.value()], cmap = 'gray')
        imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # remove the white borders
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        
        # cell text on the image
        tpmask = self.df['tidx'] == (self.tp.value() - self.hatch.value())
        cellmask = self.df['rowtype'] == 'cell'

        for idx, cell in self.df[tpmask & cellmask].iterrows():

            if cell.cZpos == self.sl.value():
                clabel = str(cell.cname) + ' ' + str(cell.cside)
                self.ax2.text( cell.cXpos, cell.cYpos + 10, clabel, color='red', size='medium', alpha=.8,
                        rotation=90)
                self.ax2.plot( cell.cXpos, cell.cYpos, 'x', color='red', alpha = .8 )


        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def updateCanvas3(self):
        # print('updating canvas 3')
        
        tidxNow = self.tp.value() - self.hatch.value()

        tidxNowMask = self.df.tidx == tidxNow
        cellMask = self.df.rowtype == 'cell'
        sideMask = self.df.cside == self.side

        # find the previous timepoint with labeled cells
        if np.sum( sideMask & (self.df.tidx < tidxNow) ) == 0:
            self.fig3.clf()
            self.fig3.subplots_adjust(left=0., right=1., top=1., bottom=0.)
            self.ax3 = self.fig3.add_subplot(111)
            self.canvas3.draw()
            return   
        else:
            tidxPrev = np.max( self.df.ix[ sideMask & ( self.df.tidx<tidxNow ), 'tidx' ] )
            tidxPrevMask = self.df['tidx'] == tidxPrev

        # load images
        prevstacksStraight = {}
        for key in self.fList.keys():
            prevstacksStraight[key] = loadstack(self.path+self.worm.split('_')[0]+'_straighten\\straight%.3d_%s.tif'%(tidxPrev+self.hatch.value()+1,key))

        # plot the image
        self.ax3.cla()

        imgplot = self.ax3.imshow(prevstacksStraight[self.channel][self.sl.value()], cmap = 'gray')
        imgplot.set_clim(self.sld1.value(), self.sld2.value())

        # remove the white borders
        self.ax3.autoscale(False)
        self.ax3.axis('Off')
        self.fig3.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        
        # cell text on the image
        for idx, cell in self.df[tidxPrevMask & cellMask].iterrows():

            if cell.cZpos == self.sl.value():
                clabel = str(cell.cname) + ' ' + str(cell.cside)
                self.ax3.text( cell.cXpos, cell.cYpos + 10, clabel, color='red', size='small', alpha=.8,
                        rotation=90)
                self.ax3.plot( cell.cXpos, cell.cYpos, 'x', color='red', alpha = .8 )

        # redraw the canvas
        self.canvas3.draw()
        self.setFocus()

    def closestCell(self,cell,clist):
        dist = np.abs( clist.relPos - cell.relPos )
        return clist[ dist == np.min(dist) ]
  
    def changeSpaceTime(self, whatToChange, increment):

        whatToChange.setValue( whatToChange.value() + increment )
        
    def rescaledImage(self, img):
        
        Nbig = img.shape[0]
        Nsmall = img.shape[0]/self.scaleFactor
        return img.reshape([Nsmall, Nbig/Nsmall, Nsmall, Nbig/Nsmall]).mean(3).mean(1)

    def updateTable(self):
        self.cellTbl.clear()

        tidxNow = self.tp.value() - self.hatch.value()

        tidxNowMask = self.df.tidx == tidxNow
        cellMask = self.df.rowtype == 'cell'

        cellsNow = self.df[cellMask&tidxNowMask]
        cellsPrev = pd.DataFrame({})
        if len(cellsNow) > 0:
	        sideMask = self.df.cside == cellsNow.cside.values[0]

	        # find the previous timepoint with labeled cells
	        if np.sum( sideMask & (self.df.tidx < tidxNow) ) == 0:
	        	cellsPrev = pd.DataFrame({})
	        else:
	            tidxPrev = np.max( self.df.ix[ sideMask & ( self.df.tidx<tidxNow ), 'tidx' ] )
	            tidxPrevMask = self.df['tidx'] == tidxPrev
	            cellsPrev = self.df[cellMask&tidxPrevMask]
	      
	        horHeaders = ['tidx','times','cell name','cell side','cellXpos','cellYpos','cellZpos','-',
	        				'tidx','times','cell name','cell side','cellXpos','cellYpos','cellZpos']
	        self.cellTbl.setColumnCount(len(horHeaders))
	        self.cellTbl.setRowCount(np.max([len(cellsNow),len(cellsPrev)]))        
	        self.cellTbl.setHorizontalHeaderLabels(horHeaders)
	        self.cellTbl.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents)
	        self.cellTbl.verticalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents)

	        row = 0
	        for idx, cell in cellsNow.iterrows():
	            self.cellTbl.setItem(row,0,QtGui.QTableWidgetItem(str(int(cell.tidx)),.0001))
	            self.cellTbl.setItem(row,1,QtGui.QTableWidgetItem(str('%.2f'%cell.times)))
	            self.cellTbl.setItem(row,2,QtGui.QTableWidgetItem(str(cell.cname)))
	            self.cellTbl.setItem(row,3,QtGui.QTableWidgetItem(cell.cside))
	            self.cellTbl.setItem(row,4,QtGui.QTableWidgetItem(str(int(cell.cXpos))))
	            self.cellTbl.setItem(row,5,QtGui.QTableWidgetItem(str(int(cell.cYpos))))
	            self.cellTbl.setItem(row,6,QtGui.QTableWidgetItem(str(int(cell.cZpos))))
	            row += 1

	        row = 0
	        for idx, cell in cellsPrev.iterrows():
	            self.cellTbl.setItem(row,8,QtGui.QTableWidgetItem(str(int(cell.tidx))))
	            self.cellTbl.setItem(row,9,QtGui.QTableWidgetItem(str('%.2f'%cell.times)))
	            self.cellTbl.setItem(row,10,QtGui.QTableWidgetItem(str(cell.cname)))
	            self.cellTbl.setItem(row,11,QtGui.QTableWidgetItem(cell.cside))
	            self.cellTbl.setItem(row,12,QtGui.QTableWidgetItem(str(int(cell.cXpos))))
	            self.cellTbl.setItem(row,13,QtGui.QTableWidgetItem(str(int(cell.cYpos))))
	            self.cellTbl.setItem(row,14,QtGui.QTableWidgetItem(str(int(cell.cZpos))))
	            row += 1
        
        self.setFocus()
class Data_Visualization_GUI(object):
    def __init__(self,Data_Visualization):
        object.__init__(self)
        
        Data_Visualization.resize(1000,650)
        Data_Visualization.setWindowTitle("Didi's Data Visualizer")
        
        self.mainLayout = QtGui.QGridLayout(Data_Visualization)
        self.mainLayout.setSpacing(5)
        
        self.trackingPlotWidget = QtGui.QWidget()
        self.fig = pylab.figure()
        self.axes = pylab.Axes(self.fig, [.1,.1,.8,.8])
        self.fig.add_axes(self.axes)   
        self.plot, = pylab.plot([0],[0],'ro')
        self.axes.set_xlim(-5, 5)
        self.axes.set_ylim(-5, 5)
        self.plotTitle = pylab.title('Tracking Data')
        self.plotxLabel = pylab.xlabel('X')
        self.plotyLabel = pylab.ylabel('Z')
        self.canvas = FigureCanvas(self.fig)       
        self.canvas.setParent(self.trackingPlotWidget)
        self.canvas.setFixedSize(400,400)
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.trackingPlotWidget)

##
##
##        self.XYZPlotWidget = QtGui.QWidget()
##        pylab.subplot(311)
##        self.fig2 = pylab.figure()
##        self.axes2 = pylab.Axes(self.fig2, [.1,.1,.8,.8])
##        self.fig2.add_axes(self.axes2)   
##        self.plot2 = pylab.plot([0],[0],'r', [0],[0],'g', [0],[0],'b')
##        self.axes2.set_xlim(-200, 0)
##        self.axes2.set_ylim(-5, 5)
##        pylab.legend([self.plot2[0], self.plot2[1], self.plot2[2]], ["X", "Y", "Z"], loc=3)
##        self.plotxLabel2 = pylab.xlabel('Time')
##        self.plotyLabel2 = pylab.ylabel('XYZ')
##        self.canvas2 = FigureCanvas(self.fig2)       
##        self.canvas2.setParent(self.XYZPlotWidget)
##        self.canvas2.setFixedSize(500,150)
##        
##        pylab.subplot(312)
##        self.fig3 = pylab.figure()
##        self.axes3 = pylab.Axes(self.fig3, [.1,.1,.8,.8])
##        self.fig3.add_axes(self.axes3)   
##        self.plot3 = pylab.plot([0],[0],'g', [0],[0],'r')
##        self.axes3.set_xlim(-200, 0)
##        self.axes3.set_ylim(-12, 12)
##        pylab.legend([self.plot3[0], self.plot3[1]], ["Pitch", "Roll"], loc=3)
##        self.plotxLabel3 = pylab.xlabel('Time')
##        self.plotyLabel3 = pylab.ylabel('PR')
##        self.canvas3 = FigureCanvas(self.fig3)       
##        self.canvas3.setParent(self.XYZPlotWidget)
##        self.canvas3.setFixedSize(500,150)
##        
##        pylab.subplot(313)
##        self.fig4 = pylab.figure()
##        self.axes4 = pylab.Axes(self.fig4, [.1,.1,.8,.8])
##        self.fig4.add_axes(self.axes4)   
##        self.plot4 = pylab.plot([0],[0],'r', [0],[0],'g', [0],[0],'b', [0],[0],'y')
##        pylab.legend([self.plot4[0], self.plot4[1], self.plot4[2], self.plot4[3]], ["w1", "w2", "w3", "w4"], loc=3)
##        self.axes4.set_xlim(-200, 0)
##        self.axes4.set_ylim(-0.5, 0.5)
##        self.plotxLabel4 = pylab.xlabel('Time')
##        self.plotyLabel4 = pylab.ylabel('WWWW')
##        self.canvas4 = FigureCanvas(self.fig4)       
##        self.canvas4.setParent(self.XYZPlotWidget)
##        self.canvas4.setFixedSize(500,150)                  


        self.XYZPlotWidget = QtGui.QWidget()
        self.fig2 = pylab.figure()
        self.axes2 = pylab.Axes(self.fig2, [.1,.1,.8,.8])
        self.fig2.add_axes(self.axes2)   
        self.plot2 = pylab.plot([0],[0],'r', [0],[0],'g', [0],[0],'b')
        self.axes2.set_xlim(-200, 0)
        self.axes2.set_ylim(-5, 5)
        pylab.legend([self.plot2[0], self.plot2[1], self.plot2[2]], ["X", "Y", "Z"], loc=3)
#        self.plotTitle2 = pylab.title('XYZ Data')
        self.plotxLabel2 = pylab.xlabel('Time')
        self.plotyLabel2 = pylab.ylabel('XYZ')
        self.canvas2 = FigureCanvas(self.fig2)       
        self.canvas2.setParent(self.XYZPlotWidget)
        self.canvas2.setFixedSize(500,150)
        
        self.PRPlotWidget = QtGui.QWidget()
        self.fig3 = pylab.figure()
        self.axes3 = pylab.Axes(self.fig3, [.1,.1,.8,.8])
        self.fig3.add_axes(self.axes3)   
        self.plot3 = pylab.plot([0],[0],'g', [0],[0],'r')
        self.axes3.set_xlim(-200, 0)
        self.axes3.set_ylim(-12, 12)
        pylab.legend([self.plot3[0], self.plot3[1]], ["Pitch", "Roll"], loc=3)
#        self.plotTitle3 = pylab.title('Pitch/Roll Data')
        self.plotxLabel3 = pylab.xlabel('Time')
        self.plotyLabel3 = pylab.ylabel('PR')
        self.canvas3 = FigureCanvas(self.fig3)       
        self.canvas3.setParent(self.PRPlotWidget)
        self.canvas3.setFixedSize(500,150)
        
        self.WWWWPlotWidget = QtGui.QWidget()
        self.fig4 = pylab.figure()
        self.axes4 = pylab.Axes(self.fig4, [.1,.1,.8,.8])
        self.fig4.add_axes(self.axes4)   
        self.plot4 = pylab.plot([0],[0],'r', [0],[0],'g', [0],[0],'b', [0],[0],'y')
        pylab.legend([self.plot4[0], self.plot4[1], self.plot4[2], self.plot4[3]], ["w1", "w2", "w3", "w4"], loc=3)
        self.axes4.set_xlim(-200, 0)
        self.axes4.set_ylim(-0.5, 0.5)
#        self.plotTitle4 = pylab.title('WWWW Data')
        self.plotxLabel4 = pylab.xlabel('Time')
        self.plotyLabel4 = pylab.ylabel('WWWW')
        self.canvas4 = FigureCanvas(self.fig4)       
        self.canvas4.setParent(self.WWWWPlotWidget)
        self.canvas4.setFixedSize(500,150)                
        
        self.lblX = QtGui.QLabel('X: ')
        self.lblY = QtGui.QLabel('Y: ')
        self.lblZ = QtGui.QLabel('Z: ')
        
        self.lblYaw = QtGui.QLabel('Yaw: ')
        self.lblPitch = QtGui.QLabel('Pitch: ')
        self.lblRoll = QtGui.QLabel('Roll: ')
        self.lblAltitude = QtGui.QLabel('Altitude: ')
        
        self.lblVX = QtGui.QLabel('Speed X: ')
        self.lblVY = QtGui.QLabel('Speed Y: ')
        self.lblVZ = QtGui.QLabel('Speed Z: ')
        
        self.lblTime = QtGui.QLabel('Time: ')
        self.lblCommand = QtGui.QLabel('Command: ')
        self.lblBattery = QtGui.QLabel('Battery: ')
        
        self.btnLoad = QtGui.QPushButton('Load')
        self.btnReplay = QtGui.QPushButton('Replay')

        self.mainLayout.addWidget(self.btnLoad,1,1)
        self.mainLayout.addWidget(self.btnReplay,1,2)
        
        self.mainLayout.addWidget(self.lblX,2,0)
        self.mainLayout.addWidget(self.lblY,2,1)
        self.mainLayout.addWidget(self.lblZ,2,2)
        
        self.mainLayout.addWidget(self.lblYaw,3,0)
        self.mainLayout.addWidget(self.lblPitch,3,1)
        self.mainLayout.addWidget(self.lblRoll,3,2)
        self.mainLayout.addWidget(self.lblAltitude,3,3)
        
        self.mainLayout.addWidget(self.lblVX,4,0)
        self.mainLayout.addWidget(self.lblVY,4,1)
        self.mainLayout.addWidget(self.lblVZ,4,2)
        
        self.mainLayout.addWidget(self.lblTime,5,0)
        self.mainLayout.addWidget(self.lblCommand,5,1)
        self.mainLayout.addWidget(self.lblBattery,5,2)
        
        self.mainLayout.addWidget(self.mpl_toolbar,6,0,1,4)
        self.mainLayout.addWidget(self.trackingPlotWidget,7,0,5,4)
        self.mainLayout.addWidget(self.XYZPlotWidget,2,5,6,4)
        self.mainLayout.addWidget(self.PRPlotWidget,8,5,2,4)
        self.mainLayout.addWidget(self.WWWWPlotWidget,10,5,2,4)
        
        for i in range(self.mainLayout.count()): 
            w = self.mainLayout.itemAt(i).widget()
            if type(w)==QtGui.QLabel: 
                w.setFixedSize(100, 15)
                
        
        QtCore.QObject.connect(self.btnReplay, QtCore.SIGNAL('clicked()'), Data_Visualization.visualize)
        QtCore.QObject.connect(self.btnLoad, QtCore.SIGNAL('clicked()'), Data_Visualization.open_file)
class GUI(QtGui.QWidget):
    def __init__(self):

        self.FFimage = 0
        self.BCK = 0
        self.Std_Dev_image = [0, 0]
        self.mask = [0, 0]
        self.savepath = 0
        self.BFpath = 0
        self.randcmap = plt.matplotlib.colors.ListedColormap(
            np.random.rand(256, 3))

        self.Hoffset = 0
        self.Voffset = 0

        super(GUI, self).__init__()

        self.setWindowTitle('FROS ANALYSIS')

        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):

        # SET THE GEOMETRY
        mainWindow = QtGui.QVBoxLayout()
        self.setLayout(mainWindow)
        self.setGeometry(100, 100, 900, 900)

        IObox = QtGui.QHBoxLayout()
        Canvasbox = QtGui.QHBoxLayout()
        Actionsbox = QtGui.QHBoxLayout()
        Textbox = QtGui.QVBoxLayout()

        Spinboxes = QtGui.QGridLayout()

        mainWindow.addLayout(IObox)
        mainWindow.addLayout(Canvasbox)
        mainWindow.addLayout(Actionsbox)
        mainWindow.addLayout(Textbox)

        Canvasbox.addLayout(Spinboxes)

        #        mainWindow.setRowMinimumHeight(9, 100)
        #        mainWindow.setRowMinimumHeight(12, 100)

        # DEFINE ALL WIDGETS AND BUTTONS

        #I/O
        loadBtn = QtGui.QPushButton('Load Bright Field image')
        loadBCKbtn = QtGui.QPushButton('Load Background Image')
        saveBtn = QtGui.QPushButton('Save data')

        #ACTIONS

        st_devBtn = QtGui.QPushButton('Compute Std Dev Image')
        SegmentationBtn = QtGui.QPushButton('Compute Segmentation Mask')
        remove_oddshsapeBtn = QtGui.QPushButton('Remove odd shaped objects')
        ALLSegmentationBtn = QtGui.QPushButton('Do ALL segmentation')

        ThScLbl = QtGui.QLabel('Threshold scaling:')
        SeedMinLbl = QtGui.QLabel('Seeds minimum size:')
        SeedMaxLbl = QtGui.QLabel('Seeds maximum size:')
        CellMinLbl = QtGui.QLabel('Cells minimum size:')
        CellMaxLbl = QtGui.QLabel('Cells maximum size:')
        OffStLbl = QtGui.QLabel('Offset:')
        BlckSzLbl = QtGui.QLabel('Block Size:')

        #SPINBOXES
        self.ThSc = QtGui.QDoubleSpinBox(self)
        self.ThSc.setSingleStep(0.01)
        self.ThSc.setMaximum(10000)
        self.ThSc.setValue(1)

        self.SeedMin = QtGui.QSpinBox(self)
        self.SeedMin.setMaximum(100000)
        self.SeedMin.setValue(0)

        self.SeedMax = QtGui.QSpinBox(self)
        self.SeedMax.setMaximum(100000)
        self.SeedMax.setValue(500)

        self.CellMin = QtGui.QSpinBox(self)
        self.CellMin.setMaximum(100000)
        self.CellMin.setValue(50)

        self.CellMax = QtGui.QSpinBox(self)
        self.CellMax.setMaximum(100000)
        self.CellMax.setValue(500)

        self.OffSt = QtGui.QSpinBox(self)
        self.OffSt.setRange(-100000, 100000)
        self.OffSt.setValue(-300)

        self.BlckSz = QtGui.QSpinBox(self)
        self.BlckSz.setMaximum(100000)
        self.BlckSz.setValue(101)

        self.StdBox = QtGui.QCheckBox('Method : Std Dev')
        self.OtsuBox = QtGui.QCheckBox('Method : Otsu')
        self.AdaptBox = QtGui.QCheckBox('Method : Adapt Threshold')

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFixedSize(QtCore.QSize(400, 400))

        self.fig2 = Figure((8.0, 8.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(400, 400))

        # PLACE ALL THE WIDGET ACCORDING TO THE mainWindowS

        IObox.addWidget(loadBtn)
        IObox.addWidget(loadBCKbtn)

        IObox.addWidget(saveBtn)

        Canvasbox.addWidget(self.canvas1)
        Canvasbox.addWidget(self.canvas2)

        Actionsbox.addWidget(st_devBtn)
        Actionsbox.addWidget(remove_oddshsapeBtn)
        Actionsbox.addWidget(SegmentationBtn)
        Actionsbox.addWidget(ALLSegmentationBtn)

        self.Toprinttext = QtGui.QTextEdit()
        Textbox.addWidget(self.Toprinttext)

        mainWindow.addWidget(self.HLine())

        Spinboxes.addWidget(ThScLbl, 0, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.ThSc, 0, 1, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(SeedMinLbl, 1, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.SeedMin, 1, 1, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(SeedMaxLbl, 2, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.SeedMax, 2, 1, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(CellMinLbl, 3, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.CellMin, 3, 1, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(CellMaxLbl, 4, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.CellMax, 4, 1, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.AdaptBox, 5, 0, 1, 1)
        Spinboxes.addWidget(self.OtsuBox, 6, 0, 1, 1)
        Spinboxes.addWidget(self.StdBox, 7, 0, 1, 1)

        Spinboxes.addWidget(self.HLine(), 8, 0, 1, 1, QtCore.Qt.AlignTop)

        Spinboxes.addWidget(OffStLbl, 9, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.OffSt, 9, 1, 1, 1, QtCore.Qt.AlignTop)

        Spinboxes.addWidget(BlckSzLbl, 10, 0, 1, 1, QtCore.Qt.AlignTop)
        Spinboxes.addWidget(self.BlckSz, 10, 1, 1, 1, QtCore.Qt.AlignTop)

        mainWindow.addWidget(self.HLine())

        mainWindow.addWidget(self.VLine())

        self.setFocus()
        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.loadDataset)
        loadBCKbtn.clicked.connect(self.loadBCKimage)
        saveBtn.clicked.connect(self.saveMask)
        SegmentationBtn.clicked.connect(self.Compute_SegmentationMask)
        remove_oddshsapeBtn.clicked.connect(self.Remove_odd_shaped_objects)
        st_devBtn.clicked.connect(self.Compute_StdDev)
        ALLSegmentationBtn.clicked.connect(self.do_ALL_segmentation)

        self.fig2.canvas.mpl_connect('button_press_event', self.remove_cells)


#        self.SeedMin.valueChanged.connect(self.updateCanvas1)

#-----------------------------------------------------------------------------------------------
# FORMATTING THE WINDOW
#-----------------------------------------------------------------------------------------------

    def center(self):
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())

    def HLine(self):
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def loadDataset(self):

        if self.BFpath:
            self.BFpath = QtGui.QFileDialog.getOpenFileName(
                self, 'Choose an Image', self.BFpath)
        else:
            self.BFpath = QtGui.QFileDialog.getOpenFileName(
                self, 'Choose an Image', '.')
        self.BF = io.imread(str(self.BFpath))
        self.bfname = str(self.BFpath).split("/")[-1]

        self.updateCanvas1()
        self.print_on_textbox(self.BFpath)
        self.setFocus()

    def loadBCKimage(self):

        self.BCKpath = QtGui.QFileDialog.getOpenFileName()
        self.BCK = io.imread(str(self.BCKpath))
        plt.imshow(self.BCK)
        plt.show()

    def Compute_StdDev(self):

        self.Std_Dev_image = std_image(self.BF)

    def Remove_odd_shaped_objects(self):

        for i in range(self.mask2.max()):

            tmpmask = self.mask2 == i
            rps = msr.regionprops(tmpmask.astype(np.int8))

            if rps[0].eccentricity < 0.85:
                self.mask2[self.mask2 == i] = 0
        [l, n] = msr.label(self.mask2, return_num=True)
        remove_reg(l, 50, 1000)
        self.mask2 = l
        self.updateCanvas1()
        self.updateCanvas2()

    def Compute_SegmentationMask(self):

        if self.StdBox.isChecked():

            if sum(sum(self.Std_Dev_image)) == 0:
                QtGui.QMessageBox.warning(
                    self, "Cannot perform required operation",
                    "Compute the standard deviation image first!",
                    QtGui.QMessageBox.Ok)

                return
            else:
                method = 'std'

        if self.AdaptBox.isChecked():

            method = 'adaptive'

        if self.OtsuBox.isChecked():

            method = 'otsu'

        [s, n, l] = mySegmentation(self.BF, self.Std_Dev_image, method, 'B',
                                   self.ThSc.value(), self.CellMin.value(),
                                   self.CellMax.value(), self.SeedMin.value(),
                                   self.SeedMax.value(), self.BlckSz.value(),
                                   self.OffSt.value())
        self.s = s
        self.mask = l
        self.mask2 = np.copy(self.mask)
        self.print_on_textbox(str(n))
        self.updateCanvas2()
        self.updateCanvas1()

    def do_ALL_segmentation(self):

        self.ALLpath = QtGui.QFileDialog.getExistingDirectory(
            self, 'choose folder containing all the bright field images',
            'H:\\Jacopo')
        self.savepath = QtGui.QFileDialog.getExistingDirectory(
            self, 'choose folder to save masks',
            'D:\\ANALISYS\\2015\\1.CLUSTER_OF_RECEPTORS_TRACKING')

        files = glob.glob(self.ALLpath + '/*.tif')
        print(files)
        for i in files:
            self.BF = io.imread(i)
            self.bfname = str(i).split("\\")[-1]

            self.Compute_SegmentationMask()
            self.Remove_odd_shaped_objects()

            myreply = QtGui.QMessageBox.warning(
                self, "are you ok with this segmentation?", "go on?",
                QtGui.QMessageBox.Ok, QtGui.QMessageBox.No,
                QtGui.QMessageBox.Cancel)

            if myreply == QtGui.QMessageBox.Ok:
                io.imsave(
                    str(self.savepath) + '/' + self.bfname[:-4] + '_mask' +
                    '.tif', self.mask2)
            if myreply == QtGui.QMessageBox.Cancel:
                break

    def saveMask(self):

        self.savepath = QtGui.QFileDialog.getExistingDirectory(
            self, 'choose saving position',
            'D:\\ANALISYS\\2015\\1.CLUSTER_OF_RECEPTORS_TRACKING\\1.Tracks_and_masks_for_mobility_structures'
        )

        io.imsave(
            str(self.savepath) + '/' + self.bfname[:-4] + '_mask' + '.tif',
            np.uint16(self.mask2))

    def remove_cells(self, event):

        value = self.mask2[np.round(event.ydata), np.round(event.xdata)]

        self.mask2[self.mask2 == value] = 0
        self.updateCanvas2()
        self.updateCanvas1()

    #-----------------------------------------------------------------------------------------------
    # UPDATE FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def print_on_textbox(self, mystring):

        self.Toprinttext.append(mystring)

    def updateCanvas1(self):
        self.ax1.cla()
        if sum(sum(self.mask)) != 0:

            self.BF2 = np.copy(self.BF)
            borders = sgm.find_boundaries(self.mask2)
            self.BF2[borders] = 0.2 * np.double(self.BF2.max())
            self.ax1.imshow(self.BF2, cmap='gray', interpolation='none')
            self.canvas1.draw()
            self.setFocus()
        else:

            self.ax1.imshow(self.BF, cmap='gray',
                            interpolation='none')  #,vmax=mymin*15,vmin=mymin)
            self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
            self.canvas1.draw()
            self.setFocus()

    def updateCanvas2(self):
        cmap = self.randcmap
        cmap.set_under(color='white')
        self.ax2.cla()
        self.ax2.imshow(self.mask2,
                        cmap=cmap,
                        interpolation='none',
                        vmin=0.0001)  #,vmax=mymin*15,vmin=mymin)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.canvas2.draw()
        self.setFocus()

    def keyPressEvent(self, event):
        #        print(event.key())

        self.mask2 = self.mask2.astype(np.float64)
        self.mask = self.mask.astype(np.float64)

        if event.key() == QtCore.Qt.Key_Right:

            self.Hoffset -= 1
            self.tform = tr.SimilarityTransform(
                translation=(int(self.Hoffset), int(self.Voffset)))
            self.mask2 = tr.warp(self.mask,
                                 self.tform,
                                 output_shape=(int(512), int(512)))
            [self.mask2, n] = msr.label(self.mask2, return_num=True)
            self.mask2 = sgm.clear_border(self.mask2)
            self.updateCanvas2()
            self.updateCanvas1()

        if event.key() == QtCore.Qt.Key_Left:

            self.Hoffset += 1

            self.tform = tr.SimilarityTransform(translation=(self.Hoffset,
                                                             self.Voffset))
            self.mask2 = tr.warp(self.mask,
                                 self.tform,
                                 output_shape=(int(512), int(512)))
            [self.mask2, n] = msr.label(self.mask2, return_num=True)
            self.mask2 = sgm.clear_border(self.mask2)
            self.updateCanvas2()
            self.updateCanvas1()

        if event.key() == QtCore.Qt.Key_Up:

            self.Voffset += 1

            self.tform = tr.SimilarityTransform(translation=(self.Hoffset,
                                                             self.Voffset))
            self.mask2 = tr.warp(self.mask,
                                 self.tform,
                                 output_shape=(int(512), int(512)))
            [self.mask2, n] = msr.label(self.mask2, return_num=True)
            self.mask2 = sgm.clear_border(self.mask2)
            self.updateCanvas2()
            self.updateCanvas1()

        if event.key() == QtCore.Qt.Key_Down:

            self.Voffset -= 1

            self.tform = tr.SimilarityTransform(translation=(self.Hoffset,
                                                             self.Voffset))
            self.mask2 = tr.warp(self.mask,
                                 self.tform,
                                 output_shape=(int(512), int(512)))
            [self.mask2, n] = msr.label(self.mask2, return_num=True)
            self.mask2 = sgm.clear_border(self.mask2)
            self.updateCanvas2()
            self.updateCanvas1()

        self.setFocus()
예제 #22
0
class GUI(QtGui.QWidget):
    def __init__(self):

        super(GUI, self).__init__()

        self.setWindowTitle('Label Cells')
        self.cellNames = [
            '1.p', '4.a', '1.pp', '4.aa', '1.ppa', '1.ppp', '4.aaa', '4.aap',
            'b_1', 'b_4'
        ]
        self.initUI()

    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):

        # SET THE GEOMETRY

        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)

        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()

        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)

        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()

        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)

        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS

        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')

        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')

        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(0)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')

        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')

        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16 - 1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16 - 1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600, 600))
        self.canvas1.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300, 300))
        self.canvas2.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)

        # self.cellNamesBox=QtGui.QMenu(self.canvas1)
        # actn = []
        # for cname in self.cellNames:
        #     actn.append( QtGui.QAction(cname, self.cellNamesBox) )
        #     self.cellNamesBox.addAction(actn[-1])
        #     actn[-1].triggered.connect( lambda item = cname : self.actionFunct(cname) )

        self.cellNamesBox = QtGui.QMenu(self.canvas1)

        ### define all actions (can be done better!!!)
        actn1p = QtGui.QAction('1.p', self.cellNamesBox)
        self.cellNamesBox.addAction(actn1p)
        actn1p.triggered.connect(lambda item='1.p': self.actionFunct1p('1.p'))

        actn1pp = QtGui.QAction('1.pp', self.cellNamesBox)
        self.cellNamesBox.addAction(actn1pp)
        actn1pp.triggered.connect(
            lambda item='1.pp': self.actionFunct1pp('1.pp'))

        actn1ppp = QtGui.QAction('1.ppp', self.cellNamesBox)
        self.cellNamesBox.addAction(actn1ppp)
        actn1ppp.triggered.connect(
            lambda item='1.ppp': self.actionFunct1ppp('1.ppp'))

        actn1ppa = QtGui.QAction('1.ppa', self.cellNamesBox)
        self.cellNamesBox.addAction(actn1ppa)
        actn1ppa.triggered.connect(
            lambda item='1.ppa': self.actionFunct1ppa('1.ppa'))

        actn4a = QtGui.QAction('4.a', self.cellNamesBox)
        self.cellNamesBox.addAction(actn4a)
        actn4a.triggered.connect(lambda item='4.a': self.actionFunct4a('4.a'))

        actn4aa = QtGui.QAction('4.aa', self.cellNamesBox)
        self.cellNamesBox.addAction(actn4aa)
        actn4aa.triggered.connect(
            lambda item='4.aa': self.actionFunct4aa('4.aa'))

        actn4aaa = QtGui.QAction('4.aaa', self.cellNamesBox)
        self.cellNamesBox.addAction(actn4aaa)
        actn4aaa.triggered.connect(
            lambda item='4.aaa': self.actionFunct4aaa('4.aaa'))

        actn4aap = QtGui.QAction('4.aap', self.cellNamesBox)
        self.cellNamesBox.addAction(actn4aap)
        actn4aap.triggered.connect(
            lambda item='4.aap': self.actionFunct4aap('4.aap'))

        actnb1 = QtGui.QAction('b_1', self.cellNamesBox)
        self.cellNamesBox.addAction(actnb1)
        actnb1.triggered.connect(lambda item='b_1': self.actionFunctb1('b_1'))

        actnb4 = QtGui.QAction('b_4', self.cellNamesBox)
        self.cellNamesBox.addAction(actnb4)
        actnb4.triggered.connect(lambda item='b_4': self.actionFunctb4('b_4'))
        ### END OF THE UGLY PART :)

        self.cellNamesBox.installEventFilter(self)
        self.canvas1.installEventFilter(self)
        self.cellNamesBox.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.cellNamesBox.connect(
            self.cellNamesBox,
            QtCore.SIGNAL("customContextMenuRequested(QPoint)"),
            self.leftClicked)

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)  #, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0)
        Col1.addWidget(self._561nmBtn, 4, 0)
        Col1.addWidget(self.CoolLEDBtn, 5, 0)

        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        # Col3.addWidget(self.cellTbl)
        # Col3.addWidget(self.cellNamesBox)
        Col3.addWidget(self.canvas2)

        self.setFocus()

        self.show()

        # BIND BUTTONS TO FUNCTIONS

        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.checkNames = True
        self.tp.valueChanged.connect(self.changeTp)
        self.sl.valueChanged.connect(self.updateCanvas1)
        self.sld1.valueChanged.connect(self.updateBC)
        self.sld2.valueChanged.connect(self.updateBC)

        self._488nmBtn.toggled.connect(self.radio488Clicked)
        self._561nmBtn.toggled.connect(self.radio561Clicked)
        self.CoolLEDBtn.toggled.connect(self.radioCoolLEDClicked)

        self.fig1.canvas.mpl_connect('scroll_event', self.wheelEvent)

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def HLine(self):

        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    #-----------------------------------------------------------------------------------------------
    # ACTION FUNCTIONS in THE POPUP MENU
    #-----------------------------------------------------------------------------------------------

    def changeName(self, item):
        idx = len(self.currentCells.cname) - 1
        self.currentCells.ix[idx, 'cname'] = str(item)
        self.currentCells = self.currentCells.reset_index(drop=True)

        self.updateCanvas1()
        self.setFocus()

    def actionFunct1p(self, item):
        self.changeName(item)

    def actionFunct1pp(self, item):
        self.changeName(item)

    def actionFunct1ppp(self, item):
        self.changeName(item)

    def actionFunct1ppa(self, item):
        self.changeName(item)

    def actionFunct4a(self, item):
        self.changeName(item)

    def actionFunct4aa(self, item):
        self.changeName(item)

    def actionFunct4aaa(self, item):
        self.changeName(item)

    def actionFunct4aap(self, item):
        self.changeName(item)

    def actionFunctb1(self, item):
        self.changeName(item)

    def actionFunctb4(self, item):
        self.changeName(item)

    def eventFilter(self, widget, event):
        # print( 'eventFilter', widget, event)
        if widget == self.canvas1 and isinstance(
                event,
                QtGui.QMouseEvent) and event.buttons() & QtCore.Qt.LeftButton:
            self.leftClicked(event.pos())
            return True
        if widget == self.canvas1 and isinstance(
                event,
                QtGui.QMouseEvent) and event.buttons() & QtCore.Qt.RightButton:
            self.rightClicked(event.pos())
            return True
        return False

    def leftClicked(self, QPos):
        refpos = np.array([
            int(QPos.x() / 600. * 512.),
            int(QPos.y() / 600. * 512.),
            self.sl.value()
        ])
        # print(refpos)

        # create an empty cell in the currentCells df: the only entries are tidx, xyzpos and cname
        newcell = create_single_cell_pos(refpos.astype(np.uint16),
                                         self.tp.value())
        self.currentCells = pd.concat([self.currentCells, newcell])

        self.currentCells = self.currentCells.reset_index(drop=True)

        self.updateCanvas1()

        parentPosition = self.canvas1.mapToGlobal(QtCore.QPoint(0, 0))
        # print('leftClicked', QPos, parentPosition)
        menuPosition = parentPosition + QPos

        self.cellNamesBox.move(menuPosition)
        self.cellNamesBox.show()
        self.setFocus()

    def rightClicked(self, QPos):
        refpos = np.array(
            [QPos.x() / 600. * 512.,
             QPos.y() / 600. * 512.,
             self.sl.value()])
        # print(refpos)

        if len(self.currentCells) == 0:
            self.setFocus()
            return

        # remove a cell (the closest to the cursor at the moment of right-click)
        idx = closer_cell(refpos.astype(np.uint16), self.currentCells)
        self.currentCells = self.currentCells.drop([idx])
        self.currentCells = self.currentCells.reset_index(drop=True)

        self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(
            self, 'Select a folder',
            'X:/Simone/160129_MCHERRY_HLH2GFP_onHB101')  #'Y:\\Images')
        self.worm = self.pathDial.split("/")[-1].split('_')[0]
        self.path = os.path.dirname(self.pathDial)
        self.setWindowTitle('Label cells - ' + self.pathDial.split("/")[-2] +
                            ' - ' + self.pathDial.split("/")[-1][:3])

        ### give error message if there is no CoolLED movie in the selected folder
        flist = glob.glob(self.pathDial + '/*_movie.tif')
        if len(
                flist
        ) == 0:  #not os.path.isfile( os.path.join( self.pathDial, '*_movie.tif' ) ):
            QtGui.QMessageBox.about(
                self, 'Warning!',
                'There is no movie in this folder! Create a movie first!')
            return

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame_pandas(self.path,
                                               self.worm + '_01params.pickle')
        self.timesDF = load_data_frame_pandas(self.path,
                                              self.worm + '_01times.pickle')
        self.gpDF = load_data_frame_pandas(self.path,
                                           self.worm + '_02gonadPos.pickle')

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int(self.paramsDF.tidxHatch)

        ### if the cellPos pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile(
                os.path.join(self.path, self.worm + '_04cellPos.pickle')):
            self.cellPosDF = load_data_frame_pandas(
                self.path, self.worm + '_04cellPos.pickle')

        else:
            self.cellPosDF = create_cell_pos(self.timesDF, self.cellNames)

        # detect available channels
        self.channels = []
        chns = ['CoolLED', '488nm', '561nm']
        for c in chns:

            if os.path.isfile(os.path.join(self.pathDial, c + '_movie.tif')):

                self.channels.append(c)
        self.currentChannel = self.channels[0]

        ### detect size of the cropped images
        tp = np.min(self.gpDF.ix[pd.notnull(self.gpDF.X), 'tidx'])
        self.prevtp = tp - 1
        tRow = self.timesDF.ix[self.timesDF.tidxRel == tp].squeeze()
        fileName = os.path.join(self.pathDial,
                                tRow.fName + self.currentChannel + '.tif')
        firststack = load_stack(fileName)
        self.cropsize = firststack.shape[1]
        self.nslices = firststack.shape[0]

        ### load CoolLED movie
        if 'CoolLED' in self.channels:
            self.LEDmovie = load_stack(
                os.path.join(self.pathDial, 'CoolLED_movie.tif'))
        else:
            self.LEDmovie = load_stack(
                os.path.join(self.pathDial,
                             self.currentChannel + '_movie.tif'))
        self.initializeCanvas1()
        self.initializeCanvas2()

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_pos(self.cellPosDF,
                                                     self.tp.value())

        ### update the text of the fileName
        self.fName.setText(self.timesDF.ix[self.timesDF.tidxRel == tp,
                                           'fName'].values[0])

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))

        ### set the max slice number
        self.sl.setMaximum(self.nslices - 1)

        self.tp.setValue(tp)

        if self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(
                True)  # this uppdates the canvas1 once more
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(
                True)  # this uppdates the canvas1 once more
        elif self.currentChannel == '488nm':
            self._488nmBtn.setChecked(
                True)  # this uppdates the canvas1 once more

        # self.pathDial.show()
        self.setFocus()

    def loadNewStack(self):

        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[self.timesDF.tidxRel ==
                               self.tp.value()].squeeze()

        ### update the text of the fileName
        self.fName.setText(
            self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                            'fName'].values[0])

        print('Loading... ', self.pathDial, tRow.fName)

        # calculate the max value of the previous stack
        try:
            prevmax = np.max([np.max(self.stacks[ch]) for ch in self.channels])
        # if it's the first time a stack is to be loaded (so if there is no previous stack), set it to zero
        except:
            prevmax = 0

        # load all the available stacks - this is the slowest part of the code!!!
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join(self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile(fileName):
                # print(MultiImage('X:\\Simone\\160129_MCHERRY_HLH2GFP_onHB101\\C02_analyzedImages\\Z003_488nm.tif'))
                # print(fileName, MultiImage( fileName ))
                # self.stacks[ch] = MultiImage( fileName )
                self.stacks[ch] = load_stack(fileName)
            # if there are no files for the timepoint, create a blank image
            else:
                self.stacks[ch] = prevmax * np.ones(
                    (self.nslices, self.cropsize, self.cropsize))

        # if the BC bound are different, the BCsliderMinMax will automatically update canvas1. Otherwise, manually update it!
        self.setBCslidersMinMax()

        self.updateCanvas1()
        self.updateCanvas2()

    def changeTp(self):

        # if it's the second time you are checking the same tp, don't do anything
        if self.checkNames:
            cellFine = self.checkConsistencyCellNames()
        else:
            return

        # before changing timepoint, print labeled cells and check if they are OK
        print('cells labeled:\n ', self.currentCells)

        ### extract current cells already labeled
        self.newCells = extract_current_cell_pos(self.cellPosDF,
                                                 self.tp.value())

        if cellFine:
            # if everything fine, load the new stack
            self.currentCells = self.newCells
            self.loadNewStack()
        else:
            # otherwise, go back to prev tp
            self.checkNames = False
            self.tp.setValue(self.prevtp)
            self.checkNames = True

        self.prevtp = self.tp.value()

    def saveData(self):

        if self.checkConsistencyCellNames():
            save_data_frame(self.cellPosDF, self.path,
                            self.worm + '_04cellPos.pickle')
        else:
            QtGui.QMessageBox.about(self, 'Warning!',
                                    'There is a mistake in the cell labels!')
        self.setFocus()

    def radio488Clicked(self, enabled):
        # print('radio 488 clicked')

        if enabled:
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')

    def radio561Clicked(self, enabled):
        # print('radio 561 clicked')

        if enabled:
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == 'CoolLED':
                    self.CoolLEDBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')

    def radioCoolLEDClicked(self, enabled):
        # print('radio LED clicked')

        if enabled:
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
                self.setFocus()
                self.updateCanvas1()
            else:
                if self.currentChannel == '561nm':
                    self._561nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                elif self.currentChannel == '488nm':
                    self._488nmBtn.setChecked(
                        True)  # this uppdates the canvas1 once more
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')

    def updateBC(self):
        # change brightness and contrast
        self.imgplot1.set_clim(self.sld1.value(), self.sld2.value())
        self.canvas1.draw()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):

        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime('time', +1)

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime('time', -1)

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime('space', +1)

        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime('space', -1)

        elif event.key() == QtCore.Qt.Key_PageDown:
            idx = self.channels.index(self.currentChannel)
            if self.channels[(idx + 1) % len(self.channels)] == 'CoolLED':
                self.CoolLEDBtn.setChecked(True)
            if self.channels[(idx + 1) % len(self.channels)] == '488nm':
                self._488nmBtn.setChecked(True)
            if self.channels[(idx + 1) % len(self.channels)] == '561nm':
                self._561nmBtn.setChecked(True)
        elif event.key() == QtCore.Qt.Key_PageUp:
            idx = self.channels.index(self.currentChannel)
            if self.channels[(idx - 1) % len(self.channels)] == 'CoolLED':
                self.CoolLEDBtn.setChecked(True)
            if self.channels[(idx - 1) % len(self.channels)] == '488nm':
                self._488nmBtn.setChecked(True)
            if self.channels[(idx - 1) % len(self.channels)] == '561nm':
                self._561nmBtn.setChecked(True)

        # key press on cropped image
        if self.canvas1.underMouse():
            self.onKeyPressOnCanvas1(event)

        self.setFocus()

    def wheelEvent(self, event):
        if self.canvas1.underMouse():
            step = event.step
        else:
            step = event.delta() / abs(event.delta())
        self.sl.setValue(self.sl.value() + step)

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onKeyPressOnCanvas1(self, event):

        motherCells = [QtCore.Qt.Key_1, QtCore.Qt.Key_4, QtCore.Qt.Key_B]
        daughterCells = [QtCore.Qt.Key_A, QtCore.Qt.Key_P]

        # find the position of the cursor relative to the image in pixel
        imgshape = self.stacks[self.currentChannel][self.sl.value()].shape
        canshape = self.canvas1.size()
        cf = imgshape[0] / canshape.width()
        refpos = self.canvas1.mapFromGlobal(QtGui.QCursor.pos())
        refpos = np.array([int(refpos.x() * cf), int(refpos.y() * cf)])
        refpos = np.append(refpos, self.sl.value())

        ### find the closest cell to the cursor
        idx = closer_cell(refpos.astype(np.uint16), self.currentCells)

        ### assign the name to the cell
        if any([event.key() == cn for cn in motherCells]):
            # if labeling bckg, add the 1 or 2 to the name
            if self.currentCells.ix[idx, 'cname'] == 'b_':
                self.currentCells.ix[idx, 'cname'] += QtGui.QKeySequence(
                    event.key()).toString().lower()
            else:
                # if not, rename the cell from scratch
                if event.key() == QtCore.Qt.Key_B:
                    self.currentCells.ix[idx, 'cname'] = QtGui.QKeySequence(
                        event.key()).toString().lower() + '_'
                else:
                    self.currentCells.ix[idx, 'cname'] = QtGui.QKeySequence(
                        event.key()).toString().lower() + '.'

        # add the anterior/posterior to the cell name
        elif any([event.key() == cp for cp in daughterCells]):
            # don't do it if labeling background (bckg doesn't have a/p!)
            if self.currentCells.ix[idx, 'cname'] == 'b_':
                return
            else:
                self.currentCells.ix[idx, 'cname'] += QtGui.QKeySequence(
                    event.key()).toString().lower()

        # remove the last entry of the name with backspace
        elif event.key() == QtCore.Qt.Key_Backspace:
            self.currentCells.ix[idx,
                                 'cname'] = self.currentCells.ix[idx,
                                                                 'cname'][:-1]

        if (event.key() != QtCore.Qt.Key_Left) and (
                event.key() != QtCore.Qt.Key_Right) and (
                    event.key() != QtCore.Qt.Key_Up) and (event.key() !=
                                                          QtCore.Qt.Key_Down):
            self.updateCanvas1()
        self.setFocus()

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(
            np.max([np.max(self.stacks[ch]) for ch in self.channels]))
        self.sld1.setMinimum(0)
        self.sld2.setMaximum(
            np.max([np.max(self.stacks[ch]) for ch in self.channels]))
        self.sld2.setMinimum(0)

    def initializeCanvas1(self):
        # print('initializing canvas1')

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        # plot the first blank image with the right size
        self.ax1.cla()
        self.imgplot1 = self.ax1.imshow(np.zeros(
            (self.cropsize, self.cropsize)),
                                        cmap='gray')

        # remove the white borders
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # plot cell pos and name
        self.text1 = []
        self.points1 = []

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas1(self):
        # print('updating canvas1')

        # plot the image
        self.imgplot1.set_data(
            self.stacks[self.currentChannel][self.sl.value()])

        # change brightness and contrast
        self.imgplot1.set_clim(self.sld1.value(), self.sld2.value())

        # clear cell text and points
        # print(self.text1,self.points1)
        for text in self.text1:
            text.remove()
        self.text1 = []

        for points in self.points1:
            self.ax1.lines.remove(points)
        self.points1 = []

        # draw cell text and point
        for idx, cell in self.currentCells.iterrows():

            if cell.Z == self.sl.value():

                self.text1.append(
                    self.ax1.text(cell.X,
                                  cell.Y + 18,
                                  cell.cname,
                                  color='orange',
                                  fontsize=10,
                                  alpha=.7,
                                  rotation=0))
                self.points1.append(
                    self.ax1.plot(cell.X,
                                  cell.Y,
                                  'o',
                                  color='orange',
                                  alpha=.7,
                                  mew=0,
                                  ms=6)[0])

        # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def initializeCanvas2(self):
        # print('initializing canvas2')

        # plot the image
        self.ax2.cla()
        self.imgplot2 = self.ax2.imshow(np.zeros((512, 512)), cmap='gray')
        self.imgplot2.set_clim(np.min(self.LEDmovie), np.max(self.LEDmovie))

        # remove the white borders and plot outline and spline
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print gonad position
        gonadPos = [np.nan, np.nan]
        self.points2, = self.ax2.plot(gonadPos[0],
                                      gonadPos[1],
                                      'o',
                                      color='blue',
                                      ms=10,
                                      mew=0,
                                      alpha=.5,
                                      lw=0)

        # print time
        self.text2 = self.ax2.text(5, 25, '--.--', color='white')

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def updateCanvas2(self):
        # print('updating canvas2')
        # plot the image
        self.imgplot2.set_data(self.LEDmovie[self.tp.value() +
                                             self.hatchingtidx])

        # print gonad position
        gonadPos = extract_pos(self.gpDF.ix[
            self.gpDF.tidx == self.tp.value()].squeeze()) / self.compression
        if len(gonadPos.shape) > 0:
            self.points2.set_xdata(gonadPos[0])
            self.points2.set_ydata(gonadPos[1])
            plt.draw()

        # print time
        # print time
        ### find ecdysis timepoint
        ecd = np.loadtxt(open(os.path.join(self.path, 'skin.txt'), 'rb'))
        # load ecdysis data
        index = np.where(ecd[:, 0] == float(self.worm[1:]))
        mintp = np.min([i for i in ecd[index, 1:6][0][0] if i >= 0])
        lethtidx = ecd[index, 1:6][0][0]
        lethtidx = lethtidx[lethtidx >= 0]
        tpL2 = self.timesDF.ix[self.timesDF.tidxRel == (lethtidx[1] - mintp),
                               'timesRel'].values[0]
        # print(self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'timesRel' ])
        self.text2.set_text(
            '%.2f' % (self.timesDF.ix[self.timesDF.tidxRel == self.tp.value(),
                                      'timesRel'].values[0] - tpL2))

        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def checkConsistencyCellNames(self):
        ### check consistency of cell names
        tp = self.prevtp

        # if no cells are labeled (currentCells df is empty), remove all labeled cells in the cellPosDF and return
        if len(self.currentCells) == 0:
            newCellPosDF = update_cell_pos_DF(self.currentCells,
                                              self.cellPosDF, tp)
            correctCellNames = True

        if len(self.currentCells) > 0:

            correctCellNames = check_cell_names(self.currentCells,
                                                self.cellNames)

            # if cells are not properly labeled, give a Warning
            if not correctCellNames:
                QtGui.QMessageBox.about(
                    self, 'Warning!', 'There is a mistake in the cell labels!')

            # else, update final cellPosDF and return OK
            else:
                newCellPosDF = update_cell_pos_DF(self.currentCells,
                                                  self.cellPosDF, tp)
                self.cellPosDF = newCellPosDF

        return correctCellNames

    def changeSpaceTime(self, whatToChange, increment):

        if whatToChange == 'time':
            # if they are OK (and not going to negative times), change timepoint
            self.tp.setValue(self.tp.value() + increment)

        if whatToChange == 'space':
            self.sl.setValue(self.sl.value() + increment)
예제 #23
0
class PomoWindow(QtGui.QWidget):
    def __init__(self, pomo):
        """
        Makes necessary variable initializations and calls other init methods.
        """
        super(PomoWindow, self).__init__()
        self.pomo = pomo
        # Enhance readability
        self.getString = self.pomo.getString
        self.initUI()
        if useAudio:
            self.initAudio()
        self.timerActive = False
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.tick)

    def initUI(self):
        """
        Initializes the UI.
        """
        # Set some general window settings.
        self.setFixedSize(480, 310)
        self.move(250, 250)
        self.setWindowTitle(self.getString("app_name"))
        self.setWindowIcon(QtGui.QIcon('/usr/share/icons/pomodorino.png'))
        self.trayIcon = QtGui.QSystemTrayIcon(
            QtGui.QIcon('/usr/share/icons/pomodorino.png'), self)
        self.trayIcon.setVisible(True)
        self.trayIcon.activated.connect(self.trayClick)

        # Add a minimal context menu for the tray icon.
        #trayMenu = QtGui.QMenu(self)
        #trayMenu.addAction("Quit", self.close)
        #self.trayIcon.setContextMenu(trayMenu)

        # Initialize and display the tabs
        pomoTab = self.initPomoTab()
        tasksTab = self.initTasksTab()
        activityTab = self.initActivityTab()

        tabWidget = QtGui.QTabWidget(self)
        tabWidget.resize(479, 309)

        tabWidget.addTab(pomoTab, self.getString("tab_pomo"))
        tabWidget.addTab(tasksTab, self.getString("tab_tasks"))
        tabWidget.addTab(activityTab, self.getString("tab_activity"))

        self.show()

    def initAudio(self):
        """
        Detects an ALSA audio device and buffers our ringtone.
        """
        # Detect an ALSA audio device
        self.audioDevice = alsaaudio.PCM()

        # Open the ringtone and set some audio settings.
        ring = wave.open("/usr/share/pomodorino/ring.wav", 'rb')
        self.audioDevice.setchannels(ring.getnchannels())
        self.audioDevice.setrate(ring.getframerate())
        self.audioDevice.setformat(alsaaudio.PCM_FORMAT_S16_LE)
        self.audioDevice.setperiodsize(320)

        # Read the audio data of the ringtone.
        self.audioData = list()
        buf = ring.readframes(320)
        while buf:
            self.audioData.append(buf)
            buf = ring.readframes(320)

    def closeEvent(self, event):
        """
        Prevents accidental shutdowns by asking the user.
        """
        if self.timerActive:
            self.stopTimer()

            if self.promptUser("ask_paused"):
                event.accept()
            else:
                event.ignore()
                self.startTimer(0, restart=True)
        else:
            event.accept()

    def setTitle(self, title):
        """
        Sets the window title.
        """
        if title is None:
            title = self.getString("app_name")
        else:
            title += " - " + self.getString("app_name")

        self.window().setWindowTitle(title)

    def startTimer(self, timeSpan, restart=False):
        """
        Starts the timer.
        """
        if restart is False:
            self.timerType = timeSpan
            self.timerCount = timeSpan * 60
        self.timerActive = True
        self.timer.start(1000)

    def stopTimer(self):
        """
        Stops the timer.
        """
        self.timerActive = False
        self.timer.stop()

    def resetTimer(self):
        """
        Resets the timer.
        """
        self.stopTimer()
        self.timerCount = 0

    def finishTimer(self, task):
        """
        Is called once the timer finished.
        """
        self.resetTimer()
        # Define the regular length of a pomodoro. Purely for debugging reasons
        POMO_CONST = 25
        pomos = math.floor(self.timerType / POMO_CONST)
        self.setVisible(True)
        if pomos >= 1 and task != '':
            newTask = self.pomo.pomoData.addPomo(task, pomos)
            if newTask is True:
                self.pomoTaskBar.addItem(task, None)
            self.fillActivityTab()
            self.updateTasksTab()

    def trayClick(self, reason):
        """
        Is called when the user clicks on the tray icon.
        """
        if reason == 2 or reason == 3:
            if self.isVisible():
                self.setVisible(False)
            else:
                self.setVisible(True)

    def promptUser(self, identifier, additional=None):
        """
        Creates predefined confirmation/warning dialogs.
        """
        if identifier == 'ask_paused':
            reply = QtGui.QMessageBox.question(
                self, self.getString("ask_paused_title"),
                self.getString("ask_paused_text"),
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No)
            if reply == QtGui.QMessageBox.Yes:
                return True
            else:
                return False

        elif identifier == 'warn_notask':
            QtGui.QMessageBox.warning(self,
                                      self.getString("warn_notask_title"),
                                      self.getString("warn_notask_text"))
            return

        elif identifier == 'ask_taskdel' and additional != None:
            askText = self.getString("ask_taskdel_text")
            askText = str.replace(askText, "%taskname%", str(additional))

            reply = QtGui.QMessageBox.question(
                self, self.getString("ask_taskdel_title"), askText,
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No)

            if reply == QtGui.QMessageBox.Yes:
                return True
            else:
                return False

        raise KeyError

    ##############
    ## Pomo Tab ##
    ##############

    def initPomoTab(self):
        """
        Creates the layout of the pomodoro tab
        """
        pomoTab = QtGui.QWidget()

        # Create a combobox with a lineedit for task selection.
        taskBar = QtGui.QComboBox()
        taskBar.setEditable(True)
        taskBarLine = taskBar.lineEdit()
        taskBarLine.setMaxLength(64)
        taskBarLine.setPlaceholderText(self.getString("input_task"))
        taskBar.setFixedSize(375, 32)
        taskBar.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically)
        taskBar.setStyleSheet('font-size: 11pt;')
        taskBar.addItem("", None)
        self.pomoTaskBar = taskBar

        # Add all the task names.
        tasks = self.pomo.pomoData.tasks
        for taskID, taskName, pomoCount, pomoLast in tasks:
            taskBar.addItem(taskName, None)

        # Create the main button.
        mainBtn = QtGui.QPushButton(self.getString("btn_start"), pomoTab)
        mainBtn.setFixedSize(180, 60)
        mainBtn.setStyleSheet('font-size: 17pt;')

        # Create the 25 min button.
        timeBtn = QtGui.QPushButton(self.getString("lbl_regularpomo"), pomoTab)
        timeBtn.setToolTip(self.getString("ttp_regularpomo"))
        timeBtn.setFixedSize(50, 25)
        timeBtn.setStyleSheet('font-size: 9pt;')

        # Create the 50 min button.
        longTimeBtn = QtGui.QPushButton(self.getString("lbl_longpomo"),
                                        pomoTab)
        longTimeBtn.setToolTip(self.getString("ttp_longpomo"))
        longTimeBtn.setFixedSize(50, 25)
        longTimeBtn.setStyleSheet('font-size: 9pt;')

        # Create the 5 min button.
        pauseBtn = QtGui.QPushButton(self.getString("lbl_shortpause"), pomoTab)
        pauseBtn.setToolTip(self.getString("ttp_shortpause"))
        pauseBtn.setFixedSize(50, 25)
        pauseBtn.setStyleSheet('font-size: 9pt;')

        # Create the 10 min button.
        longPauseBtn = QtGui.QPushButton(self.getString("lbl_longpause"),
                                         pomoTab)
        longPauseBtn.setToolTip(self.getString("ttp_longpause"))
        longPauseBtn.setFixedSize(50, 25)
        longPauseBtn.setStyleSheet('font-size: 9pt;')

        # Select 25 min button as default on startup.
        timeBtn.setDisabled(True)
        self.pomoButtonActive = timeBtn

        # Save button references for later usage.
        self.pomoBtns = dict()
        self.pomoBtns['main'] = mainBtn
        self.pomoBtns['time'] = timeBtn
        self.pomoBtns['longTime'] = longTimeBtn
        self.pomoBtns['pause'] = pauseBtn
        self.pomoBtns['longPause'] = longPauseBtn

        # Connect the buttons to the handler function.
        for name, button in self.pomoBtns.items():
            button.clicked.connect(self.onClicked)

        # Create and set the layout.
        firstRow = QtGui.QHBoxLayout()
        firstRow.addWidget(taskBar)

        secondRow = QtGui.QHBoxLayout()
        secondRow.addStretch()
        secondRow.addWidget(pauseBtn)
        secondRow.addWidget(longPauseBtn)
        secondRow.addStretch()
        secondRow.addWidget(timeBtn)
        secondRow.addWidget(longTimeBtn)
        secondRow.addStretch()

        thirdRow = QtGui.QHBoxLayout()
        thirdRow.addWidget(mainBtn)

        vbox = QtGui.QVBoxLayout()
        vbox.addStretch()
        vbox.addLayout(firstRow)
        vbox.addStretch()
        vbox.addLayout(secondRow)
        vbox.addStretch()
        vbox.addLayout(thirdRow)
        vbox.addStretch()

        pomoTab.setLayout(vbox)

        return pomoTab

    def onClicked(self):
        """
        Main function for catching button clicks in the pomo tab.
        """
        sender = self.sender()
        if sender == self.pomoBtns['main']:
            return self.onClickedPomoMain()

        elif (sender == self.pomoBtns['pause']
              or sender == self.pomoBtns['longPause']
              or sender == self.pomoBtns['time']
              or sender == self.pomoBtns['longTime']):
            return self.onClickedPomoTime()

        raise ValueError()

    def onClickedPomoMain(self):
        """
        Starts/Stops the timer depending on the state of the button.
        """
        sender = self.sender()

        if self.timerActive:
            self.stopTimer()
            # Ask the user whether he wants to reset the running timer.
            if self.promptUser("ask_paused"):
                self.resetPomoTab()
                self.resetTimer()
            else:
                self.startTimer(0, restart=True)
        else:
            newText = self.pomoTaskBar.currentText().strip()
            self.pomoTaskBar.setEditText(newText)

            if newText != "" or self.pomoTaskBar.isEnabled() is False:
                self.pomoTaskBar.setDisabled(True)
                for k, v in self.pomoBtns.items():
                    if k != 'main':
                        v.setDisabled(True)
                timeSpan = int(self.pomoButtonActive.text())
                title = "{0:0>2}:00".format(timeSpan)
                sender.setText(title)
                self.setTitle(title)
                self.startTimer(timeSpan)
            else:
                self.promptUser("warn_notask")

    def onClickedPomoTime(self):
        """
        Toggles the state of the timer buttons in the pomo tab.
        """
        sender = self.sender()

        if self.pomoBtns['main'].text() == 'start':
            self.pomoButtonActive.setDisabled(False)
            sender.setDisabled(True)
            self.pomoButtonActive = sender

            if sender == self.pomoBtns['pause'] or sender == self.pomoBtns[
                    'longPause']:
                self.pomoTaskBar.setDisabled(True)
            else:
                self.pomoTaskBar.setDisabled(False)

    def resetPomoTab(self):
        """
        Resets the button states in the pomo tab.
        """
        if self.pomoButtonActive != self.pomoBtns[
                'pause'] and self.pomoButtonActive != self.pomoBtns[
                    'longPause']:
            self.pomoTaskBar.setDisabled(False)

        self.pomoBtns['main'].setText("start")
        for k, v in self.pomoBtns.items():
            if k != 'main' and v is not self.pomoButtonActive:
                v.setDisabled(False)

        # Also reset the window title.
        self.setTitle(None)

    def tick(self):
        """
        Updates the GUI every second when the timer is running.
        """
        self.timerCount -= 1

        timeStr = "{0:0>2}:{1:0>2}".format(math.floor(self.timerCount / 60),
                                           self.timerCount % 60)
        self.pomoBtns['main'].setText(timeStr)
        # Show current time in the title.
        self.setTitle(timeStr)

        # Timer finished?
        if self.timerCount == 0:
            self.playRingtone()
            self.finishTimer(self.pomoTaskBar.currentText())
            self.resetPomoTab()

    def playRingtone(self):
        """
        Creates a thread for playing the ringtone.
        """
        t = threading.Thread(target=self.playRingThread)
        # Kill the thread once it finishes.
        t.daemon = True
        t.start()

    def playRingThread(self):
        """
        Plays the Ringtone.
        """
        for data in self.audioData:
            self.audioDevice.write(data)

    ###############
    ## tasks tab ##
    ###############

    def initTasksTab(self):
        """
        Creates the layout of the tasks tab.
        """
        tasksTab = QtGui.QWidget()

        self.tasksTable = self.fillTasksTable()
        self.tasksVBox = QtGui.QVBoxLayout()
        self.tasksVBox.addWidget(self.tasksTable)
        self.tasksTable.sortItems(0)

        tasksTab.setLayout(self.tasksVBox)
        return tasksTab

    def fillTasksTable(self):
        """
        Fills the table in the tasks tab.
        """
        tasks = self.pomo.pomoData.tasks
        self.taskTableSelChange = False

        # Create a table with three columns.
        table = QtGui.QTableWidget(len(tasks), 3)
        table.itemSelectionChanged.connect(self.taskListSelectionChanged)
        table.itemClicked.connect(self.taskListClick)
        table.setShowGrid(True)
        table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        table.setFocusPolicy(QtCore.Qt.NoFocus)
        table.setHorizontalHeaderLabels([
            self.getString("lbl_stats_task"),
            self.getString("lbl_stats_pomos"),
            self.getString("lbl_stats_last")
        ])
        table.verticalHeader().setVisible(False)
        table.horizontalHeader().setHighlightSections(False)

        # Create a context menu for the table.
        def ctMenuEvent(event):
            self.taskTableSelChange = False
            menu = QtGui.QMenu(table)
            rnAct = menu.addAction("Rename", self.renameTask)
            dlAct = menu.addAction("Delete", self.deleteTask)
            menu.popup(QtGui.QCursor.pos())
            if self.timerActive and self.pomoTaskBar.currentText(
            ) == self.tasksTable.selectedItems()[0].text():
                rnAct.setEnabled(False)
                dlAct.setEnabled(False)

        table.contextMenuEvent = ctMenuEvent

        # Columwidth depends on the existence of a scrollbar.
        if len(tasks) <= 7:
            table.setColumnWidth(0, 345)
        else:
            table.setColumnWidth(0, 329)
        table.setColumnWidth(1, 48)
        table.setColumnWidth(2, 60)

        # There must be a row counter since the taskID can be different.
        rowCount = 0

        # Fill the table rows.
        for taskID, taskName, pomoCount, pomoLast in tasks:
            # First column: taskName
            item = QtGui.QTableWidgetItem()
            item.setText(taskName)
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            table.setItem(rowCount, 0, item)

            # Second column: pomoCount
            item = QtGui.QTableWidgetItem()
            item.setText(str(pomoCount))
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            item.setToolTip("~" + str(round((pomoCount * 25) / 60, 1)) + "h")
            table.setItem(rowCount, 1, item)

            # Third column: pomoLast
            pomoLastDate = datetime.datetime.fromtimestamp(pomoLast)
            item = QtGui.QTableWidgetItem()
            item.setText(pomoLastDate.strftime("%x"))
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            table.setItem(rowCount, 2, item)

            rowCount += 1
        return table

    def updateTasksTab(self):
        """
        Updates the pomodoro statistics in the tasks tab.
        """
        self.tasksVBox.removeWidget(self.tasksTable)
        self.tasksTable.close()
        self.tasksTable = self.fillTasksTable()
        self.tasksVBox.insertWidget(0, self.tasksTable)

    def taskListSelectionChanged(self):
        """
        Sets a flag when the selection in the task table was changed.
        """
        if self.tasksTable.selectedItems() != []:
            self.taskTableSelChange = True

    def taskListClick(self, item):
        """
        Detects when an item in the task table was clicked and clears selection if necessary.
        """
        if self.taskTableSelChange == False:
            self.tasksTable.clearSelection()
        self.taskTableSelChange = False

    def deleteTask(self):
        """
        Deletes a task by the users request.
        """
        taskName = self.tasksTable.selectedItems()[0].text()
        okay = self.promptUser("ask_taskdel", additional=taskName)
        if okay:
            # Delete entry from GUI
            pbID = self.pomoTaskBar.findText(taskName)
            self.pomoTaskBar.removeItem(pbID)

            stID = self.activitySelTask.findText(taskName)
            self.activitySelTask.removeItem(stID)

            rownum = self.tasksTable.row(self.tasksTable.selectedItems()[0])
            self.tasksTable.removeRow(rownum)

            if self.tasksTable.rowCount() <= 7:
                self.tasksTable.setColumnWidth(0, 345)

            # Delete entry from db and cache
            taskID = self.pomo.pomoData.getTaskID(taskName)
            self.pomo.pomoData.delTask(taskID)

            # Reset the activity tab
            self.fillActivityTab()

    def renameTask(self, warn=""):
        """
        Renames a task by the users request.
        """
        oldname = self.tasksTable.selectedItems()[0].text()
        name, okay = QtGui.QInputDialog.getText(
            self, self.getString("lbl_rename_task"), warn, text=oldname)
        if okay and name != '' and name != oldname:
            try:
                self.pomo.pomoData.getTaskID(name)
                self.renameTask(self.getString("lbl_rename_taken"))
            except KeyError:
                # Update entry in GUI
                self.tasksTable.selectedItems()[0].setText(name)

                pbID = self.pomoTaskBar.findText(oldname)
                self.pomoTaskBar.setItemText(pbID, name)

                stID = self.activitySelTask.findText(oldname)
                self.activitySelTask.setItemText(stID, name)

                # Update entry in db and cache
                tID = self.pomo.pomoData.getTaskID(oldname)
                self.pomo.pomoData.renameTask(tID, name)

    ##################
    ## activity tab ##
    ##################

    def initActivityTab(self):
        """
        Creates the layout of the activity tab and prepares the graph.
        """
        activityTab = QtGui.QWidget()

        # Get the background color of the window to make the graph fit in.
        color = self.palette().color(QtGui.QPalette.Background)

        # Create a fixed-size canvas for the graph.
        self.figure = plt.figure(facecolor=color.name(), tight_layout=False)
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setFixedSize(460, 236)

        # Set default values for some attributes used in fillActivityTab
        self.lockYLim = False
        self.intervalShift = 0
        self.intervalScale = 3  # [3] days - [2] weeks - [1] months
        self.activityTaskID = 0

        # Combobox for selecting the active task to be displayed.
        selTask = QtGui.QComboBox()
        selTask.insertItem(0, self.getString("lbl_stats_all"), None)
        for tID, tskName, pomoCount, pomoLast in self.pomo.pomoData.tasks:
            selTask.addItem(tskName, None)

        selTask.currentIndexChanged['QString'].connect(self.onChangeTask)
        # Save handle for later use.
        self.activitySelTask = selTask

        # Navigation buttons to change the active timespan.
        farLeftButton = QtGui.QPushButton("<<", activityTab)
        farLeftButton.setStyleSheet('font-size: 12pt;')
        farLeftButton.setFixedSize(30, 20)
        farLeftButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state
        self.farLeftButtonHandle = farLeftButton

        farRightButton = QtGui.QPushButton(">>", activityTab)
        farRightButton.setStyleSheet('font-size: 12pt;')
        farRightButton.setFixedSize(30, 20)
        farRightButton.setDisabled(True)
        farRightButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state.
        self.farRightButtonHandle = farRightButton

        leftButton = QtGui.QPushButton("<", activityTab)
        leftButton.setStyleSheet('font-size: 12pt;')
        leftButton.setFixedSize(30, 20)
        leftButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state
        self.leftButtonHandle = leftButton

        rightButton = QtGui.QPushButton(">", activityTab)
        rightButton.setStyleSheet('font-size: 12pt;')
        rightButton.setFixedSize(30, 20)
        rightButton.setDisabled(True)
        rightButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state.
        self.rightButtonHandle = rightButton

        # Disable left navigation buttons when there are no finished pomos.
        if self.pomo.pomoData.firstPomo == 0:
            leftButton.setDisabled(True)
            farLeftButton.setDisabled(True)

        # Zoom buttons to change the active timespan.
        zoomOutButton = QtGui.QPushButton("−", activityTab)
        zoomOutButton.setStyleSheet('font-size: 12pt;')
        zoomOutButton.setFixedSize(30, 20)
        zoomOutButton.clicked.connect(self.timeZoom)
        # Save the handle for toggling the button state.
        self.zoomOutButtonHandle = zoomOutButton

        zoomInButton = QtGui.QPushButton("+", activityTab)
        zoomInButton.setStyleSheet('font-size: 12pt;')
        zoomInButton.setFixedSize(30, 20)
        zoomInButton.setDisabled(True)
        zoomInButton.clicked.connect(self.timeZoom)
        # Save the handle for toggling the button state.
        self.zoomInButtonHandle = zoomInButton

        # Get highest pomo count on a single day.
        self.highestPomoCount = list()

        self.highestPomoCount.append(
            self.pomo.pomoData.getHighestPomoCountMonthly())
        self.highestPomoCount.append(
            self.pomo.pomoData.getHighestPomoCountWeekly())
        self.highestPomoCount.append(
            self.pomo.pomoData.getHighestPomoCountDaily())

        # Draw the graph.
        self.fillActivityTab()

        # Create and set the layout.
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.canvas)
        layout2 = QtGui.QHBoxLayout()
        layout2.addWidget(farLeftButton)
        layout2.addWidget(leftButton)
        layout2.addWidget(rightButton)
        layout2.addWidget(farRightButton)
        layout2.addStretch()
        layout2.addWidget(zoomOutButton)
        layout2.addWidget(zoomInButton)
        layout2.addStretch()
        layout2.addWidget(selTask)
        layout.addLayout(layout2)

        activityTab.setLayout(layout)
        return activityTab

    def fillActivityTab(self):
        """
        Fills and displays the bar graph in the activity tab.
        """
        taskID = self.activityTaskID

        # First get the absolute value of today.
        today = datetime.date.today()
        delta = datetime.timedelta(days=1)

        # Now construct shiftable intervals.
        beginInt = datetime.datetime
        endInt = datetime.datetime

        # Default scale (days): Begin interval at midnight of today.
        beginInt = datetime.datetime(today.year, today.month, today.day, 0, 0,
                                     0)
        shiftDelta = delta

        if self.intervalScale == 2:  # Scale: Weeks
            # Begin interval at midnight of this weeks monday.
            weekDayNum = calendar.weekday(today.year, today.month, today.day)
            beginInt = beginInt - delta * weekDayNum
            shiftDelta = 7 * delta
        elif self.intervalScale == 1:  # Scale: Months
            # Begin interval at midnight of the first day of the month.
            beginInt = datetime.datetime(today.year, today.month, 1, 0, 0, 0)
            shiftDelta = 30 * delta
        self.shiftDelta = shiftDelta

        # Get the data of the last units since today.
        units = list()
        values = list()
        size = 6 + self.intervalScale

        for i in range(size):
            # Shift
            offset = (size - i - 1 - self.intervalShift)
            shiftedBegin = beginInt - offset * shiftDelta
            # When scaled to months, an arithmetical shift is not practical.
            if self.intervalScale == 1:
                yearDiff, monDiff = divmod(offset, 12)
                newMon = beginInt.month - monDiff
                if newMon < 0:
                    newMon = 12 + newMon
                    yearDiff += 1

                if newMon == 0:
                    newMon = 12
                    yearDiff += 1

                shiftedBegin = datetime.datetime(beginInt.year - yearDiff,
                                                 newMon, 1, 0, 0, 0)
            shiftedEnd = datetime.datetime

            if self.intervalScale == 3:
                units.append(
                    str(shiftedBegin.month) + "/" + str(shiftedBegin.day))
                shiftedEnd = datetime.datetime(shiftedBegin.year,
                                               shiftedBegin.month,
                                               shiftedBegin.day, 23, 59, 59)
            elif self.intervalScale == 2:
                units.append(shiftedBegin.strftime("CW %W"))
                shiftedEnd = datetime.datetime(shiftedBegin.year,
                                               shiftedBegin.month,
                                               shiftedBegin.day, 23, 59, 59)
                shiftedEnd = shiftedEnd + delta * 6
            else:
                units.append(shiftedBegin.strftime("%b %y"))
                lastDay = calendar.monthrange(shiftedBegin.year,
                                              shiftedBegin.month)[1]
                shiftedEnd = datetime.datetime(shiftedBegin.year,
                                               shiftedBegin.month, lastDay, 23,
                                               59, 59)
            timeInt = [
                int(shiftedBegin.timestamp()),
                int(shiftedEnd.timestamp())
            ]
            values.append(self.pomo.pomoData.getPomoCount(timeInt, taskID))

        # Disable left buttons once we scrolled far enough
        if self.pomo.pomoData.firstPomo != 0:
            shiftedBegin = beginInt - (size - 1 -
                                       self.intervalShift) * shiftDelta
            self.shiftedBegin = shiftedBegin
            if shiftedBegin.timestamp() <= self.pomo.pomoData.firstPomo:
                self.leftButtonHandle.setDisabled(True)
                self.farLeftButtonHandle.setDisabled(True)
            else:
                self.leftButtonHandle.setDisabled(False)
                self.farLeftButtonHandle.setDisabled(False)

        # Create a new subplot.
        ax = self.figure.add_subplot(111)
        ax.hold(False)

        # Create the bar graphs
        bars = ax.bar(list(range(1, size + 1)),
                      values,
                      width=0.4,
                      align="center",
                      color="#E04B3F")
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width() / 2.,
                     height + 0.08,
                     '%d' % int(height),
                     ha='center',
                     va='bottom',
                     weight="medium")
        plt.xticks(list(range(1, size + 1)), units)

        # y-Limit of the graph depends on the maximum bar height.
        yLim = self.highestPomoCount[self.intervalScale - 1] * 1.24

        # To avoid rescaling the graph when changing the task, we lock the
        # y-Limit to the first one generated after startup.
        if self.lockYLim is False:
            if yLim == 0:
                # When no pomodoros have been done, use a constant y-Limit.
                yLim = 15
            else:
                self.lockYLim = True
            self.yLim = yLim
        else:
            # Update the y-Limit when it exceeds the saved one.
            if yLim > self.yLim:
                self.yLim = yLim

        # Set the graph limits.
        ax.set_ylim([0, self.yLim])
        ax.set_xlim([0.5, size + 0.5])

        # Additional plot and graph settings.
        plt.subplots_adjust(left=0, right=0.99, top=1, bottom=0.087)
        ax.get_yaxis().set_visible(False)
        plt.minorticks_off()
        for tick in ax.get_xticklines():
            tick.set_visible(False)

        # Write currently viewed month and year in the upper right corner,
        # when zoomed out, only display the year.
        if self.intervalScale != 1:
            tempDate = beginInt - (size - 1 - self.intervalShift) * shiftDelta
            dateString = tempDate.strftime("%b %Y")
            if self.intervalScale != 3:
                dateString = tempDate.strftime("%Y")

            plt.text(0.99,
                     0.937,
                     dateString,
                     horizontalalignment='right',
                     verticalalignment='center',
                     transform=ax.transAxes,
                     weight="bold")

        # Show.
        self.canvas.draw()

    def timeNavigate(self):
        """
        Handling function for the navigation buttons in the activity tab.
        """
        sender = self.sender()

        if sender.text() == '<':
            self.intervalShift -= 6
            self.rightButtonHandle.setDisabled(False)
            self.farRightButtonHandle.setDisabled(False)
        elif sender.text() == '>':
            self.intervalShift += 6
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)
            if self.intervalShift == 0:
                # Once we hit todays date, disable the right button.
                sender.setDisabled(True)
                self.farRightButtonHandle.setDisabled(True)
        elif sender.text() == '<<':
            sender.setDisabled(True)
            self.leftButtonHandle.setDisabled(True)
            self.rightButtonHandle.setDisabled(False)
            self.farRightButtonHandle.setDisabled(False)

            date = self.shiftedBegin
            while date.timestamp() >= self.pomo.pomoData.firstPomo:
                self.intervalShift -= 6
                date -= 6 * self.shiftDelta
        elif sender.text() == '>>':
            self.intervalShift = 0
            sender.setDisabled(True)
            self.rightButtonHandle.setDisabled(True)
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)

        self.fillActivityTab()

    def timeZoom(self):
        """
        Handling function for the zoom buttons in the activity tab.
        """
        sender = self.sender()

        # Always reset the navigation while zooming
        self.intervalShift = 0
        self.lockYLim = False

        if self.pomo.pomoData.firstPomo != 0:
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)
        self.rightButtonHandle.setDisabled(True)
        self.farRightButtonHandle.setDisabled(True)

        # Zoom Out:
        if sender.text() == '−':
            self.intervalScale -= 1
            if self.intervalScale == 1:
                self.zoomOutButtonHandle.setDisabled(True)
            self.zoomInButtonHandle.setDisabled(False)
        # Zoom In:
        else:
            self.intervalScale += 1
            if self.intervalScale == 3:
                sender.setDisabled(True)
            self.zoomOutButtonHandle.setDisabled(False)

        self.fillActivityTab()

    def onChangeTask(self, string=str()):
        """
        Will be called when the user changes the task in the activity tab.
        """
        try:
            self.activityTaskID = self.pomo.pomoData.getTaskID(string)
        except KeyError:
            self.activityTaskID = 0
        self.fillActivityTab()
예제 #24
0
class GUI(QtGui.QWidget):
    
    def __init__(self):

        super(GUI, self).__init__()
        
        self.setWindowTitle( 'Outline Cells' )
        self.cellNames = ['1.p','4.a','1.pp','4.aa','1.ppa','1.ppp','4.aaa','4.aap','b_1','b_4']
        self.initUI()
        
    #-----------------------------------------------------------------------------------------------
    # INITIALIZATION OF THE WINDOW - DEFINE AND PLACE ALL THE WIDGETS
    #-----------------------------------------------------------------------------------------------

    def initUI(self):
        # SET THE GEOMETRY
        
        mainWindow = QtGui.QVBoxLayout()
        mainWindow.setSpacing(15)
        
        fileBox = QtGui.QHBoxLayout()
        spaceBox1 = QtGui.QHBoxLayout()
        rawDataBox = QtGui.QHBoxLayout()
        
        mainWindow.addLayout(fileBox)
        mainWindow.addLayout(spaceBox1)
        mainWindow.addLayout(rawDataBox)
        
        Col1 = QtGui.QGridLayout()
        Col2 = QtGui.QHBoxLayout()
        Col3 = QtGui.QVBoxLayout()
        
        rawDataBox.addLayout(Col1)
        rawDataBox.addLayout(Col2)
        rawDataBox.addLayout(Col3)
        
        self.setLayout(mainWindow)

        # DEFINE ALL WIDGETS AND BUTTONS
        
        loadBtn = QtGui.QPushButton('Load DataSet')
        saveBtn = QtGui.QPushButton('Save data (F12)')
        
        tpLbl = QtGui.QLabel('Relative Tp:')
        slLbl = QtGui.QLabel('Slice:')
        fNameLbl = QtGui.QLabel('File name:')
        
        self.tp = QtGui.QSpinBox(self)
        self.tp.setValue(-5)
        self.tp.setMaximum(100000)

        self.sl = QtGui.QSpinBox(self)
        self.sl.setValue(0)
        self.sl.setMaximum(100000)

        self.fName = QtGui.QLabel('')
        
        self._488nmBtn = QtGui.QRadioButton('488nm')
        self._561nmBtn = QtGui.QRadioButton('561nm')
        self.CoolLEDBtn = QtGui.QRadioButton('CoolLED')
        
        self.sld1 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld1.setMaximum(2**16-1)
        self.sld1.setValue(0)
        self.sld2 = QtGui.QSlider(QtCore.Qt.Vertical, self)
        self.sld2.setMaximum(2**16)
        self.sld2.setValue(2**16-1)

        self.fig1 = Figure((8.0, 8.0), dpi=100)
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1 = FigureCanvas(self.fig1)
        self.canvas1.setFocusPolicy( QtCore.Qt.ClickFocus )
        self.canvas1.setFocus()
        self.canvas1.setFixedSize(QtCore.QSize(600,600))
        self.canvas1.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        self.cellTbl = QtGui.QTableWidget()

        self.fig2 = Figure((4.0, 4.0), dpi=100)
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax2 = self.fig2.add_subplot(111)
        self.canvas2 = FigureCanvas(self.fig2)
        self.canvas2.setFixedSize(QtCore.QSize(300,300))
        self.canvas2.setSizePolicy( QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding )

        # PLACE ALL THE WIDGET ACCORDING TO THE GRIDS

        fileBox.addWidget(loadBtn)
        fileBox.addWidget(saveBtn)

        spaceBox1.addWidget(self.HLine())

        Col1.addWidget(tpLbl, 0, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.tp, 0, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(slLbl, 1, 0)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(self.sl, 1, 1)#, 1, 1, Qt.AlignTop)
        Col1.addWidget(fNameLbl, 2, 0)
        Col1.addWidget(self.fName, 2, 1)
        Col1.addWidget(self._488nmBtn, 3, 0 )
        Col1.addWidget(self._561nmBtn, 4, 0 )
        Col1.addWidget(self.CoolLEDBtn, 5, 0 )
        
        Col2.addWidget(self.sld1)
        Col2.addWidget(self.sld2)
        Col2.addWidget(self.canvas1)

        Col3.addWidget(self.cellTbl)
        Col3.addWidget(self.canvas2)
        
        self.setFocus()
        self.show()
        
        # BIND BUTTONS TO FUNCTIONS
        
        loadBtn.clicked.connect(self.selectWorm)
        saveBtn.clicked.connect(self.saveData)

        self.tp.valueChanged.connect(self.loadNewStack)
        self.sl.valueChanged.connect(self.updateAllCanvas)
        self.sld1.valueChanged.connect(self.updateAllCanvas)
        self.sld2.valueChanged.connect(self.updateAllCanvas)

        self._488nmBtn.toggled.connect(self.radioClicked)
        self._561nmBtn.toggled.connect(self.radioClicked)
        self.CoolLEDBtn.toggled.connect(self.radioClicked)

        self.fig1.canvas.mpl_connect('button_press_event',self.onMouseClickOnCanvas1)        
        self.fig1.canvas.mpl_connect('scroll_event',self.wheelEvent)        

    #-----------------------------------------------------------------------------------------------
    # FORMATTING THE WINDOW
    #-----------------------------------------------------------------------------------------------

    def center(self):
        
        qr = self.frameGeometry()
        cp = QtGui.QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        
    def HLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.HLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def VLine(self):
        
        toto = QtGui.QFrame()
        toto.setFrameShape(QtGui.QFrame.VLine)
        toto.setFrameShadow(QtGui.QFrame.Sunken)
        return toto

    def heightForWidth(self, width):
        
        return width
    
    #-----------------------------------------------------------------------------------------------
    # BUTTON FUNCTIONS
    #-----------------------------------------------------------------------------------------------

    def selectWorm(self):

        ### store the folders
        self.pathDial = QtGui.QFileDialog.getExistingDirectory(self, 'Select a folder', 'Y:\\Images')
        self.worm = self.pathDial.split("\\")[-1].split('_')[0]
        self.path = os.path.dirname( self.pathDial )
        self.setWindowTitle('Outline Cells - ' + self.pathDial)
        
        ### give error message if there is no CoolLED movie in the selected folder
        if not os.path.isfile( os.path.join( self.pathDial, 'CoolLED_movie.tif' ) ):
            QtGui.QMessageBox.about(self,'Warning!','There is no movie in this folder! Create a movie first!')
            return

        # detect available channels
        self.channels = []
        chns = ['CoolLED','488nm','561nm']
        for c in chns:

            if os.path.isfile( os.path.join( self.pathDial, c + '_movie.tif' ) ):

                self.channels.append(c)

        self.currentChannel = self.channels[0]

        ### load parameters and times dataframes
        self.paramsDF = load_data_frame( self.path, self.worm + '_01params.pickle' )
        self.timesDF = load_data_frame( self.path, self.worm + '_01times.pickle' )
        self.gpDF = load_data_frame( self.path, self.worm + '_02gonadPos.pickle' )
        self.cellPosDF = load_data_frame( self.path, self.worm + '_04cellPos.pickle' )

        # extract some info
        self.compression = self.paramsDF.compression
        self.hatchingtidx = int( self.paramsDF.tidxHatch )

        ### if the cellOutline pickle file already exists, load it, otherwise create a blank one
        if os.path.isfile( os.path.join(self.path, self.worm + '_05cellOut.pickle' ) ):
            self.cellOutDF = load_data_frame( self.path, self.worm + '_05cellOut.pickle' )
        
        else:
            self.cellOutDF = create_cell_out( self.timesDF, self.cellNames )

        self.analyzedCell = '---'

        ### set the timepoint to the hatching time
        self.tp.setMinimum(np.min(self.timesDF.tidxRel))
        self.tp.setMaximum(np.max(self.timesDF.tidxRel))
        self.tp.setValue( first_tidx_pos_all_cells( self.cellPosDF ) )
        
        # self.pathDial.show()
        self.updateAllCanvas()
        self.setFocus()

    def loadNewStack(self):
        
        # print(self.fList['gfp'][self.tp.value()])
        tRow = self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value() ].squeeze()

        print( 'Loading... ', self.pathDial, tRow.fName )

        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

        ### extract current cells already labeled
        self.currentCells = extract_current_cell_out( self.cellPosDF, self.cellOutDF, self.tp.value() )

        if len(self.currentCells) > 0:
            ### update current analyzed cell
            if self.analyzedCell not in list( self.currentCells.cname ):
                self.analyzedCell = self.currentCells.cname[0]

        ### update the text of the fileName
        self.fName.setText( self.timesDF.ix[ self.timesDF.tidxRel == self.tp.value(), 'fName' ].values[0])

        # load all the available stacks
        self.stacks = {}
        for ch in self.channels:
            fileName = os.path.join( self.pathDial, tRow.fName + ch + '.tif')
            if os.path.isfile( fileName ):
                self.stacks[ch] = load_stack( fileName )

        if len( self.stacks.keys() ) > 0:
            # print(self.stacks.keys(), self.stacksStraight)
            self.sl.setMaximum(self.stacks[self.currentChannel].shape[0]-1)

            self.setBCslidersMinMax()

        if len( self.currentCells ) > 0:
            ### update slice
            self.sl.setValue( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ] )
        
        # self.updateTable()
        self.updateAllCanvas()

    def saveData(self):
        
        save_data_frame( self.cellOutDF, self.path, self.worm + '_05cellOut.pickle' )       
        self.setFocus()
        
    def updateAllCanvas(self):
        self.updateRadioBtn()
        self.updateCanvas1()
        self.updateCanvas2()
        
    def radioClicked(self):
        if self._488nmBtn.isChecked():
            if '488nm' in self.channels:
                self.currentChannel = '488nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 488nm channel!')
        elif self._561nmBtn.isChecked():
            if '561nm' in self.channels:
                self.currentChannel = '561nm'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No 561nm channel!')
        elif self.CoolLEDBtn.isChecked():
            if 'CoolLED' in self.channels:
                self.currentChannel = 'CoolLED'
            else:
                QtGui.QMessageBox.about(self, 'Warning', 'No CoolLED channel!')
        self.setBCslidersMinMax()
        self.resetBC()
        self.setFocus()
        self.updateAllCanvas()

    #-----------------------------------------------------------------------------------------------
    # DEFAULT FUNCTION FOR KEY AND MOUSE PRESS ON WINDOW
    #-----------------------------------------------------------------------------------------------

    def keyPressEvent(self, event):
        
        # print(event.key())

        # change timepoint
        if event.key() == QtCore.Qt.Key_Right:
            self.changeSpaceTime( 'time', +1 )

        elif event.key() == QtCore.Qt.Key_Left:
            self.changeSpaceTime( 'time', -1 )

        # change slice
        elif event.key() == QtCore.Qt.Key_Up:
            self.changeSpaceTime( 'space', +1 )
            
        elif event.key() == QtCore.Qt.Key_Down:
            self.changeSpaceTime( 'space', -1 )

        elif event.key() == QtCore.Qt.Key_Space:

            if len( self.currentCells ) > 0:
                idx = np.mod( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].index + 1, len(self.currentCells) )
                self.analyzedCell = self.currentCells.cname.values[idx][0]
                self.sl.setValue( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell, 'Z' ] )

                self.updateAllCanvas()

        self.setFocus()

    def wheelEvent(self,event):
        if self.canvas1.underMouse():
            step = event.step
        else:          
            step = event.delta()/abs(event.delta())
        self.sl.setValue( self.sl.value() + step) 

    #-----------------------------------------------------------------------------------------------
    # ADDITIONAL FUNCTIONS FOR KEY AND MOUSE PRESS ON CANVASES
    #-----------------------------------------------------------------------------------------------

    def onMouseClickOnCanvas1(self, event):

        pos = np.array( [ int(event.xdata), int(event.ydata) ] )

        outline = extract_out( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

        if event.button == 1:

            if np.isnan( outline[0,0] ):
                outline = np.array( [ pos ] )
            else:
                outline = np.vstack( [ outline, pos ] )

        elif event.button == 3:

            if len( outline[ :, 0 ] ) == 1:
                outline = np.array( [ [ np.nan, np.nan ] ] )
            else:
                outline = outline[:-1,:]

        idx = self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].index

        self.currentCells.Xout.values[ idx ] = [ outline[:,0] ]
        self.currentCells.Yout.values[ idx ] = [ outline[:,1] ]

        self.updateCanvas1()
        self.setFocus()
        # print(event.button,event.xdata,event.ydata)

    #-----------------------------------------------------------------------------------------------
    # UTILS
    #-----------------------------------------------------------------------------------------------

    def updateRadioBtn(self):
        if self.currentChannel == '488nm':
            self._488nmBtn.setChecked(True)
        elif self.currentChannel == '561nm':
            self._561nmBtn.setChecked(True)
        elif self.currentChannel == 'CoolLED':
            self.CoolLEDBtn.setChecked(True)
        self.setFocus()

    def setBCslidersMinMax(self):
        self.sld1.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld1.setMinimum(np.min(self.stacks[self.currentChannel]))
        self.sld2.setMaximum(np.max(self.stacks[self.currentChannel]))
        self.sld2.setMinimum(np.min(self.stacks[self.currentChannel]))

    def resetBC(self):
        self.sld1.setValue(np.min(self.stacks[self.currentChannel]))
        self.sld2.setValue(np.max(self.stacks[self.currentChannel]))
        
    def updateCanvas1(self):

        self.fig1.clf()
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)
        self.ax1 = self.fig1.add_subplot(111)
        self.canvas1.draw()

        if ( len( self.stacks.keys() ) == 0 ) or ( len( self.currentCells ) == 0 ):
            # if no images are found, leave the canvas empty
            return

        # extract current cell data
        pos = extract_3Dpos( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

        # plot the image
        imgpxl = 50
        self.ax1.cla()
        imgplot = self.ax1.imshow(self.stacks[self.currentChannel][self.sl.value(),pos[1]-imgpxl/2:pos[1]+imgpxl/2+1,pos[0]-imgpxl/2:pos[0]+imgpxl/2+1], cmap = 'gray', interpolation = 'nearest')
        
        # remove the white borders
        self.ax1.autoscale(False)
        self.ax1.axis('Off')
        self.fig1.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # print cell name
        if pos[2] == self.sl.value():
            self.ax1.text( 1, 2, self.analyzedCell, color='yellow', size='medium', alpha=.8,
                    rotation=0, fontsize = 20 )
            self.ax1.plot( imgpxl/2, imgpxl/2, 'x', color='yellow', alpha = .8, ms = 5 )

        ### draw outline
        outline = extract_out( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

        # print(self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze())

        if len( outline ) > 1:
            outline = np.vstack( [ outline, outline[0] ] )

        self.ax1.plot( outline[:,0], outline[:,1], '-x', color='yellow', ms=2, alpha=1., lw = .5 )      

        # change brightness and contrast
        self.sld1.setValue(np.min([self.sld1.value(),self.sld2.value()]))
        self.sld2.setValue(np.max([self.sld1.value(),self.sld2.value()]))
        imgplot.set_clim(self.sld1.value(), self.sld2.value())  

        # # redraw the canvas
        self.canvas1.draw()
        self.setFocus()

    def updateCanvas2(self):
        
        # plot the image
        self.ax2.cla()
        imgplot = self.ax2.imshow(self.stacks[self.currentChannel][self.sl.value()], cmap = 'gray')
        
        # remove the white borders
        self.ax2.autoscale(False)
        self.ax2.axis('Off')
        self.fig2.subplots_adjust(left=0., right=1., top=1., bottom=0.)

        # extract current cell data
        if len( self.currentCells ) > 0:
            pos = extract_3Dpos( self.currentCells.ix[ self.currentCells.cname == self.analyzedCell ].squeeze() )

            for idx, cell in self.currentCells.iterrows():

                if cell.Z == self.sl.value():

                    color = 'red'
                    if cell.cname == self.analyzedCell:
                        color = 'yellow'

                    self.ax2.text( cell.X+10, cell.Y + 10, cell.cname, color=color, size='medium', alpha=.8,
                            rotation=0)
                    self.ax2.plot( cell.X, cell.Y, 'o', color=color, alpha = .8, ms=5, mew = 0 )


        # redraw the canvas
        self.canvas2.draw()
        self.setFocus()

    def changeSpaceTime(self, whatToChange, increment):


        if whatToChange == 'time':

            newCellOutDF = update_cell_out_DF( self.currentCells, self.cellOutDF, self.tp.value() )
            self.cellOutDF = newCellOutDF

            # if they are OK (and not going to negative times), change timepoint
            self.tp.setValue( self.tp.value() + increment )

        if whatToChange == 'space':
            self.sl.setValue( self.sl.value() + increment )
예제 #25
0
    def plot_data(self, recordings):
        fig = Figure(figsize=(200,200), dpi=72, facecolor=(1,1,1), edgecolor=(0,0,0))
        ax = fig.add_subplot(111)

        # Sort the recordings by increasing date
        recordings = sorted(recordings, key=lambda r: r.date)

        # list of tuples (year, month, day, consumption, index)
        interpolated_consumptions = []

        for r in recordings:
            if(len(interpolated_consumptions) == 0):
                year = r.date.year
                month = r.date.month
                day = r.date.day
                cons = 0
                index = r.value
                interpolated_consumptions.append((year, month, day, cons, index))
                continue

            prev_entry = interpolated_consumptions[-1]
            prev_year, prev_month, prev_day, prev_cons, prev_index = prev_entry
            cur_year, cur_month, cur_day, cur_index = r.date.year, r.date.month, r.date.day, r.value

            # Necessarily, as we sorted the data, we have :
            # prev_year <= cur_year and prev_month <= cur_month


            # Point : determine r.cons and fill in between with intermediate consumptions
            #         to get one entry per month in interpolated_consumptions

            if prev_year == cur_year and prev_month == cur_month:
                # We can guarantee that we have consumed cur_index - prev_index
                # on this month;
                interpolated_consumptions[-1] = (cur_year, cur_month, cur_day, prev_cons + (cur_index - prev_index), cur_index)
            elif prev_year == cur_year:
                # and prev_month != cur_month
                #print("Last entry : %i - %i - %i" % (prev_year, prev_month, prev_day))
                tot_cons = cur_index - prev_index
                tot_days = 0
                nb_days = []
                # For the first month
                nb_days.append((prev_year, prev_month, nb_days_in_month(prev_year, prev_month) - prev_day))
                tot_days += nb_days_in_month(prev_year, prev_month) - prev_day
                # For the months in between
                for m in range(prev_month+1, cur_month):
                    days = nb_days_in_month(prev_year, m)
                    nb_days.append((prev_year, m, days))
                    tot_days += days
                # For the last month
                tot_days += cur_day
                nb_days.append((prev_year, cur_month, cur_day))
                #print(nb_days)
                #print(" A total of %i days" % tot_days)

                # We can now provide the interpolated values for interpolated_consumptions
                # The last entry has to be modified to close the month
                interpolated_consumptions[-1] = (prev_year, prev_month, nb_days_in_month(prev_year, prev_month), prev_cons + float(nb_days[0][2])/tot_days * tot_cons, -1)
                for (yr, mth, nbd) in nb_days[1:-1]:
                    interpolated_consumptions.append((yr, mth, nb_days_in_month(yr, mth), float(nbd) / tot_days * tot_cons, -1))
                # For the last month, we need to take the correct day..
                (yr, mth, nbd) = nb_days[-1]
                interpolated_consumptions.append((yr, mth, cur_day, float(nbd) / tot_days * tot_cons, cur_index))
            else:
                # we are not in the same year
                tot_cons = cur_index - prev_index
                tot_days = 0
                nb_days = []
                #####
                ## Deal with the consummption until the end of the year
                # For the first month
                nb_days.append((prev_year, prev_month, nb_days_in_month(prev_year, prev_month) - prev_day))
                tot_days += nb_days_in_month(prev_year, prev_month) - prev_day
                for m in range(prev_month, 13):
                    nb_days.append((prev_year, m, nb_days_in_month(prev_year, m)))
                    tot_days += nb_days_in_month(prev_year, m)

                # Deal with the years in between
                for yr in range(prev_year+1, cur_year):
                    for m in range(1, 13):
                        nb_days.append((yr, m, nb_days_in_month(yr, m)))
                        tot_days += nb_days_in_month(yr, m)

                # Deal with the months until the current month and year
                for m in range(1, cur_month):
                    nb_days.append((cur_year, m, nb_days_in_month(cur_year, m)))
                    tot_days += nb_days_in_month(cur_year, m)
                # Deal with the last month
                nb_days.append((cur_year, cur_month, cur_day))
                tot_days +=  cur_day

                interpolated_consumptions[-1] = (prev_year, prev_month, nb_days_in_month(prev_year, prev_month), prev_cons + float(nb_days[0][2])/tot_days * tot_cons, -1)
                for (yr, mth, nbd) in nb_days[1:-1]:
                    interpolated_consumptions.append((yr, mth, nb_days_in_month(yr, mth), float(nbd) / tot_days * tot_cons, -1))
                # For the last month, we need to take the correct day..
                (yr, mth, nbd) = nb_days[-1]
                interpolated_consumptions.append((yr, mth, cur_day, float(nbd) / tot_days * tot_cons, cur_index))


        # We now have the interpolated_consumptions
        # We split them by year ;
        years = []
        for yr,mth,day,cons,index in interpolated_consumptions:
            if yr not in years:
                years.append(yr)

        nyears = len(years)
        data = np.zeros((len(years),12))
        data.fill(np.nan)
        for yr, mth, day, cons, index in interpolated_consumptions:
            data[years.index(yr), mth-1] = cons


        ax.plot(range(1,13), data.T)
        ax.set_xlim([1,12])
        ylim = ax.get_ylim()
        ax.set_ylim([0, ylim[1]])
        ax.legend(years, loc='upper center')

        ax.set_xticks(range(1,13))
        ax.set_xticklabels( ['Jan.','Feb.','March', 'April', 'May', 'June', 'July', 'Aug.', 'Sept.', 'Oct.', 'Nov.', 'Dec.'], rotation=45 )
        ax.set_ylabel('Delta index')

        #fig.autofmt_xdate()
        #ax.fmt_xdata = mdates.DateFormatter('%m')

        # generate the canvas to display the plot
        canvas = FigureCanvas(fig)
        canvas.setFixedSize(QSize(600,400))
        return canvas
예제 #26
0
파일: form.py 프로젝트: bigzz/PyGator
    def __init__(self, streamline, parent=None, width=5, height=4, dpi=50, subs=1):
        self.fig = Figure(figsize=(width - 50, height), dpi=dpi)

        pos = 0

        self.sl = streamline
        self.subs = subs
        self.cpunum = self.sl.mDevice.cpu_num

        self.gpu_pos = 0
        self.fps_pos = 0
        self.temp_pos = 0

        self.axes = []
        for i in range(self.cpunum):
            self.axes.append(self.fig.add_subplot(self.subs, 1, i + 1))  # For CPU CORES
            # We want the axes cleared every time plot() is called
            self.axes[i].set_title('CPU' + str(i))
            # self.axes[i].set_xticks([])   # not show x
            self.axes[i].set_xlim(0, 20000)
            self.axes[i].set_ylim(0, 2500)

        if self.sl.mDevice.show_gpu == 1:
            self.gpu_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + pos + 1))  # FOR GPU
            self.axes[self.cpunum + self.gpu_pos].set_title('GPU')
            self.axes[self.cpunum + self.gpu_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.gpu_pos].set_ylim(0, 850)
            pos += 1

        if self.sl.mDevice.show_fps == 1:
            self.fps_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.fps_pos + 1))  # FOR FPS
            self.axes[self.cpunum + self.fps_pos].set_title('FPS')
            self.axes[self.cpunum + self.fps_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.fps_pos].set_ylim(0, 100)
            pos += 1

        if self.sl.mDevice.show_temp == 1:
            self.temp_pos = pos
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.temp_pos + 1))  # FOR CPU TEMP
            self.axes[self.cpunum + self.temp_pos].set_title('CPU Temperature')
            self.axes[self.cpunum + self.temp_pos].set_xlim(0, 20000)
            self.axes[self.cpunum + self.temp_pos].set_ylim(0, 100)
            self.axes.append(self.fig.add_subplot(self.subs, 1, self.cpunum + self.temp_pos + 2))  # FOR BOARD TEMP
            self.axes[self.cpunum + self.temp_pos + 1].set_title('Board Temperature')
            self.axes[self.cpunum + self.temp_pos + 1].set_xlim(0, 20000)
            self.axes[self.cpunum + self.temp_pos + 1].set_ylim(0, 100)

        self.fig.set_tight_layout(True)
        self.compute_initial_figure()

        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)

        FigureCanvas.setFixedSize(self, width - 50, subs * 100)

        FigureCanvas.setSizePolicy(self,
                                   QtGui.QSizePolicy.Expanding,
                                   QtGui.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
예제 #27
0
파일: gui.py 프로젝트: prjw/pomodorino
class PomoWindow(QtGui.QWidget):
    def __init__(self, pomo):
        """
        Makes necessary variable initializations and calls other init methods.
        """
        super(PomoWindow, self).__init__()
        self.pomo = pomo
        # Enhance readability
        self.getString = self.pomo.getString
        self.initUI()
        self.initAudio()
        self.timerActive = False
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.tick)

    def initUI(self):
        """
        Initializes the UI.
        """
        # Set some general window settings.
        self.setFixedSize(480, 310)
        self.move(250, 250)
        self.setWindowTitle(self.getString("app_name"))
        self.setWindowIcon(QtGui.QIcon("/usr/share/icons/pomodorino.png"))
        self.trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon("/usr/share/icons/pomodorino.png"), self)
        self.trayIcon.setVisible(True)
        self.trayIcon.activated.connect(self.trayClick)

        # Add a minimal context menu for the tray icon.
        # trayMenu = QtGui.QMenu(self)
        # trayMenu.addAction("Quit", self.close)
        # self.trayIcon.setContextMenu(trayMenu)

        # Initialize and display the tabs
        pomoTab = self.initPomoTab()
        tasksTab = self.initTasksTab()
        activityTab = self.initActivityTab()

        tabWidget = QtGui.QTabWidget(self)
        tabWidget.resize(479, 309)

        tabWidget.addTab(pomoTab, self.getString("tab_pomo"))
        tabWidget.addTab(tasksTab, self.getString("tab_tasks"))
        tabWidget.addTab(activityTab, self.getString("tab_activity"))

        self.show()

    def initAudio(self):
        """
        Detects an ALSA audio device and buffers our ringtone.
        """
        # Detect an ALSA audio device
        self.audioDevice = alsaaudio.PCM()

        # Open the ringtone and set some audio settings.
        ring = wave.open("/usr/share/pomodorino/ring.wav", "rb")
        self.audioDevice.setchannels(ring.getnchannels())
        self.audioDevice.setrate(ring.getframerate())
        self.audioDevice.setformat(alsaaudio.PCM_FORMAT_S16_LE)
        self.audioDevice.setperiodsize(320)

        # Read the audio data of the ringtone.
        self.audioData = list()
        buf = ring.readframes(320)
        while buf:
            self.audioData.append(buf)
            buf = ring.readframes(320)

    def closeEvent(self, event):
        """
        Prevents accidental shutdowns by asking the user.
        """
        if self.timerActive:
            self.stopTimer()

            if self.promptUser("ask_paused"):
                event.accept()
            else:
                event.ignore()
                self.startTimer(0, restart=True)
        else:
            event.accept()

    def setTitle(self, title):
        """
        Sets the window title.
        """
        if title is None:
            title = self.getString("app_name")
        else:
            title += " - " + self.getString("app_name")

        self.window().setWindowTitle(title)

    def startTimer(self, timeSpan, restart=False):
        """
        Starts the timer.
        """
        if restart is False:
            self.timerType = timeSpan
            self.timerCount = timeSpan * 60
        self.timerActive = True
        self.timer.start(1000)

    def stopTimer(self):
        """
        Stops the timer.
        """
        self.timerActive = False
        self.timer.stop()

    def resetTimer(self):
        """
        Resets the timer.
        """
        self.stopTimer()
        self.timerCount = 0

    def finishTimer(self, task):
        """
        Is called once the timer finished.
        """
        self.resetTimer()
        # Define the regular length of a pomodoro. Purely for debugging reasons
        POMO_CONST = 25
        pomos = math.floor(self.timerType / POMO_CONST)
        self.setVisible(True)
        if pomos >= 1 and task != "":
            newTask = self.pomo.pomoData.addPomo(task, pomos)
            if newTask is True:
                self.pomoTaskBar.addItem(task, None)
            self.fillActivityTab()
            self.updateTasksTab()

    def trayClick(self, reason):
        """
        Is called when the user clicks on the tray icon.
        """
        if reason == 2 or reason == 3:
            if self.isVisible():
                self.setVisible(False)
            else:
                self.setVisible(True)

    def promptUser(self, identifier, additional=None):
        """
        Creates predefined confirmation/warning dialogs.
        """
        if identifier == "ask_paused":
            reply = QtGui.QMessageBox.question(
                self,
                self.getString("ask_paused_title"),
                self.getString("ask_paused_text"),
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No,
            )
            if reply == QtGui.QMessageBox.Yes:
                return True
            else:
                return False

        elif identifier == "warn_notask":
            QtGui.QMessageBox.warning(self, self.getString("warn_notask_title"), self.getString("warn_notask_text"))
            return

        elif identifier == "ask_taskdel" and additional != None:
            askText = self.getString("ask_taskdel_text")
            askText = str.replace(askText, "%taskname%", str(additional))

            reply = QtGui.QMessageBox.question(
                self,
                self.getString("ask_taskdel_title"),
                askText,
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No,
            )

            if reply == QtGui.QMessageBox.Yes:
                return True
            else:
                return False

        raise KeyError

    ##############
    ## Pomo Tab ##
    ##############

    def initPomoTab(self):
        """
        Creates the layout of the pomodoro tab
        """
        pomoTab = QtGui.QWidget()

        # Create a combobox with a lineedit for task selection.
        taskBar = QtGui.QComboBox()
        taskBar.setEditable(True)
        taskBarLine = taskBar.lineEdit()
        taskBarLine.setMaxLength(64)
        taskBarLine.setPlaceholderText(self.getString("input_task"))
        taskBar.setFixedSize(375, 32)
        taskBar.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically)
        taskBar.setStyleSheet("font-size: 11pt;")
        taskBar.addItem("", None)
        self.pomoTaskBar = taskBar

        # Add all the task names.
        tasks = self.pomo.pomoData.tasks
        for taskID, taskName, pomoCount, pomoLast in tasks:
            taskBar.addItem(taskName, None)

        # Create the main button.
        mainBtn = QtGui.QPushButton(self.getString("btn_start"), pomoTab)
        mainBtn.setFixedSize(180, 60)
        mainBtn.setStyleSheet("font-size: 17pt;")

        # Create the 25 min button.
        timeBtn = QtGui.QPushButton(self.getString("lbl_regularpomo"), pomoTab)
        timeBtn.setToolTip(self.getString("ttp_regularpomo"))
        timeBtn.setFixedSize(50, 25)
        timeBtn.setStyleSheet("font-size: 9pt;")

        # Create the 50 min button.
        longTimeBtn = QtGui.QPushButton(self.getString("lbl_longpomo"), pomoTab)
        longTimeBtn.setToolTip(self.getString("ttp_longpomo"))
        longTimeBtn.setFixedSize(50, 25)
        longTimeBtn.setStyleSheet("font-size: 9pt;")

        # Create the 5 min button.
        pauseBtn = QtGui.QPushButton(self.getString("lbl_shortpause"), pomoTab)
        pauseBtn.setToolTip(self.getString("ttp_shortpause"))
        pauseBtn.setFixedSize(50, 25)
        pauseBtn.setStyleSheet("font-size: 9pt;")

        # Create the 10 min button.
        longPauseBtn = QtGui.QPushButton(self.getString("lbl_longpause"), pomoTab)
        longPauseBtn.setToolTip(self.getString("ttp_longpause"))
        longPauseBtn.setFixedSize(50, 25)
        longPauseBtn.setStyleSheet("font-size: 9pt;")

        # Select 25 min button as default on startup.
        timeBtn.setDisabled(True)
        self.pomoButtonActive = timeBtn

        # Save button references for later usage.
        self.pomoBtns = dict()
        self.pomoBtns["main"] = mainBtn
        self.pomoBtns["time"] = timeBtn
        self.pomoBtns["longTime"] = longTimeBtn
        self.pomoBtns["pause"] = pauseBtn
        self.pomoBtns["longPause"] = longPauseBtn

        # Connect the buttons to the handler function.
        for name, button in self.pomoBtns.items():
            button.clicked.connect(self.onClicked)

        # Create and set the layout.
        firstRow = QtGui.QHBoxLayout()
        firstRow.addWidget(taskBar)

        secondRow = QtGui.QHBoxLayout()
        secondRow.addStretch()
        secondRow.addWidget(pauseBtn)
        secondRow.addWidget(longPauseBtn)
        secondRow.addStretch()
        secondRow.addWidget(timeBtn)
        secondRow.addWidget(longTimeBtn)
        secondRow.addStretch()

        thirdRow = QtGui.QHBoxLayout()
        thirdRow.addWidget(mainBtn)

        vbox = QtGui.QVBoxLayout()
        vbox.addStretch()
        vbox.addLayout(firstRow)
        vbox.addStretch()
        vbox.addLayout(secondRow)
        vbox.addStretch()
        vbox.addLayout(thirdRow)
        vbox.addStretch()

        pomoTab.setLayout(vbox)

        return pomoTab

    def onClicked(self):
        """
        Main function for catching button clicks in the pomo tab.
        """
        sender = self.sender()
        if sender == self.pomoBtns["main"]:
            return self.onClickedPomoMain()

        elif (
            sender == self.pomoBtns["pause"]
            or sender == self.pomoBtns["longPause"]
            or sender == self.pomoBtns["time"]
            or sender == self.pomoBtns["longTime"]
        ):
            return self.onClickedPomoTime()

        raise ValueError()

    def onClickedPomoMain(self):
        """
        Starts/Stops the timer depending on the state of the button.
        """
        sender = self.sender()

        if self.timerActive:
            self.stopTimer()
            # Ask the user whether he wants to reset the running timer.
            if self.promptUser("ask_paused"):
                self.resetPomoTab()
                self.resetTimer()
            else:
                self.startTimer(0, restart=True)
        else:
            newText = self.pomoTaskBar.currentText().strip()
            self.pomoTaskBar.setEditText(newText)

            if newText != "" or self.pomoTaskBar.isEnabled() is False:
                self.pomoTaskBar.setDisabled(True)
                for k, v in self.pomoBtns.items():
                    if k != "main":
                        v.setDisabled(True)
                timeSpan = int(self.pomoButtonActive.text())
                title = "{0:0>2}:00".format(timeSpan)
                sender.setText(title)
                self.setTitle(title)
                self.startTimer(timeSpan)
            else:
                self.promptUser("warn_notask")

    def onClickedPomoTime(self):
        """
        Toggles the state of the timer buttons in the pomo tab.
        """
        sender = self.sender()

        if self.pomoBtns["main"].text() == "start":
            self.pomoButtonActive.setDisabled(False)
            sender.setDisabled(True)
            self.pomoButtonActive = sender

            if sender == self.pomoBtns["pause"] or sender == self.pomoBtns["longPause"]:
                self.pomoTaskBar.setDisabled(True)
            else:
                self.pomoTaskBar.setDisabled(False)

    def resetPomoTab(self):
        """
        Resets the button states in the pomo tab.
        """
        if self.pomoButtonActive != self.pomoBtns["pause"] and self.pomoButtonActive != self.pomoBtns["longPause"]:
            self.pomoTaskBar.setDisabled(False)

        self.pomoBtns["main"].setText("start")
        for k, v in self.pomoBtns.items():
            if k != "main" and v is not self.pomoButtonActive:
                v.setDisabled(False)

        # Also reset the window title.
        self.setTitle(None)

    def tick(self):
        """
        Updates the GUI every second when the timer is running.
        """
        self.timerCount -= 1

        timeStr = "{0:0>2}:{1:0>2}".format(math.floor(self.timerCount / 60), self.timerCount % 60)
        self.pomoBtns["main"].setText(timeStr)
        # Show current time in the title.
        self.setTitle(timeStr)

        # Timer finished?
        if self.timerCount == 0:
            self.playRingtone()
            self.finishTimer(self.pomoTaskBar.currentText())
            self.resetPomoTab()

    def playRingtone(self):
        """
        Creates a thread for playing the ringtone.
        """
        t = threading.Thread(target=self.playRingThread)
        # Kill the thread once it finishes.
        t.daemon = True
        t.start()

    def playRingThread(self):
        """
        Plays the Ringtone.
        """
        for data in self.audioData:
            self.audioDevice.write(data)

    ###############
    ## tasks tab ##
    ###############

    def initTasksTab(self):
        """
        Creates the layout of the tasks tab.
        """
        tasksTab = QtGui.QWidget()

        self.tasksTable = self.fillTasksTable()
        self.tasksVBox = QtGui.QVBoxLayout()
        self.tasksVBox.addWidget(self.tasksTable)
        self.tasksTable.sortItems(0)

        tasksTab.setLayout(self.tasksVBox)
        return tasksTab

    def fillTasksTable(self):
        """
        Fills the table in the tasks tab.
        """
        tasks = self.pomo.pomoData.tasks
        self.taskTableSelChange = False

        # Create a table with three columns.
        table = QtGui.QTableWidget(len(tasks), 3)
        table.itemSelectionChanged.connect(self.taskListSelectionChanged)
        table.itemClicked.connect(self.taskListClick)
        table.setShowGrid(True)
        table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        table.setFocusPolicy(QtCore.Qt.NoFocus)
        table.setHorizontalHeaderLabels(
            [self.getString("lbl_stats_task"), self.getString("lbl_stats_pomos"), self.getString("lbl_stats_last")]
        )
        table.verticalHeader().setVisible(False)
        table.horizontalHeader().setHighlightSections(False)

        # Create a context menu for the table.
        def ctMenuEvent(event):
            self.taskTableSelChange = False
            menu = QtGui.QMenu(table)
            rnAct = menu.addAction("Rename", self.renameTask)
            dlAct = menu.addAction("Delete", self.deleteTask)
            menu.popup(QtGui.QCursor.pos())
            if self.timerActive and self.pomoTaskBar.currentText() == self.tasksTable.selectedItems()[0].text():
                rnAct.setEnabled(False)
                dlAct.setEnabled(False)

        table.contextMenuEvent = ctMenuEvent

        # Columwidth depends on the existence of a scrollbar.
        if len(tasks) <= 7:
            table.setColumnWidth(0, 345)
        else:
            table.setColumnWidth(0, 329)
        table.setColumnWidth(1, 48)
        table.setColumnWidth(2, 60)

        # There must be a row counter since the taskID can be different.
        rowCount = 0

        # Fill the table rows.
        for taskID, taskName, pomoCount, pomoLast in tasks:
            # First column: taskName
            item = QtGui.QTableWidgetItem()
            item.setText(taskName)
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            table.setItem(rowCount, 0, item)

            # Second column: pomoCount
            item = QtGui.QTableWidgetItem()
            item.setText(str(pomoCount))
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            item.setToolTip("~" + str(round((pomoCount * 25) / 60, 1)) + "h")
            table.setItem(rowCount, 1, item)

            # Third column: pomoLast
            pomoLastDate = datetime.datetime.fromtimestamp(pomoLast)
            item = QtGui.QTableWidgetItem()
            item.setText(pomoLastDate.strftime("%x"))
            item.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
            table.setItem(rowCount, 2, item)

            rowCount += 1
        return table

    def updateTasksTab(self):
        """
        Updates the pomodoro statistics in the tasks tab.
        """
        self.tasksVBox.removeWidget(self.tasksTable)
        self.tasksTable.close()
        self.tasksTable = self.fillTasksTable()
        self.tasksVBox.insertWidget(0, self.tasksTable)

    def taskListSelectionChanged(self):
        """
        Sets a flag when the selection in the task table was changed.
        """
        if self.tasksTable.selectedItems() != []:
            self.taskTableSelChange = True

    def taskListClick(self, item):
        """
        Detects when an item in the task table was clicked and clears selection if necessary.
        """
        if self.taskTableSelChange == False:
            self.tasksTable.clearSelection()
        self.taskTableSelChange = False

    def deleteTask(self):
        """
        Deletes a task by the users request.
        """
        taskName = self.tasksTable.selectedItems()[0].text()
        okay = self.promptUser("ask_taskdel", additional=taskName)
        if okay:
            # Delete entry from GUI
            pbID = self.pomoTaskBar.findText(taskName)
            self.pomoTaskBar.removeItem(pbID)

            stID = self.activitySelTask.findText(taskName)
            self.activitySelTask.removeItem(stID)

            rownum = self.tasksTable.row(self.tasksTable.selectedItems()[0])
            self.tasksTable.removeRow(rownum)

            if self.tasksTable.rowCount() <= 7:
                self.tasksTable.setColumnWidth(0, 345)

            # Delete entry from db and cache
            taskID = self.pomo.pomoData.getTaskID(taskName)
            self.pomo.pomoData.delTask(taskID)

            # Reset the activity tab
            self.fillActivityTab()

    def renameTask(self, warn=""):
        """
        Renames a task by the users request.
        """
        oldname = self.tasksTable.selectedItems()[0].text()
        name, okay = QtGui.QInputDialog.getText(self, self.getString("lbl_rename_task"), warn, text=oldname)
        if okay and name != "" and name != oldname:
            try:
                self.pomo.pomoData.getTaskID(name)
                self.renameTask(self.getString("lbl_rename_taken"))
            except KeyError:
                # Update entry in GUI
                self.tasksTable.selectedItems()[0].setText(name)

                pbID = self.pomoTaskBar.findText(oldname)
                self.pomoTaskBar.setItemText(pbID, name)

                stID = self.activitySelTask.findText(oldname)
                self.activitySelTask.setItemText(stID, name)

                # Update entry in db and cache
                tID = self.pomo.pomoData.getTaskID(oldname)
                self.pomo.pomoData.renameTask(tID, name)

    ##################
    ## activity tab ##
    ##################

    def initActivityTab(self):
        """
        Creates the layout of the activity tab and prepares the graph.
        """
        activityTab = QtGui.QWidget()

        # Get the background color of the window to make the graph fit in.
        color = self.palette().color(QtGui.QPalette.Background)

        # Create a fixed-size canvas for the graph.
        self.figure = plt.figure(facecolor=color.name(), tight_layout=False)
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setFixedSize(460, 236)

        # Set default values for some attributes used in fillActivityTab
        self.lockYLim = False
        self.intervalShift = 0
        self.intervalScale = 3  # [3] days - [2] weeks - [1] months
        self.activityTaskID = 0

        # Combobox for selecting the active task to be displayed.
        selTask = QtGui.QComboBox()
        selTask.insertItem(0, self.getString("lbl_stats_all"), None)
        for tID, tskName, pomoCount, pomoLast in self.pomo.pomoData.tasks:
            selTask.addItem(tskName, None)

        selTask.currentIndexChanged["QString"].connect(self.onChangeTask)
        # Save handle for later use.
        self.activitySelTask = selTask

        # Navigation buttons to change the active timespan.
        farLeftButton = QtGui.QPushButton("<<", activityTab)
        farLeftButton.setStyleSheet("font-size: 12pt;")
        farLeftButton.setFixedSize(30, 20)
        farLeftButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state
        self.farLeftButtonHandle = farLeftButton

        farRightButton = QtGui.QPushButton(">>", activityTab)
        farRightButton.setStyleSheet("font-size: 12pt;")
        farRightButton.setFixedSize(30, 20)
        farRightButton.setDisabled(True)
        farRightButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state.
        self.farRightButtonHandle = farRightButton

        leftButton = QtGui.QPushButton("<", activityTab)
        leftButton.setStyleSheet("font-size: 12pt;")
        leftButton.setFixedSize(30, 20)
        leftButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state
        self.leftButtonHandle = leftButton

        rightButton = QtGui.QPushButton(">", activityTab)
        rightButton.setStyleSheet("font-size: 12pt;")
        rightButton.setFixedSize(30, 20)
        rightButton.setDisabled(True)
        rightButton.clicked.connect(self.timeNavigate)
        # Save the handle for toggling the button state.
        self.rightButtonHandle = rightButton

        # Disable left navigation buttons when there are no finished pomos.
        if self.pomo.pomoData.firstPomo == 0:
            leftButton.setDisabled(True)
            farLeftButton.setDisabled(True)

        # Zoom buttons to change the active timespan.
        zoomOutButton = QtGui.QPushButton("−", activityTab)
        zoomOutButton.setStyleSheet("font-size: 12pt;")
        zoomOutButton.setFixedSize(30, 20)
        zoomOutButton.clicked.connect(self.timeZoom)
        # Save the handle for toggling the button state.
        self.zoomOutButtonHandle = zoomOutButton

        zoomInButton = QtGui.QPushButton("+", activityTab)
        zoomInButton.setStyleSheet("font-size: 12pt;")
        zoomInButton.setFixedSize(30, 20)
        zoomInButton.setDisabled(True)
        zoomInButton.clicked.connect(self.timeZoom)
        # Save the handle for toggling the button state.
        self.zoomInButtonHandle = zoomInButton

        # Get highest pomo count on a single day.
        self.highestPomoCount = list()

        self.highestPomoCount.append(self.pomo.pomoData.getHighestPomoCountMonthly())
        self.highestPomoCount.append(self.pomo.pomoData.getHighestPomoCountWeekly())
        self.highestPomoCount.append(self.pomo.pomoData.getHighestPomoCountDaily())

        # Draw the graph.
        self.fillActivityTab()

        # Create and set the layout.
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.canvas)
        layout2 = QtGui.QHBoxLayout()
        layout2.addWidget(farLeftButton)
        layout2.addWidget(leftButton)
        layout2.addWidget(rightButton)
        layout2.addWidget(farRightButton)
        layout2.addStretch()
        layout2.addWidget(zoomOutButton)
        layout2.addWidget(zoomInButton)
        layout2.addStretch()
        layout2.addWidget(selTask)
        layout.addLayout(layout2)

        activityTab.setLayout(layout)
        return activityTab

    def fillActivityTab(self):
        """
        Fills and displays the bar graph in the activity tab.
        """
        taskID = self.activityTaskID

        # First get the absolute value of today.
        today = datetime.date.today()
        delta = datetime.timedelta(days=1)

        # Now construct shiftable intervals.
        beginInt = datetime.datetime
        endInt = datetime.datetime

        # Default scale (days): Begin interval at midnight of today.
        beginInt = datetime.datetime(today.year, today.month, today.day, 0, 0, 0)
        shiftDelta = delta

        if self.intervalScale == 2:  # Scale: Weeks
            # Begin interval at midnight of this weeks monday.
            weekDayNum = calendar.weekday(today.year, today.month, today.day)
            beginInt = beginInt - delta * weekDayNum
            shiftDelta = 7 * delta
        elif self.intervalScale == 1:  # Scale: Months
            # Begin interval at midnight of the first day of the month.
            beginInt = datetime.datetime(today.year, today.month, 1, 0, 0, 0)
            shiftDelta = 30 * delta
        self.shiftDelta = shiftDelta

        # Get the data of the last units since today.
        units = list()
        values = list()
        size = 6 + self.intervalScale

        for i in range(size):
            # Shift
            offset = size - i - 1 - self.intervalShift
            shiftedBegin = beginInt - offset * shiftDelta
            # When scaled to months, an arithmetical shift is not practical.
            if self.intervalScale == 1:
                yearDiff, monDiff = divmod(offset, 12)
                newMon = beginInt.month - monDiff
                if newMon < 0:
                    newMon = 12 + newMon
                    yearDiff += 1

                if newMon == 0:
                    newMon = 12
                    yearDiff += 1

                shiftedBegin = datetime.datetime(beginInt.year - yearDiff, newMon, 1, 0, 0, 0)
            shiftedEnd = datetime.datetime

            if self.intervalScale == 3:
                units.append(str(shiftedBegin.month) + "/" + str(shiftedBegin.day))
                shiftedEnd = datetime.datetime(shiftedBegin.year, shiftedBegin.month, shiftedBegin.day, 23, 59, 59)
            elif self.intervalScale == 2:
                units.append(shiftedBegin.strftime("CW %W"))
                shiftedEnd = datetime.datetime(shiftedBegin.year, shiftedBegin.month, shiftedBegin.day, 23, 59, 59)
                shiftedEnd = shiftedEnd + delta * 6
            else:
                units.append(shiftedBegin.strftime("%b %y"))
                lastDay = calendar.monthrange(shiftedBegin.year, shiftedBegin.month)[1]
                shiftedEnd = datetime.datetime(shiftedBegin.year, shiftedBegin.month, lastDay, 23, 59, 59)
            timeInt = [int(shiftedBegin.timestamp()), int(shiftedEnd.timestamp())]
            values.append(self.pomo.pomoData.getPomoCount(timeInt, taskID))

        # Disable left buttons once we scrolled far enough
        if self.pomo.pomoData.firstPomo != 0:
            shiftedBegin = beginInt - (size - 1 - self.intervalShift) * shiftDelta
            self.shiftedBegin = shiftedBegin
            if shiftedBegin.timestamp() <= self.pomo.pomoData.firstPomo:
                self.leftButtonHandle.setDisabled(True)
                self.farLeftButtonHandle.setDisabled(True)
            else:
                self.leftButtonHandle.setDisabled(False)
                self.farLeftButtonHandle.setDisabled(False)

        # Create a new subplot.
        ax = self.figure.add_subplot(111)
        ax.hold(False)

        # Create the bar graphs
        bars = ax.bar(list(range(1, size + 1)), values, width=0.4, align="center", color="#E04B3F")
        for bar in bars:
            height = bar.get_height()
            plt.text(
                bar.get_x() + bar.get_width() / 2.0,
                height + 0.08,
                "%d" % int(height),
                ha="center",
                va="bottom",
                weight="medium",
            )
        plt.xticks(list(range(1, size + 1)), units)

        # y-Limit of the graph depends on the maximum bar height.
        yLim = self.highestPomoCount[self.intervalScale - 1] * 1.24

        # To avoid rescaling the graph when changing the task, we lock the
        # y-Limit to the first one generated after startup.
        if self.lockYLim is False:
            if yLim == 0:
                # When no pomodoros have been done, use a constant y-Limit.
                yLim = 15
            else:
                self.lockYLim = True
            self.yLim = yLim
        else:
            # Update the y-Limit when it exceeds the saved one.
            if yLim > self.yLim:
                self.yLim = yLim

        # Set the graph limits.
        ax.set_ylim([0, self.yLim])
        ax.set_xlim([0.5, size + 0.5])

        # Additional plot and graph settings.
        plt.subplots_adjust(left=0, right=0.99, top=1, bottom=0.087)
        ax.get_yaxis().set_visible(False)
        plt.minorticks_off()
        for tick in ax.get_xticklines():
            tick.set_visible(False)

        # Write currently viewed month and year in the upper right corner,
        # when zoomed out, only display the year.
        if self.intervalScale != 1:
            tempDate = beginInt - (size - 1 - self.intervalShift) * shiftDelta
            dateString = tempDate.strftime("%b %Y")
            if self.intervalScale != 3:
                dateString = tempDate.strftime("%Y")

            plt.text(
                0.99,
                0.937,
                dateString,
                horizontalalignment="right",
                verticalalignment="center",
                transform=ax.transAxes,
                weight="bold",
            )

        # Show.
        self.canvas.draw()

    def timeNavigate(self):
        """
        Handling function for the navigation buttons in the activity tab.
        """
        sender = self.sender()

        if sender.text() == "<":
            self.intervalShift -= 6
            self.rightButtonHandle.setDisabled(False)
            self.farRightButtonHandle.setDisabled(False)
        elif sender.text() == ">":
            self.intervalShift += 6
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)
            if self.intervalShift == 0:
                # Once we hit todays date, disable the right button.
                sender.setDisabled(True)
                self.farRightButtonHandle.setDisabled(True)
        elif sender.text() == "<<":
            sender.setDisabled(True)
            self.leftButtonHandle.setDisabled(True)
            self.rightButtonHandle.setDisabled(False)
            self.farRightButtonHandle.setDisabled(False)

            date = self.shiftedBegin
            while date.timestamp() >= self.pomo.pomoData.firstPomo:
                self.intervalShift -= 6
                date -= 6 * self.shiftDelta
        elif sender.text() == ">>":
            self.intervalShift = 0
            sender.setDisabled(True)
            self.rightButtonHandle.setDisabled(True)
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)

        self.fillActivityTab()

    def timeZoom(self):
        """
        Handling function for the zoom buttons in the activity tab.
        """
        sender = self.sender()

        # Always reset the navigation while zooming
        self.intervalShift = 0
        self.lockYLim = False

        if self.pomo.pomoData.firstPomo != 0:
            self.leftButtonHandle.setDisabled(False)
            self.farLeftButtonHandle.setDisabled(False)
        self.rightButtonHandle.setDisabled(True)
        self.farRightButtonHandle.setDisabled(True)

        # Zoom Out:
        if sender.text() == "−":
            self.intervalScale -= 1
            if self.intervalScale == 1:
                self.zoomOutButtonHandle.setDisabled(True)
            self.zoomInButtonHandle.setDisabled(False)
        # Zoom In:
        else:
            self.intervalScale += 1
            if self.intervalScale == 3:
                sender.setDisabled(True)
            self.zoomOutButtonHandle.setDisabled(False)

        self.fillActivityTab()

    def onChangeTask(self, string=str()):
        """
        Will be called when the user changes the task in the activity tab.
        """
        try:
            self.activityTaskID = self.pomo.pomoData.getTaskID(string)
        except KeyError:
            self.activityTaskID = 0
        self.fillActivityTab()