def __init__(self, parent, size=(800,-1), **kwargs): wx.Frame.__init__(self, parent, -1, size=size, title='Plate Viewer', **kwargs) CPATool.__init__(self) self.SetName(self.tool_name) self.SetBackgroundColour("white") # Fixing the color # Check for required properties fields. fail = False for field in required_fields: if not p.field_defined(field): fail = True raise Exception('Properties field "%s" is required for PlateViewer.'%(field)) if fail: self.Destroy() return self.chMap = p.image_channel_colors[:] self.menuBar = wx.MenuBar() self.SetMenuBar(self.menuBar) self.fileMenu = wx.Menu() self.exitMenuItem = self.fileMenu.Append(id=wx.ID_EXIT, text='Exit\tCtrl+Q', help='Close Plate Viewer') self.GetMenuBar().Append(self.fileMenu, 'File') self.menuBar.Append(cpa.helpmenu.make_help_menu(self), 'Help') save_csv_menu_item = self.fileMenu.Append(-1, 'Save table to CSV\tCtrl+S') self.Bind(wx.EVT_MENU, self.on_save_csv, save_csv_menu_item) wx.EVT_MENU(self, wx.ID_EXIT, lambda _:self.Close()) dataSourceSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Source:'), wx.VERTICAL) dataSourceSizer.Add(wx.StaticText(self, label='Data source:')) self.sourceChoice = TableComboBox(self, -1, size=fixed_width) dataSourceSizer.Add(self.sourceChoice) dataSourceSizer.AddSpacer((-1,3)) dataSourceSizer.Add(wx.StaticText(self, label='Measurement:')) measurements = get_non_blob_types_from_table(p.image_table) self.measurementsChoice = ComboBox(self, choices=measurements, size=fixed_width) self.measurementsChoice.Select(0) dataSourceSizer.Add(self.measurementsChoice) dataSourceSizer.Add(wx.StaticText(self, label='Filter:')) self.filterChoice = FilterComboBox(self, size=fixed_width) dataSourceSizer.Add(self.filterChoice) groupingSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Data aggregation:'), wx.VERTICAL) groupingSizer.Add(wx.StaticText(self, label='Aggregation method:')) aggregation = ['mean', 'sum', 'median', 'stdev', 'cv%', 'min', 'max'] self.aggregationMethodsChoice = ComboBox(self, choices=aggregation, size=fixed_width) self.aggregationMethodsChoice.Select(0) groupingSizer.Add(self.aggregationMethodsChoice) viewSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='View options:'), wx.VERTICAL) viewSizer.Add(wx.StaticText(self, label='Color map:')) maps = [m for m in matplotlib.cm.datad.keys() if not m.endswith("_r")] maps.sort() self.colorMapsChoice = ComboBox(self, choices=maps, size=fixed_width) self.colorMapsChoice.SetSelection(maps.index('jet')) viewSizer.Add(self.colorMapsChoice) viewSizer.AddSpacer((-1,3)) viewSizer.Add(wx.StaticText(self, label='Well display:')) if p.image_thumbnail_cols: choices = pmp.all_well_shapes else: choices = list(pmp.all_well_shapes) choices.remove(pmp.THUMBNAIL) self.wellDisplayChoice = ComboBox(self, choices=choices, size=fixed_width) self.wellDisplayChoice.Select(0) viewSizer.Add(self.wellDisplayChoice) viewSizer.AddSpacer((-1,3)) viewSizer.Add(wx.StaticText(self, label='Number of plates:')) self.numberOfPlatesTE = wx.TextCtrl(self, -1, '1', style=wx.TE_PROCESS_ENTER) viewSizer.Add(self.numberOfPlatesTE) if not p.plate_id: self.numberOfPlatesTE.Disable() annotationSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Annotation:'), wx.VERTICAL) annotationSizer.Add(wx.StaticText(self, label='Annotation column:')) annotationColSizer = wx.BoxSizer(wx.HORIZONTAL) self.annotation_cols = dict([(col, db.GetColumnType(p.image_table, col)) for col in db.GetUserColumnNames(p.image_table)]) self.annotationCol = ComboBox(self, choices=self.annotation_cols.keys(), size=(120,-1)) if len(self.annotation_cols) > 0: self.annotationCol.SetSelection(0) annotationColSizer.Add(self.annotationCol, flag=wx.ALIGN_CENTER_VERTICAL) annotationColSizer.AddSpacer((3,-1)) self.addAnnotationColBtn = wx.Button(self, -1, 'Add', size=(44,-1)) annotationColSizer.Add(self.addAnnotationColBtn, flag=wx.ALIGN_CENTER_VERTICAL) annotationSizer.Add(annotationColSizer) annotationSizer.AddSpacer((-1,3)) annotationSizer.Add(wx.StaticText(self, label='Label:')) self.annotationLabel = wx.TextCtrl(self, -1, 'Select wells')#, style=wx.TE_PROCESS_ENTER) self.annotationLabel.Disable() self.annotationLabel.SetForegroundColour(wx.Colour(80,80,80)) self.annotationLabel.SetBackgroundColour(wx.LIGHT_GREY) annotationSizer.Add(self.annotationLabel) annotationSizer.AddSpacer((-1,3)) self.outlineMarked = wx.CheckBox(self, -1, label='Outline annotated wells') annotationSizer.Add(self.outlineMarked) annotationSizer.AddSpacer((-1,3)) self.annotationShowVals = wx.CheckBox(self, -1, label='Show values on plate') annotationSizer.Add(self.annotationShowVals) if len(db.GetUserColumnNames(p.image_table)) == 0: self.outlineMarked.Disable() self.annotationShowVals.Disable() controlSizer = wx.BoxSizer(wx.VERTICAL) controlSizer.Add(dataSourceSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(groupingSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(viewSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(annotationSizer, 0 , wx.EXPAND) self.plateMapSizer = wx.GridSizer(1,1,5,5) self.plateMaps = [] self.plateMapChoices = [] self.rightSizer = wx.BoxSizer(wx.VERTICAL) self.rightSizer.Add(self.plateMapSizer, 1, wx.EXPAND|wx.BOTTOM, 10) self.colorBar = ColorBarPanel(self, 'jet', size=(-1,25)) self.rightSizer.Add(self.colorBar, 0, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL) mainSizer = wx.BoxSizer(wx.HORIZONTAL) mainSizer.Add(controlSizer, 0, wx.LEFT|wx.TOP|wx.BOTTOM, 10) mainSizer.Add(self.rightSizer, 1, wx.EXPAND|wx.ALL, 10) self.SetSizer(mainSizer) self.SetClientSize((self.Size[0],self.Sizer.CalcMin()[1])) self.sourceChoice.Bind(wx.EVT_COMBOBOX, self.UpdateMeasurementChoice) self.measurementsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectMeasurement) self.measurementsChoice.Select(0) self.aggregationMethodsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectAggregationMethod) self.colorMapsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectColorMap) self.numberOfPlatesTE.Bind(wx.EVT_TEXT_ENTER, self.OnEnterNumberOfPlates) self.wellDisplayChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectWellDisplay) self.annotationCol.Bind(wx.EVT_COMBOBOX, self.OnSelectAnnotationCol) self.addAnnotationColBtn.Bind(wx.EVT_BUTTON, self.OnAddAnnotationCol) self.annotationLabel.Bind(wx.EVT_KEY_UP, self.OnEnterAnnotation) self.outlineMarked.Bind(wx.EVT_CHECKBOX, self.OnOutlineMarked) self.annotationShowVals.Bind(wx.EVT_CHECKBOX, self.OnShowAnnotationValues) self.filterChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectFilter) self.AddPlateMap() self.OnSelectMeasurement()
def __init__(self,Yield): """Create a PELvis frame Keyword arguments: Yield -- A function to give control back to the main event loop """ wx.Frame.__init__(self,None,wx.ID_ANY,"PEL Visualizer") self.data = PelFile() self.Yield = Yield self.mask = np.ones((128,16),dtype=np.bool) #Create items in the frame self.yPanel = GraphPanel(self,(2,8),64,GraphPanel.VERTICAL) self.xPanel = GraphPanel(self,(8,2),64,GraphPanel.INVERTED) self.colorbar = ColorBarPanel(self,cm.jet) self.opPanel = PelvisOptionPanel(self) self.posPanel = PositionPanel(self) self.imPanel = ImagePanel(self,self.posPanel.set, self.opPanel.setPosMin,self.opPanel.setPosMax) self.specDlg = SpectrumDialog(self) self.cmp = None #color map self.imageSaveDialog=wx.FileDialog(self,"Choose graphics file",wildcard="Portable Network Graphic (png)|*.PNG|Windows Bitmap (bmp)|*.BMP|Joint Photographic Experts Group (jpg)|*.JPG|Portable Network Monocrome (pnm)|*.PNM|Tagged Image File Format (tif)|*.TIF|Archaic, useless format (pcx)|*.PCX",style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) self.update = self.updateSingle#update the image self.updateData = self.updateSingleData#update the data in the image #Create the menu menubar = wx.MenuBar() filemenu = wx.Menu() editmenu = wx.Menu() scalemenu = wx.Menu() analysismenu = wx.Menu() noisemenu = wx.Menu() #populate the menu filemenu.Append(self.ID_OPEN,"&Open\tCtrl-O"," Open a PEL file") filemenu.Append(self.ID_OPENTWO,"&Polarized Set"," Open two PEL files") filemenu.Append(self.ID_SAVE,"&Save\tCtrl-S"," Save an image file") filemenu.Append(self.ID_SPECTRUM,"Spectrum"," View the TOF spectrum") filemenu.Append(self.ID_IMAGE_ARRAY,"&Export Images..."," Save a series of TOF snapshots") filemenu.Append(self.ID_EXIT,"&Quit\tCtrl-Q"," Quit") editmenu.Append(self.ID_COPY,"&Copy\tCtrl-c","Copy the current image to the clipboard") scalemenu.Append(self.ID_GREY,"Greyscale\tCtrl-G","Monochrome images") scalemenu.Append(self.ID_HUEVAL,"Hue and Value\tCtrl-H","Scaled Rainbow Images") scalemenu.Append(self.ID_SPECTRAL,"spectral","Uses spectrum of light") scalemenu.Append(self.ID_PICKER,"Map Picker..."," Select from the full list of colormaps") analysismenu.Append(self.ID_POLAR,"Check Polarization\tCtrl-P","2d plot of polarization data") analysismenu.Append(self.ID_FLIPPING,"Check Flipping Ratio\tCtrl-F","2d plot of spin up over spin down") analysismenu.Append(self.ID_SPIN_UP,"View Spin Up State\tCtrl-U","2d plot of spin up") analysismenu.Append(self.ID_SPIN_DOWN,"View Spin Down State\tCtrl-D","2d plot of spin down") noisemenu.Append(self.ID_FLAT,"&Load Flat"," Load a blank run for background subtraction") noisemenu.Append(self.ID_FAKEFLAT,"Si&mulate Flat"," Drop out background within the same image") noisemenu.Append(self.ID_ROD,"Region of &Disinterest"," Drop out background within the same image") noisemenu.Append(self.ID_EXPORT_ROI,"Export ROI"," Export a binary file corresponding to where the data is above the minimum intensity.") noisemenu.Append(self.ID_IMPORT_ROI,"Import ROI"," Add another exclusion mask.") #Bind events to the menu self.Connect(self.ID_EXIT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnExit) self.Connect(self.ID_OPEN,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnOpen) self.Connect(self.ID_OPENTWO,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnOpenSet) self.Connect(self.ID_SAVE,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSave) self.Connect(self.ID_SPECTRUM,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSpectrum) self.Connect(self.ID_IMAGE_ARRAY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnImageArray) self.Connect(self.ID_GREY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnGrey) self.Connect(self.ID_HUEVAL,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnHueVal) self.Connect(self.ID_SPECTRAL,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSpectral) self.Connect(self.ID_PICKER,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnPicker) self.Connect(self.ID_POLAR,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnPolar) self.Connect(self.ID_FLIPPING,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFlipping) self.Connect(self.ID_SPIN_UP,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnAnalysisSpinUp) self.Connect(self.ID_SPIN_DOWN,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnAnalysisSpinDown) self.Connect(self.ID_FLAT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFlat) self.Connect(self.ID_FAKEFLAT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFakeFlat) self.Connect(self.ID_ROD,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnROD) self.Connect(self.ID_EXPORT_ROI,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnExportROI) self.Connect(self.ID_IMPORT_ROI,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnImportROI) self.Connect(self.ID_COPY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnCopy) menubar.Append(filemenu,"&File") menubar.Append(editmenu,"&Edit") menubar.Append(scalemenu,"&Color") menubar.Append(analysismenu,"&Analysis") menubar.Append(noisemenu,"&Noise") self.SetMenuBar(menubar) #arrange window sizer = wx.GridBagSizer() sizer.Add(self.colorbar,pos=wx.GBPosition(0,9),span=wx.GBSpan(9,1)) sizer.Add(self.imPanel,pos=wx.GBPosition(0,1),span=wx.GBSpan(8,8)) sizer.Add(self.yPanel,pos=wx.GBPosition(0,0),span=wx.GBSpan(8,1)) sizer.Add(self.xPanel,pos=wx.GBPosition(8,1),span=wx.GBSpan(1,8)) sizer.Add(self.opPanel,pos=wx.GBPosition(0,10),span=wx.GBSpan(8,1),flag=wx.EXPAND) sizer.Add(self.posPanel,pos=wx.GBPosition(8,0),flag=wx.EXPAND) self.progress = wx.Gauge(self,range=1000) sizer.Add(self.progress,pos=wx.GBPosition(9,0),span=wx.GBSpan(1,11),flag=wx.EXPAND) updateButton = wx.Button(self,-1,"Update") updateButton.Bind(wx.EVT_BUTTON,self.OnUpdateButton) sizer.Add(updateButton,flag=wx.EXPAND,pos=wx.GBPosition(8,10)) self.data = self.makePel() self.flatrun = None#background data sizer.SetSizeHints(self) self.SetSizer(sizer) self.Show(True)
class PlateViewer(wx.Frame, CPATool): def __init__(self, parent, size=(800,-1), **kwargs): wx.Frame.__init__(self, parent, -1, size=size, title='Plate Viewer', **kwargs) CPATool.__init__(self) self.SetName(self.tool_name) self.SetBackgroundColour("white") # Fixing the color # Check for required properties fields. fail = False for field in required_fields: if not p.field_defined(field): fail = True raise Exception('Properties field "%s" is required for PlateViewer.'%(field)) if fail: self.Destroy() return self.chMap = p.image_channel_colors[:] self.menuBar = wx.MenuBar() self.SetMenuBar(self.menuBar) self.fileMenu = wx.Menu() self.exitMenuItem = self.fileMenu.Append(id=wx.ID_EXIT, text='Exit\tCtrl+Q', help='Close Plate Viewer') self.GetMenuBar().Append(self.fileMenu, 'File') self.menuBar.Append(cpa.helpmenu.make_help_menu(self), 'Help') save_csv_menu_item = self.fileMenu.Append(-1, 'Save table to CSV\tCtrl+S') self.Bind(wx.EVT_MENU, self.on_save_csv, save_csv_menu_item) wx.EVT_MENU(self, wx.ID_EXIT, lambda _:self.Close()) dataSourceSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Source:'), wx.VERTICAL) dataSourceSizer.Add(wx.StaticText(self, label='Data source:')) self.sourceChoice = TableComboBox(self, -1, size=fixed_width) dataSourceSizer.Add(self.sourceChoice) dataSourceSizer.AddSpacer((-1,3)) dataSourceSizer.Add(wx.StaticText(self, label='Measurement:')) measurements = get_non_blob_types_from_table(p.image_table) self.measurementsChoice = ComboBox(self, choices=measurements, size=fixed_width) self.measurementsChoice.Select(0) dataSourceSizer.Add(self.measurementsChoice) dataSourceSizer.Add(wx.StaticText(self, label='Filter:')) self.filterChoice = FilterComboBox(self, size=fixed_width) dataSourceSizer.Add(self.filterChoice) groupingSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Data aggregation:'), wx.VERTICAL) groupingSizer.Add(wx.StaticText(self, label='Aggregation method:')) aggregation = ['mean', 'sum', 'median', 'stdev', 'cv%', 'min', 'max'] self.aggregationMethodsChoice = ComboBox(self, choices=aggregation, size=fixed_width) self.aggregationMethodsChoice.Select(0) groupingSizer.Add(self.aggregationMethodsChoice) viewSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='View options:'), wx.VERTICAL) viewSizer.Add(wx.StaticText(self, label='Color map:')) maps = [m for m in matplotlib.cm.datad.keys() if not m.endswith("_r")] maps.sort() self.colorMapsChoice = ComboBox(self, choices=maps, size=fixed_width) self.colorMapsChoice.SetSelection(maps.index('jet')) viewSizer.Add(self.colorMapsChoice) viewSizer.AddSpacer((-1,3)) viewSizer.Add(wx.StaticText(self, label='Well display:')) if p.image_thumbnail_cols: choices = pmp.all_well_shapes else: choices = list(pmp.all_well_shapes) choices.remove(pmp.THUMBNAIL) self.wellDisplayChoice = ComboBox(self, choices=choices, size=fixed_width) self.wellDisplayChoice.Select(0) viewSizer.Add(self.wellDisplayChoice) viewSizer.AddSpacer((-1,3)) viewSizer.Add(wx.StaticText(self, label='Number of plates:')) self.numberOfPlatesTE = wx.TextCtrl(self, -1, '1', style=wx.TE_PROCESS_ENTER) viewSizer.Add(self.numberOfPlatesTE) if not p.plate_id: self.numberOfPlatesTE.Disable() annotationSizer = wx.StaticBoxSizer(wx.StaticBox(self, label='Annotation:'), wx.VERTICAL) annotationSizer.Add(wx.StaticText(self, label='Annotation column:')) annotationColSizer = wx.BoxSizer(wx.HORIZONTAL) self.annotation_cols = dict([(col, db.GetColumnType(p.image_table, col)) for col in db.GetUserColumnNames(p.image_table)]) self.annotationCol = ComboBox(self, choices=self.annotation_cols.keys(), size=(120,-1)) if len(self.annotation_cols) > 0: self.annotationCol.SetSelection(0) annotationColSizer.Add(self.annotationCol, flag=wx.ALIGN_CENTER_VERTICAL) annotationColSizer.AddSpacer((3,-1)) self.addAnnotationColBtn = wx.Button(self, -1, 'Add', size=(44,-1)) annotationColSizer.Add(self.addAnnotationColBtn, flag=wx.ALIGN_CENTER_VERTICAL) annotationSizer.Add(annotationColSizer) annotationSizer.AddSpacer((-1,3)) annotationSizer.Add(wx.StaticText(self, label='Label:')) self.annotationLabel = wx.TextCtrl(self, -1, 'Select wells')#, style=wx.TE_PROCESS_ENTER) self.annotationLabel.Disable() self.annotationLabel.SetForegroundColour(wx.Colour(80,80,80)) self.annotationLabel.SetBackgroundColour(wx.LIGHT_GREY) annotationSizer.Add(self.annotationLabel) annotationSizer.AddSpacer((-1,3)) self.outlineMarked = wx.CheckBox(self, -1, label='Outline annotated wells') annotationSizer.Add(self.outlineMarked) annotationSizer.AddSpacer((-1,3)) self.annotationShowVals = wx.CheckBox(self, -1, label='Show values on plate') annotationSizer.Add(self.annotationShowVals) if len(db.GetUserColumnNames(p.image_table)) == 0: self.outlineMarked.Disable() self.annotationShowVals.Disable() controlSizer = wx.BoxSizer(wx.VERTICAL) controlSizer.Add(dataSourceSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(groupingSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(viewSizer, 0, wx.EXPAND) controlSizer.AddSpacer((-1,3)) controlSizer.Add(annotationSizer, 0 , wx.EXPAND) self.plateMapSizer = wx.GridSizer(1,1,5,5) self.plateMaps = [] self.plateMapChoices = [] self.rightSizer = wx.BoxSizer(wx.VERTICAL) self.rightSizer.Add(self.plateMapSizer, 1, wx.EXPAND|wx.BOTTOM, 10) self.colorBar = ColorBarPanel(self, 'jet', size=(-1,25)) self.rightSizer.Add(self.colorBar, 0, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL) mainSizer = wx.BoxSizer(wx.HORIZONTAL) mainSizer.Add(controlSizer, 0, wx.LEFT|wx.TOP|wx.BOTTOM, 10) mainSizer.Add(self.rightSizer, 1, wx.EXPAND|wx.ALL, 10) self.SetSizer(mainSizer) self.SetClientSize((self.Size[0],self.Sizer.CalcMin()[1])) self.sourceChoice.Bind(wx.EVT_COMBOBOX, self.UpdateMeasurementChoice) self.measurementsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectMeasurement) self.measurementsChoice.Select(0) self.aggregationMethodsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectAggregationMethod) self.colorMapsChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectColorMap) self.numberOfPlatesTE.Bind(wx.EVT_TEXT_ENTER, self.OnEnterNumberOfPlates) self.wellDisplayChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectWellDisplay) self.annotationCol.Bind(wx.EVT_COMBOBOX, self.OnSelectAnnotationCol) self.addAnnotationColBtn.Bind(wx.EVT_BUTTON, self.OnAddAnnotationCol) self.annotationLabel.Bind(wx.EVT_KEY_UP, self.OnEnterAnnotation) self.outlineMarked.Bind(wx.EVT_CHECKBOX, self.OnOutlineMarked) self.annotationShowVals.Bind(wx.EVT_CHECKBOX, self.OnShowAnnotationValues) self.filterChoice.Bind(wx.EVT_COMBOBOX, self.OnSelectFilter) self.AddPlateMap() self.OnSelectMeasurement() def AddPlateMap(self, plateIndex=0): ''' Adds a new blank plateMap to the PlateMapSizer. ''' data = np.ones(p.plate_shape) # Try to get explicit labels for all wells. res = db.execute('SELECT DISTINCT %s FROM %s WHERE %s != "" and %s IS NOT NULL'% (dbconnect.UniqueWellClause(), p.image_table, p.well_id, p.well_id)) if p.plate_id: self.plateMapChoices += [ComboBox(self, choices=db.GetPlateNames(), size=(400,-1))] self.plateMapChoices[-1].Select(plateIndex) self.plateMapChoices[-1].Bind(wx.EVT_COMBOBOX, self.OnSelectPlate) #plate_col_type = db.GetColumnType(p.image_table, p.plate_id) #plate_id = plate_col_type(self.plateMapChoices[-1].GetString(plateIndex)) plateMapChoiceSizer = wx.BoxSizer(wx.HORIZONTAL) plateMapChoiceSizer.Add(wx.StaticText(self, label='Plate:'), flag=wx.ALIGN_CENTER_VERTICAL) plateMapChoiceSizer.Add(self.plateMapChoices[-1], flag=wx.ALIGN_CENTER_VERTICAL) well_keys = res platemap = pmp.PlateMapPanel(self, data, well_keys, p.plate_shape, colormap = self.colorMapsChoice.Value, well_disp = self.wellDisplayChoice.Value) platemap.add_well_selection_handler(self.OnSelectWell) self.plateMaps += [platemap] singlePlateMapSizer = wx.BoxSizer(wx.VERTICAL) if p.plate_id: singlePlateMapSizer.Add(plateMapChoiceSizer, 0, wx.ALIGN_CENTER) singlePlateMapSizer.Add(platemap, 1, wx.EXPAND|wx.ALIGN_CENTER) self.plateMapSizer.Add(singlePlateMapSizer, 1, wx.EXPAND|wx.ALIGN_CENTER) def UpdatePlateMaps(self): self.measurement = self.measurementsChoice.Value measurement = self.measurement table = self.sourceChoice.Value self.aggMethod = self.aggregationMethodsChoice.Value categorical = measurement not in get_numeric_columns_from_table(table) fltr = self.filterChoice.Value self.colorBar.ClearNotifyWindows() q = sql.QueryBuilder() well_key_cols = [sql.Column(p.image_table, col) for col in well_key_columns()] select = list(well_key_cols) if not categorical: if self.aggMethod=='mean': select += [sql.Column(table, measurement, 'AVG')] elif self.aggMethod=='stdev': select += [sql.Column(table, measurement, 'STDDEV')] elif self.aggMethod=='cv%': # stddev(col) / avg(col) * 100 select += [sql.Expression( sql.Column(table, measurement, 'STDDEV'), ' / ', sql.Column(table, measurement, 'AVG'), ' * 100')] elif self.aggMethod=='sum': select += [sql.Column(table, measurement, 'SUM')] elif self.aggMethod=='min': select += [sql.Column(table, measurement, 'MIN')] elif self.aggMethod=='max': select += [sql.Column(table, measurement, 'MAX')] elif self.aggMethod=='median': select += [sql.Column(table, measurement, 'MEDIAN')] elif self.aggMethod=='none': select += [sql.Column(table, measurement)] else: select += [sql.Column(table, measurement)] q.set_select_clause(select) q.set_group_columns(well_key_cols) if fltr not in (FilterComboBox.NO_FILTER, FilterComboBox.NEW_FILTER, ''): if fltr in p._filters: q.add_filter(p._filters[fltr]) elif fltr in p.gates: q.add_filter(p.gates[fltr].as_filter()) else: raise Exception('Could not find filter "%s" in gates or filters'%(fltr)) wellkeys_and_values = db.execute(str(q)) wellkeys_and_values = np.array(wellkeys_and_values, dtype=object) # Replace measurement None's with nan for row in wellkeys_and_values: if row[-1] is None: row[-1] = np.nan data = [] key_lists = [] dmax = -np.inf dmin = np.inf if p.plate_id: for plateChoice, plateMap in zip(self.plateMapChoices, self.plateMaps): plate = plateChoice.Value plateMap.SetPlate(plate) self.colorBar.AddNotifyWindow(plateMap) self.keys_and_vals = [v for v in wellkeys_and_values if str(v[0])==plate] platedata, wellkeys, ignore = FormatPlateMapData(self.keys_and_vals, categorical) data += [platedata] key_lists += [wellkeys] if not categorical: dmin = np.nanmin([float(kv[-1]) for kv in self.keys_and_vals]+[dmin]) dmax = np.nanmax([float(kv[-1]) for kv in self.keys_and_vals]+[dmax]) else: self.colorBar.AddNotifyWindow(self.plateMaps[0]) platedata, wellkeys, ignore = FormatPlateMapData(wellkeys_and_values, categorical) data += [platedata] key_lists += [wellkeys] if not categorical: dmin = np.nanmin([float(kv[-1]) for kv in wellkeys_and_values]) dmax = np.nanmax([float(kv[-1]) for kv in wellkeys_and_values]) if not categorical: if len(wellkeys_and_values) > 0: # Compute the global extents if there is any data whatsoever gmin = np.nanmin([float(vals[-1]) for vals in wellkeys_and_values]) gmax = np.nanmax([float(vals[-1]) for vals in wellkeys_and_values]) if np.isinf(dmin) or np.isinf(dmax): gmin = gmax = dmin = dmax = 1. # Warn if there was no data for this plate (and no filter was used) if fltr == FilterComboBox.NO_FILTER: wx.MessageBox('No numeric data was found in "%s.%s" for plate "%s"' %(table, measurement, plate), 'Warning') else: gmin = gmax = 1. if fltr == FilterComboBox.NO_FILTER: wx.MessageBox('No numeric data was found in %s.%s' %(table, measurement), 'Warning') if categorical: self.colorBar.Hide() else: self.colorBar.Show() self.colorBar.SetLocalExtents([dmin,dmax]) self.colorBar.SetGlobalExtents([gmin,gmax]) self.rightSizer.Layout() for keys, d, plateMap in zip(key_lists, data, self.plateMaps): plateMap.SetWellKeys(keys) if categorical: plateMap.SetData(np.ones(d.shape) * np.nan) plateMap.SetTextData(d) else: plateMap.SetData(d, data_range=self.colorBar.GetLocalExtents(), clip_interval=self.colorBar.GetLocalInterval(), clip_mode=self.colorBar.GetClipMode()) for keys, d, plateMap in zip(key_lists, data, self.plateMaps): plateMap.SetWellKeys(keys) if categorical: plateMap.SetData(np.ones(d.shape) * np.nan) plateMap.SetTextData(d) else: plateMap.SetData(d, data_range=self.colorBar.GetLocalExtents(), clip_interval=self.colorBar.GetLocalInterval(), clip_mode=self.colorBar.GetClipMode()) def UpdateMeasurementChoice(self, evt=None): ''' Handles the selection of a source table (per-image or per-object) from a choice box. The measurement choice box is populated with the names of numeric columns from the selected table. ''' table = self.sourceChoice.Value if table == TableComboBox.OTHER_TABLE: t = get_other_table_from_user(self) if t is not None: self.sourceChoice.Items = self.sourceChoice.Items[:-1] + [t] + self.sourceChoice.Items[-1:] self.sourceChoice.Select(self.sourceChoice.Items.index(t)) table = t else: self.sourceChoice.Select(0) return self.measurementsChoice.SetItems(get_non_blob_types_from_table(table)) self.measurementsChoice.Select(0) self.colorBar.ResetInterval() self.UpdatePlateMaps() def on_save_csv(self, evt): defaultFileName = 'my_plate_table.csv' saveDialog = wx.FileDialog(self, message="Save as:", defaultDir=os.getcwd(), defaultFile=defaultFileName, wildcard='csv|*', style=(wx.SAVE | wx.FD_OVERWRITE_PROMPT | wx.FD_CHANGE_DIR)) if saveDialog.ShowModal() == wx.ID_OK: filename = saveDialog.GetPath() self.save_to_csv(filename) self.Title = filename saveDialog.Destroy() def save_to_csv(self, filename): with open(filename, 'wb') as f: w = csv.writer(f) w.writerow(['Plate', 'Well', self.measurement + ' ' + self.aggMethod]) w.writerows(self.keys_and_vals) logging.info('Table saved to %s'%filename) def OnSelectPlate(self, evt): ''' Handles the selection of a plate from the plate choice box. ''' self.UpdatePlateMaps() def OnSelectMeasurement(self, evt=None): ''' Handles the selection of a measurement to plot from a choice box. ''' selected_measurement = self.measurementsChoice.Value table = self.sourceChoice.Value numeric_measurements = get_numeric_columns_from_table(table) if (selected_measurement in numeric_measurements): self.aggregationMethodsChoice.Enable() self.colorMapsChoice.Enable() else: self.aggregationMethodsChoice.Disable() self.colorMapsChoice.Disable() self.colorBar.ResetInterval() self.UpdatePlateMaps() def OnSelectAggregationMethod(self, evt=None): ''' Handles the selection of an aggregation method from the choice box. ''' self.colorBar.ResetInterval() self.UpdatePlateMaps() def OnSelectColorMap(self, evt=None): ''' Handles the selection of a color map from a choice box. ''' map = self.colorMapsChoice.Value cm = matplotlib.cm.get_cmap(map) self.colorBar.SetMap(map) for plateMap in self.plateMaps: plateMap.SetColorMap(map) def OnSelectWellDisplay(self, evt=None): ''' Handles the selection of a well display choice from a choice box. ''' sel = self.wellDisplayChoice.Value if sel.lower() == 'image': dlg = wx.MessageDialog(self, 'This mode will render each well as a shrunken image loaded ' 'from that well. This feature is currently VERY SLOW since it ' 'requires loading hundreds of full sized images. Are you sure ' 'you want to continue?', 'Load all images?', wx.OK|wx.CANCEL|wx.ICON_QUESTION) if dlg.ShowModal() != wx.ID_OK: self.wellDisplayChoice.SetSelection(0) return if sel.lower() in ['image', 'thumbnail']: self.colorBar.Hide() else: self.colorBar.Show() for platemap in self.plateMaps: platemap.SetWellDisplay(sel) def OnEnterNumberOfPlates(self, evt=None): ''' Handles the entry of a plates to view from a choice box. ''' try: nPlates = int(self.numberOfPlatesTE.GetValue()) except: logging.warn('Invalid # of plates! Please enter a number between 1 and 100') return if nPlates>100: logging.warn('Too many plates! Please enter a number between 1 and 100') return if nPlates<1: logging.warn('You must display at least 1 plate.') self.numberOfPlatesTE.SetValue('1') nPlates = 1 # Record the indices of the plates currently selected. # Pad the list with sequential plate indices then crop to the new number of plates. currentPlates = [plateChoice.GetSelection() for plateChoice in self.plateMapChoices] currentPlates = (currentPlates+[(currentPlates[-1]+1+p) % len(db.GetPlateNames()) for p in range(nPlates)])[:nPlates] # Remove all plateMaps self.plateMapSizer.Clear(deleteWindows=True) self.plateMaps = [] self.plateMapChoices = [] # Restructure the plateMapSizer appropriately rows = cols = np.ceil(np.sqrt(nPlates)) self.plateMapSizer.SetRows(rows) self.plateMapSizer.SetCols(cols) # Add the plate maps for plateIndex in currentPlates: self.AddPlateMap(plateIndex) self.UpdatePlateMaps() self.plateMapSizer.Layout() # Update outlines self.OnOutlineMarked() def OnSelectWell(self): '''When wells are selected: display their annotation in the annotation label control. If multiple annotations are found then make sure the user knows. ''' wellkeys = [] for pm in self.plateMaps: wellkeys += pm.get_selected_well_keys() if len(wellkeys) > 0 and self.annotationCol.Value != '': self.annotationLabel.Enable() self.annotationLabel.SetForegroundColour(wx.BLACK) self.annotationLabel.SetBackgroundColour(wx.WHITE) annotations = db.execute('SELECT %s FROM %s WHERE %s'%( self.annotationCol.Value, p.image_table, GetWhereClauseForWells(wellkeys))) annotations = list(set([a[0] for a in annotations])) if len(annotations) == 1: if annotations[0] == None: self.annotationLabel.SetValue('') else: self.annotationLabel.SetValue(str(annotations[0])) else: self.annotationLabel.SetValue(','.join([str(a) for a in annotations if a is not None])) else: self.annotationLabel.Disable() self.annotationLabel.SetForegroundColour(wx.Colour(80,80,80)) self.annotationLabel.SetBackgroundColour(wx.LIGHT_GREY) self.annotationLabel.SetValue('Select wells') def OnAddAnnotationCol(self, evt): '''Add a new user annotation column to the database. ''' dlg = wx.TextEntryDialog(self, 'New annotation column name: User_','Add Annotation Column') if dlg.ShowModal() != wx.ID_OK: return new_column = 'User_'+dlg.GetValue() # user-type ==> (sql-type, python-type) coltypes = {'Text' : ('VARCHAR(255)', str), 'Number' : ('FLOAT', float)} dlg = wx.SingleChoiceDialog(self, 'What type of annotation column would you like to add?\nThis can not be changed.', 'Add Annotation Column', coltypes.keys(), wx.CHOICEDLG_STYLE) if dlg.ShowModal() != wx.ID_OK: return usertype = dlg.GetStringSelection() db.AppendColumn(p.image_table, new_column, coltypes[usertype][0]) self.annotation_cols[new_column] = coltypes[usertype][1] self.annotationCol.Items += [new_column] self.annotationCol.SetSelection(len(self.annotation_cols) - 1) current_selection = self.measurementsChoice.Selection self.measurementsChoice.SetItems(self.measurementsChoice.Strings + [new_column]) if self.annotationShowVals.IsChecked(): column = self.annotationCol.Value self.sourceChoice.SetStringSelection(p.image_table) self.measurementsChoice.SetStringSelection(column) self.UpdatePlateMaps() else: self.measurementsChoice.SetSelection(current_selection[0]) self.annotationShowVals.Enable() self.outlineMarked.Enable() self.OnSelectWell() def OnSelectAnnotationCol(self, evt=None): '''Handles selection of an annotation column. ''' col = self.annotationCol.Value if col == '': return coltype = self.annotation_cols[col] self.OnSelectWell() self.OnOutlineMarked() if self.annotationShowVals.IsChecked(): if coltype != str: self.colorMapsChoice.Enable() else: self.colorMapsChoice.Disable() self.measurementsChoice.SetStringSelection(col) self.UpdatePlateMaps() def OnEnterAnnotation(self, evt=None): '''Store the annotation value in the annotation column of the db. ''' if evt.KeyCode < 32 or evt.KeyCode > 127: return column = self.annotationCol.Value value = self.annotationLabel.Value wellkeys = [] for pm in self.plateMaps: wellkeys += pm.get_selected_well_keys() if value == '': value = None elif self.annotation_cols[column] == float: try: value = float(value) self.annotationLabel.SetForegroundColour(wx.BLACK) except: self.annotationLabel.SetForegroundColour(wx.Color(255,0,0)) return db.UpdateWells(p.image_table, column, value, wellkeys) if self.outlineMarked.IsChecked(): for pm in self.plateMaps: if value is None: pm.UnOutlineWells(wellkeys) else: pm.OutlineWells(wellkeys) if (self.sourceChoice.Value == p.image_table and self.measurementsChoice.Value == column): self.UpdatePlateMaps() def OnOutlineMarked(self, evt=None): '''Outlines all non-NULL values of the current annotation ''' # Disable filters when outlining marked wells #if self.outlineMarked.IsChecked(): #self.filterChoice.SetStringSelection(FilterComboBox.NO_FILTER) #self.filterChoice.Disable() #else: #if not self.annotationShowVals.IsChecked(): #self.filterChoice.Enable() # Update outlined wells in PlateMapPanels for pm in self.plateMaps: if self.outlineMarked.IsChecked(): column = self.annotationCol.Value if p.plate_id: res = db.execute('SELECT %s, %s FROM %s WHERE %s="%s"'%( dbconnect.UniqueWellClause(), column, p.image_table, p.plate_id, pm.plate)) else: # if there's no plate_id, we assume there is only 1 plate # and fetch all the data res = db.execute('SELECT %s, %s FROM %s'%( dbconnect.UniqueWellClause(), column, p.image_table)) keys = [tuple(r[:-1]) for r in res if r[-1] is not None] pm.SetOutlinedWells(keys) else: pm.SetOutlinedWells([]) self.UpdatePlateMaps() def OnShowAnnotationValues(self, evt=None): '''Handler for the show values checkbox. ''' if self.annotationShowVals.IsChecked(): column = self.annotationCol.Value self.sourceChoice.SetStringSelection(p.image_table) self.measurementsChoice.SetItems(get_non_blob_types_from_table(p.image_table)) self.measurementsChoice.SetStringSelection(column) self.filterChoice.SetStringSelection(FilterComboBox.NO_FILTER) self.sourceChoice.Disable() self.measurementsChoice.Disable() self.filterChoice.Disable() self.aggregationMethodsChoice.Disable() self.aggregationMethodsChoice.SetValue('none') else: self.sourceChoice.Enable() self.measurementsChoice.Enable() if not self.outlineMarked.IsChecked(): self.filterChoice.Enable() if db.GetColumnType(self.sourceChoice.Value, self.measurementsChoice.Value) != str: self.aggregationMethodsChoice.Enable() self.aggregationMethodsChoice.SetSelection(0) self.UpdatePlateMaps() def OnSelectFilter(self, evt): self.filterChoice.on_select(evt) self.UpdatePlateMaps() self.colorBar.ResetInterval() def save_settings(self): '''save_settings is called when saving a workspace to file. returns a dictionary mapping setting names to values encoded as strings ''' settings = {'table' : self.sourceChoice.Value, 'measurement' : self.measurementsChoice.Value, 'aggregation' : self.aggregationMethodsChoice.Value, 'colormap' : self.colorMapsChoice.Value, 'well display' : self.wellDisplayChoice.Value, 'number of plates' : self.numberOfPlatesTE.GetValue(), } for i, choice in enumerate(self.plateMapChoices): settings['plate %d'%(i+1)] = choice.Value return settings def load_settings(self, settings): '''load_settings is called when loading a workspace from file. settings - a dictionary mapping setting names to values encoded as strings. ''' if 'table' in settings: self.sourceChoice.SetStringSelection(settings['table']) self.UpdateMeasurementChoice() if 'measurement' in settings: self.measurementsChoice.SetStringSelection(settings['measurement']) self.OnSelectMeasurement() if 'aggregation' in settings: self.aggregationMethodsChoice.SetStringSelection(settings['aggregation']) self.OnSelectAggregationMethod() if 'colormap' in settings: self.colorMapsChoice.SetStringSelection(settings['colormap']) self.OnSelectColorMap() if 'number of plates' in settings: self.numberOfPlatesTE.SetValue(settings['number of plates']) self.OnEnterNumberOfPlates() for s, v in settings.items(): if s.startswith('plate '): self.plateMapChoices[int(s.strip('plate ')) - 1].SetValue(v) # set well display last since each step currently causes a redraw and # this could take a long time if they are displaying images if 'well display' in settings: self.wellDisplayChoice.SetStringSelection(settings['well display']) self.OnSelectWellDisplay()
class PelvisFrame(wx.Frame): """The main application window for PELvis""" #Menu ID constants ID_OPEN = 100 ID_OPENTWO = 110 ID_SAVE = 130 ID_SPECTRUM=140 ID_IMAGE_ARRAY=160 ID_EXIT = 190 ID_GREY = 200 ID_HUEVAL = 220 ID_SPECTRAL = 230 ID_PICKER = 290 ID_POLAR = 300 ID_FLIPPING = 310 ID_SPIN_UP = 320 ID_SPIN_DOWN = 330 ID_FLAT = 420 ID_FAKEFLAT = 430 ID_ROD = 440 ID_EXPORT_ROI = 450 ID_IMPORT_ROI = 460 ID_COPY = 500 def __init__(self,Yield): """Create a PELvis frame Keyword arguments: Yield -- A function to give control back to the main event loop """ wx.Frame.__init__(self,None,wx.ID_ANY,"PEL Visualizer") self.data = PelFile() self.Yield = Yield self.mask = np.ones((128,16),dtype=np.bool) #Create items in the frame self.yPanel = GraphPanel(self,(2,8),64,GraphPanel.VERTICAL) self.xPanel = GraphPanel(self,(8,2),64,GraphPanel.INVERTED) self.colorbar = ColorBarPanel(self,cm.jet) self.opPanel = PelvisOptionPanel(self) self.posPanel = PositionPanel(self) self.imPanel = ImagePanel(self,self.posPanel.set, self.opPanel.setPosMin,self.opPanel.setPosMax) self.specDlg = SpectrumDialog(self) self.cmp = None #color map self.imageSaveDialog=wx.FileDialog(self,"Choose graphics file",wildcard="Portable Network Graphic (png)|*.PNG|Windows Bitmap (bmp)|*.BMP|Joint Photographic Experts Group (jpg)|*.JPG|Portable Network Monocrome (pnm)|*.PNM|Tagged Image File Format (tif)|*.TIF|Archaic, useless format (pcx)|*.PCX",style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) self.update = self.updateSingle#update the image self.updateData = self.updateSingleData#update the data in the image #Create the menu menubar = wx.MenuBar() filemenu = wx.Menu() editmenu = wx.Menu() scalemenu = wx.Menu() analysismenu = wx.Menu() noisemenu = wx.Menu() #populate the menu filemenu.Append(self.ID_OPEN,"&Open\tCtrl-O"," Open a PEL file") filemenu.Append(self.ID_OPENTWO,"&Polarized Set"," Open two PEL files") filemenu.Append(self.ID_SAVE,"&Save\tCtrl-S"," Save an image file") filemenu.Append(self.ID_SPECTRUM,"Spectrum"," View the TOF spectrum") filemenu.Append(self.ID_IMAGE_ARRAY,"&Export Images..."," Save a series of TOF snapshots") filemenu.Append(self.ID_EXIT,"&Quit\tCtrl-Q"," Quit") editmenu.Append(self.ID_COPY,"&Copy\tCtrl-c","Copy the current image to the clipboard") scalemenu.Append(self.ID_GREY,"Greyscale\tCtrl-G","Monochrome images") scalemenu.Append(self.ID_HUEVAL,"Hue and Value\tCtrl-H","Scaled Rainbow Images") scalemenu.Append(self.ID_SPECTRAL,"spectral","Uses spectrum of light") scalemenu.Append(self.ID_PICKER,"Map Picker..."," Select from the full list of colormaps") analysismenu.Append(self.ID_POLAR,"Check Polarization\tCtrl-P","2d plot of polarization data") analysismenu.Append(self.ID_FLIPPING,"Check Flipping Ratio\tCtrl-F","2d plot of spin up over spin down") analysismenu.Append(self.ID_SPIN_UP,"View Spin Up State\tCtrl-U","2d plot of spin up") analysismenu.Append(self.ID_SPIN_DOWN,"View Spin Down State\tCtrl-D","2d plot of spin down") noisemenu.Append(self.ID_FLAT,"&Load Flat"," Load a blank run for background subtraction") noisemenu.Append(self.ID_FAKEFLAT,"Si&mulate Flat"," Drop out background within the same image") noisemenu.Append(self.ID_ROD,"Region of &Disinterest"," Drop out background within the same image") noisemenu.Append(self.ID_EXPORT_ROI,"Export ROI"," Export a binary file corresponding to where the data is above the minimum intensity.") noisemenu.Append(self.ID_IMPORT_ROI,"Import ROI"," Add another exclusion mask.") #Bind events to the menu self.Connect(self.ID_EXIT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnExit) self.Connect(self.ID_OPEN,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnOpen) self.Connect(self.ID_OPENTWO,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnOpenSet) self.Connect(self.ID_SAVE,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSave) self.Connect(self.ID_SPECTRUM,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSpectrum) self.Connect(self.ID_IMAGE_ARRAY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnImageArray) self.Connect(self.ID_GREY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnGrey) self.Connect(self.ID_HUEVAL,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnHueVal) self.Connect(self.ID_SPECTRAL,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnSpectral) self.Connect(self.ID_PICKER,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnPicker) self.Connect(self.ID_POLAR,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnPolar) self.Connect(self.ID_FLIPPING,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFlipping) self.Connect(self.ID_SPIN_UP,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnAnalysisSpinUp) self.Connect(self.ID_SPIN_DOWN,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnAnalysisSpinDown) self.Connect(self.ID_FLAT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFlat) self.Connect(self.ID_FAKEFLAT,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnFakeFlat) self.Connect(self.ID_ROD,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnROD) self.Connect(self.ID_EXPORT_ROI,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnExportROI) self.Connect(self.ID_IMPORT_ROI,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnImportROI) self.Connect(self.ID_COPY,-1,wx.wxEVT_COMMAND_MENU_SELECTED,self.OnCopy) menubar.Append(filemenu,"&File") menubar.Append(editmenu,"&Edit") menubar.Append(scalemenu,"&Color") menubar.Append(analysismenu,"&Analysis") menubar.Append(noisemenu,"&Noise") self.SetMenuBar(menubar) #arrange window sizer = wx.GridBagSizer() sizer.Add(self.colorbar,pos=wx.GBPosition(0,9),span=wx.GBSpan(9,1)) sizer.Add(self.imPanel,pos=wx.GBPosition(0,1),span=wx.GBSpan(8,8)) sizer.Add(self.yPanel,pos=wx.GBPosition(0,0),span=wx.GBSpan(8,1)) sizer.Add(self.xPanel,pos=wx.GBPosition(8,1),span=wx.GBSpan(1,8)) sizer.Add(self.opPanel,pos=wx.GBPosition(0,10),span=wx.GBSpan(8,1),flag=wx.EXPAND) sizer.Add(self.posPanel,pos=wx.GBPosition(8,0),flag=wx.EXPAND) self.progress = wx.Gauge(self,range=1000) sizer.Add(self.progress,pos=wx.GBPosition(9,0),span=wx.GBSpan(1,11),flag=wx.EXPAND) updateButton = wx.Button(self,-1,"Update") updateButton.Bind(wx.EVT_BUTTON,self.OnUpdateButton) sizer.Add(updateButton,flag=wx.EXPAND,pos=wx.GBPosition(8,10)) self.data = self.makePel() self.flatrun = None#background data sizer.SetSizeHints(self) self.SetSizer(sizer) self.Show(True) def makePel(self): """Create a blank Pel object for loading detector data""" data = PelFile() def statusfunc(x): self.progress.SetValue(x) self.Yield() data.statusfunc = statusfunc return data def loadPel(self,message): """Load a .pel file and its monitor data. Keyword arguments: message -- The title for the load file dialog. """ dlg=wx.FileDialog(self,message,wildcard="He3 data|*neutron_event.dat|Preformatted Histograms|*.npy",style=wx.FD_OPEN) if dlg.ShowModal()==wx.ID_OK: # self.SetCursor(wx.CURSOR_WAIT) path = dlg.GetPath() if path[-3:] == "dat": data = self.makePel() data.readfileimage(path) elif path[-3:] == "npy": data = np.load(path) # self.SetCursor(wx.CURSOR_ARROW) else: return (None,None) mon = MonFile(path[:-17]+"bmon_histo.dat") return (data,mon) def OnImageArray(self,event): """Exports the 2d detector image by wavelength""" dlg = self.imageSaveDialog if dlg.ShowModal()==wx.ID_OK: path=dlg.GetPath() ext = path[-4:] path = path[:-4] (lmin,lmax) = self.opPanel.getLambdaRange() for i in range(lmin,lmax): file=path+("%03i"%i)+ext self.opPanel.setLambdaRange(0.1*i,0.1*(i+1)) self.updateData() self.update() self.imPanel.saveImage(file) self.progress.SetValue(1000*(i-lmin)/(lmax-lmin)) self.Yield() self.opPanel.setLambdaRange(lmin*0.1,lmax*0.1) self.updateData() self.progress.SetValue(0) def loadNormPel(self,message): """Load a .pel file, normalize it by monitor, and subtract background""" (data,mon) = self.loadPel(message) if isinstance(data,PelFile): data = np.asarray(data.make3d(),np.float32) if mon is None: return (data,1) if self.flatrun != None: flatrun = np.load(self.flatrun) self.flatrun.seek(0) flatrun *= mon.time data -= flatrun spec = mon.spec monsum = np.sum(spec) print("Integrated monitor counts: " + str(monsum)) data /= monsum return (data,np.sum(mon.spec)) # def getLambdaRange(self): # try: # lmin = int(float(self.lambdaMin.GetValue())*10) # except ValueError: # lmin = 0 # try: # lmax = int(float(self.lambdaMax.GetValue())*10) # except ValueError: # lmax = 200 # return (lmin,lmax) def updateSingleData(self,event=None): """Update changes in wavelength on a single file""" print("Make 2d") (lmin,lmax) = self.opPanel.getLambdaRange() self.flatdata = np.sum(self.data[:,:,lmin:lmax],2) self.update() def updateDataFlip(self,event=None): """Update changes in wavelength for flipping ratios""" (lmin,lmax) = self.opPanel.getLambdaRange() (u3d,d3d)=self.data u = np.sum(u3d[:,:,lmin:lmax],2) d = np.sum(d3d[:,:,lmin:lmax],2) self.flatdata = u/(d+1e-6) self.update() def updateDataPolar(self,event=None): """Update changes in wavelength for polarizations""" (lmin,lmax) = self.opPanel.getLambdaRange() (u3d,d3d)=self.data u = np.sum(u3d[:,:,lmin:lmax],2) d = np.sum(d3d[:,:,lmin:lmax],2) self.flatdata = (u-d)/(u+d+1e-6) self.update() def updateDataUp(self,event=None): """Update changes in wavelength for the spin up state""" (lmin,lmax) = self.opPanel.getLambdaRange() (u3d,_)=self.data self.flatdata = np.sum(u3d[:,:,lmin:lmax],2) self.update() def updateDataDown(self,event=None): """Update changes in wavelength for the spin down state""" (lmin,lmax) = self.opPanel.getLambdaRange() (_,d3d)=self.data self.flatdata = np.sum(d3d[:,:,lmin:lmax],2) self.update() def updateSingle(self,event=None): """Update the 2D data for the region of interest and intensity""" (vMin,vMax) = self.opPanel.getIntensityRange() (xMin,xMax,yMin,yMax) = self.opPanel.getRoi() data = self.flatdata[:,:] #Mask to zero during the summing parts data[np.logical_not(self.mask)] = 0 self.posPanel.data = data self.posPanel.setRange(xMin,yMin,xMax,yMax) x=np.arange(128,0,-1) y=np.sum(data[:,xMin:xMax],axis=1) self.yPanel.SetPlot(x,y) #handle the x-plot x=np.arange(0,16,1) y=np.sum(data[yMin:yMax,:],axis=0) self.xPanel.SetPlot(x,y) if vMin is None: vMin = np.min(data) if vMax is None: vMax = np.max(data) self.colorbar.setRange(vMin,vMax) self.colorbar.update() #mask to vmin for the plotting data[np.logical_not(self.mask)] = vMin self.imPanel.update(self.flatdata,vMin,vMax) def OnUpdateButton(self,event): """Refresh the data when the user pushes the "Update" button""" #This function is needed for wxWidgets to allow #for dynamically changing the bound function self.updateData(event) def OnOpen(self,event): """Load a single .pel file for display""" data,scale = self.loadNormPel("Choose the Pel File to Open") if data is None: return self.data = data self.scale = scale self.progress.SetValue(0) self.specDlg.setMode("up") self.updateData = self.updateSingleData self.update = self.updateSingle self.updateData() def OnOpenSet(self,event): """Load a spin flip measurement for display""" if self.loadUpAndDown(): self.OnPolar(event) def OnFlat(self,event): """Load a blank run for background subtraction""" (data,mon) = self.loadPel("Choose a Blank Run") if data == None: return if isinstance(data,PelFile): flatrun = data.make3d() elif isinstance(data,np.ndarray): flatrun = data flatrun = np.sum(flatrun,axis=2) flatrun /= RESOLUTION flatrun /= float(mon.time) flatrun = np.expand_dims(flatrun,2) self.flatrun = TemporaryFile() np.save(self.flatrun,flatrun) self.flatrun.seek(0) self.progress.SetValue(0) def OnFakeFlat(self,event): """Create a fake background run from outside the region of interest.""" (xMin,xMax,yMin,yMax)=self.opPanel.getRoi() totarea = 512*512 centarea = (yMax-yMin)*(xMax-xMin) backgroundarea = totarea-centarea if type(self.data) is tuple: (u,d)=self.data totu = np.sum(u) totd = np.sum(d) centu = np.sum(u[yMin:yMax,xMin:xMax,:]) centd = np.sum(d[yMin:yMax,xMin:xMax,:]) backgroundu = totu-centu backgroundd = totd-centd backgroundrateu = backgroundu/backgroundarea backgroundrated = backgroundd/backgroundarea backgroundrateu /= (RESOLUTION + 1) #normalize against the wavelengths backgroundrated /= (RESOLUTION + 1) #normalize against the wavelengths ###Stupid Memory Errors del self.data u -= backgroundrateu d -= backgroundrated ### self.data=(u,d) else: d=self.data tot = np.sum(d) cent = np.sum(d[yMin:yMax,xMin:xMax,:]) background = tot-cent backgroundrate = background/backgroundarea backgroundrate /= (RESOLUTION + 1) #normalize against the wavelengths self.data-=backgroundrate self.updateData() #Subtract out the region of disinterest def OnROD(self,event): """Take the region of interest as background noise""" (xMin,xMax,yMin,yMax)=self.opPanel.getRoi() area = (yMax-yMin)*(xMax-xMin) if type(self.data) is tuple: u,d=self.data del self.data totu = np.sum(np.sum(u[yMin:yMax,xMin:xMax,:],axis=0),axis=0) totd = np.sum(np.sum(d[yMin:yMax,xMin:xMax,:],axis=0),axis=0) totu /= area totd /= area u -= totu d -= totd self.data=(u,d) else: d=self.data totd = np.sum(np.sum(d[yMin:yMax,xMin:xMax,:],axis=0),axis=0) #totd = np.atleast_3d(totd) totd /= area #print(totd.shape) #print(self.data.shape) self.data -= totd self.updateData() def OnExportROI(self,event): """Save a file containing a map of where the current data image is greater than vmin""" vMin,_ = self.opPanel.getIntensityRange() mask = self.flatdata > vMin # (vMin,vMax) = self.opPanel.getIntensityRange()# # (xMin,xMax,yMin,yMax) = self.opPanel.getRoi()# # (lMin,lMax) = self.opPanel.getLambdaRange()# # (lMin,lMax) = (lMin/10,lMax/10)# # mask = [["xMin",xMin], ["xMax",xMax], ["yMin",yMin], ["yMax",yMax], \ # ["lMin",lMin], ["lMax",lMax], ["vMin",vMin], ["vMax",vMax]]# dlg = wx.FileDialog(self, "Where to save the mask file?", wildcard="Numpy dump (npy)|*.npy|Text (dat)|*.dat", style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal()==wx.ID_OK: path=dlg.GetPath() ext = path[-4:] if ext == ".dat": np.savetxt(path,mask,fmt="%d") else: np.save(path,mask) def OnImportROI(self,event): """Adds another mask to the current system mask""" dlg = wx.FileDialog(self, "Which Mask File?", wildcard="Numpy dump (npy)|*.npy|Text (dat)|*.dat", style=wx.FD_OPEN) time.sleep(.1) if dlg.ShowModal()==wx.ID_OK: path = dlg.GetPath() ext = path[-4:] if ext == ".dat": newmask = np.loadtxt(path,dtype=np.bool) newmask=dict(newmask)# else: newmask = np.load(path) self.mask = np.logical_and(self.mask,newmask) #self.opPanel.setPosMin(newmask["xMin"],newmask["yMin"])# #self.opPanel.setPosMax(newmask["xMax"],newmask["yMax"])# #self.opPanel.setLambdaRange(newmask["lMin"],newmask["lMax"])# #self.opPanel.setIntensityRange(newmask["vMin"],newmask["vMax"])# self.updateData() def OnSave(self,event): """Save the current 2D image to a file""" print("OnSave") # dlg=wx.FileDialog(self,"Choose graphics file",wildcard="Windows Bitmap (bmp)|*.BMP|Portable Network Graphic (png)|*.PNG|Joint Photographic Experts Group (jpg)|*.JPG|Portable Network Monocrome (pnm)|*.PNM|Tagged Image File Format (tif)|*.TIF|Archaic, useless format (pcx)|*.PCX",style=wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) dlg = self.imageSaveDialog if dlg.ShowModal()==wx.ID_OK: self.imPanel.saveImage(dlg.GetPath()) def OnSpectrum(self,event): """Display a plot of the region of interest versus wavelength""" print("OnSpectrum") (xMin,xMax,yMin,yMax)=self.opPanel.getRoi() if type(self.data) is tuple: u3d,d3d = self.data u3d = u3d[:,:,:] d3d = d3d[:,:,:] u3d[np.logical_not(self.mask)] = 0 d3d[np.logical_not(self.mask)] = 0 u = np.sum(np.sum(u3d[yMin:yMax,xMin:xMax],0),0) d = np.sum(np.sum(d3d[yMin:yMax,xMin:xMax],0),0) uscale,dscale = self.scale self.specDlg.setScale(uscale,dscale) self.specDlg.setData(u,d) else: copy = self.data[:,:,:] copy[np.logical_not(self.mask)] = 0 u = np.sum(np.sum(copy[yMin:yMax,xMin:xMax],0),0) # u *= self.scale self.specDlg.setScale(self.scale) self.specDlg.setData(u) self.specDlg.setIntensityRange(self.opPanel.getIntensityRange()) self.specDlg.Show() def OnGrey(self,event): """Set the colormap to gray""" self.imPanel.cmap = cm.gray self.colorbar.setCmap(cm.gray) self.update() def OnHueVal(self,event): """Set the colormap to a rainbow""" self.imPanel.cmap = cm.jet self.colorbar.setCmap(cm.jet) self.update() def OnSpectral(self,event): """Set the colormap to the spectral map""" self.imPanel.cmap = cm.spectral self.colorbar.setCmap(cm.spectral) self.update() def OnPicker(self,event): """Let the user pick a color map from a list""" if self.cmp is None: self.cmp = ColorMapPicker(self,self.setColorMap) self.cmp.Show() def setColorMap(self,cmap): """Changes to the given colormap""" self.imPanel.cmap = cmap self.colorbar.setCmap(cmap) self.update() def OnExit(self,event): """Quit the program""" self.Close() def loadUpAndDown(self): """Read in spin flip data""" u3d,uscale = self.loadNormPel("Spin Up State") if u3d is None: return False del self.data d3d,dscale = self.loadNormPel("Spin Down State") self.data = (u3d,d3d) self.scale = (uscale,dscale) return True def OnPolar(self,event): """Display neutron polarization""" print("OnPolar") self.specDlg.setMode("polar") self.updateData = self.updateDataPolar self.update = self.updateSingle self.updateData() def OnFlipping(self,event): """Display the flipping ratio""" print("OnFlip") self.specDlg.setMode("flipping") self.updateData = self.updateDataFlip self.update = self.updateSingle self.updateData() def OnAnalysisSpinUp(self,event): """Display the Spin Up data""" print("OnSpinUp") self.specDlg.setMode("up") self.updateData = self.updateDataUp self.update = self.updateSingle self.updateData() def OnAnalysisSpinDown(self,event): """Display the Spin Down data""" print("OnSpinDown") self.specDlg.setMode("down") self.updateData = self.updateDataDown self.update = self.updateSingle self.updateData() def OnCopy(self,event): """Copy the image to a clipboard""" self.imPanel.copyToClipboard()