def deleteSelection(self): """ Delete the data object referenced by the current tree selection. """ item = self.getSanitizedItemSelectionData() if item is None: return if item[0] is DATA_SET_ITEM: ids = (item[1], None) if len(item) < 3 else (item[1], item[2]) self.Parent.TopLevelParent.facsPlotPanel.deleteAssociatedSubplots(ids) self.applyToSelection(DataStore.remove, FacsData.removeClustering) # if all data deleted, clear axes selectors if len(DataStore.getData()) == 0: self.Parent.TopLevelParent.updateAxesList([]) if item[0] is FIGURE_SET_ITEM: id = item[1] #TODO: figure out if this is a good shortcut for clearing the figure of subplots if id == FigureStore.getSelectedIndex(): wx.MessageBox('The currently selected Figure cannot be deleted.', 'Invalid Action', wx.OK | wx.ICON_WARNING) else: FigureStore.remove(id) self.updateTree()
def updateTree(self): """ Rebuilds the tree from the current state of the DataStore. """ self.tree.DeleteAllItems() self.root = self.tree.AddRoot("Project") self.tree.SetPyData(self.root, None) self.tree.SetItemImage(self.root, self.fldridx, wx.TreeItemIcon_Normal) self.tree.SetItemImage(self.root, self.fldropenidx, wx.TreeItemIcon_Expanded) dataTree = self.tree.AppendItem(self.root, "Data Sets") self.tree.SetPyData(dataTree, DATA_SET_ITEM) self.tree.SetItemImage(dataTree, self.fldridx, wx.TreeItemIcon_Normal) self.tree.SetItemImage(dataTree, self.fldropenidx, wx.TreeItemIcon_Expanded) figsTree = self.tree.AppendItem(self.root, "Figure Sets") self.tree.SetPyData(figsTree, FIGURE_SET_ITEM) self.tree.SetItemImage(figsTree, self.fldridx, wx.TreeItemIcon_Normal) self.tree.SetItemImage(figsTree, self.fldropenidx, wx.TreeItemIcon_Expanded) # create tree self.buildDataTree(dataTree, DataStore.getData(), []) self.buildFigureTree(figsTree, FigureStore.getFigures()) self.tree.Expand(self.root) if self.dataTreeExpanded: self.tree.Expand(dataTree) if self.figureTreeExpanded: self.tree.Expand(figsTree)
def buildFigureTree(self, root, figures): for id, fig in figures.iteritems(): child = self.tree.AppendItem(root, fig.name) if (FigureStore.getSelectedIndex() == id): self.tree.SetItemBold(child, True) self.tree.SetPyData(child, (FIGURE_SET_ITEM, id)) self.tree.SetItemImage(child, self.figureicn, wx.TreeItemIcon_Normal)
def renameItem(self): """ Give a new display name to the currently selected data item """ item = self.getSanitizedItemSelectionData() if item is None: return if (item[0] is DATA_SET_ITEM): data = DataStore.get(item[1]) dlg = EditNameDialog(self.Parent, data.displayname) if dlg.ShowModal() == wx.ID_OK: data.displayname = dlg.Text dlg.Destroy() if (item[0] is FIGURE_SET_ITEM): figure = FigureStore.get(item[1]) dlg = EditNameDialog(self.Parent, figure.name) if dlg.ShowModal() == wx.ID_OK: figure.name = dlg.Text dlg.Destroy() item = self.tree.GetSelection() item.SetText(dlg.Text) self.tree.RefreshSelected() item.SetHilight(False) item.SetHilight(True)
def OnAddFigure(self, event): if len(DataStore.getData()) == 0: return nameDlg = displayDialogs.EditNameDialog(self, '') if (nameDlg.ShowModal() == wx.ID_OK): newFig = Figure(nameDlg.Text, [dv.Subplot()], 1, (1,1), (0,1)) currFig = FigureStore.getSelectedFigure() FigureStore.add(newFig) dv.switchFigures(self.facsPlotPanel, currFig, newFig) self.facsPlotPanel.subplots = [] self.addSubplot() self.treeCtrlPanel.updateTree() nameDlg.Destroy()
def selectItemTreeSelection(self, rightClick=False): """ Using the selected tree item, set the corresponding object in the data store as the current selection. """ item = self.getSanitizedItemSelectionData() if item is not None: if item[0] is DATA_SET_ITEM: self.applyToSelection(DataStore.selectDataSet, FacsData.selectClustering) if item[0] is FIGURE_SET_ITEM and not rightClick: if item[1] != FigureStore.getSelectedIndex(): currFig = FigureStore.getSelectedFigure() newFig = FigureStore.get(item[1]) switchFigures(self.Parent.TopLevelParent.facsPlotPanel, currFig, newFig, True) self.Parent.TopLevelParent.selectAxes(newFig.axes) FigureStore.setSelectedFigure(item[1])
def OnLoadState(self, event): from data.io import loadState if len(DataStore.getData()) > 0: dlgWarn = wx.MessageDialog(self, 'This action may overwrite currently loaded datasets and/or plots.\n\nContinue anyway?', 'Warning', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING) if dlgWarn.ShowModal() == wx.ID_NO: dlgWarn.Destroy() return dlgWarn.Destroy() formats = "FIND Project File (*.find)|*.find" dlg = wx.FileDialog(self, "Select saved project", self.dirname, "", formats, wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: try: loadState(dlg.Directory, dlg.Filename) except error.ProjectLoadingError: return # Load all Figures with Subplot instances from the stored dicts for fID in FigureStore.getFigures(): fig = FigureStore.get(fID) splots = [] for plot in fig.subplots: s = dv.Subplot() s.load(plot) s.parent = self.facsPlotPanel.figure splots.append(s) fig.subplots = splots currFigure = FigureStore.getSelectedFigure() self.facsPlotPanel.subplots = currFigure.subplots self.facsPlotPanel.SelectedSubplotIndex = currFigure.selectedSubplot self.facsPlotPanel.updateAxes(currFigure.axes, False) self.facsPlotPanel.updateSubplotGrid(currFigure.grid[0], currFigure.grid[1], True) self.chkLinked.Value = self.facsPlotPanel.CurrentSubplotLinked labels = DataStore.getCurrentDataSet().labels if DataStore.getCurrentDataSet() is not None else [] self.updateAxesList(labels, currFigure.axes) self.treeCtrlPanel.updateTree() self.statusbar.SetStatusText("Project loaded from %s" % dlg.Path, 0) dlg.Destroy()
def OnSaveState(self, event): from data.io import saveState dlg = wx.FileDialog(self, "Save project to file", "", "", "*.find", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) if dlg.ShowModal() == wx.ID_OK and dlg.Filename: if not '.find' in dlg.Filename: dlg.Filename = dlg.Filename + '.find' dlg.Path = dlg.Path + '.find' dv.saveToFigure(self.facsPlotPanel, FigureStore.getSelectedFigure()) saveState(dlg.Directory, dlg.Filename) self.statusbar.SetStatusText("Project saved to %s" % dlg.Path, 0) dlg.Destroy()
def loadState(dir, filename): """ Restore the system state as stored to disk. @type dir: string @param path: The directory under which the the saved system state is stored @type filename: str @param filename: The name of the saved project file (.find) @rtype: tuple @return: A list of subplot settings (dicts) retrieved from the file, The index of the currently selected subplot, The currently selected axes, The number of rows and columns in the figure (grid size) """ store = shelve.open(os.path.join(dir, filename)) #store = dbopen(os.path.join(dir, filename)) datakeys = store['data'] try: bindata = np.load(os.path.join(dir,store['binfile'])) except IOError: bindata = None except BadZipfile: wx.MessageBox('The file \'%s\' may have become corrupted. Project loading has been cancelled' % store['binfile'], 'Data Loading Error', wx.OK|wx.ICON_ERROR) raise ProjectLoadingError('BadZipfile: %s' % os.path.join(dir,store['binfile'])) # Parse data sets for dID in datakeys: dStr = 'data-%s' % dID dsett = store[dStr] ann = dsett['annotations'] if 'annotations' in dsett else {} ana = dsett['analysis'] if 'analysis' in dsett else {} fdata = FacsData(dsett['filename'], dsett['labels'], bindata[dStr], annotations=ann, analysis=ana, parent=dsett['parent']) fdata.displayname = dsett['displayname'] fdata.ID = dsett['ID'] fdata.children = dsett['children'] fdata.selDims = dsett['selDims'] fdata.nodeExpanded = dsett['nodeExpanded'] # Parse clusterings for cID in dsett['clustering']: cStr = 'clust-%i-%i' % (dID, cID) csett = store[cStr] clusterIDs = bindata[cStr] fdata.addClustering(csett['method'], clusterIDs, csett['opts'], cID) fdata.clusteringSelDims[cID] = csett['clusteringSelDims'] fdata.infoExpanded[cID] = csett['infoExpanded'] DataStore.add(fdata) DataStore.selectDataSet(store['current-data']) # Figures if 'figures' in store: for fStr in store['figures']: fDict = store[fStr] splots = [] for pStr in fDict['subplots']: splots.append(store[pStr]) fDict['subplots'] = splots f = Figure() f.load(fDict) FigureStore.add(f) # handle older save files w/o Figure support else: # load the saved subplots into a new 'Default' Figure plots = [] for pStr in store['plots']: plots.append(store[pStr]) defFig = Figure('Default', plots, store['current-subplot'], store['grid'], store['selected-axes']) FigureStore.add(defFig) if 'current-figure' in store: FigureStore.setSelectedFigure(store['current-figure']) else: FigureStore.setSelectedFigure(0)
def saveState(dir, filename): """ Save a representation of the system state: All the loaded data sets, their clusterings, any transformations or analyses (future), and all plots. The state is saved in JSON format based on a dict of the following form: data: list of IDs binfile: the filename of the binary file used to store all the actual data data-dID: dict of settings belonging to a FacsData instance clust-dID-cID: a dict of attributes belonging to a clustering figures: list of figureID strings fig-ID: A dict for each figure keyed on the ID. The subplot attribute here is replaced with a list of fig-ID-p-ID strings for locating subplot dicts fig-ID-p-ID: A dict for each subplot in each figure keyed on fig ID and plot ID. current-data: data ID current-figure: figure ID """ store = shelve.open(os.path.join(dir, filename)) #store = dbopen(os.path.join(dir, filename), 'c', format='csv') # The actual numeric data will be stored in a separate binary file using # the numpy savez() method allowing for efficient storage/retrieval of data binfile = '%s.npz' % filename bindata = {} store['data'] = DataStore.getData().keys() store['binfile'] = binfile for dID in DataStore.getData(): fdata = DataStore.get(dID) dStr = 'data-%i' % dID dfname = fdata.filename if (fdata.filename is not '') else binfile bindata[dStr] = fdata.data store[dStr] = {'filename': dfname, 'displayname': fdata.displayname, 'labels': fdata.labels, 'annotations': fdata.annotations, 'analysis': fdata.analysis, 'ID': fdata.ID, 'parent': fdata.parent, 'children': fdata.children, 'selDims': fdata.selDims, 'clustering': fdata.clustering.keys(), 'nodeExpanded': fdata.nodeExpanded, 'selectedClustering': fdata.selectedClustering} # clusterings for cID in fdata.clustering: cStr = 'clust-%i-%i' % (dID, cID) csett = {'method': fdata.methodIDs[cID], 'opts': fdata.clusteringOpts[cID], 'clusteringSelDims': fdata.clusteringSelDims[cID], 'infoExpanded': fdata.infoExpanded[cID]} store[cStr] = csett bindata[cStr] = fdata.clustering[cID] # figures sfigs = [] for figID in FigureStore.getFigures(): fig = FigureStore.get(figID) fStr = 'fig-%i' % figID d = dict(fig.__dict__) splots = packSubplots(store, figID, fig.subplots) d['subplots'] = splots store[fStr] = d sfigs.append(fStr) store['figures'] = list(sfigs) # other store['current-data'] = DataStore.getCurrentIndex() store['current-figure'] = FigureStore.getSelectedIndex() # write out settings data store.close() # write out numeric data to binary file np.savez(os.path.join(dir, binfile), **bindata)
def OnOpen(self, event): """ Opens a FACS data file, parses it, and updates the FacsPlotPanel instance. """ # retrieve the I/O methods for inputting files inputMethods = [m[2]() for m in io.AvailableMethods().values()] formats = '|'.join([m.FileType for m in inputMethods if io.FILE_INPUT in m.register()]) allLabels = [] allColArr = [] allDims = [] fColsMoved = False numLoaded = 0 # keep track of the common number of dimensions for datasets numDims = DataStore.getCurrentDataSet() if numDims is not None: numDims = len(numDims.labels) dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", formats, wx.FD_OPEN|wx.FD_MULTIPLE|wx.FD_CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: #TODO: move to data.io module? # process each file selected for n, path in enumerate(dlg.Paths): self.statusbar.SetStatusText('loading: ' + path, 0) try: (labels, data, annotations) = io.loadDataFile(path, window=self) except TypeError: # if there was an error loading the file, # loadDataFile should return None, so skip this file continue # make sure the new file matches dimensions of loaded files if numDims is None: numDims = len(labels) elif len(labels) != numDims: wx.MessageBox("Error loading file: %s\n\nThe number of channels does not match those in currently loaded datasets. \n\nThis file will not be loaded." % dlg.Filenames[n], "File Error", wx.OK | wx.ICON_ERROR) continue # Give the user a brief preview of the data (10 rows) and allow # column rearrangement and renaming if (not allLabels): dgridDlg = displayDialogs.SampleDataDisplayDialog(self, data[0:10,:], labels) if (dgridDlg.ShowModal() == wx.ID_OK): ca = dgridDlg.ColumnArrangement lbls = dgridDlg.ColumnLabels # Reassign the column labels labels = [lbls[i] for i in ca] if dgridDlg.ApplyToAll: allLabels = list(labels) allColArr = list(ca) # Rearrange the data columns if (dgridDlg.ColumnsMoved): fColsMoved = True data = dh.reorderColumns(data, ca) else: dgridDlg.Destroy() continue dgridDlg.Destroy() else: labels = list(allLabels) if fColsMoved: data = dh.reorderColumns(data, allColArr) # update the DataStore DataStore.add(FacsData(dlg.Filenames[n], labels, data, annotations=annotations)) numLoaded += 1 if n == 0: self.updateAxesList(labels) if (not allDims): # Allow the user to choose columns for use in analysis dimDlg = displayDialogs.DimensionExclusionDialog(self, labels) dimDlg.Size=(dimDlg.Size[0]*.75, dimDlg.Size[1]*.8) if (dimDlg.ShowModal() == wx.ID_OK): DataStore.getCurrentDataSet().selDims = dimDlg.SelectedDimensions if (dimDlg.ApplyToAll): allDims = list(dimDlg.SelectedDimensions) dimDlg.Destroy() else: DataStore.getCurrentDataSet().selDims = list(allDims) # update the panel self.facsPlotPanel.updateAxes([0,1]) if (len(self.facsPlotPanel.subplots) == 0 or len(dlg.Paths) > 1): self.facsPlotPanel.addSubplot(DataStore.getCurrentIndex()) # Create an n/2 x 2 grid for the n selected data files if (numLoaded > 1): self.facsPlotPanel.updateSubplotGrid(int(math.ceil(numLoaded/2.0)), 2) self.statusbar.SetStatusText('All data files loaded.') if FigureStore.isEmpty(): fig = Figure('Default', self.facsPlotPanel.subplots, 1, self.facsPlotPanel.Grid, self.facsPlotPanel.SelectedAxes) FigureStore.add(fig) self.treeCtrlPanel.updateTree() dlg.Destroy()