def __init__(self, scrollAreaWidgetContents): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) canvas = FigureCanvas(Figure((3.0, 2.0), dpi=100)) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) toolbar.disableButtons() temporal_toolbar = temporalNavigationToolbar(canvas, self) mainImage = QtGui.QLabel(self) mainImage.setText(_fromUtf8("")) mainImage.setPixmap( QtGui.QPixmap( _fromUtf8(":/newPrefix/images/fromHelyx/emptyFigure.png"))) mainImage.setObjectName(_fromUtf8("mainImage")) plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(mainImage) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) canvas.setMinimumSize(canvas.size())
def __init__(self, scrollAreaWidgetContents, currentFolder): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) canvas = FigureCanvas(Figure((3.0, 2.0), dpi=100)) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) toolbar.disableButtons() temporal_toolbar = temporalNavigationToolbar(canvas, self) mainImage = QtGui.QLabel(self) mainImage.setText(_fromUtf8("")) mainImage.setPixmap( QtGui.QPixmap( _fromUtf8(":/newPrefix/images/fromHelyx/emptyFigure.png"))) mainImage.setObjectName(_fromUtf8("mainImage")) mainImage.setScaledContents(True) mainImage.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored) plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(mainImage, 1) plotLayout.addWidget(toolbar, 0, QtCore.Qt.AlignCenter) self.setLayout(plotLayout) self.lastPos = -1 self.dirList = [] self.currentFolder = currentFolder canvas.setMinimumSize(canvas.size())
def __init__(self, scrollAreaWidgetContents, dataname): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) fig = Figure((3.0, 2.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) temporal_toolbar = temporalNavigationToolbar(canvas, self) axes = fig.add_subplot(111) axes.autoscale(True) axes.set_yscale('log') axes.set_title(dataname) # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) canvas.setMinimumSize(canvas.size()) self.name = dataname self.dirList = [] self.dirType = 'Sampled Line' self.lastPos = -1 self.colors = ['r', 'b', 'k', 'g', 'y', 'c'] self.labels = ['_x', '_y', '_z']
def __init__(self, scrollAreaWidgetContents, dataname, currentFolder): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) fig = Figure((3.0, 2.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) temporal_toolbar = temporalNavigationToolbar(canvas, self) axes = fig.add_subplot(111) axes.autoscale(True) axes.set_yscale('log') axes.set_title(dataname) # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(canvas,1) plotLayout.addWidget(toolbar,0,QtCore.Qt.AlignCenter) self.setLayout(plotLayout) canvas.setMinimumSize(canvas.size()) self.name = dataname self.dirList = [] self.dirType = 'Sampled Line' self.lastPos = -1 self.colors = ['r', 'b', 'k', 'g', 'y', 'c'] self.labels = ['x','y','z'] self.currentFolder = currentFolder filename = '%s/system/controlDict'%(self.currentFolder) parsedData = ParsedParameterFile(filename,createZipped=False) self.ifield=parsedData['functions'][dataname]['fields'][0] self.archifield = 'data_%s.xy'%self.ifield
def __init__(self, scrollAreaWidgetContents, name): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) fig = Figure((3.0, 2.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) axes = fig.add_subplot(111) axes.autoscale(True) axes.set_title(name) axes.set_xlabel('Time [s]') axes.set_ylabel('T') # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) self.dataPlot = [] self.dirList = [] self.dirType = 'Tracers' self.lastPos = -1 self.name = name self.colors = ['r', 'b', 'k', 'g', 'y', 'c'] # prevent the canvas to shrink beyond a point #original size looks like a good minimum size canvas.setMinimumSize(canvas.size())
def __init__(self, scrollAreaWidgetContents, currentFolder): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) canvas = FigureCanvas(Figure((3.0, 2.0), dpi=100)) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) toolbar.disableButtons() temporal_toolbar = temporalNavigationToolbar(canvas, self) mainImage = QtGui.QLabel(self) mainImage.setText(_fromUtf8("")) mainImage.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/fromHelyx/emptyFigure.png"))) mainImage.setObjectName(_fromUtf8("mainImage")) mainImage.setScaledContents(True) mainImage.setSizePolicy(QtGui.QSizePolicy.Ignored,QtGui.QSizePolicy.Ignored) plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(mainImage,1) plotLayout.addWidget(toolbar,0,QtCore.Qt.AlignCenter) self.setLayout(plotLayout) self.lastPos = -1 self.dirList = [] self.currentFolder = currentFolder canvas.setMinimumSize(canvas.size())
def __init__(self, scrollAreaWidgetContents, dataname): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) fig = Figure((3.0, 2.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) temporal_toolbar = temporalNavigationToolbar(canvas, self) axes = fig.add_subplot(111) axes.autoscale(True) axes.set_yscale('log') axes.set_title(dataname) # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) canvas.setMinimumSize(canvas.size()) self.name = dataname self.dirList = [] self.dirType = 'Sampled Line' self.lastPos = -1 self.colors = ['r', 'b', 'k', 'g', 'y', 'c'] self.labels = ['_x','_y','_z']
def __init__(self, scrollAreaWidgetContents, name): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) fig = Figure((3.0, 2.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) axes = fig.add_subplot(111) axes.autoscale(True) axes.set_yscale('log') axes.set_title(name) axes.set_xlabel('Time [s]') axes.set_ylabel('|R|') # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) self.dataPlot = [] self.dirList = [] self.dirType = 'Residuals' self.lastPos = -1 self.name = name self.colors = ['r', 'b', 'k', 'g', 'y', 'c'] # prevent the canvas to shrink beyond a point #original size looks like a good minimum size canvas.setMinimumSize(canvas.size())
def plot_file(fps, base_dir, string_graph_map): app = QtGui.QApplication('Bodysim') graph_map = ast.literal_eval(string_graph_map) # Find the length of the simulation by looking at trajectory results. start_frame = 1 count = 0 with open(base_dir + os.sep + 'Trajectory' + os.sep + graph_map.keys()[0] + '.csv') as f: iterF = iter(f) # Skip header next(iterF) line = next(iterF) start_frame = float(line.split(',')[0]) count = sum(1 for line in iterF) frame = MainWindow(start_frame, count) for sensor in graph_map: layout_contents = frame.add_tab(sensor) for plugin in graph_map[sensor]: data = get_data(base_dir + os.sep + plugin + os.sep + sensor + '.csv') for variable_group in graph_map[sensor][plugin]: qfigWidget = QtGui.QWidget(layout_contents[1]) fig = Figure((5.0, 4.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(qfigWidget) toolbar = NavigationToolbar(canvas, qfigWidget) axes = fig.add_subplot(111) axes.set_title(plugin + ' ' + variable_group[2]) yDatum = [data[variable[1]] for variable in graph_map[sensor][plugin][variable_group]] yLabels = [variable[0] for variable in graph_map[sensor][plugin][variable_group]] for i in range(len(yDatum)): axes.plot(data[0], yDatum[i], label=yLabels[i]) axes.grid(True) axes.legend() axes.autoscale(enable=False, axis='both') axes.set_xlabel(variable_group[0]) axes.set_ylabel(variable_group[1]) # Place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) qfigWidget.setLayout(plotLayout) frame.toolbars[fig] = toolbar frame.plots.append(axes) canvas.setMinimumSize(canvas.size()) frame.bind_to_onclick_event(fig) layout_contents[0].addWidget(qfigWidget) frame.show() sys.exit(app.exec_())
def __init__(self, scrollAreaWidgetContents): QtGui.QWidget.__init__(self) self.setParent(scrollAreaWidgetContents) canvas = FigureCanvas(Figure((3.0, 2.0), dpi=100)) canvas.setParent(self) toolbar = myNavigationToolbar(canvas, self) toolbar.disableButtons() temporal_toolbar = temporalNavigationToolbar(canvas, self) mainImage = QtGui.QLabel(self) mainImage.setText(_fromUtf8("")) mainImage.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/fromHelyx/emptyFigure.png"))) mainImage.setObjectName(_fromUtf8("mainImage")) plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(temporal_toolbar) plotLayout.addWidget(mainImage) plotLayout.addWidget(toolbar) self.setLayout(plotLayout) canvas.setMinimumSize(canvas.size())
qscrollLayout.setGeometry(QtCore.QRect(0, 0, 1000, 1000)) qscroll.setWidget(qscrollContents) qscroll.setWidgetResizable(True) for i in xrange(5): qfigWidget = QtGui.QWidget(qscrollContents) fig = Figure((5.0, 4.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(qfigWidget) toolbar = NavigationToolbar(canvas, qfigWidget) axes = fig.add_subplot(111) axes.plot([1, 2, 3, 4]) # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) qfigWidget.setLayout(plotLayout) # prevent the canvas to shrink beyond a point # original size looks like a good minimum size canvas.setMinimumSize(canvas.size()) qscrollLayout.addWidget(qfigWidget) qscrollContents.setLayout(qscrollLayout) qwidget.show() exit(qapp.exec_())
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()
import sys app = QtGui.QApplication(sys.argv) imageViewer = ImageViewer() imageViewer.show() figure = plt.figure() figure.set_size_inches(11, 8.5) figure.patch.set_facecolor('white') plt.plot([1, 2, 3, 4], [1, 2, 3, 4], '-b') figure_canvas = FigureCanvasQTAgg(figure) figure_canvas.draw() size = figure_canvas.size() width, height = size.width(), size.height() print(width, height) print(figure_canvas.get_width_height()) imgbuffer = figure_canvas.buffer_rgba() image = QtGui.QImage(imgbuffer, width, height, QtGui.QImage.Format_ARGB32) # Reference for the RGB to BGR swap: # http://sourceforge.net/p/matplotlib/mailman/message/5194542/ image = QtGui.QImage.rgbSwapped(image) imageViewer.load_image(image, 0) sys.exit(app.exec_())
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 )
class Amoeba_Line_Graph(): def __init__(self): """ This class is for the plot on each of the parameter UIs. """ #Generate plot x = [] y = [] self.fig = Figure(figsize=(8,4),dpi=72, facecolor=(1,1,1), edgecolor=(0,0,0)) self.sub_plot = self.fig.add_subplot(111) self.sub_plot.xaxis_date() if AMOEBA_LINE_GRAPH_DEBUG: print "X = " print x print "Y = " print y print "Create " print self.sub_plot.plot self.sub_plot.plot(y,x,'b') self.sub_plot.set_xlabel('Time') self.fig.autofmt_xdate() #Create canvas for the plot self.canvas = FigureCanvas(self.fig) self.canvas.setMinimumSize(self.canvas.size()) def update(self,datay,datax): """ This method updates the plot with the input data. :param datay: Y axis of the points to plot. :param datax: X axis of the points to plot. """ if AMOEBA_LINE_GRAPH_DEBUG: print "Update sub plot" print "X = " print datax print "Y = " print datay print "Update " print self.sub_plot.plot # Clear the graph. self.clear_graph() self.sub_plot.plot(datax,datay,'b') self.sub_plot.set_visible(True) self.sub_plot.autoscale(True,"both") self.canvas.draw() def retrieve_graph(self): """ This method returns the plot's widget. :return: """ return self.canvas def clear_graph(self): """ This method clears the graph. """ y = [] x = [] self.sub_plot.clear() self.sub_plot.set_visible(True) self.sub_plot.autoscale(True,"both",False) self.sub_plot.plot(y,x,'b') self.canvas.draw()
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)
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 main(QMainWindow): #Definimos variables globales lista = [] lstlst = [] a = [] number_axe_1 = 0 number_axe_2 = 0 cwd = os.getcwd() dirs = os.listdir(cwd) #Creamos el constructor de la clase def __init__(self): QMainWindow.__init__(self) #Cargamos el archivo que contiene la interfáz gráfica uic.loadUi("main.ui", self) #Configuramos tamaño mínimo y máximo self.setMinimumSize(863, 640) self.setMaximumSize(863, 640) #Configuramos la fuente qfont = QFont("Arial", 12) self.setFont(qfont) #Centramos la ventana en la pantalla qr = self.frameGeometry() cp = QtGui.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) #Definimos el área de dibujo grid = QtGui.QGridLayout() self.frame_figure.setLayout(grid) self.figure = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas) #Desactivamos los botones btn_select_file, btn_plot_data, btn_save_figure self.btn_select_file.setEnabled(False) self.btn_plot_data.setEnabled(False) self.btn_save_figure.setEnabled(False) #Asociamos los eventos (Funciones) a los botones del sistema self.btn_show_files.clicked.connect(self.show_files) self.btn_select_file.clicked.connect(self.select_file) self.btn_plot_data.clicked.connect(self.show_plot) self.btn_save_figure.clicked.connect(self.save_figure) self.btn_restart.clicked.connect(self.restart) #Función show_files def show_files(self): """ La función show_files hace un análisis de los archivos que se encuentren en el directorio actual, haciendo un filtro con la extención de cada archivo y guardando en lista[] los archivos cuya extención sea .txt o .csv, posteriormente muestra en un área de texto dicha lista. """ #Declaramos variables locales n = 0 #Deshabilitamos el botón btn_show_files y habilitamos el botón btn_select_file self.btn_show_files.setEnabled(False) self.btn_select_file.setEnabled(True) #Creamos el ciclo que se encarga de analizar la extensión de los archivos y almacenarlos en la lista for i in self.dirs: if ".csv" in i or ".txt" in i: self.lista.append(i) #Creamos una condición preventiva que se ejecutará en caso de que el directorio no contenga archivos válidos if (len(self.lista) == 0): #Mostramos un mensaje de alerta indicando de que no hay archivos válidos QMessageBox.warning( self, "File Error", "Ha ocurrido un error, No hay archivos disponibles!!!") # Deshabilitamos el botón btn_select_files y habilitamos el botón btn_show_file self.btn_select_file.setEnabled(False) self.btn_show_files.setEnabled(True) #Creamos la condición para el caso de que si hayan archivos else: text = ( " ARCHIVOS DISPONIBLES\n" "----------------------------------------------------------------------------------------------------------\n" ) #Mostramos los archivos disponibles en un área de texto for i in self.lista: n = n + 1 text += (str(n) + "." + i + "\t\t") self.area_text.setText(text) #Función select_files def select_file(self): """ La función select_files permite seleccionar de la lista de archivos disponibles un archivo, además se encarga de crear las estructuras de datos necesarias para almacenarlas en memoria local y de corregir posibles errores en los datos """ #Definimos variables locales error = [] indiceserror = [] filaserror = [] #Deshabilitamos el botón btn_select_file y habilitamos el botón btn_plot_data self.btn_select_file.setEnabled(False) self.btn_plot_data.setEnabled(True) #Solicitamos al usuario que ingrese el índice del archivo a ser cargado, la variable number_file almacena #dicho índice, mientras la variable ok almacena el estado de la solicitud number_file, ok = QInputDialog.getInt( self, "Select File", "Ingrese el número del archivo a procesar") #Verificamos que la variable ok contenga un dato exitoso, esto es, verdadero if ok: #Verificamos que el número ingresado por el usuario corresponda al índice de un archivo if number_file in range(1, len(self.lista) + 1): #Guardamos en la variable file el nombre del archivo file = self.lista[number_file - 1] #Abrimos el archivo openf = open(file) #Mostramos en el campo de texto file_loaded_text el nombre del archivo cargado self.file_loaded.setText("Se ha abierto el archivo " + openf.name) #Creamos la variable route que contiene la ruta absoluta del archivo route = self.cwd + "/" + openf.name #Mostramos en el campo de texto dir_file_loaded la ruta self.dir_file_loaded.setText(route) #Procesamos el archivo cargado eliminando comas y puntoycomas que se encuentren en los archivos for line in openf: #Realizamos los procedimientos necesarios en caso de que el archivo sea txt if ".txt" in file: if "," in line: temp_list = line.split(",") if ";" in line: temp_list = line.split(";") #Agregamos los datos a la lista lstlst self.lstlst.append(temp_list) # Realizamos los procedimientos necesarios en caso de que el archivo sea csv if ".csv" in file: temp_list = line.split(";") # Agregamos los datos a la lista lstlst self.lstlst.append(temp_list) #Procesamos la lista lstlst eliminando posibles errores for i in self.lstlst: for j in i: #Intentamos convertir los datos de la lista en números reales try: j = float(j) #Capturamos cualquier posible error en el proceso de conversión y obtenemos el índice del error except ValueError: error.append(j) indiceserror.append(i.index(j)) filaserror.append(self.lstlst.index(i)) #Eliminamos de lstlst los datos que contengan errores for i in range(0, len(error)): self.lstlst[filaserror[i]].remove(error[i]) self.lstlst[filaserror[i]].insert(indiceserror[i], None) #Mostramos una alerta en caso de que el usuario ingrese un número que no corresponde aun índice else: QMessageBox.warning( self, "Select File Error", "Ha ocurrido un error, verifique los datos ingresados!!!") #Habilitamos el botón btn_select_file y deshabilitamos el botón btn_plot_data self.btn_select_file.setEnabled(True) self.btn_plot_data.setEnabled(False) #Procesamos un posible error en la entrada de datos, esto es, ok es falso else: QMessageBox.warning( self, "Select File Error", "Ha ocurrido un error, verifique los datos ingresados!!!") #Habilitamos el botón btn_select_file y deshabilitamos el botón btn_plot_data self.btn_select_file.setEnabled(True) self.btn_plot_data.setEnabled(False) #Función show_plot def show_plot(self): """ La funcíón show_plot es la encargada de mostar la gráfica de los datos, para realizar dicha tarea, primero se muestran las columnas disponibles para la comparación (lo que llamarémos ejes), cada eje corresponde a una columna del archivo, además permite al usuario seleccionar dos de dichos ejes para realizar la comparación, separa los datos en listas y por último grafica dicha información, """ #Definimos variables locales primereje = [] segundoeje = [] op = 0 e = "eje " n = 0 text_eje_x = " " text_eje_y = " " #Deshabilitamos el botón btn_plot_data y habilitamos el botón btn_save_figure self.btn_plot_data.setEnabled(False) self.btn_save_figure.setEnabled(True) #Contamos el número de ejes temp_list = self.lstlst[1] #Agregamos los ejes dispobibles a la lista a for i in range(1, len(temp_list) + 1): op += 1 self.a.append(e + str(op)) text = ( " EJES DISPONIBLES\n" "----------------------------------------------------------------------------------------------------------\n" ) #Mostramos los ejes disponibles en un área de texto for i in self.a: n = n + 1 text += (str(n) + ". " + i + " \t\t ") self.area_text.setText(text) #Solicitamos al usuario que ingrese el primer eje a graficar (La solicitud se realiza mientras #los datos ingresados sean erroneos) while (True): #Solicitamos el primer eje a graficar, la variable global number_axe_1 contiene el número del eje, #la variable ok contiene información sobre el éxito de la solicitud self.number_axe_1, ok = QInputDialog.getInt( self, "Select Axe", "Ingrese el número del primer eje a graficar") #Definimos las instrucciones correspondientes al éxito de la solicitud if ok: #Verificamos que el número ingresado corresponda a un índice de eje, en caso de que sea cierto #salimos del ciclo while if self.number_axe_1 in range(1, len(self.a) + 1): break #Procesamos el posible error de que el dato ingresado sea erroneo else: QMessageBox.warning( self, "Select Axe Error", "Ha ocurrido un error, verifique los datos ingresados!!!" ) #Procesamos un posible error en caso de que la solicitud no se realice con éxito else: QMessageBox.warning( self, "Select Axe Error", "Ha ocurrido un error, verifique los datos ingresados!!!") #Solicitamos al usuario que ingrese el segundo eje a graficar (La solicitud se realiza mientras #los datos ingresados sean erroneos) while (True): #Solicitamos el segundo eje a graficar, la variable global number_axe_2 contiene el número del eje, #la variable ok contiene información sobre el éxito de la solicitud self.number_axe_2, ok = QInputDialog.getInt( self, "Select Axe", "Ingrese el número del segundo eje a graficar") #Definimos las instrucciones correspondientes al éxito de la solicitud if ok: #Verificamos que el número ingresado corresponda a un índice de eje if self.number_axe_2 in range(1, len(self.a) + 1): #Comprobamos que el número ingresado para el segundo eje sea diferente del número ingresado #para el primer eje, si la condición se cumple salimos del while if (self.number_axe_1 != self.number_axe_2): break #Procesamos el posible error de que el dato ingresado sea igual al primero else: QMessageBox.warning( self, "Select Axe Error", "Ha ocurrido un error, Debe seleccionar un eje diferente!!" ) #Procesamos el posible error de que el dato ingresado sea erroneo else: QMessageBox.warning( self, "Select Axe Error", "Ha ocurrido un error, verifique los datos ingresados!!!" ) #Procesamos un posible error en caso de que la solicitud no se realice con éxito else: QMessageBox.warning( self, "Select Axe Error", "Ha ocurrido un error, verifique los datos ingresados!!!") #Agregamos los datos de los ejes a comparar en dos listas for i in self.lstlst: primereje.append(i[self.number_axe_1 - 1]) segundoeje.append(i[self.number_axe_2 - 1]) #Agregamos los datos de los ejes a comparar en dos cadenas for i in range(len(primereje)): text_eje_x += (primereje[i]) + "\n " for i in range(len(segundoeje)): text_eje_y += (segundoeje[i]) + "\n " #Mostramos en las áreas de texto data_eje_x y data_eje_y las cadenas que contienen los datos self.data_eje_x.setText(text_eje_x) self.data_eje_y.setText(text_eje_y) #Preparamos la figura para mostrar la gráfica self.figure.clf() ax = self.figure.add_subplot(111) #Mostramos la gráfica de los datos ax.plot(primereje, segundoeje, 'r.-') #Agregamos un título a la gráfica ax.set_title(self.a[self.number_axe_2 - 1] + " vs " + self.a[self.number_axe_1 - 1]) #Mostramos los datos self.canvas.draw() #Función save_figure def save_figure(self): """ La función save_figure contiene las instrucciones necesarias para almacenar una imagen en formato png de la gráfica mostrada """ #Deshabilitamos el botón btn_save_figure self.btn_save_figure.setEnabled(False) #Obtenemos el tamaño de la gráfica size = self.canvas.size() #Obtenemos el ancho y el alto de la imagen en las variables width y height width, height = size.width(), size.height() #Creamos la imagen a guardar im = QImage(self.canvas.buffer_rgba(), width, height, QImage.Format_ARGB32) #Guardamos la imagen en formato png im.save( str(self.a[self.number_axe_2 - 1] + self.a[self.number_axe_1 - 1] + ".png")) #Informamos que la imagen ha sido guardad con éxito QMessageBox.information(self, "Save Figure Success", "La gráfica ha sido guardada!!!") #Mostramos en el campo de texto dir_img_shown la dirección de la imagen guardada dir_image_save = self.cwd + "/" + str(self.a[self.number_axe_2 - 1] + self.a[self.number_axe_1 - 1] + ".png") self.dir_img_shown.setText(dir_image_save) #Función restart def restart(self): """ La función restart contiene el conjunto de instrucciones necesarias para preparar el sistema con el fin repetir el proceso de graficación de imágenes, se encarga de llevar a sus estados iniciales todas las variables globales utilizadas, limpiar los campos y áreas de texto y limpiar el área de graficado """ #Restauramos las variables globales self.lista = [] self.lstlst = [] self.a = [] self.number_axe_1 = 0 self.number_axe_2 = 0 #Limpiamos campos y áreas de texto self.data_eje_x.setText("") self.data_eje_y.setText("") self.file_loaded.setText("") self.dir_file_loaded.setText("") self.dir_img_shown.setText("") self.area_text.setText("") #Habilitamos el botón btn_show_files y deshabilitamos el botón btn_save_figure self.btn_show_files.setEnabled(True) self.btn_save_figure.setEnabled(False) #Reseteamos el área de graficado self.figure.clf() ax = self.figure.add_subplot(111) ax.plot(0, 0) self.canvas.draw() #Función closeEvent def closeEvent(self, QCloseEvent): """ La función closeEvent contiene las instrucciones a ser seguidas al momento de cerrar la aplicación """ #Preguntamos al usuario si realmente quiere salir de la aplicación result = QMessageBox.question( self, "Salir...", "¿Seguro que quieres cerrar la aplicación?", QMessageBox.Yes | QMessageBox.No) #Cerramos la aplicación en caso de respuesta afirmatica if result == QMessageBox.Yes: QCloseEvent.accept() #Ignoramos el evento en caso de que la respuesta sea negativa else: QCloseEvent.ignore()
class Amoeba_Line_Graph(): def __init__(self): """ This class is for the plot on each of the parameter UIs. """ #Generate plot x = [] y = [] self.fig = Figure(figsize=(8, 4), dpi=72, facecolor=(1, 1, 1), edgecolor=(0, 0, 0)) self.sub_plot = self.fig.add_subplot(111) self.sub_plot.xaxis_date() if AMOEBA_LINE_GRAPH_DEBUG: print "X = " print x print "Y = " print y print "Create " print self.sub_plot.plot self.sub_plot.plot(y, x, 'b') self.sub_plot.set_xlabel('Time') self.fig.autofmt_xdate() #Create canvas for the plot self.canvas = FigureCanvas(self.fig) self.canvas.setMinimumSize(self.canvas.size()) def update(self, datay, datax): """ This method updates the plot with the input data. :param datay: Y axis of the points to plot. :param datax: X axis of the points to plot. """ if AMOEBA_LINE_GRAPH_DEBUG: print "Update sub plot" print "X = " print datax print "Y = " print datay print "Update " print self.sub_plot.plot # Clear the graph. self.clear_graph() self.sub_plot.plot(datax, datay, 'b') self.sub_plot.set_visible(True) self.sub_plot.autoscale(True, "both") self.canvas.draw() def retrieve_graph(self): """ This method returns the plot's widget. :return: """ return self.canvas def clear_graph(self): """ This method clears the graph. """ y = [] x = [] self.sub_plot.clear() self.sub_plot.set_visible(True) self.sub_plot.autoscale(True, "both", False) self.sub_plot.plot(y, x, 'b') self.canvas.draw()
def __init__(self, parent=None): #======================================== super(ImageViewer, self).__init__(parent) self.scaleFactor = 0 self.scaleStep = 1.2 self.pan = False #---- image container Set Up ---- self.imageLabel = QtGui.QLabel() self.imageLabel.setBackgroundRole(QtGui.QPalette.Base) self.imageLabel.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored) self.imageLabel.setScaledContents(True) self.imageLabel.installEventFilter(self) self.imageLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.imageLabel.setLineWidth(2) self.imageLabel.setMidLineWidth(1) #---- Scroll Area Set Up ---- self.scrollArea = QtGui.QScrollArea(self) self.scrollArea.setWidget(self.imageLabel) self.scrollArea.setAlignment(QtCore.Qt.AlignCenter) #---- Grid Set Up ---- grid = QtGui.QGridLayout() grid.addWidget(self.scrollArea, 0, 0) grid.setSpacing(10) grid.setContentsMargins(0, 0, 0, 0) # (Left,Top, Right, Bottom) self.setLayout(grid) self.setWindowTitle("Image Viewer") #---- Create Initial Image with Matplotlib ---- # http://stackoverflow.com/questions/17676373/ # python-matplotlib-pyqt-copy-image-to-clipboard # http://stackoverflow.com/questions/21939658/ # matplotlib-render-into-buffer-access-pixel-data figure = plt.figure() figure.patch.set_facecolor('white') figure_canvas = FigureCanvasQTAgg(figure) figure_canvas.draw() size = figure_canvas.size() width, height = size.width(), size.height() imgbuffer = figure_canvas.buffer_rgba() image = QtGui.QImage(imgbuffer, width, height, QtGui.QImage.Format_ARGB32) # Reference for the RGB to BGR swap: # http://sourceforge.net/p/matplotlib/mailman/message/5194542/ image = QtGui.QImage.rgbSwapped(image) self.load_image(image, 0)
class GUI(QtGui.QDialog): def __init__(self): super(GUI, self).__init__() # Pola pomocnicze do obsługi pętli self._generator = None self._timerId = None # Właściwe pola klasy self.serial = serial.Serial() self.data = np.array([[], [], []]) self.frames = 0; self.last_frame = 0; self.frames_lost = 0; self.window = 100 # Szerokość okna rysowanego sygnału # Ustawienia ramki self.frame_length = 30; # Długość ramki z danymi self.frame_markers = np.array([int('A5', 16), int('5a', 16)]) self.buffer = bytearray(self.frame_length - len(self.frame_markers)) # Elementy okna self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setMinimumSize(self.canvas.size()) self.serial_line = QtGui.QLineEdit(self) self.serial_line.setText('COM9') self.serial_line.setAlignment(QtCore.Qt.AlignCenter) self.serial_line.setMaxLength(30) self.serial_line_label = QtGui.QLabel("Port") self.serial_line_label.setAlignment(QtCore.Qt.AlignCenter) self.lost_frames_count = QtGui.QLineEdit(self) self.lost_frames_count.setText('0%') self.lost_frames_count.setAlignment(QtCore.Qt.AlignCenter) self.lost_frames_count.setMaxLength(30) self.lost_frames_label = QtGui.QLabel("Frames lost") self.lost_frames_label.setAlignment(QtCore.Qt.AlignCenter) self.start_button = self.createButton("Start", self.start) self.stop_button = self.createButton("Stop", self.stop) self.stop_button.setEnabled(False) self.info_line = QtGui.QLineEdit(self) self.info_line.setReadOnly(True) self.info_line.setAlignment(QtCore.Qt.AlignCenter) self.info_line.setMaxLength(30) self.info_line.setText('INFO') self.setWindowTitle('Signal Reader v.1.0') # Układanie layout'u layout = QtGui.QGridLayout() layout.setSizeConstraint(QtGui.QLayout.SetFixedSize) layout layout.addWidget(self.canvas, 0, 0, 1, 2) layout.addWidget(self.serial_line_label, 1, 0, 1, 2) layout.addWidget(self.serial_line, 2, 0, 1, 2) layout.addWidget(self.start_button, 3, 0, 1, 1) layout.addWidget(self.stop_button, 3, 1, 1, 1) layout.addWidget(self.lost_frames_label, 4, 0, 1, 2) layout.addWidget(self.lost_frames_count, 5, 0, 1, 2) layout.addWidget(self.info_line, 6, 0, 1, 2) self.setLayout(layout) self.setFigures() def setFigures(self): self.channel1 = self.figure.add_subplot(3, 1, 1) self.channel1.hold(True) self.channel1_data, = self.channel1.plot(np.zeros(self.window)) plt.ylim([0, 4096]) plt.title('Channel 1') plt.grid() plt.tight_layout(pad = 0.4, w_pad = 0.5, h_pad = 1.0) self.channel2 = self.figure.add_subplot(3, 1, 2) self.channel2.hold(True) self.channel2_data, = self.channel2.plot(np.zeros(self.window)) plt.ylim([0, 4096]) plt.title('Channel 2') plt.grid() plt.tight_layout(pad = 0.4, w_pad = 0.5, h_pad = 1.0) self.channel3 = self.figure.add_subplot(3, 1, 3) self.channel3.hold(True) self.channel3_data, = self.channel3.plot(np.zeros(self.window)) plt.ylim([0, 4096]) plt.title('Channel 3') plt.grid() plt.tight_layout(pad = 0.4, w_pad = 0.5, h_pad = 1.0) plt.ion() def start(self): # Aktywancja/deazktywacja przycisków self.start_button.setEnabled(False) self.stop_button.setEnabled(True) self.port = str(self.serial_line.text()) # Zapisuje nazwę portu if self._timerId is not None: self.killTimer(self._timerId) self.serial_line.setReadOnly(True) # Ustawia pole z portem na niezmienialne self._generator = self.readData() # Wchodzi do pętli wczytywania danych self._timerId = self.startTimer(0) def stop(self): # Aktywancja/deazktywacja przycisków self.start_button.setEnabled(True) self.stop_button.setEnabled(False) if self._timerId is not None: self.killTimer(self._timerId) self._generator = None self._timerId = None self.serial_line.setReadOnly(False) if(self.serial.isOpen()): self.serial.close() self.info_line.setText('STOP') def readData(self): ''' Metoda do czytania dancyh z podanego portu. ''' try: self.serial = serial.Serial(self.port) # Otwiera port self.info_line.setText('Reading data...') # Zmienia napis while (True): input = self.serial.read() # Czyta 1 bajt # Sprawdzenie czy jest starszym bajtem znacznika if(int.from_bytes(input, byteorder = 'big') == self.frame_markers[0]): # Czytanie kolejnego 1 bajtu input = self.serial.read() # Sprawdzenie czy następny jest młodszym bajtem znacznika if(int.from_bytes(input, byteorder = 'big') == self.frame_markers[1]): # Jeśli tak to znaczy, że mamy ramkę self.frames += 1 # Wczytujemy do struktury buffer (która jest tablicą # bajtów) 28 bajtów (bo taki został ustalony jej rozmiar) self.serial.readinto(self.buffer) # Zamiana tablicy bajtów na macierz liczb całkowitych self.buffer = np.array(self.buffer, dtype = np.int32); self.parseData() self.plot() self.buffer = bytearray(self.frame_length - 2) yield except serial.SerialException as ex: self.info_line.setText('Can\'t open the serial port!') def parseData(self): ''' Metoda analizująca pobraną ramkę z danymi. ''' if(self.last_frame == 0): self.last_frame = self.buffer[0] * 256 + self.buffer[1] else: frame = self.buffer[0] * 256 + self.buffer[1] if(frame - 1 != self.last_frame): self.frames_lost += 1 self.last_frame = frame self.lost_frames_count.setText(str(round(self.frames_lost / self.frames * 100, 2)) + '%') # Sprawdzanie sumy kontrolnej checksum = self.buffer[-2] * 256 + self.buffer[-1] sum = np.sum(self.buffer[:-2]) #----------------------------------------------------------------------- # Tutaj w warunku ustawić sum == checksum #----------------------------------------------------------------------- if(True): self.buffer = self.buffer[2:-2].reshape((-1, 2)) self.buffer[:, 0] *= 256 self.buffer = np.sum(self.buffer, 1) self.buffer = self.buffer.reshape((-1, 3)).T self.data = np.hstack((self.data, self.buffer)) def plot(self): if(self.data.shape[1] >= self.window): self.data = self.data[:, -self.window:] self.channel1_data.set_ydata(self.data[0]) self.channel2_data.set_ydata(self.data[1]) self.channel3_data.set_ydata(self.data[2]) self.canvas.draw() def timerEvent(self, event): if self._generator is None: return try: next(self._generator) except StopIteration: self.stop() def closeEvent(self, event): self.stop() event.accept() def createButton(self, text, member): button = Button(text) button.clicked.connect(member) return button
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 FilterDesignDialog(QtGui.QDialog): """A dialog to apply Takanami's AR picking method to a selected piece of a seismic signal. Attributes: document: Current opened document containing a seismic record. seismic_event: A seismic event to be refined by using Takanami method. If no event is provided, then a new seismic event will be created by using the estimated arrival time after clicking on 'Accept' """ def __init__(self, stream, trace_list=None, parent=None): super(FilterDesignDialog, self).__init__(parent) # Calc max. frequency traces = stream.traces if not trace_list else trace_list self.max_freq = max([trace.fs for trace in traces]) self._init_ui() self.load_settings() # Initial draw w, h_db, angles = self._retrieve_filter_plot_data() self._module_data = self.module_axes.plot(w, h_db, 'b')[0] self._phase_data = self.phase_axes.plot(w, angles, 'g')[0] self.module_axes.set_ylim([-60,10]) self.phase_axes.set_ylim([min(angles), max(angles)]) self.canvas.draw_idle() self.start_point_spinbox.valueChanged.connect(self.on_freq_min_changed) self.end_point_spinbox.valueChanged.connect(self.on_freq_max_changed) self.start_point_spinbox.valueChanged.connect(self._draw_filter_response) self.end_point_spinbox.valueChanged.connect(self._draw_filter_response) self.number_coefficient_spinbox.valueChanged.connect(self._draw_filter_response) self.zeroPhaseCheckBox.toggled.connect(self._draw_filter_response) self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) self.button_box.clicked.connect(self.on_click) def _init_ui(self): self.setWindowTitle("Filter Design (Butterworth-Bandpass Filter)") self.fig, _ = plt.subplots(1, 1, sharex=True) # Set up filter axes self.module_axes = self.fig.axes[0] self.phase_axes = self.module_axes.twinx() self.module_axes.set_title('Digital filter frequency response (Butterworth-Bandpass filter)') self.module_axes.set_xlabel('Frequency [Hz]') self.module_axes.set_ylabel('Amplitude [dB]', color='b') self.module_axes.axis('tight') self.module_axes.grid(which='both', axis='both') self.phase_axes.set_ylabel('Angle (radians)', color='g') self.canvas = FigureCanvas(self.fig) self.canvas.setMinimumSize(self.canvas.size()) self.canvas.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)) self.toolBarNavigation = navigationtoolbar.NavigationToolBar(self.canvas, self) self.group_box = QtGui.QGroupBox(self) self.group_box2 = QtGui.QGroupBox(self) self.group_box3 = QtGui.QGroupBox(self) self.group_box4 = QtGui.QGroupBox(self) self.group_box.setTitle("") self.group_box2.setTitle("") self.group_box3.setTitle("Parameters") self.start_point_label = QtGui.QLabel("Lower cutoff frequency (Hz): ") self.start_point_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.start_point_spinbox = QtGui.QDoubleSpinBox(self.group_box) self.start_point_spinbox.setMinimum(1.0) self.start_point_spinbox.setSingleStep(1.00) self.start_point_spinbox.setAccelerated(True) self.start_point_spinbox.setMaximum(self.max_freq * 0.5) self.end_point_label = QtGui.QLabel("Higher cutoff frequency (Hz):") self.end_point_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.end_point_spinbox = QtGui.QDoubleSpinBox(self.group_box4) self.end_point_spinbox.setMinimum(1.0) self.end_point_spinbox.setSingleStep(1.00) self.end_point_spinbox.setAccelerated(True) self.end_point_spinbox.setMaximum(self.max_freq * 0.5) self.end_point_spinbox.setValue(5.0) ####################################################################### self.number_coefficient_label = QtGui.QLabel("Order: ") self.number_coefficient_label2 = QtGui.QLabel("") self.number_coefficient_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.number_coefficient_label2.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.number_coefficient_spinbox = QtGui.QSpinBox(self.group_box3) self.number_coefficient_spinbox.adjustSize() self.number_coefficient_spinbox.setMinimum(1) self.number_coefficient_spinbox.setSingleStep(1) self.number_coefficient_spinbox.setAccelerated(True) self.zeroPhaseCheckBox = QtGui.QCheckBox("Zero phase filtering", self.group_box2) self.zeroPhaseCheckBox.setChecked(True) ####################################################################### self.group_box_layout = QtGui.QHBoxLayout(self.group_box) self.group_box_layout.setContentsMargins(9, 9, 9, 9) self.group_box_layout.setSpacing(12) self.group_box_layout.addWidget(self.start_point_label) self.group_box_layout.addWidget(self.start_point_spinbox) self.group_box4_layout = QtGui.QHBoxLayout(self.group_box4) self.group_box4_layout.setContentsMargins(9, 9, 9, 9) self.group_box4_layout.setSpacing(12) self.group_box4_layout.addWidget(self.end_point_label) self.group_box4_layout.addWidget(self.end_point_spinbox) ##################################################################### self.group_box2_layout = QtGui.QHBoxLayout(self.group_box2) self.group_box2_layout.setContentsMargins(9, 9, 9, 9) self.group_box2_layout.setSpacing(12) self.group_box2_layout.addWidget(self.zeroPhaseCheckBox) ################################################################### self.group_box3_layout = QtGui.QHBoxLayout(self.group_box3) self.group_box3_layout.setContentsMargins(9, 9, 9, 9) self.group_box3_layout.setSpacing(12) self.group_box3_layout.addWidget(self.number_coefficient_label) self.group_box3_layout.addWidget(self.number_coefficient_spinbox) self.group_box3_layout.addWidget(self.number_coefficient_label2) ##################################################################### self.button_box = QtGui.QDialogButtonBox(self) self.button_box.setOrientation(QtCore.Qt.Horizontal) self.button_box.setStandardButtons(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) self.layout = QtGui.QVBoxLayout(self) self.layout.setContentsMargins(9, 9, 9, 9) self.layout.setSpacing(6) self.layout.addWidget(self.toolBarNavigation) self.layout.addWidget(self.canvas) self.layout.addWidget(self.group_box3) self.layout.addWidget(self.group_box) self.layout.addWidget(self.group_box4) #self.layout.addWidget(self.group_box2) self.layout.addWidget(self.zeroPhaseCheckBox) self.layout.addWidget(self.button_box) def on_freq_min_changed(self, value): self.end_point_spinbox.setMinimum(value + 1.0) def on_freq_max_changed(self, value): self.start_point_spinbox.setMaximum(value - 1.0) def on_click(self, button): if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Ok: self.save_settings() if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Apply: self._draw_filter_response() def save_settings(self): """Save settings to persistent storage.""" settings = QtCore.QSettings(_organization, _application_name) settings.beginGroup("filterdesign_settings") #self.default_margin = int(float(settings.value('filterdesign_margin', 5.0)) * #self.record.fs) settings.setValue('freq_min', self.start_point_spinbox.value()) settings.setValue('freq_max', self.end_point_spinbox.value()) settings.setValue('coef_number', self.number_coefficient_spinbox.value()) settings.setValue('zero_phase', self.zeroPhaseCheckBox.isChecked()) settings.endGroup() def load_settings(self): """Loads settings from persistent storage.""" settings = QtCore.QSettings(_organization, _application_name) settings.beginGroup("filterdesign_settings") self.start_point_spinbox.setValue(float(settings.value('freq_min', 0.0))) self.end_point_spinbox.setValue(float(settings.value('freq_max', self.max_freq * 0.5))) self.number_coefficient_spinbox.setValue(int(settings.value('coef_number', 1))) self.zeroPhaseCheckBox.setChecked(bool(settings.value('zero_phase', True))) settings.endGroup() def _butter_bandpass(self, lowcut, highcut, fs, order=5): nyq = 0.5 * fs low = lowcut / nyq high = highcut / nyq b, a = butter(order, [low, high], btype='band') return b, a def _retrieve_filter_plot_data(self): b, a = self._butter_bandpass(self.start_point_spinbox.value(), self.end_point_spinbox.value(), self.max_freq, order=self.number_coefficient_spinbox.value()) #w, h = freqz(b, a) w, h = freqz(b, a,1024) angles = np.unwrap(np.angle(h)) #return (self.max_freq * 0.5 / np.pi) * w, 20 * np.log10(abs(h)), angles f= (self.max_freq/2)*(w/np.pi) return f, 20 * np.log10(abs(h)), angles def _draw_filter_response(self, *args, **kwargs): w, h_db, angles = self._retrieve_filter_plot_data() self._module_data.set_xdata(w) self._module_data.set_ydata(h_db) self._phase_data.set_xdata(w) self._phase_data.set_ydata(angles) self.phase_axes.set_ylim([min(angles), max(angles)]) self.canvas.draw_idle()
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 TakanamiDialog(QtGui.QDialog): """A dialog to apply Takanami's AR picking method to a selected piece of a seismic signal. Attributes: document: Current opened document containing a seismic record. seismic_event: A seismic event to be refined by using Takanami method. If no event is provided, then a new seismic event will be created by using the estimated arrival time after clicking on 'Accept' """ def __init__(self, document, t_start=None, t_end=None, seismic_event=None, parent=None): super(TakanamiDialog, self).__init__(parent) self.document = document self.record = self.document.record self.load_settings() self.seismic_event = seismic_event self._start = t_start self._end = t_end if self.seismic_event is not None: self.event_time = self.seismic_event.time if self._start is None: self._start = max(0, self.event_time - self.default_margin) if self._end is None: self._end = min( len(self.record.signal) - 1, self.event_time + self.default_margin) else: if self._start is None or self._end is None: raise ValueError("t_start and t_end values not specified") else: self._start = max(0, int(t_start * self.record.fs)) self._end = min( len(self.record.signal) - 1, int(t_end * self.record.fs)) self.event_time = self._start + int( (self._end - self._start) / 2) if not 0 <= self._start < self._end: raise ValueError("Invalid t_start value") if not self._start < self._end < len(self.record.signal): raise ValueError("Invalid t_end value") if (self._end - self._start) < (MINIMUM_MARGIN_IN_SECS * self.record.fs): raise ValueError("Distance between t_start and t_end must be" " at least of %g seconds" % MINIMUM_MARGIN_IN_SECS) if not self._start < self.event_time < self._end: raise ValueError( "Event time must be a value between t-start and t_end") self._init_ui() self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) self.button_box.clicked.connect(self.on_click) self.start_point_spinbox.timeChanged.connect( self.on_start_point_changed) self.end_point_spinbox.timeChanged.connect(self.on_end_point_changed) def _init_ui(self): self.setWindowTitle("Takanami's Autoregressive Method") self.fig, _ = plt.subplots(2, 1, sharex=True) self.canvas = FigureCanvas(self.fig) self.canvas.setMinimumSize(self.canvas.size()) self.canvas.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)) self.toolBarNavigation = navigationtoolbar.NavigationToolBar( self.canvas, self) self.position_label = QtGui.QLabel( "Estimated Arrival Time: 00 h 00 m 00.000 s") self.group_box = QtGui.QGroupBox(self) self.group_box.setTitle("Limits") self.start_point_label = QtGui.QLabel("Start point:") self.start_point_label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.start_point_spinbox = QtGui.QTimeEdit(self.group_box) self.start_point_spinbox.setDisplayFormat("hh 'h' mm 'm' ss.zzz 's'") self.end_point_label = QtGui.QLabel("End point:") self.end_point_label.setSizePolicy( QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.end_point_spinbox = QtGui.QTimeEdit(self.group_box) self.end_point_spinbox.setDisplayFormat("hh 'h' mm 'm' ss.zzz 's'") self.group_box_layout = QtGui.QHBoxLayout(self.group_box) self.group_box_layout.setContentsMargins(9, 9, 9, 9) self.group_box_layout.setSpacing(12) self.group_box_layout.addWidget(self.start_point_label) self.group_box_layout.addWidget(self.start_point_spinbox) self.group_box_layout.addWidget(self.end_point_label) self.group_box_layout.addWidget(self.end_point_spinbox) self.button_box = QtGui.QDialogButtonBox(self) self.button_box.setOrientation(QtCore.Qt.Horizontal) self.button_box.setStandardButtons(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) self.layout = QtGui.QVBoxLayout(self) self.layout.setContentsMargins(9, 9, 9, 9) self.layout.setSpacing(6) self.layout.addWidget(self.toolBarNavigation) self.layout.addWidget(self.canvas) self.layout.addWidget(self.position_label) self.layout.addWidget(self.group_box) self.layout.addWidget(self.button_box) # set spinboxes's initial values and limits max_time_in_msecs = int( ((len(self.record.signal) - 1) * 1000) / self.record.fs) start_time_in_msecs = int((self._start * 1000.0) / self.record.fs) end_time_in_msecs = int((self._end * 1000.0) / self.record.fs) self.start_point_spinbox.setTime( QtCore.QTime().addMSecs(start_time_in_msecs)) self.end_point_spinbox.setTime( QtCore.QTime().addMSecs(end_time_in_msecs)) self.start_point_spinbox.setMinimumTime(QtCore.QTime().addMSecs(0)) self.end_point_spinbox.setMinimumTime( QtCore.QTime().addMSecs(start_time_in_msecs + MINIMUM_MARGIN_IN_SECS * 1000)) self.start_point_spinbox.setMaximumTime( QtCore.QTime().addMSecs(end_time_in_msecs - MINIMUM_MARGIN_IN_SECS * 1000)) self.end_point_spinbox.setMaximumTime( QtCore.QTime().addMSecs(max_time_in_msecs)) def on_click(self, button): if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Ok: self.save_event() if self.button_box.standardButton( button) == QtGui.QDialogButtonBox.Apply: self.do_takanami() def on_start_point_changed(self, value): time_in_msecs = QtCore.QTime().msecsTo(value) t_start = int(max(0, (time_in_msecs / 1000.0) * self.record.fs)) if self._start != t_start: self._start = t_start self.end_point_spinbox.setMinimumTime( QtCore.QTime().addMSecs(time_in_msecs + MINIMUM_MARGIN_IN_SECS * 1000)) def on_end_point_changed(self, value): time_in_msecs = QtCore.QTime().msecsTo(value) t_end = int( min(len(self.record.signal), ((time_in_msecs / 1000.0) * self.record.fs))) if self._end != t_end: self._end = t_end self.start_point_spinbox.setMaximumTime( QtCore.QTime().addMSecs(time_in_msecs - MINIMUM_MARGIN_IN_SECS * 1000)) def on_position_estimated(self, time, aic, n0_aic): self.event_time = time time_in_msecs = QtCore.QTime().addMSecs( (self.event_time * 1000.0) / self.record.fs) self.position_label.setText( "Estimated Arrival Time: %s" % time_in_msecs.toString("hh 'h' mm 'm' ss.zzz 's'")) # Plot estimated arrival time m_event = rc.Event(self.record, time, aic=aic, n0_aic=n0_aic) m_event.plot_aic(show_envelope=True, num=self.fig.number) self.fig.canvas.draw_idle() def load_settings(self): """Loads settings from persistent storage.""" settings = QtCore.QSettings(_organization, _application_name) settings.beginGroup("takanami_settings") self.default_margin = int( float(settings.value('takanami_margin', 5.0)) * self.record.fs) settings.endGroup() def save_event(self): """""" if self.seismic_event is not None: if self.seismic_event.time != self.event_time: self.document.editEvent(self.seismic_event, time=self.event_time, method=rc.method_takanami, mode=rc.mode_automatic, status=rc.status_reported) else: self.document.createEvent(self.event_time, method=rc.method_takanami, mode=rc.mode_automatic, status=rc.status_reported) def do_takanami(self): self._task = TakanamiTask(self.record, self._start, self._end) self._task.position_estimated.connect(self.on_position_estimated) self.wait_dialog = processingdialog.ProcessingDialog( label_text="Applying Takanami's AR method...") self.wait_dialog.setWindowTitle("Event detection") return self.wait_dialog.run(self._task) def exec_(self, *args, **kwargs): return_code = self.do_takanami() if return_code == QtGui.QDialog.Accepted: return QtGui.QDialog.exec_(self, *args, **kwargs)
class MatplotWidget(QWidget): """ Class to plot data inside a QWidget """ def __init__(self, parent=None, toolbar=False): """ """ super(MatplotWidget, self).__init__(parent) self.figure, self.axes = plt.subplots(nrows=1, ncols=1) self.canvas = FigureCanvasQTAgg(self.figure) self.figure.subplots_adjust(right=0.85) self.figure.subplots_adjust(left=0.1) self.figure.subplots_adjust(bottom=0.3) self.axes1 = self.axes.twinx() self.axes1.set_ylabel('quality') self.axes.locator_params(nbins=5) self.axes1.locator_params(nbins=5) self.vbox = QVBoxLayout(self) if toolbar: self.toolbar = NavigationToolbar(self.canvas, self) self.vbox.addWidget(self.toolbar) self.vbox.addWidget(self.canvas) def set_data(self, data, qi=False, min_size=False): """ draw data to canvas Args: data (sensor) : sensor containing data qi (bool): if true plot quality min_size (bool): force to set min size to chart """ self.figure.suptitle(data.name, fontsize=12) self.axes.set_ylabel(data.unit, fontsize=12) self.axes.set_xlabel('') ax = data.plot(quality=qi, axis=self.axes, qaxis=self.axes1) n = 5 ticks = ax.xaxis.get_ticklocs() ticklabels = [l.get_text() for l in ax.xaxis.get_ticklabels()] ax.xaxis.set_ticks(ticks[::n]) ax.xaxis.set_ticklabels(ticklabels[::n]) if min_size: size = self.canvas.size() size.setHeight(size.height() / 2) self.canvas.setMinimumSize(size) def set_multiple_data(self, data, qi=False): """ Plot multiple data source to chart Args: data (list): list of sensor to plot qi (bool): if true plot quality """ colors = ['b', 'g', 'm', 'lime', 'orange', 'gray', 'salmon', 'tomato'] ax = None labels = [] for idx, evt in enumerate(data): if len(evt.ts) == 0: continue color = colors[idx % len(colors)] ax = evt.plot(quality=qi, data_color=color, axis=self.axes, qaxis=self.axes1) labels.append(evt.name) lines, _ = ax.get_legend_handles_labels() ax.legend(lines, labels, loc='best') plt.legend(loc="upper left", bbox_to_anchor=[0, 1], ncol=2, shadow=True, title="Legend", fancybox=True) if not ax: n = 5 ticks = ax.xaxis.get_ticklocs() ticklabels = [l.get_text() for l in ax.xaxis.get_ticklabels()] ax.xaxis.set_ticks(ticks[::n]) ax.xaxis.set_ticklabels(ticklabels[::n])
def plot_file(fps, base_dir, string_graph_map): app = QtGui.QApplication('Bodysim') graph_map = ast.literal_eval(string_graph_map) # Find the length of the simulation by looking at trajectory results. start_frame = 1 count = 0 with open(base_dir + os.sep + 'Trajectory' + os.sep + graph_map.keys()[0] + '.csv') as f: iterF = iter(f) # Skip header next(iterF) line = next(iterF) start_frame = float(line.split(',')[0]) count = sum(1 for line in iterF) frame = MainWindow(start_frame, count) for sensor in graph_map: layout_contents = frame.add_tab(sensor) for plugin in graph_map[sensor]: data = get_data(base_dir + os.sep + plugin + os.sep + sensor + '.csv') for variable_group in graph_map[sensor][plugin]: qfigWidget = QtGui.QWidget(layout_contents[1]) fig = Figure((5.0, 4.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(qfigWidget) toolbar = NavigationToolbar(canvas, qfigWidget) axes = fig.add_subplot(111) axes.set_title(plugin + ' ' + variable_group[2]) yDatum = [ data[variable[1]] for variable in graph_map[sensor][plugin][variable_group] ] yLabels = [ variable[0] for variable in graph_map[sensor][plugin][variable_group] ] for i in range(len(yDatum)): axes.plot(data[0], yDatum[i], label=yLabels[i]) axes.grid(True) axes.legend() axes.autoscale(enable=False, axis='both') axes.set_xlabel(variable_group[0]) axes.set_ylabel(variable_group[1]) # Place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) qfigWidget.setLayout(plotLayout) frame.toolbars[fig] = toolbar frame.plots.append(axes) canvas.setMinimumSize(canvas.size()) frame.bind_to_onclick_event(fig) layout_contents[0].addWidget(qfigWidget) frame.show() sys.exit(app.exec_())
class TakanamiDialog(QtGui.QDialog): """A dialog to apply Takanami's AR picking method to a selected piece of a seismic signal. Attributes: document: Current opened document containing a seismic record. seismic_event: A seismic event to be refined by using Takanami method. If no event is provided, then a new seismic event will be created by using the estimated arrival time after clicking on 'Accept' """ def __init__(self, document, t_start=None, t_end=None, seismic_event=None, parent=None): super(TakanamiDialog, self).__init__(parent) self.document = document self.record = self.document.record self.load_settings() self.seismic_event = seismic_event self._start = t_start self._end = t_end if self.seismic_event is not None: self.event_time = self.seismic_event.stime if self._start is None: self._start = max(0, self.event_time - self.default_margin) if self._end is None: self._end = min(len(self.record.signal) - 1, self.event_time + self.default_margin) else: if self._start is None or self._end is None: raise ValueError("t_start and t_end values not specified") else: self._start = max(0, int(t_start * self.record.fs)) self._end = min(len(self.record.signal) - 1, int(t_end * self.record.fs)) self.event_time = self._start + int((self._end - self._start) / 2) if not 0 <= self._start < self._end: raise ValueError("Invalid t_start value") if not self._start < self._end < len(self.record.signal): raise ValueError("Invalid t_end value") if (self._end - self._start) < (MINIMUM_MARGIN_IN_SECS * self.record.fs): raise ValueError("Distance between t_start and t_end must be" " at least of %g seconds" % MINIMUM_MARGIN_IN_SECS) if not self._start < self.event_time < self._end: raise ValueError("Event time must be a value between t-start and t_end") self._init_ui() self.button_box.accepted.connect(self.accept) self.button_box.rejected.connect(self.reject) self.button_box.clicked.connect(self.on_click) self.start_point_spinbox.timeChanged.connect(self.on_start_point_changed) self.end_point_spinbox.timeChanged.connect(self.on_end_point_changed) def _init_ui(self): self.setWindowTitle("Takanami's Autoregressive Method") self.fig, _ = plt.subplots(2, 1, sharex=True) self.canvas = FigureCanvas(self.fig) self.canvas.setMinimumSize(self.canvas.size()) self.canvas.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding, QtGui.QSizePolicy.Policy.Expanding)) self.toolBarNavigation = navigationtoolbar.NavigationToolBar(self.canvas, self) self.position_label = QtGui.QLabel("Estimated Arrival Time: 00 h 00 m 00.000 s") self.group_box = QtGui.QGroupBox(self) self.group_box.setTitle("Limits") self.start_point_label = QtGui.QLabel("Start point:") self.start_point_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.start_point_spinbox = QtGui.QTimeEdit(self.group_box) self.start_point_spinbox.setDisplayFormat("hh 'h' mm 'm' ss.zzz 's'") self.end_point_label = QtGui.QLabel("End point:") self.end_point_label.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Maximum, QtGui.QSizePolicy.Policy.Preferred)) self.end_point_spinbox = QtGui.QTimeEdit(self.group_box) self.end_point_spinbox.setDisplayFormat("hh 'h' mm 'm' ss.zzz 's'") self.group_box_layout = QtGui.QHBoxLayout(self.group_box) self.group_box_layout.setContentsMargins(9, 9, 9, 9) self.group_box_layout.setSpacing(12) self.group_box_layout.addWidget(self.start_point_label) self.group_box_layout.addWidget(self.start_point_spinbox) self.group_box_layout.addWidget(self.end_point_label) self.group_box_layout.addWidget(self.end_point_spinbox) self.button_box = QtGui.QDialogButtonBox(self) self.button_box.setOrientation(QtCore.Qt.Horizontal) self.button_box.setStandardButtons(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok) self.layout = QtGui.QVBoxLayout(self) self.layout.setContentsMargins(9, 9, 9, 9) self.layout.setSpacing(6) self.layout.addWidget(self.toolBarNavigation) self.layout.addWidget(self.canvas) self.layout.addWidget(self.position_label) self.layout.addWidget(self.group_box) self.layout.addWidget(self.button_box) # set spinboxes's initial values and limits max_time_in_msecs = int(((len(self.record.signal) - 1) * 1000) / self.record.fs) start_time_in_msecs = int((self._start * 1000.0) / self.record.fs) end_time_in_msecs = int((self._end * 1000.0) / self.record.fs) self.start_point_spinbox.setTime(QtCore.QTime().addMSecs(start_time_in_msecs)) self.end_point_spinbox.setTime(QtCore.QTime().addMSecs(end_time_in_msecs)) self.start_point_spinbox.setMinimumTime(QtCore.QTime().addMSecs(0)) self.end_point_spinbox.setMinimumTime(QtCore.QTime().addMSecs(start_time_in_msecs + MINIMUM_MARGIN_IN_SECS * 1000)) self.start_point_spinbox.setMaximumTime(QtCore.QTime().addMSecs(end_time_in_msecs - MINIMUM_MARGIN_IN_SECS * 1000)) self.end_point_spinbox.setMaximumTime(QtCore.QTime().addMSecs(max_time_in_msecs)) def on_click(self, button): if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Ok: self.save_event() if self.button_box.standardButton(button) == QtGui.QDialogButtonBox.Apply: self.do_takanami() def on_start_point_changed(self, value): time_in_msecs = QtCore.QTime().msecsTo(value) t_start = int(max(0, (time_in_msecs / 1000.0) * self.record.fs)) if self._start != t_start: self._start = t_start self.end_point_spinbox.setMinimumTime(QtCore.QTime(). addMSecs(time_in_msecs + MINIMUM_MARGIN_IN_SECS * 1000)) def on_end_point_changed(self, value): time_in_msecs = QtCore.QTime().msecsTo(value) t_end = int(min(len(self.record.signal), ((time_in_msecs / 1000.0) * self.record.fs))) if self._end != t_end: self._end = t_end self.start_point_spinbox.setMaximumTime(QtCore.QTime(). addMSecs(time_in_msecs - MINIMUM_MARGIN_IN_SECS * 1000)) def on_position_estimated(self, time, aic, n0_aic): self.event_time = time time_in_secs = self.event_time / self.record.fs self.position_label.setText("Estimated Arrival Time: {}".format( clt.float_secs_2_string_date(time_in_secs, starttime=self.record.starttime))) # Plot estimated arrival time m_event = rc.ApasvoEvent(self.record, time, aic=aic, n0_aic=n0_aic) m_event.plot_aic(show_envelope=True, num=self.fig.number) self.fig.canvas.draw_idle() def load_settings(self): """Loads settings from persistent storage.""" settings = QtCore.QSettings(_organization, _application_name) settings.beginGroup("takanami_settings") self.default_margin = int(float(settings.value('takanami_margin', 5.0)) * self.record.fs) settings.endGroup() def save_event(self): """""" if self.seismic_event is not None: if self.seismic_event.stime != self.event_time: self.document.editEvent(self.seismic_event, stime=self.event_time, method=rc.method_takanami, evaluation_mode=rc.mode_automatic, evaluation_status=rc.status_preliminary) else: self.document.createEvent(self.event_time, method=rc.method_takanami, evaluation_mode=rc.mode_automatic, evaluation_status=rc.status_preliminary) def do_takanami(self): self._task = TakanamiTask(self.record, self._start, self._end) self._task.position_estimated.connect(self.on_position_estimated) self.wait_dialog = processingdialog.ProcessingDialog(label_text="Applying Takanami's AR method...") self.wait_dialog.setWindowTitle("Event detection") return self.wait_dialog.run(self._task) def exec_(self, *args, **kwargs): return_code = self.do_takanami() if return_code == QtGui.QDialog.Accepted: return QtGui.QDialog.exec_(self, *args, **kwargs)
qscrollLayout.setGeometry(QtCore.QRect(0, 0, 1000, 1000)) qscroll.setWidget(qscrollContents) qscroll.setWidgetResizable(True) for i in xrange(5): qfigWidget = QtGui.QWidget(qscrollContents) fig = Figure((5.0, 4.0), dpi=100) canvas = FigureCanvas(fig) canvas.setParent(qfigWidget) toolbar = NavigationToolbar(canvas, qfigWidget) axes = fig.add_subplot(111) axes.plot([1,2,3,4]) # place plot components in a layout plotLayout = QtGui.QVBoxLayout() plotLayout.addWidget(canvas) plotLayout.addWidget(toolbar) qfigWidget.setLayout(plotLayout) # prevent the canvas to shrink beyond a point # original size looks like a good minimum size canvas.setMinimumSize(canvas.size()) qscrollLayout.addWidget(qfigWidget) qscrollContents.setLayout(qscrollLayout) qwidget.show() exit(qapp.exec_())