def _tool_bars_default(self): xls = True try: import xlwt except ImportError: xls = False pdf = True try: from reportlab import Version except ImportError: pdf = False tb1 = SToolBar(SGroup(ToggleStatusAction(), SummaryTableAction(), AppendSummaryTableAction()), SGroup(AppendTableAction()), image_size=(16, 16)) actions = [] if pdf: actions.append(MakePDFTableAction()) if xls: actions.append(MakeXLSTableAction()) actions.append(MakeCSVTableAction()) tb2 = SToolBar(*actions, image_size=(16, 16)) # orientation='vertical' # ) return [tb1, tb2]
def _tool_bars_default(self): tb = SToolBar( SampleLoadingAction(), # IsolateChamberAction(), # EvacuateChamberAction(), # FinishChamberChangeAction(), image_size=(16, 16)) tb2 = SToolBar(AutoReloadAction()) return [tb, tb2]
class SampleEntryTask(BaseManagerTask): name = 'Sample' id = 'pychron.entry.sample.task' tool_bars = [ SToolBar(SaveAction()), SToolBar(DumpAction(), LoadAction(), RecoverAction()), SToolBar(ClearAction()) ] def activated(self): self.manager.activated() def prepare_destroy(self): self.manager.prepare_destroy() def create_central_pane(self): return SampleEntryPane(model=self.manager) def create_dock_panes(self): return [SampleEditorPane(model=self.manager)] # toolbar handlers def clear(self): self.manager.clear() def save(self): self.manager.save() def load(self): p = self.open_file_dialog(default_directory=paths.sample_dir) if p: self.manager.load(p) def recover(self): p = os.path.join(paths.sample_dir, '.last.yaml') if os.path.isfile(p): self.manager.load(p) def dump(self): p = self.save_file_dialog(default_directory=paths.sample_dir) # p = '/Users/ross/Sandbox/sample_entry.yaml' if p: self.manager.dump(p) # defaults def _manager_default(self): dvc = self.application.get_service(DVC_PROTOCOL) dvc.connect() return SampleEntry(application=self.application, dvc=dvc) def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.entry.sample.editor'))
class SamplePrepTask(BaseManagerTask): name = 'Sample Prep' id = 'pychron.entry.sample.prep.task' tool_bars = [SToolBar(LocateSampleAction())] def activated(self): self.manager.activated() def prepare_destroy(self): self.manager.prepare_destroy() def create_central_pane(self): return SamplePrepPane(model=self.manager) def create_dock_panes(self): panes = [ SamplePrepFilterPane(model=self.manager), SamplePrepSessionPane(model=self.manager) ] return panes def locate_sample(self): self.debug('locate sample') self.manager.locate_sample() def _manager_default(self): dvc = self.application.get_service(DVC_PROTOCOL) dvc.connect() return SamplePrep(application=self.application, dvc=dvc) def _default_layout_default(self): return TaskLayout( left=VSplitter(PaneItem('pychron.entry.sample.session'), PaneItem('pychron.entry.sample.filter')))
class VisualElProgrammerTask(BaseTask): model = Instance(ExtractionLineScriptWriter, ()) tool_bars = [SToolBar(GenericSaveAction(), GenericSaveAsAction())] def activated(self): self.model.set_default_states() def new(self): self.model.new() return True def open(self, path=None): return self.model.open_file(path) def save_as(self): self.model.save_as() def save(self): self.model.save() def create_central_pane(self): return CentralPane(model=self.model) def create_dock_panes(self): return [ControlPane(model=self.model)] def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.pyscript.visual.control'))
class CanvasDesignerTask(BaseTask): name = 'Canvas Designer' tool_bars = [SToolBar(OpenAction(), SaveAction() )] designer = Instance(Designer) def _designer_default(self): return Designer() def open(self): print 'asfsfdsf open' p = os.path.join(paths.canvas2D_dir, 'canvas.xml' ) self.designer.open_xml(p) def save(self): p = os.path.join(paths.canvas2D_dir, 'canvas.xml' ) self.designer.save_xml(p) #================================================================ # Task interface #================================================================ def create_central_pane(self): return CanvasDesignerPane(model=self.designer)
def _tool_bars_default(self): tb = SToolBar(IsolateChamberAction(), EvacuateChamberAction(), FinishChamberChangeAction(), image_size=(16, 16)) return [ tb, ]
def __init__(self, *args, **kw): super(PyScriptTask, self).__init__(*args, **kw) self.bind_preferences() if self.use_git_repo: if not next((ti for ti in self.tool_bars if ti.id == 'pychron.pyscript.git_toolbar'), None): self.tool_bars.append( SToolBar(CommitChangesAction(), name='pychron.pyscript.git_toolbar'))
class SensitivityEntryTask(BaseManagerTask): name = 'Sensitivity Entry' tool_bars = [ SToolBar( SaveSensitivityAction(), AddSensitivityAction(), image_size=(16, 16) ), ] def activated(self): self.manager.activate() def create_central_pane(self): return SensitivityPane(model=self.manager) # def create_dock_panes(self): # return [ # IrradiationPane(model=self.manager), # ImporterPane(model=self.extractor), # IrradiationEditorPane(model=self.manager) # ] # @on_trait_change('extractor:update_irradiations_needed') # def _update_irradiations(self): # self.manager.updated = True # =========================================================================== # GenericActon Handlers # =========================================================================== def save_as(self): self.debug('sensitivity entry save as') self.save() def save(self): self.debug('sensitivity entry save') self.manager.save() def add(self): self.debug('sensitivity entry add') self.manager.add() # =============================================================================== # defaults # =============================================================================== def _manager_default(self): man = self.application.get_service('pychron.database.isotope_database_manager.IsotopeDatabaseManage') return SensitivityEntry(db=man.db)
class SensitivityEntryTask(BaseManagerTask): name = 'Sensitivity Entry' tool_bars = [ SToolBar(SaveSensitivityAction(), AddSensitivityAction(), image_size=(16, 16)), ] def activated(self): self.manager.activate() def create_central_pane(self): return SensitivityPane(model=self.manager) # def create_dock_panes(self): # return [ # IrradiationPane(model=self.manager), # ImporterPane(model=self.extractor), # IrradiationEditorPane(model=self.manager) # ] # =========================================================================== # GenericActon Handlers # =========================================================================== def save_as(self): self.debug('sensitivity entry save as') self.save() def save(self): self.debug('sensitivity entry save') self.manager.save() def add(self): self.debug('sensitivity entry add') self.manager.add() # =============================================================================== # defaults # =============================================================================== def _manager_default(self): dvc = self.application.get_service('pychron.dvc.dvc.DVC') return SensitivityEntry(dvc=dvc)
class LoadingTask(BaseManagerTask): name = 'Loading' load_pane = Any tool_bars = [SToolBar(SaveLoadingPDFAction(), ConfigurePDFAction()), SToolBar(SaveLoadingDBAction())] def activated(self): if self.manager.verify_database_connection(inform=True): if self.manager.load(): self.manager.username = globalv.username if self.manager.setup(): bind_preference(self.manager, 'save_directory', 'pychron.loading.save_directory') def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.loading.controls'), right=PaneItem('pychron.loading.positions')) def prepare_destroy(self): self.manager.dvc.close_session() def create_dock_panes(self): control_pane = LoadControlPane(model=self.manager) table_pane = LoadTablePane(model=self.manager) return [control_pane, table_pane] def create_central_pane(self): self.load_pane = LoadPane(model=self.manager) return self.load_pane def save(self): self.manager.save() # actions # def set_entry(self): # self.manager.set_entry() # # def set_info(self): # self.manager.set_info() # # def set_edit(self): # self.manager.set_edit() def configure_pdf(self): self.manager.configure_pdf() def save_loading_pdf(self): self.manager.save_pdf() def save_loading_db(self): self.manager.save(inform=True) def save_tray_pdf(self): self.manager.save_tray_pdf() # def generate_results(self): # self.manager.generate_results() def _prompt_for_save(self): if self.manager.dirty: message = 'You have unsaved changes. Save changes to Database?' ret = self._handle_prompt_for_save(message) if ret == 'save': return self.manager.save() return ret return True
class PyScriptTask(EditorTask, ScriptExecutorMixin): id = 'pychron.pyscript.task' name = 'PyScript' kind = String kinds = List(['Extraction', 'Measurement']) commands_pane = Instance(CommandsPane) script_browser_pane = Instance(ScriptBrowserPane) command_editor_pane = Instance(CommandEditorPane) context_editor_pane = Instance(ContextEditorPane) repo_manager = Instance('pychron.git_archive.repo_manager.GitRepoManager') repo_pane = None wildcard = '*.py' _default_extension = '.py' auto_detab = Bool(True) # _current_script = Any # use_trace = Bool(False) # trace_delay = Int(50) description = String tool_bars = [ SToolBar(JumpToGosubAction(), ExpandGosubsAction(), MakeGosubAction()), ] use_git_repo = Bool _on_close = None _on_save_as = None def __init__(self, *args, **kw): super(PyScriptTask, self).__init__(*args, **kw) self.bind_preferences() if self.use_git_repo: if not next((ti for ti in self.tool_bars if ti.id == 'pychron.pyscript.git_toolbar'), None): self.tool_bars.append( SToolBar(CommitChangesAction(), name='pychron.pyscript.git_toolbar')) def set_on_close_handler(self, func): self._on_close = func def set_on_save_as_handler(self, func): self._on_save_as = func def commit_changes(self): self.repo_manager.commit_dialog() if self.active_editor: self.repo_manager.load_file_history(self.active_editor.path) def make_gosub(self): editor = self.has_active_editor() if editor: editor.make_gosub() def expand_gosubs(self): editor = self.has_active_editor() if editor: text = editor.expand_gosub() editor = editor.__class__() if self.editor_area: self.editor_area.add_editor(editor) self.editor_area.activate_editor(editor) editor.set_text(text) def jump_to_gosub(self): editor = self.has_active_editor() if editor: editor.jump_to_gosub() # root = os.path.dirname(self.active_editor.path) # name = self.active_editor.get_active_gosub() # if name: # self._open_pyscript(name, root) # def execute_script(self, *args, **kw): # return self._do_execute(*args, **kw) def find(self): if self.active_editor: self.active_editor.control.enable_find() def replace(self): if self.active_editor: self.active_editor.control.enable_replace() def new(self): # todo ask for script type info = self.edit_traits(view='kind_select_view') if info.result: self._open_editor(path='') return True def kind_select_view(self): v = okcancel_view(UItem('kind', editor=EnumEditor(name='kinds')), title='Select Pyscript kind') return v # task protocol def activated(self): super(PyScriptTask, self).activated() self._use_git_repo_changed(self.use_git_repo) def bind_preferences(self): self._preference_binder('pychron.pyscript', ('auto_detab', 'use_git_repo')) if self.use_git_repo: self._preference_binder('pychron.pyscript', ('remote', ), obj=self.repo_manager) def create_dock_panes(self): self.commands_pane = CommandsPane() self.command_editor_pane = CommandEditorPane() self.control_pane = ControlPane(model=self) self.script_browser_pane = ScriptBrowserPane() self.context_editor_pane = ContextEditorPane() panes = [ self.commands_pane, self.command_editor_pane, self.control_pane, DescriptionPane(model=self), self.script_browser_pane, self.context_editor_pane ] if self.use_git_repo: self.repo_pane = RepoPane(model=self.repo_manager) self.repo_manager.on_trait_change(self._handle_path_change, 'path_dirty') panes.append(self.repo_pane) return panes def save_as(self): if super(PyScriptTask, self).save_as(): if self._on_save_as: self._on_save_as() # private def _prompt_for_save(self): ret = super(PyScriptTask, self)._prompt_for_save() if self.use_git_repo: # check for uncommitted changes if self.repo_manager.has_staged(): return self.repo_manager.commit_dialog() if ret: if self._on_close: self._on_close() return ret # def _do_execute(self, name=None, root=None, kind='Extraction', **kw): # self._start_execute() # # self.debug('do execute') # # self._current_script = None # # if not (name and root and kind): # ae = self.active_editor # if isinstance(ae, ExtractionEditor): # root, name = os.path.split(ae.path) # kind = self._extract_kind(ae.path) # # if name and root and kind: # ret = self._execute_extraction(name, root, kind, **kw) # self.executing = False # return ret # def _execute_extraction(self, name, root, kind, new_thread=True, # delay_start=0, # on_completion=None, # context=None, # manager=None): # from pychron.pyscripts.extraction_line_pyscript import ExtractionPyScript # # klass = ExtractionPyScript # if kind == 'Laser': # from pychron.pyscripts.laser_pyscript import LaserPyScript # # klass = LaserPyScript # elif kind == 'Spectrometer': # from pychron.pyscripts.spectrometer_pyscript import SpectrometerPyScript # klass = SpectrometerPyScript # # script = klass(application=self.application, # manager=manager, # root=root, # name=add_extension(name, '.py'), # runner=self._runner) # # if script.bootstrap(): # script.set_default_context(**context) # try: # script.test() # except Exception as e: # return # self._current_script = script # # # script.setup_context(extract_device='fusions_diode') # # if self.use_trace: # self.active_editor.trace_delay = self.trace_delay # # ret = script.execute(trace=self.use_trace, new_thread=new_thread, delay_start=delay_start, # on_completion=on_completion) # return not script.is_canceled() and ret # def _start_execute(self): # self.debug('start execute') # # # make a script runner # self._runner = None # runner = self._runner_factory() # if runner is None: # return # else: # self._runner = runner # return True def _cancel_execute(self): self.debug('cancel execute') if self._current_script: self._current_script.cancel() def _default_directory_default(self): return paths.scripts_dir def _save_file(self, path): self.active_editor.dump(path) if self.use_git_repo: self.repo_manager.add(path, commit=False) return True def _open_file(self, path, **kw): self.info('opening pyscript: {}'.format(path)) return self._open_editor(path, **kw) def _extract_kind(self, path): with open(path, 'r') as rfile: for line in rfile: if line.startswith('#!'): return line.strip()[2:] def _open_editor(self, path, kind=None): if path: kind = self._extract_kind(path) if kind == 'Measurement': klass = MeasurementEditor else: klass = ExtractionEditor dets, isotopes, valves = [], [], [] man = self.application.get_service( 'pychron.spectrometer.base_spectrometer_manager.BaseSpectrometerManager' ) if man: dets = [di.name for di in man.spectrometer.detectors] isotopes = man.spectrometer.isotopes man = self.application.get_service( 'pychron.extraction_line.extraction_line_manager.ExtractionLineManager' ) if man: valves = man.get_valve_names() editor = klass(path=path, auto_detab=self.auto_detab, valves=valves, isotopes=isotopes, detectors=dets) super(PyScriptTask, self)._open_editor(editor) return True def _open_pyscript(self, new, root): new = new.replace('/', ':') new = add_extension(new, '.py') paths = new.split(':') for editor in self.editor_area.editors: if editor.name == paths[-1]: self.activate_editor(editor) break else: p = os.path.join(root, *paths) if os.path.isfile(p): self._open_file(p) else: self.warning_dialog('File does not exist {}'.format(p)) def _get_example(self): if self.selected: return self.selected.example return '' # handlers def _handle_path_change(self, new): self.debug('path changed {}'.format(new)) for ei in self.editor_area.editors: if ei.path == new: ei.load() def _use_git_repo_changed(self, new): self.debug('use git repo changed {}'.format(new)) if new: self.debug('initialize git repo at {}'.format(paths.scripts_dir)) if self.repo_manager.init_repo(paths.scripts_dir): pass # self.repo_manager.add_unstaged(None, extension='.py', use_diff=True) else: for p in (paths.measurement_dir, paths.extraction_dir, paths.post_equilibration_dir, paths.post_measurement_dir): self.debug('add unstaged files from {}'.format(p)) self.repo_manager.add_unstaged(p, extension='.py', use_diff=False) self.debug('committing unstaged pyscripts') self.repo_manager.commit('auto added unstaged pyscripts') def _active_editor_changed(self): if self.active_editor: self.commands_pane.name = self.active_editor.kind self.commands_pane.command_objects = self.active_editor.commands.command_objects self.commands_pane.commands = self.active_editor.commands.script_commands self.script_browser_pane.root = os.path.dirname( self.active_editor.path) self.context_editor_pane.editor = self.active_editor.context_editor if self.use_git_repo: self.repo_manager.selected = self.active_editor.path @on_trait_change('command_editor_pane:insert_button') def _insert_fired(self): self.active_editor.insert_command( self.command_editor_pane.command_object) @on_trait_change('commands_pane:command_object') def _update_selected(self, new): self.command_editor_pane.command_object = new if new: self.description = new.description @on_trait_change('_current_script:trace_line') def _handle_lineno(self, new): self.active_editor.highlight_line = new @on_trait_change('script_browser_pane:dclicked') def _handle_selected_file(self): new = self.script_browser_pane.selected self.debug('selected file {}'.format(new)) root = self.script_browser_pane.root self._open_pyscript(new, root) @on_trait_change('active_editor:gosub_event') def _handle_selected_gosub(self, new): self.debug('selected gosub {}'.format(new)) if new: root = os.path.dirname(self.active_editor.path) self._open_pyscript(new, root) # self.active_editor.trait_set(selected_gosub='', trait_change_notify=False) @on_trait_change('active_editor:selected_command') def _handle_selected_command(self, new): self.debug('selected command {}'.format(new)) if new: self.commands_pane.set_command(new) def _runner_factory(self): runner = self.application.get_service( 'pychron.extraction_line.ipyscript_runner.IPyScriptRunner') # get the extraction line manager's mode # man = self._get_el_manager() # # if man is None: # self.warning_dialog('No Extraction line manager available') # mode = 'normal' # else: # mode = man.mode # # if mode == 'client': # # em = self.extraction_line_manager # from pychron.envisage.initialization.initialization_parser import InitializationParser # # ip = InitializationParser() # # elm = ip.get_plugin('Experiment', category='general') # elm = ip.get_plugin('ExtractionLine', category='hardware') # runner = elm.find('runner') # host, port, kind = None, None, None # # if runner is not None: # comms = runner.find('communications') # host = comms.find('host') # port = comms.find('port') # kind = comms.find('kind') # # if host is not None: # host = host.text # if host else 'localhost' # if port is not None: # port = int(port.text) # if port else 1061 # if kind is not None: # kind = kind.text # if kind else 'udp' # # from pychron.extraction_line.pyscript_runner import RemotePyScriptRunner # # runner = RemotePyScriptRunner(host, port, kind) # else: # from pychron.extraction_line.pyscript_runner import PyScriptRunner # # runner = PyScriptRunner() return runner # defaults def _repo_manager_default(self): from pychron.git_archive.repo_manager import GitRepoManager return GitRepoManager(application=self.application) def _default_layout_default(self): # left = Splitter(Tabbed(PaneItem('pychron.pyscript.commands', height=300, width=125), # PaneItem('pychron.pyscript.script_browser')), # PaneItem('pychron.pyscript.commands_editor', height=100, width=125), # orientation='vertical') # bottom = PaneItem('pychron.pyscript.description') left = VSplitter(PaneItem('pychron.pyscript.commands'), PaneItem('pychron.pyscript.commands_editor')) if self.use_git_repo: right = Tabbed(PaneItem('pychron.pyscript.repo'), PaneItem('pychron.pyscript.context_editor')) else: right = VSplitter( PaneItem('pychron.pyscript.context_editor', width=200), PaneItem('pychron.pyscript.script_browser', width=200)) return TaskLayout(id='pychron.pyscript', left=left, right=right)
class InterpolationTask(AnalysisEditTask): references_pane = Any references_adapter = ReferencesAdapter references_pane_klass = ReferencesPane default_reference_analysis_type = 'air' tool_bars = [SToolBar(DatabaseSaveAction(), BinAnalysesAction())] def bin_analyses(self): self.debug('binning analyses') if self.active_editor: self.active_editor.bin_analyses() def create_dock_panes(self): panes = super(InterpolationTask, self).create_dock_panes() self._create_references_pane() return panes + [self.references_pane] def _create_references_pane(self): self.references_pane = self.references_pane_klass( adapter_klass=self.references_adapter) self.references_pane.load() @on_trait_change('references_pane:[items, update_needed, dclicked]') def _update_references_runs(self, obj, name, old, new): if name == 'dclicked': if new: if isinstance(new.item, (IsotopeRecordView, Analysis)): self._recall_item(new.item) elif not obj._no_update: if self.active_editor: self.active_editor.references = self.references_pane.items @on_trait_change('references_pane:previous_selection') def _update_rp_previous_selection(self, obj, name, old, new): self._set_previous_selection(obj, new) @on_trait_change('references_pane:[append_button, replace_button]') def _append_references(self, obj, name, old, new): is_append = name == 'append_button' if self.active_editor: refs = None if is_append: refs = self.active_editor.references s = self._get_selected_analyses(refs) if s: if is_append: refs = self.active_editor.references refs.extend(s) else: self.active_editor.references = s @on_trait_change('active_editor:references') def _update_references(self): if self.references_pane: self.references_pane.items = self.active_editor.references #def _handle_key_pressed(self, c): # s = self.data_selector.selector.selected # if c == 'r': # self.references_pane.items.extend(s) # elif c == 'R': # self.references_pane.items = s def _load_references(self, analyses, atype=None): if not hasattr(analyses, '__iter__'): analyses = (analyses, ) ds = [ai.rundate for ai in analyses] dt = timedelta(days=self.days_pad, hours=self.hours_pad) sd = min(ds) - dt ed = max(ds) + dt self.start_date = sd.date() self.end_date = ed.date() self.start_time = sd.time() self.end_time = ed.time() at = atype or self.analysis_type if self.analysis_type == DEFAULT_AT: self.analysis_type = at = self.default_reference_analysis_type ref = analyses[-1] exd = ref.extract_device ms = ref.mass_spectrometer self.trait_set(extraction_device=exd or 'Extraction Device', mass_spectrometer=ms or 'Mass Spectrometer', trait_change_notify=False) db = self.manager.db with db.session_ctx(): ans = db.get_analyses_date_range(sd, ed, analysis_type=at, mass_spectrometer=ms, extract_device=exd) ans = [self._record_view_factory(ai) for ai in ans] self.danalysis_table.set_analyses(ans) return ans def _do_easy_func(self): if self.active_editor: manager = EasyManager(db=self.manager.db, func=self._easy_func) manager.execute() manager.edit_traits() else: self.warning_dialog('No active tab') def _easy_func(self): raise NotImplementedError
class FluxTask(InterpolationTask): name = 'Flux' id = 'pychron.processing.flux' flux_editor_count = 1 unknowns_adapter = UnknownsAdapter references_adapter = ReferencesAdapter references_pane_klass = ReferencesPane unknowns_pane_klass = UnknownsPane analyses = List tool_bars = [SToolBar(DatabaseSaveAction())] update_on_level_change = False def find_associated_analyses(self): pass def activated(self): """ no need to do BaseBrowserTask.activated """ def create_dock_panes(self): panes = super(FluxTask, self).create_dock_panes() return panes + [ IrradiationPane(model=self.manager), AnalysesPane(model=self) ] def new_flux(self): from pychron.processing.tasks.flux.flux_editor import FluxEditor editor = FluxEditor(name='Flux {:03d}'.format(self.flux_editor_count), processor=self.manager) self._open_editor(editor) self.flux_editor_count += 1 # self.irradiation='NM-263' # self.level='E' @on_trait_change('manager:level') def _level_changed(self, new): if new: with self.manager.db.session_ctx(): level = self.manager.get_level(new) if self.active_editor: self.active_editor.level = level if level: refs, unks = self.manager.group_level(level) r, u = list(refs), list(unks) self.unknowns_pane.items = u self.references_pane.items = r # self.active_editor.set_items(u) # self.active_editor.references= r @on_trait_change('active_editor:tool:calculate_button') def _calculate_flux(self): if self.references_pane.items: editor = self.active_editor editor.monitor_positions = {} editor.positions_dirty = True editor.suppress_update = True db = self.manager.db with db.session_ctx(): geom = self._get_geometry() editor.geometry = geom def add_pos(i, use=False): if i.identifier: ref = db.get_labnumber(i.identifier) pid = ref.irradiation_position.position ident = ref.identifier sample = '' if ref.sample: sample = ref.sample.name cj = ref.selected_flux_history.flux.j cjerr = ref.selected_flux_history.flux.j_err x, y, r = geom[pid - 1] editor.add_position(int(pid), ident, sample, x, y, cj, cjerr, use) for ii in self.unknowns_pane.items: add_pos(ii) for ii in self.references_pane.items: add_pos(ii) editor.positions_dirty = True if editor.tool.data_source == 'database': self._calculate_flux_db(editor) else: self._calculate_flux_file(editor) # editor.rebuild_graph() # editor.set_predicted_j() editor.refresh_j() editor.suppress_update = False def _calculate_flux_file(self, editor): #p = self.open_file_dialog() p = '/Users/ross/Sandbox/flux_visualizer/Tray I NM-261.xls' if p: #open flux file parser if p.endswith('.xls'): parser = XLSFluxParser(path=p) else: parser = CSVFluxParser(path=p) irrad, level = parser.get_irradiation() geom = self._get_geometry(irrad=irrad, level=level) editor.geometry = geom n = parser.get_npositions() prog = self.manager.open_progress(n=n) for pos in parser.iterpositions(): pid = pos.hole_id prog.change_message('Loading Position {}'.format(pid)) #get x,y from geometry try: x, y, r = geom[pid - 1] editor.add_monitor_position(pid, pos.identifier, x, y, pos.j, pos.je) except IndexError: self.warning( 'Skipping hole {}. Only {} in this tray'.format( pid, len(geom))) prog.close() def _calculate_flux_db(self, editor): # reg = WeightedMeanRegressor() # reg.error_calc_type = editor.tool.mean_j_error_type error_kind = editor.tool.mean_j_error_type monitor_age = editor.tool.monitor_age print 'exception', error_kind # helper funcs def mean_j(ans): ufs = (ai.uF for ai in ans) fs, es = zip(*((fi.nominal_value, fi.std_dev) for fi in ufs)) av, werr = calculate_weighted_mean(fs, es) if error_kind == 'SD': n = len(fs) werr = (sum((av - fs)**2) / (n - 1))**0.5 elif error_kind == 'SEM, but if MSWD>1 use SEM * sqrt(MSWD)': mswd = calculate_mswd(fs, es) werr *= (mswd**0.5 if mswd > 1 else 1) # reg.trait_set(ys=fs, yserr=es) # uf = (reg.predict([0]), reg.predict_error([0])) uf = (av, werr) return ufloat(*calculate_flux(uf, monitor_age)) proc = self.manager db = proc.db with db.session_ctx(): refs = self.references_pane.items # ans, tcs = zip(*[db.get_labnumber_analyses(ri.identifier, omit_key='omit_ideo') # for ri in refs]) lns = [ri.identifier for ri in refs] tcs = db.get_labnumber_analyses(lns, omit_key='omit_ideo', count_only=True) prog = proc.open_progress(n=tcs, close_at_end=False) geom = self._get_geometry() editor = self.active_editor editor.geometry = geom editor.suppress_update = True for ri in refs: ais, n = db.get_labnumber_analyses(ri.identifier, omit_key='omit_ideo') if n: ref = ais[0] sj = ref.labnumber.selected_flux_history.flux.j sjerr = ref.labnumber.selected_flux_history.flux.j_err ident = ref.labnumber.identifier aa = proc.make_analyses(ais, progress=prog, calculate_age=True) # n = len(aa) dev = 100 # j = 0 # if n: j = mean_j(aa) if sj: dev = (j.nominal_value - sj) / sj * 100 if editor.tool.save_mean_j: db.save_flux(ident, j.nominal_value, j.std_dev, inform=False) sj, sjerr = j.nominal_value, j.std_dev d = dict(saved_j=sj, saved_jerr=sjerr, mean_j=nominal_value(j), mean_jerr=std_dev(j), dev=dev, n=n, use=True) editor.set_position_j(ident, **d) if editor.tool.auto_clear_cache: proc.remove_from_cache(aa) editor.suppress_update = False prog.close() def _get_geometry(self, irrad=None, level=None, holder=None): man = self.manager db = man.db with db.session_ctx(): if holder is None: if irrad is None: irrad = man.irradiation level = man.level level = db.get_irradiation_level(irrad, level) holder = level.holder else: holder = db.get_irradiation_holder(holder) geom = holder.geometry return [ struct.unpack('>fff', geom[i:i + 12]) for i in xrange(0, len(geom), 12) ] @on_trait_change( 'unknowns_pane:[items, update_needed, dclicked, refresh_editor_needed]' ) def _update_unknowns_runs(self, obj, name, old, new): if name == 'dclicked': if new: if isinstance(new.item, (IsotopeRecordView, Analysis)): self._recall_item(new.item) elif name == 'refresh_editor_needed': self.active_editor.rebuild() # else: # if not obj._no_update: # if self.active_editor: # self.active_editor.set_items(self.unknowns_pane.items) # if self.plot_editor_pane: # self.plot_editor_pane.analyses = self.unknowns_pane.items def _active_editor_changed(self): if self.active_editor: if self.controls_pane: tool = None if hasattr(self.active_editor, 'tool'): tool = self.active_editor.tool self.controls_pane.tool = tool # if self.unknowns_pane: # # if hasattr(self.unknowns_pane, 'previous_selections'): # # self.unknowns_pane.previous_selection = self.unknowns_pane.previous_selections[0] # if hasattr(self.active_editor, 'analyses'): # #if self.active_editor.unknowns: # self.unknowns_pane.items = self.active_editor.analyses def do_easy_flux(self): from pychron.easy_parser import EasyParser path = os.path.join(paths.dissertation, 'data', 'minnabluff', 'flux.yaml') ep = EasyParser(path=path) # db = self.manager.db doc = ep.doc('flux') # projects = doc['projects'] # identifiers = doc.get('identifiers') levels = doc.get('levels') # editor = FluxEditor(processor=self) # prog=self.manager.open_progress(n=len(levels)) if levels: editor = self.active_editor mon_age = doc.get('monitor_age', 28.201e6) editor.tool.monitor_ge = mon_age for li_str in levels: irrad, level = li_str.split(' ') # print irrad, level self.manager.irradiation = irrad self.manager.level = level # print self.manager # #unknowns and refs now loaded self._calculate_flux() # self._calculate_flux_db(self.active_editor) # # #update flux in db for all positions # editor.set_save_all(True) editor.set_save_unknowns(True) editor.save() self.information_dialog('Easy Flux Finished') # prog.close() return True def _default_layout_default(self): return TaskLayout( id='pychron.processing', left=HSplitter( VSplitter( PaneItem('pychron.processing.irradiation'), Tabbed(PaneItem('pychron.processing.unknowns'), PaneItem('pychron.processing.references'), PaneItem('pychron.processing.analyses')), PaneItem('pychron.processing.controls'))))
class IsotopeEvolutionTask(AnalysisEditTask): name = 'Isotope Evolutions' default_task_name = 'IsoEvo' iso_evo_editor_count = 1 id = 'pychron.processing.isotope_evolution', # auto_select_analysis = False tool_bars = [ SToolBar(DatabaseSaveAction(), FindAssociatedAction(), image_size=(16, 16)), SToolBar(SavePDFFigureAction()) ] def _default_layout_default(self): return TaskLayout( id='pychron.processing.isotope_evolution', left=HSplitter( browser_pane_item(), # Tabbed(PaneItem('pychron.browser'), # PaneItem('pychron.search.query') # ), VSplitter( Tabbed(PaneItem('pychron.plot_editor'), PaneItem('pychron.processing.unknowns')), PaneItem('pychron.processing.controls')))) def create_dock_panes(self): self.unknowns_pane = self._create_unknowns_pane() self.controls_pane = ControlsPane() self.plot_editor_pane = PlotEditorPane() panes = [ self.unknowns_pane, self.controls_pane, self.plot_editor_pane, self._create_browser_pane() ] return panes def new_isotope_evolution(self): editor = IsotopeEvolutionEditor(name='Iso Evo {:03d}'.format( self.iso_evo_editor_count), processor=self.manager) #selector = self.manager.db.selector # selector.queries[0].criterion = 'NM-251' # selector._search_fired() # selector = self.manager.db.selector # self.unknowns_pane.items = selector.records[150:160] # # editor.unknowns = self.unknowns_pane.items self._open_editor(editor) self.iso_evo_editor_count += 1 def find_associated_analyses(self): """ """ if not self.has_active_editor(): return if not isinstance(self.active_editor, IsotopeEvolutionEditor): self.warning_dialog( 'Find associated only available from Isotope Evolution tab.') return db = self.manager.db ret = self._get_find_parameters() if not ret: return model = ret uuids = [ai.uuid for ai in self.unknowns_pane.items] tans = [] atypes = model.get_atypes() ms = model.get_mass_spectrometers() if not (ms and atypes): self.information_dialog( 'Select a set of Analysis Types and Spectrometers') return with db.session_ctx(): progress = self.manager.open_progress(len(atypes)) found = [] for name, atype in atypes: progress.change_message('Finding associated {}'.format(atype)) lpost, hpost = model.get_posts() for mi in ms: ans = self._find_associated_analyses( db, lpost, hpost, atype, mi) ans = [ai for ai in ans if ai.uuid not in uuids] uuids.extend([ai.uuid for ai in ans]) tans.extend(ans) found.append((mi, name, len(ans))) progress.close() m = '\n'.join(['{} {} = {}'.format(*f) for f in found]) msg = 'Found Associated Analyses\n{}\n Continue?'.format(m) if self.confirmation_dialog(msg): # tans = [IsotopeRecordView(ai) for ai in tans] # ans = self.active_editor.analyses # ans.extend(tans) self.active_editor.set_items(tans, is_append=True) def _get_find_parameters(self): f = FindAssociatedParametersDialog() ais = self.active_editor.analyses if ais: unks = ais elif self.analysis_table.selected: ans = self.analysis_table.selected unks = ans[:] elif self.selected_samples: ans = self.analysis_table.analyses unks = ans[:] elif self.selected_projects: with self.manager.db.session_ctx(): ans = self._get_projects_analyzed_analyses( self.selected_projects) unks = [IsotopeRecordView(ai) for ai in ans] else: self.information_dialog( 'Select a list of projects, samples or analyses') return ts = [get_datetime(ai.timestamp) for ai in unks] lpost, hpost = min(ts), max(ts) f.model.nominal_lpost_date = lpost.date() f.model.nominal_hpost_date = hpost.date() f.model.nominal_lpost_time = lpost.time() f.model.nominal_hpost_time = hpost.time() ms = list(set([ai.mass_spectrometer for ai in unks])) f.model.available_mass_spectrometers = ms f.model.mass_spectrometers = ms info = f.edit_traits(kind='livemodal') if info.result: return f.model def _find_associated_analyses(self, db, lpost, hpost, atype, ms): ans = db.get_analyses_date_range(lpost, hpost, analysis_type=atype, mass_spectrometers=ms) if ans: self.debug('{} {} to {}. nanalyses={}'.format( atype, lpost, hpost, len(ans))) # ans = [ai for ai in ans if ai.uuid not in uuids] self.debug('new ans {}'.format(len(ans))) return ans def _get_projects_analyzed_analyses(self, projects): db = self.manager.db if not hasattr(projects, '__iter__'): projects = (projects, ) ans = [] test = lambda x: len(x.analyses) with db.session_ctx(): for pp in projects: ss = db.get_samples(project=pp.name) ans.extend([ ai for s in ss for li in s.labnumbers if test(li) for ai in li.analyses ]) return ans # =============================================================================== # equilibration tools # =============================================================================== def calculate_optimal_eqtime(self): if self.active_editor: self.active_editor.calculate_optimal_eqtime() # =============================================================================== # handlers # =============================================================================== # =============================================================================== # easy # =============================================================================== def do_easy_fit(self): self._do_easy(self._do_easy_fit) def _do_easy_fit(self, db, ep, prog): doc = ep.doc('iso_fits') projects = doc['projects'] unks = (ai for proj in projects \ for si in db.get_samples(project=proj) \ for ln in si.labnumbers \ for ai in ln.analyses) found = [] while 1: u = [] for _ in xrange(200): try: u.append(unks.next()) except (Exception, StopIteration), e: self.debug(traceback.print_exc()) break if u: self.active_editor.set_items(u, use_cache=False, progress=prog) found = self._easy_find_associated_analyses(found=found, use_cache=False, progress=prog) fits = doc['fit_isotopes'] filters = doc['filter_isotopes'] self.active_editor.save_fits(fits, filters, progress=prog) db.sess.commit() else: break return True
class LabnumberEntryTask(BaseManagerTask, BaseBrowserModel): name = 'Labnumber' id = 'pychron.entry.irradiation.task' clear_sample_button = Button refresh_needed = Event dclicked = Event tool_bars = [ SToolBar(SavePDFAction(), DatabaseSaveAction(), image_size=(16, 16)), SToolBar(GenerateIdentifiersAction(), PreviewGenerateIdentifiersAction(), image_size=(16, 16)), SToolBar(ClearSelectionAction()) ] invert_flag = Bool selection_freq = Int estimate_j_button = Button j = Float j_err = Float note = Str weight = Float include_recent = False _suppress_load_labnumbers = True def activated(self): if self.manager.verify_database_connection(inform=True): if self.db.connected: self.manager.activated() self.load_principal_investigators() self.load_projects(include_recent=False) def clear_selection(self): cs = ClearSelectionView() info = cs.edit_traits() if info.result: for s in self.manager.selected: for attr, value in cs.attributes(): setattr(s, attr, value) self.manager.refresh_table = True def get_igsns(self): self.info('Get IGSNs') igsn_repo = self.application.get_service( 'pychron.repo.igsn.IGSNRepository') if not igsn_repo.url: self.warning_dialog('No IGSN URL set in preferences. ' 'The url is required before proceeding. ') return self.manager.get_igsns(igsn_repo) def transfer_j(self): self.info('Transferring J Data') self.manager.transfer_j() def import_irradiation(self): self.manager.import_irradiation() def generate_tray(self): # p='/Users/ross/Sandbox/entry_tray' p = self.open_file_dialog() if p is not None: gm = GraphicModel() # op='/Users/ross/Pychrondata_dev/setupfiles/irradiation_tray_maps/newtrays/26_no_spokes.txt' gm.srcpath = p # gm.xmlpath=p # p = make_xml(p, # default_radius=radius, # default_bounds=bounds, # convert_mm=convert_mm, # use_label=use_label, # make=make, # rotate=rotate) # # # p = '/Users/ross/Sandbox/graphic_gen_from_csv.xml' # gm.load(p) gcc = GraphicGeneratorController(model=gm) info = gcc.edit_traits(kind='livemodal') if info.result: if self.confirmation_dialog( 'Do you want to save this tray to the database. Saving tray as "{}"' .format(gm.name)): self.manager.save_tray_to_db(gm.srcpath, gm.name) def save_pdf(self): if globalv.irradiation_pdf_debug: p = '/Users/ross/Sandbox/irradiation.pdf' else: p = self.save_file_dialog() if p: self.debug('saving pdf to {}'.format(p)) if self.manager.save_pdf(p): self.view_pdf(p) def make_irradiation_book_pdf(self): if globalv.entry_labbook_debug: p = '/Users/ross/Sandbox/irradiation.pdf' else: p = self.save_file_dialog() if p: self.manager.make_labbook(p) self.view_pdf(p) def generate_identifiers(self): self.manager.generate_identifiers() def preview_generate_identifiers(self): self.manager.preview_generate_identifiers() def import_irradiation_load_xls(self): if globalv.entry_irradiation_import_from_file_debug: path = self.open_file_dialog() else: path = '/Users/ross/Sandbox/template.xls' if path: self.manager.import_irradiation_load_xls(path) # def make_irradiation_load_template(self): # path = self.save_file_dialog() # if path: # # p = '/Users/ross/Sandbox/irrad_load_template.xls' # path = add_extension(path, '.xls') # self.manager.make_irradiation_load_template(path) # # self.information_dialog('Template saved to {}'.format(path)) # # self.view_xls(path) def import_sample_from_file(self): # path = self.open_file_dialog(default_directory=paths.root_dir, # wildcard='*.xls') path = '/Users/ross/Desktop/sample_import.xls' if path: from pychron.entry.loaders.xls_sample_loader import XLSSampleLoader sample_loader = XLSSampleLoader() sample_loader.do_loading(self.manager, self.manager.db, path) spnames = [] if self.selected_projects: spnames = [ni.name for ni in self.selected_projects] self.load_projects(include_recent=False) if spnames: sel = [si for si in self.projects if si.name in spnames] self.selected_projects = sel self._load_associated_samples() def import_sample_metadata(self): self.warning('Import sample metadata Deprecated') # path = '/Users/ross/Programming/git/dissertation/data/minnabluff/lithologies.xls' # path = '/Users/ross/Programming/git/dissertation/data/minnabluff/tables/TAS.xls' # path = '/Users/ross/Programming/git/dissertation/data/minnabluff/tables/environ.xls' # if not os.path.isfile(path): # path = self.open_file_dialog() # # if path: # self.manager.import_sample_metadata(path) def export_irradiation(self): from pychron.entry.export.export_selection_view import ExportSelectionView pref = self.application.preferences connection = { attr: pref.get('pychron.massspec.database.{}'.format(attr)) for attr in ('name', 'host', 'password', 'username') } es = ExportSelectionView(irradiations=self.manager.irradiations, default_massspec_connection=connection) info = es.edit_traits(kind='livemodal') if info.result: if not es.selected: self.warning_dialog('Please select Irradiation(s) to export') else: from pychron.entry.export.export_util import do_export do_export(self.manager.dvc, es.export_type, es.destination_dict, es.selected) def _manager_default(self): dvc = self.application.get_service('pychron.dvc.dvc.DVC') dvc.connect() return LabnumberEntry(application=self.application, dvc=dvc) # def _importer_default(self): # return ImportManager(db=self.manager.db, # connect=False) def _default_layout_default(self): return TaskLayout( left=Splitter( PaneItem('pychron.labnumber.irradiation'), Tabbed( # PaneItem('pychron.labnumber.extractor'), PaneItem('pychron.labnumber.editor')), orientation='vertical'), right=Splitter(PaneItem('pychron.entry.level'), PaneItem('pychron.entry.chronology'), PaneItem('pychron.entry.irradiation_canvas'), orientation='vertical')) def create_central_pane(self): return LabnumbersPane(model=self.manager) def create_dock_panes(self): iep = IrradiationEditorPane(model=self) self.labnumber_tabular_adapter = iep.sample_tabular_adapter return [ IrradiationPane(model=self.manager), ChronologyPane(model=self.manager), LevelInfoPane(model=self.manager), # ImporterPane(model=self.importer), iep, IrradiationCanvasPane(model=self.manager) ] # =========================================================================== # GenericActon Handlers # =========================================================================== def save_as(self): self.save() def save(self): self.warning_dialog( 'Please use "Data -> Database Save" to save changes to the database' ) def save_to_db(self): self.manager.save() def _estimate_j_button_fired(self): self.manager.estimate_j() @on_trait_change('selection_freq, invert_flag') def _handle_selection(self): if self.selection_freq: self.manager.select_positions(self.selection_freq, self.invert_flag) @on_trait_change('j,j_err, note, weight') def _handle_j(self, obj, name, old, new): if new: self.manager.set_selected_attr(new, name) def _selected_samples_changed(self, new): if new: ni = new[0] # self.manager.set_selected_attr(new.name, 'sample') self.manager.set_selected_attrs((ni.name, ni.material, ni.project), ('sample', 'material', 'project')) def _load_associated_samples(self, names=None): if names is None: if self.selected_projects: names = [ni.name for ni in self.selected_projects] db = self.db with db.session_ctx(): # load associated samples sams = db.get_samples(project=names) sams = [SampleRecordView(si) for si in sams] self.samples = sams self.osamples = sams # handlers def _dclicked_fired(self): self.selected_samples = [] def _clear_sample_button_fired(self): self.selected_samples = [] @on_trait_change('extractor:update_irradiations_needed') def _update_irradiations(self): self.manager.updated = True # def _generate_identifiers_button_fired(self): # self.generate_identifiers() # # def _preview_generate_identifiers_button_fired(self): # self.preview_generate_identifiers() # # def _add_project_button_fired(self): # # dvc = self.manager.dvc # # pr = ProjectEntry(dvc=self.manager.dvc) # # pr.available = dvc.get_project_names() # # if pr.do(): # # self.load_projects(include_recent=False) # # # # def _add_sample_button_fired(self): # # project = '' # # if self.selected_projects: # # project = self.selected_projects[0].name # # # # mats = self.db.get_material_names() # # sam = SampleEntry(dvc=self.manager.dvc, # # project=project, # # projects=[p.name for p in self.projects], # # materials=mats) # # if sam.do(): # # self._load_associated_samples() # # def _add_material_button_fired(self): # dvc = self.manager.dvc # mat = MaterialEntry(dvc=dvc) # mat.available = dvc.get_material_names() # mat.do() # # self._load_materials() # def _edit_project_button_fired(self): # pr = ProjectEntry(db=self.manager.db) # pr.edit_project(self.selected_projects) # # def _edit_sample_button_fired(self): # se = SampleEntry(db=self.manager.db) # sam = self.selected_samples # # se.edit_sample(sam.name, # self.selected_projects, # sam.material) # def _selected_projects_changed(self, old, new): if new: names = [ni.name for ni in new] self.debug('selected projects={}'.format(names)) self._load_associated_samples(names) def _prompt_for_save(self): self.manager.push_changes() if self.manager.dirty: message = 'You have unsaved changes. Save changes to Database?' ret = self._handle_prompt_for_save(message) if ret == 'save': return self.manager.save() return ret return True
class SpectrometerTask(EditorTask): scan_manager = Any name = 'Scan' id = 'pychron.spectrometer' _scan_editor = Instance(ScanEditor) tool_bars = [SToolBar(StopScanAction(), )] def stop_scan(self): self.debug('stop scan fired') editor = self.active_editor self.debug('active editor {}'.format(editor)) if editor: if isinstance(editor, (ScanEditor, PeakCenterEditor, CoincidenceEditor)): self.debug('editor stop') editor.stop() def do_coincidence(self): es = [ int(e.name.split(' ')[-1]) for e in self.editor_area.editors if isinstance(e, CoincidenceEditor) ] i = max(es) + 1 if es else 1 man = self.scan_manager.ion_optics_manager name = 'Coincidence {:02d}'.format(i) if man.setup_coincidence(): self._open_editor( CoincidenceEditor(model=man.coincidence, name=name)) man.do_coincidence_scan() def do_peak_center(self): es = [ int(e.name.split(' ')[-1]) for e in self.editor_area.editors if isinstance(e, PeakCenterEditor) ] i = max(es) + 1 if es else 1 man = self.scan_manager.ion_optics_manager name = 'Peak Center {:02d}'.format(i) if man.setup_peak_center(new=True, standalone_graph=False): self._on_peak_center_start() self._open_editor( PeakCenterEditor(model=man.peak_center, name=name)) man.do_peak_center(confirm_save=True, warn=True, message='manual peakcenter', on_end=self._on_peak_center_end) def define_peak_center(self): from pychron.spectrometer.ion_optics.define_peak_center_view import DefinePeakCenterView man = self.scan_manager.ion_optics_manager spec = man.spectrometer dets = spec.detector_names isos = spec.isotopes dpc = DefinePeakCenterView(detectors=dets, isotopes=isos, detector=dets[0], isotope=isos[0]) info = dpc.edit_traits() if info.result: det = dpc.detector isotope = dpc.isotope dac = dpc.dac self.debug('manually setting mftable to {}:{}:{}'.format( det, isotope, dac)) message = 'manually define peak center {}:{}:{}'.format( det, isotope, dac) man.spectrometer.magnet.update_field_table(det, isotope, dac, message) def _on_peak_center_start(self): self.scan_manager.log_events_enabled = False self.scan_manager.scan_enabled = False def _on_peak_center_end(self): self.scan_manager.log_events_enabled = True self.scan_manager.scan_enabled = True def send_configuration(self): self.scan_manager.spectrometer.send_configuration() def prepare_destroy(self): for e in self.editor_area.editors: if hasattr(e, 'stop'): e.stop() self.scan_manager.prepare_destroy() super(SpectrometerTask, self).prepare_destroy() # def activated(self): # self.scan_manager.activate() # self._scan_factory() # super(SpectrometerTask, self).activated() def create_dock_panes(self): panes = [ ControlsPane(model=self.scan_manager), RecordControlsPane(model=self.scan_manager), MassScannerPane(model=self.scan_manager), DACScannerPane(model=self.scan_manager), ReadoutPane(model=self.scan_manager), IntensitiesPane(model=self.scan_manager) ] panes = self._add_canvas_pane(panes) return panes # def _active_editor_changed(self, new): # if not new: # try: # self._scan_factory() # except AttributeError: # pass def _scan_factory(self): sim = self.scan_manager.spectrometer.simulation name = 'Scan (Simulation)' if sim else 'Scan' # self._open_editor(ScanEditor(model=self.scan_manager, name=name)) # print 'asdfas', self.editor_area.control # print [e for e in self.editor_area.control.children() if isinstance(e, EditorWidget)] # super(SpectrometerTask, self).activated() se = ScanEditor(model=self.scan_manager, name=name) self._open_editor(se) def _default_layout_default(self): return TaskLayout( left=Splitter(PaneItem('pychron.spectrometer.controls'), orientation='vertical'), right=VSplitter(PaneItem('pychron.spectrometer.intensities'), PaneItem('pychron.spectrometer.readout'))) # def create_central_pane(self): # g = ScanPane(model=self.scan_manager) # return g @on_trait_change('scan_manager:mass_scanner:new_scanner') def _handle_mass_scan_event(self): self._scan_event(self.scan_manager.mass_scanner) @on_trait_change('scan_manager:dac_scanner:new_scanner') def _handle_dac_scan_event(self): self._scan_event(self.scan_manager.dac_scanner) def _scan_event(self, scanner): sim = self.scan_manager.spectrometer.simulation name = 'Magnet Scan (Simulation)' if sim else 'Magnet Scan' editor = next( (e for e in self.editor_area.editors if e.id == 'pychron.scanner'), None) if editor is not None: scanner.reset() else: editor = ScannerEditor(model=scanner, name=name, id='pychron.scanner') self._open_editor(editor, activate=False) self.split_editors(0, 1, h2=300, orientation='vertical') self.activate_editor(editor) @on_trait_change('window:opened') def _opened(self): self.scan_manager.activate() self._scan_factory() ee = [ e for e in self.editor_area.control.children() if isinstance(e, EditorWidget) ][0]
class LaserCalibrationTask(BaseLaserTask): id = 'pychron.laser.calibration' execute = Event execute_label = Property(depends_on='executing') executing = Bool tool_bars = [SToolBar(PyrometerCalibrationAction(), image_size=(16, 16))] def _get_execute_label(self): return 'Stop' if self.executing else 'Start' def _default_layout_default(self): return TaskLayout(left=Splitter( PaneItem('pychron.laser_calibration.execute', width=200), PaneItem('pychron.laser_calibration.control', width=200), orientation='vertical')) # def activated(self): # self.new_power_map() def create_dock_panes(self): ep = LaserCalibrationExecutePane(model=self) lp = LaserCalibrationControlPane() self.control_pane = lp return [lp, ep] def get_power_maps(self): ps = self.open_file_dialog(action='open files', default_directory=paths.power_map_dir) return ps def open_power_maps(self, ps): # ps = self.open_file_dialog(action='open files', # default_directory=paths.power_map_dir # ) # p = '/Users/ross/Pychrondata_demo/data/scans/powermap-2013-07-17001.hdf5' # p = '/Users/ross/Sandbox/powermap/powermap-2013-07-26005.hdf5' # p = '/Users/ross/Sandbox/powermap/powermap-2013-07-27008.hdf5' # p = '/Users/ross/Sandbox/powermap/Archive 2/powermap-2013-07-31001.hdf5' # p = '/Users/ross/Sandbox/powermap/Archive 2/powermap-2013-07-31002.hdf5' # p = '/Users/ross/Sandbox/powermap-2013-07-26005.hdf5' if ps: for p in ps: try: # p = '/Users/ross/Sandbox/powermap/Archive 2/powermap-2013-07-31{:03n}.hdf5'.format(i) editor = PowerMapEditor( # name='Power Map {:03n}'.format(n + 1), name='Power Map {}'.format(os.path.basename(p))) editor.load(p) self._open_editor(editor) except Exception: self.debug('invalid power map file {}'.format(p)) def new_power_map(self): n = len([ ed for ed in self.editor_area.editors if isinstance(ed, PowerMapEditor) ]) editor = PowerMapEditor(name='Power Map {:03d}'.format(n + 1)) if self.active_editor: editor.editor = self.control_pane.editor self._open_editor(editor) def new_power_calibration(self): n = len([ ed for ed in self.editor_area.editors if isinstance(ed, PowerCalibrationEditor) ]) editor = PowerCalibrationEditor( name='Power Calibration {:03d}'.format(n + 1)) self._open_editor(editor) def new_pyrometer_calibration(self): editor = PyrometerCalibrationEditor(name='Pyrometer Calibration') self._open_editor(editor) def new_pid_tuner(self): editor = PIDTuningEditor(name='PID Tuning') self._open_editor(editor) # =============================================================================== # handlers # =============================================================================== def execute_active_editor(self, block=False): if self.active_editor.do_execute(self.manager): self.executing = True if block: self.active_editor.block() # def execute_last_editor(self, block=False): # editor = self.editor_area.editors[-1] # if editor.do_execute(self.manager): # self.executing = True # # if block: # self.editor.block() def _execute_changed(self): if self.active_editor: if self.executing: self.active_editor.stop() self.executing = False else: if self.active_editor.was_executed: self.new_power_map() self.execute_active_editor() else: self.new_power_map() self.execute_active_editor() def _active_editor_changed(self): if self.active_editor: if hasattr(self.active_editor, 'editor'): self.control_pane.editor = self.active_editor.editor @on_trait_change('active_editor:completed') def _update_completed(self, new): print 'asdf', new if new: self.executing = False self.active_editor.was_executed = True
class ImageUploadTask(BaseManagerTask, BaseBrowserModel): id = 'pychron.image.upload' name = 'Image Uploader' tool_bars = [SToolBar(AssociateAction(), SaveAction())] items = List selected_items = List # association_enabled = Property(depends_on='selected_items[]') association_enabled = Bool def handle_new_images(self, new): if new: for ni in new: name = os.path.basename(ni) self.debug('Adding {} to database'.format(name)) self.items.append(UploadItem(name=name)) # move file out of staging area shutil.move(ni, os.path.join(paths.sample_image_backup_dir, name)) # actions def save(self): self.debug('save associations') def associate_sample(self): self.debug('associate sample') sample = self.selected_samples[0].name print type(self.selected_samples[0]) for si in self.selected_items: si.sample = sample print si.name, si.sample # task interface def activated(self): self.load_projects(include_recent=False) def prepare_destroy(self): pass def create_central_pane(self): return UploadPane(model=self) def create_dock_panes(self): return [SampleBrowserPane(model=self)] def _default_layout_default(self): return TaskLayout(left=PaneItem(id='pychron.image.browser')) def _selected_samples_changed(self): self._set_association_enabled() def _selected_items_changed(self): self._set_association_enabled() def _set_association_enabled(self): self.association_enabled = bool(self.selected_items and len( self.selected_samples) == 1 if self.selected_samples else False) # ============= EOF =============================================
class PipelineTask(BaseBrowserTask): name = 'Pipeline Data Processing' engine = Instance(PipelineEngine) tool_bars = [ SToolBar(PipelineRecallAction(), ConfigureRecallAction(), name='Recall'), SToolBar( RunAction(), ResumeAction(), RunFromAction(), ResetAction(), ClearAction(), # SavePipelineTemplateAction(), name='Pipeline'), SToolBar( SavePDFAction(), # SaveFigureAction(), name='Save'), SToolBar(EditAnalysisAction(), name='Edit'), SToolBar(LoadReviewStatusAction(), DiffViewAction(), name='View'), SToolBar(TagAction(), SetInvalidAction(), SetFilteringTagAction(), SetInterpretedAgeAction(), SaveTableAction(), name='Misc') ] state = Instance(EngineState) set_interpreted_enabled = Bool(False) active_editor_options = Any modified = False projects = None diff_enabled = Bool _browser_info = None _interpreted_age_browser_info = None def activated(self): # 2=a self.debug('activating pipeline') super(PipelineTask, self).activated() self.engine.dvc = self.dvc self.browser_model.dvc = self.dvc self.browser_model.analysis_table.dvc = self.dvc self.engine.browser_model = self.browser_model self.engine.interpreted_age_browser_model = self.interpreted_age_browser_model def _debug(self): # self.engine.add_data() # if globalv.select_default_data: # self.engine.select_default() if globalv.pipeline_template: self.engine.set_template(globalv.pipeline_template) if globalv.run_pipeline: self.run() def prepare_destroy(self): self.interpreted_age_browser_model.dump_browser() self.engine.reset() super(PipelineTask, self).prepare_destroy() def create_dock_panes(self): panes = [ PipelinePane(model=self.engine), AnalysesPane(model=self.engine), RepositoryPane(model=self.engine), EditorOptionsPane(model=self) ] return panes # toolbar actions def run_script(self): path = self.open_file_dialog() if path is not None: script = DataReductionScript() script.dvc = self.dvc script.run(path) def diff_analysis(self): self.debug('diff analysis') if not self.has_active_editor(): return active_editor = self.active_editor if not isinstance(active_editor, RecallEditor): self.warning_dialog('Active tab must be a Recall tab') return left = active_editor.analysis recaller = self.application.get_service( 'pychron.mass_spec.mass_spec_recaller.MassSpecRecaller') if recaller is None: self.warning_dialog('Could not access MassSpec database') return if not recaller.connect(): self.warning_dialog( 'Could not connect to MassSpec database. {}'.format( recaller.db.datasource_url)) return from pychron.pipeline.editors.diff_editor import DiffEditor editor = DiffEditor(recaller=recaller) if not left.check_has_n(): left.load_raw_data(n_only=True) if editor.setup(left): editor.set_diff(left) self._open_editor(editor) else: self.warning_dialog( 'Failed to locate analysis {} in MassSpec database'.format( left.record_id)) def pipeline_recall(self): if self._browser_info: if self._browser_info.control: self._browser_info.control.raise_() return self.dvc.create_session(force=True) self.browser_model.activated() browser_view = BrowserView(model=self.browser_model) info = browser_view.edit_traits(kind='live') self._browser_info = info def pipeline_interpreted_age_recall(self): if self._interpreted_age_browser_info: if self._interpreted_age_browser_info.control: self._interpreted_age_browser_info.control.raise_() return self.interpreted_age_browser_model.activated() browser_view = InterpretedAgeBrowserView( model=self.interpreted_age_browser_model) info = browser_view.edit_traits(kind='live') self._interpreted_age_browser_info = info def tabular_view(self): self.debug('open tabular view') if not self.has_active_editor(): return ed = self.active_editor from pychron.pipeline.plot.editors.ideogram_editor import IdeogramEditor if isinstance(ed, IdeogramEditor): from pychron.pipeline.editors.fusion.fusion_table_editor import FusionTableEditor ted = FusionTableEditor() ted.items = ed.analyses self._open_editor(ted) def set_filtering_tag(self): ans = self.engine.selected.unknowns refs = self.engine.selected.references ans.extend(refs) omit_ans = [ ai for ai in ans if ai.temp_status == 'omit' and ai.tag != 'omit' ] outlier_ans = [ ai for ai in ans if ai.temp_status == 'outlier' and ai.tag != 'outlier' ] invalid_ans = [ ai for ai in ans if ai.temp_status == 'invalid' and ai.tag != 'invalid' ] self.set_tag('omit', omit_ans, use_filter=False) self.set_tag('outlier', outlier_ans, use_filter=False) self.set_tag('invalid', invalid_ans) def set_tag(self, tag=None, items=None, use_filter=True, warn=True): """ set tag for either analyses selected in unknowns pane or analyses selected in figure e.g temp_status!=0 """ if items is None: items = self._get_selection() if not items: if warn: self.warning_dialog('No analyses selected to Tag') return note = '' if items: if tag is None: a = self._get_tagname(items) if a: tag, items, use_filter, note = a # set tags for items if tag and items: # tags stored as lowercase tag = tag.lower() self.dvc.tag_items(tag, items, note) if use_filter: for e in self.editor_area.editors: if hasattr(e, 'set_items'): try: ans = e.items except AttributeError: ans = e.analyses if ans: fans = [ ai for ai in ans if ai.tag.lower() != 'invalid' ] e.set_items(fans) if self.active_editor: self.active_editor.figure_model = None self.active_editor.refresh_needed = True self.browser_model.analysis_table.set_tags(tag, items) self.browser_model.analysis_table.remove_invalid() self.engine.remove_invalid() def set_invalid(self): items = self._get_selection() self._set_invalid(items) def save_figure(self): self.debug('save figure') if not self.has_active_editor(): return ed = self.active_editor root = paths.figure_dir path = os.path.join(root, 'test.json') obj = self._make_save_figure_object(ed) dvc_dump(obj, path) def save_table(self): self.debug('save table') if not self.has_active_editor(): return ed = self.active_editor if isinstance(ed, FigureEditor): from pychron.pipeline.tables.xlsx_table_options import XLSXAnalysisTableWriterOptions from pychron.pipeline.tables.xlsx_table_writer import XLSXAnalysisTableWriter from pychron.pipeline.plot.editors.isochron_editor import InverseIsochronEditor from pychron.pipeline.plot.editors.spectrum_editor import SpectrumEditor ek = ed.plotter_options.error_calc_method pk = WEIGHTED_MEAN if isinstance(ed, SpectrumEditor): pk = PLATEAU elif isinstance(ed, InverseIsochronEditor): pk = ISOCHRON options = XLSXAnalysisTableWriterOptions() ri = tuple({ai.repository_identifier for ai in ed.analyses}) options.root_name = ri[0] info = options.edit_traits(kind='modal') if info.result: writer = XLSXAnalysisTableWriter() gs = ed.get_analysis_groups() # convert each group to an InterpretedAgeGroup from pychron.processing.analyses.analysis_group import InterpretedAgeGroup ggs = [] for gi in gs: gg = InterpretedAgeGroup(analyses=gi.analyses) gg.set_preferred_age(pk, ek) gg.set_preferred_kind('kca', WEIGHTED_MEAN, MSEM) ggs.append(gg) run_groups = {'unknowns': ggs, 'machine_unknowns': ggs} writer.build(run_groups, options=options) def save_figure_pdf(self): self.debug('save figure pdf') if not self.has_active_editor(): return ed = self.active_editor if isinstance(ed, FigureEditor): sfm = SaveFigureModel(ed.analyses) sfv = SaveFigureView(model=sfm) info = sfv.edit_traits() if info.result: path = sfm.prepare_path(make=True) save_pdf(ed.component, path=path, options=sfm.pdf_options, view=True) def run(self): self._run_pipeline() def resume(self): self._resume_pipeline() def run_from(self): self._run_from_pipeline() def set_interpreted_age(self): ias = self.active_editor.get_interpreted_ages() set_interpreted_age(self.dvc, ias) def clear(self): self.reset() self.engine.clear() self.close_all() def reset(self): self.engine.run_enabled = True self.engine.resume_enabled = False self.engine.reset() def save_pipeline_template(self): self.engine.save_pipeline_template() # action handlers def edit_runid(self): self._set_action_template('Edit RunID') def mass_spec_reduced_transfer(self): self._set_action_template('Mass Spec Reduced') def freeze_flux(self): ans = self._get_active_analyses() if ans: self.dvc.freeze_flux() else: self._set_action_template('FreezeFlux') def freeze_production_ratios(self): ans = self._get_active_analyses() if ans: self.dvc.freeze_production_ratios(ans) else: self._set_action_template('FreezeProductionRatios') def set_isotope_evolutions_template(self): self._set_action_template('Iso Evo') def set_icfactor_template(self): self._set_action_template('IC Factor') def set_blanks_template(self): self._set_action_template('Blanks') def set_flux_template(self): self._set_action_template('Flux') def set_ideogram_template(self): self._set_action_template('Ideogram', 'Plot') def set_spectrum_template(self): self._set_action_template('Spectrum', 'Plot') def set_isochron_template(self): self._set_action_template('Isochron') def set_inverse_isochron_template(self): self._set_action_template('InverseIsochron') def set_series_template(self): self._set_action_template('Series') def set_vertical_flux_template(self): self._set_action_template('VerticalFlux') def set_xy_scatter_template(self): self._set_action_template('XYScatter') def set_subgroup_ideogram_template(self): self._set_action_template('SubGroup Ideogram') def set_hybrid_ideogram_template(self): self._set_action_template('Hybrid Ideogram') def set_history_ideogram_template(self): self._set_action_template('Ideogram', 'History') def set_last_n_analyses_template(self): self.engine.selected_pipeline_template = 'Series' # get n analyses from user n = 10 # get the unknowns node node = self.engine.get_unknowns_node() if node: # get last n analyses as unks node.set_last_n_analyses(n) self.run() def set_last_n_hours_template(self): self.engine.selected_pipeline_template = 'Series' # get last n hours from user n = 10 self._set_last_nhours(n) def set_last_day_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24) def set_last_week_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24 * 7) def set_last_month_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24 * 7 * 30.5) def set_analysis_table_template(self): self.engine.selected_pipeline_template = 'Analysis' self.run() # private def _get_active_analyses(self): if self.active_editor: return self.active_editor.analyses def _set_last_nhours(self, n): node = self.engine.get_unknowns_node() if node: node.set_last_n_hours_analyses(n) self.run() def _set_action_template(self, name, group=None): self.activated() self.engine.selected_pipeline_template = (name, group) self.run() def _make_save_figure_object(self, editor): po = editor.plotter_options plotter_options = po.to_dict() obj = { 'plotter_options': plotter_options, 'analyses': [ { 'record_id': ai.record_id, 'uuid': ai.uuid, # 'status': ai.temp_status, 'group_id': ai.group_id } for ai in editor.analyses ] } return obj def _close_editor(self, editor): for e in self.editor_area.editors: if e.name == editor.name: self.close_editor(e) break def _run(self, message, func, close_all=False): if self.engine.pre_run_check(func): self.debug('{} started'.format(message)) if close_all: self.close_all() self.dvc.db.session = None self.dvc.create_session() if not getattr(self.engine, func)(): self.engine.resume_enabled = True self.engine.run_enabled = False self.debug('false {} {}'.format(message, func)) else: self.engine.run_enabled = True self.engine.resume_enabled = False self.debug('true {} {}'.format(message, func)) for editor in self.engine.state.editors: self._open_editor(editor) self.debug('{} finished'.format(message)) def _run_from_pipeline(self): self._run('run from', 'run_from_pipeline') def _resume_pipeline(self): self._run('resume pipeline', 'resume_pipeline') def _run_pipeline(self): self._run('run pipeline', 'run_pipeline') def _toggle_run(self, v): self.engine.resume_enabled = v self.engine.run_enabled = not v def _sa_factory(self, path, factory, **kw): return SchemaAddition(path=path, factory=factory, **kw) def _set_invalid(self, items): self.set_tag(tag='invalid', items=items, warn=True) def _set_omit(self, items): self.set_tag(tag='omit', items=items, warn=True) # defaults def _default_layout_default(self): return TaskLayout(left=Splitter( Splitter(PaneItem('pychron.pipeline.pane', width=200), PaneItem('pychron.pipeline.analyses', width=200)), PaneItem('pychron.pipeline.repository'), orientation='vertical')) def _extra_actions_default(self): sas = (('MenuBar/data.menu', RunAction, {}), ) return [ self._sa_factory(path, factory, **kw) for path, factory, kw in sas ] def _help_tips_default(self): return [ 'Use <b>Data>Ideogram</b> to plot an Ideogram', 'Use <b>Data>Spectrum</b> to plot a Spectrum', 'Use <b>Data>Series</b> to plot a Time series of Analyses', 'Use <b>Data>XY Scatter</b> to plot a XY Scatter plot of ' 'any Analysis value versus any other Analysis value', 'Use <b>Data>Recall</b> to view analytical data for individual analyses' ] # handlers @on_trait_change('editor_area:editors[]') def _handle_editors(self): self.engine.editors = self.editor_area.editors @on_trait_change('engine:reset_event') def _handle_reset(self): self.reset() def _active_editor_changed(self, new): if new: self.engine.select_node_by_editor(new) self.set_interpreted_enabled = isinstance(new, InterpretedAgeEditor) if hasattr(new, 'editor_options'): self.active_editor_options = new.editor_options else: self.active_editor_options = None @on_trait_change('engine:selected') def _handle_engine_selected(self, obj, name, old, new): if isinstance(new, Pipeline): self.engine.pipeline = new elif isinstance(new, NodeGroup): pass else: # self.engine.selected_node = new if old: old.on_trait_change(self._handle_tag, 'unknowns:tag_event,references:tag_event', remove=True) old.on_trait_change( self._handle_invalid, 'unknowns:invalid_event,references:invalid_event', remove=True) old.on_trait_change( self._handle_omit, 'unknowns:omit_event,references:omit_event', remove=True) old.on_trait_change( self._handle_recall, 'unknowns:recall_event,references:recall_event', remove=True) old.on_trait_change(self.engine.handle_len_unknowns, 'unknowns_items', remove=True) old.on_trait_change(self.engine.handle_len_references, 'references_items', remove=True) old.on_trait_change( self.engine.handle_status, 'unknowns:temp_status,references:temp_status', remove=True) if new: new.on_trait_change(self._handle_tag, 'unknowns:tag_event,references:tag_event') new.on_trait_change( self._handle_invalid, 'unknowns:invalid_event,references:invalid_event') new.on_trait_change( self._handle_omit, 'unknowns:omit_event,references:omit_event') new.on_trait_change( self._handle_recall, 'unknowns:recall_event,references:recall_event') new.on_trait_change( self.engine.handle_status, 'unknowns:temp_status,references:temp_status') new.on_trait_change(self.engine.handle_len_unknowns, 'unknowns_items') new.on_trait_change(self.engine.handle_len_references, 'references_items') if isinstance(new, FigureNode): if new.editor: editor = new.editor self.engine.selected_editor = editor self.engine.active_editor = editor @on_trait_change('engine:tag_event') def _handle_engine_tag(self, new): self.set_tag(items=new) def _handle_tag(self, name, new): self.set_tag(items=new) def _handle_invalid(self, name, new): self._set_invalid(new) def _handle_omit(self, name, new): self._set_omit(new) @on_trait_change('engine:run_needed') def _handle_run_needed(self, new): self.debug('run needed for {}'.format(new)) if self.engine.resume_enabled: self.resume() else: self.run() @on_trait_change('engine:recall_analyses_needed') def _handle_recall(self, new): if not isinstance(new, DVCInterpretedAge): self.recall(new) def _prompt_for_save(self): if globalv.ignore_shareable: return True ret = True ps = self.engine.get_experiment_ids() if ps: changed = repository_has_staged(ps) self.debug('task has changes to {}'.format(changed)) if changed: m = 'You have changes to analyses. Would you like to share them?' ret = self._handle_prompt_for_save(m, 'Share Changes') if ret == 'save': self.dvc.push_repositories(changed) return ret def _opened_hook(self): super(PipelineTask, self)._opened_hook() if globalv.pipeline_debug: self._debug() def _get_selection(self): selected = self.engine.selected if selected and not isinstance(selected, Pipeline): items = selected.unknowns items.extend(selected.references) items = [i for i in items if i.temp_selected] uuids = [i.uuid for i in items] for ans in (self.engine.selected_unknowns, self.engine.selected_references): for i in ans: if i.uuid not in uuids: items.append(i) return items def _get_tagname(self, items): from pychron.pipeline.tagging.analysis_tags import AnalysisTagModel from pychron.pipeline.tagging.views import AnalysisTagView model = AnalysisTagModel() tv = AnalysisTagView(model=model) tv.model.items = items info = tv.edit_traits() if info.result: return model.tag, model.get_items(), model.use_filter, model.note def _engine_default(self): e = PipelineEngine(application=self.application) return e
class ExperimentRepoTask(BaseTask, ColumnSorterMixin): id = 'pychron.repo.task' name = 'Repositories' filter_repository_value = Str filter_origin_value = Str selected_repository = Instance(RepoItem) ncommits = Int(50, enter_set=True, auto_set=False) selected_local_repositories = List selected_local_repository_name = Property(depends_on='selected_local_repositories')#Instance(RepoItem) repository_names = List local_names = List tool_bars = [SToolBar(CloneAction(), LoadOriginAction()), SToolBar(AddBranchAction(), CheckoutBranchAction(), SyncRepoAction(), PushAction(), PullAction(), RebaseAction(), FindChangesAction(), DeleteLocalChangesAction(), ArchiveRepositoryAction(), DeleteChangesAction(), RepoStatusAction(), BookmarkAction()), SToolBar(SyncSampleInfoAction())] commits = List git_tags = List _repo = None selected_commit = Any branch = Str branches = List dvc = Any o_local_repos = None o_origin_repos = None check_for_changes = Bool(True) origin_column_clicked = Any def activated(self): bind_preference(self, 'check_for_changes', 'pychron.dvc.repository.check_for_changes') # self._preference_binder('pychron.dvc.connection', ('organization',)) # prefid = 'pychron.dvc.connection' # bind_preference(self, 'favorites', '{}.favorites'.format(prefid)) # self._preference_binder('pychron.github', ('oauth_token',)) self.refresh_local_names() if self.check_for_changes: if self.confirmation_dialog('Check all Repositories for changes'): self.find_changes() def archive_repository(self): self.debug('archive repository') root = os.path.join(paths.dvc_dir, 'archived_repositories') if not os.path.isdir(root): os.mkdir(root) src = self._repo.path name = os.path.basename(src) dst = unique_dir(root, name, make=False) shutil.move(self._repo.path, dst) self.refresh_local_names() self.information_dialog('"{}" Successfully archived to {}'.format(name, dst)) def refresh_local_names(self): self.local_names = [RepoItem(name=i, active_branch=branch) for i, branch in sorted(list_local_repos())] self.o_local_repos = None def find_changes(self, remote='origin', branch='master'): self.debug('find changes') # def func(item, prog, i, n): # def func(item, prog, i, n): # name = item.name # if prog: # prog.change_message('Examining: {}({}/{})'.format(name, i, n)) # self.debug('examining {}'.format(name)) # r = Repo(repository_path(name)) # try: # r.git.fetch() # line = r.git.log('{}/{}..HEAD'.format(remote, branch), '--oneline') # item.dirty = bool(line) # item.update(fetch=False) # except GitCommandError as e: # self.warning('error examining {}. {}'.format(name, e)) names = self.selected_local_repositories if not names: names = self.local_names self.dvc.find_changes(names, remote, branch) # progress_loader(names, func) self.local_names = sorted(self.local_names, key=lambda k: k.dirty, reverse=True) def rebase(self): self._repo.rebase() def pull(self): self._repo.smart_pull(quiet=False) def push(self): if not self._repo.has_remote(): from pychron.dvc.tasks.add_remote_view import AddRemoteView a = AddRemoteView() info = a.edit_traits(kind='livemodal') if info.result: if a.url and a.name: self._repo.create_remote(a.url, a.name) self._repo.push(remote=a.name, inform=True) else: self._repo.push(inform=True) self.selected_local_repository_name.dirty = False def clone(self): repo = self.selected_repository if not repo: self.warning_dialog('Please Select a repository to clone') return name = repo.name if name == 'meta': root = paths.dvc_dir else: root = paths.repository_dataset_dir path = os.path.join(root, name) if not os.path.isdir(path): self.debug('cloning repository {}'.format(name)) service = self.dvc.application.get_service(IGitHost) service.clone_from(name, path, self.dvc.organization) self.refresh_local_names() msg = 'Repository "{}" successfully cloned'.format(name) else: msg = 'Repository "{}" already exists locally. Clone aborted '.format(name) self.information_dialog(msg) def add_branch(self): self.info('add branch') refresh = False commit = self.selected_commit if commit: if self._repo.create_branch(commit=commit.hexsha if commit else 'HEAD'): refresh = True else: name = None for r in self.selected_local_repositories: repo = self._get_repo(r.name) name = repo.create_branch(commit='HEAD', name=name, inform=False) if name is not None: r.active_branch = repo.get_active_branch() refresh = True if refresh: rs = ','.join((r.name for r in self.selected_local_repositories)) self.information_dialog('Repositories "{}" now on branch "{}"'.format(rs, name)) self._refresh_branches() def checkout_branch(self): branch = self.branch self.info('checkout branch {}'.format(branch)) names = [] for r in self.selected_local_repositories: r = self._get_repo(r.name) try: r.checkout_branch(branch, inform=False) r.active_branch = branch names.append(r.name) except BaseException: pass self.information_dialog('{} now on branch "{}'.format(names, branch)) def load_origin(self): self.debug('load origin') self.repository_names = [RepoItem(name=r['name'], push_date=format_iso_datetime(r['pushed_at'], as_str=False), create_date=format_iso_datetime(r['created_at'], as_str=False)) for r in self.dvc.remote_repositories()] self.o_origin_repos = None def delete_local_changes(self): self.info('delete local changes') selected = self._has_selected_local() if selected: name = selected.name msg = 'Are you sure you want to delete your non-shared changes in "{}"'.format(name) if self.confirmation_dialog(msg): self._repo.delete_local_commits() self.selected_local_repository_name.dirty = False def sync_sample_info(self): self.info('sync sample info') selected = self._has_selected_local() if selected: name = selected.name if self.confirmation_dialog('Are you sure you want to copy values from the ' 'database into the repository "{}"'.format(name)): self.dvc.repository_db_sync(name) self.information_dialog('Sync complete') def sync_repo(self): selected = self._has_selected_local() if selected: if self.confirmation_dialog('Are you sure you want to Sync to Origin. aka Pull/Push'): self.pull() self.push() def status(self): selected = self._has_selected_local() if selected: self.dvc.status_view(selected.name) def add_bookmark(self): selected = self._has_selected_local() if selected: hexsha = None if self.selected_commit: hexsha = self.selected_commit.hexsha from pychron.git_archive.views import NewTagView nt = NewTagView() info = nt.edit_traits() if info.result: if nt.name: self.dvc.add_bookmark(selected.name, nt.name, nt.message or 'No message provided', hexsha=hexsha) else: self.warning_dialog('A name is required to add a bookmark. Please try again') def delete_commits(self): selected = self._has_selected_local() if selected and self.selected_commit: hexsha = self.selected_commit.hexsha msg = 'Are you sure you want to permanently delete your changes in "{}"'.format(selected.name) if self.confirmation_dialog(msg): self._repo.delete_commits(hexsha) # task def create_central_pane(self): return RepoCentralPane(model=self) def create_dock_panes(self): return [SelectionPane(model=self)] # private def _refresh_tags(self): self.git_tags = get_tags(self._repo.active_repo) def _refresh_branches(self): self.branches = self._repo.get_branch_names() b = self._repo.get_active_branch() force = self.branch == b self.branch = b if force: self._branch_changed(self.branch) self.selected_local_repository_name.active_branch = b def _filter_origin_value_changed(self, new): if new: if self.o_origin_repos is None: self.o_origin_repos = self.repository_names self.repository_names = fuzzyfinder(new, self.o_origin_repos, attr='name') elif self.o_origin_repos: self.repository_names = self.o_origin_repos def _filter_repository_value_changed(self, new): if new: if self.o_local_repos is None: self.o_local_repos = self.local_names self.local_names = fuzzyfinder(new, self.o_local_repos, attr='name') elif self.o_local_repos: self.local_names = self.o_local_repos def _has_selected_local(self): if not self.selected_local_repository_name: self.information_dialog('Please select a local repository') return return self.selected_local_repository_name def _get_repo(self, name): root = repository_path(name) if os.path.isdir(root): repo = GitRepoManager() repo.open_repo(root) return repo def _get_selected_local_repository_name(self): if self.selected_local_repositories: return self.selected_local_repositories[0] def _selected_local_repositories_changed(self, new): if new: repo = self._get_repo(new[0].name) if repo: self._repo = repo self._refresh_branches() self._refresh_tags() def _get_commits(self, new): if new: self.commits = get_commits(self._repo.active_repo, new, None, '', limit=self.ncommits) else: self.commits = [] def _ncommits_changed(self): self._get_commits(self.branch) def _branch_changed(self, new): self._get_commits(new) def _origin_column_clicked_changed(self, event): self._column_clicked_handled(event) def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.repo.selection'))
class InterpretedAgeTask(BaseBrowserTask): name = 'Interpreted Ages' id = 'pychron.processing.interpreted_age' tool_bars = [ SToolBar(SavePDFTablesAction()), SToolBar(SaveAsInterpretedAgeGroupAction(), SaveInterpretedAgeGroupAction(), OpenInterpretedAgeGroupAction(), MakeGroupFromFileAction(), DeleteInterpretedAgeGroupAction()) ] def external_delete_group(self): self.load_projects() self.delete_group() def delete_group(self): dlg = DeleteGroupDialog(projects=self.projects, db=self.manager.db) info = dlg.edit_traits(kind='livemodal') if info.result: ids = dlg.get_selected_ids() if ids: if self.confirmation_dialog( 'Are you sure to want to delete the selected groups?'): editor = InterpretedAgeEditor(processor=self.manager) editor.delete_groups(ids) def make_group_from_file(self): if self.has_active_editor(): p = '/Users/ross/Programming/git/dissertation/data/minnabluff/interpreted_ages_lt8_no_int.yaml' p = '/Users/ross/Programming/git/dissertation/data/minnabluff/interpreted_ages_gt8_no_int.yaml' if not os.path.isfile(p): p = self.open_file_dialog() if p: with open(p, 'r') as fp: d = yaml.load(fp) project = d['project'] name = d['name'] ids = d['interpreted_age_ids'] self.active_editor.save_group(name, project, ids=ids) self.db_save_info() def external_open_interpreted_age_group(self): self.load_projects() ogd = OpenGroupDialog(projects=self.projects, db=self.manager.db) info = ogd.edit_traits(kind='livemodal') if info.result: return ogd.get_selected_ids() def open_interpreted_age_group(self): if self.has_active_editor(): ogd = OpenGroupDialog(projects=self.projects, db=self.manager.db) if self.selected_projects: ogd.selected_project = self.selected_projects[-1] info = ogd.edit_traits(kind='livemodal') if info.result: ids = ogd.get_selected_ids() if ids: self.open_interpreted_age_groups(ids) def open_interpreted_age_groups(self, gids): if self.has_active_editor(): self.active_editor.open_group(gids[0]) for i in gids[1:]: editor = self._new_editor() editor.open_group(i) def save_interpreted_age_group(self): if self.has_active_editor(): if self.active_editor.saved_group_id: self.active_editor.update_group() else: self.save_as_interpreted_age_group() self.db_save_info() def save_as_interpreted_age_group(self): if self.has_active_editor(): if self.active_editor.interpreted_ages: sgd = SaveGroupDialog(projects=self.projects) if self.selected_projects: sgd.selected_project = self.selected_projects[-1] info = sgd.edit_traits(kind='livemodal') if info.result: name = sgd.name project = sgd.selected_project.name if name and project: self.active_editor.save_group(name, project) def save_pdf_tables(self): if self.has_active_editor(): # p=self.save_file_dialog() # p = '/Users/ross/Sandbox/interpreted_age.pdf' n = self.active_editor.name p = '/Users/ross/Programming/git/dissertation/data/minnabluff/interpreted_ages/{}.pdf'.format( n) if p: self.active_editor.save_pdf_tables(p) self.view_pdf(p) def create_dock_panes(self): panes = [self._create_browser_pane(analyses_defined='0')] return panes def _new_editor(self): editor = InterpretedAgeEditor(processor=self.manager) self._open_editor(editor) return editor def _selected_samples_changed(self): if not self.active_editor: self._new_editor() self.active_editor.set_samples(self.selected_samples) def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.browser'))
class SampleImageTask(BaseEditorTask, BaseBrowserModel): name = 'Sample Imager' id = 'pychron.image.sample_imager' tool_bars = [SToolBar(SnapshotAction()), SToolBar(UploadAction())] save_event = Event images = List selected_image = Instance(SampleImageRecordView) selected_info_model = Instance(ImageModel, ()) dclicked = Event _prev_name = None def __init__(self, *args, **kw): super(SampleImageTask, self).__init__(*args, **kw) if self.manager: self.tool_bars[0].items.append(DBSnapshotAction()) self.camera = ToupCamCamera() self.filter_non_run_samples = False def save(self, path=None): if self.active_editor and isinstance(self.active_editor, ImageTabEditor): if self.active_editor.dirty: db = self.manager.db with db.session_ctx(): dbim = db.get_sample_image(self.active_editor.record_id) dbim.note = self.active_editor.model.note dbim.name = self.active_editor.model.name self.active_editor.model.original_note = dbim.note self.active_editor.model.original_name = dbim.name self.active_editor.dirty = False self._load_associated_images(self.selected_samples) def save_as(self): self.save() # actions def upload_image_from_file(self): if not self.selected_samples: self.information_dialog( 'Please select a sample to associate with the image') return path = self.open_file_dialog(default_directory=os.path.expanduser('~'), wildcard='*.jpg|*.jpeg') if path is not None: with open(path, 'rb') as rfile: self.save_db_snapshot(rfile.read()) self._load_associated_images(self.selected_samples) def save_file_snapshot(self): from pychron.core.helpers.filetools import unique_path2 p, _ = unique_path2(paths.sample_image_dir, 'nosample', extension='.jpg') p, _ = unique_path2(paths.sample_image_dir, 'nosample', extension='.tiff') self.camera.save(p) def save_db_snapshot(self, blob=None): if not self.selected_samples: self.warning_dialog('Please select a sample') return sample = self.selected_samples[0] self.info('adding image to sample. name={}, identifier={}'.format( sample.name, sample.identifier)) name = self._prev_name if not name: # get existing images for this sample db = self.manager.db with db.session_ctx(): # sample = db.get_sample(sample.name, identifier=sample.identifier) cnt = db.get_sample_image_count(sample.name, project=sample.project, material=sample.material, identifier=sample.identifier) cnt += 1 name = '{}{:03d}'.format(sample.name, cnt) v = DBSaveView(name=name) info = v.edit_traits() if info.result: self._prev_name = v.name self.debug('save image with name={}'.format(name)) if blob is None: blob = self.camera.get_jpeg_data(quality=75) db.add_sample_image(sample.name, v.name, blob, v.note, identifier=sample.identifier) # task interface def activated(self): self.camera.open() editor = CameraTab(model=self, name='Camera') self._open_editor(editor) self.load_projects(include_recent=False) def prepare_destroy(self): self.camera.close() def create_dock_panes(self): return [SampleBrowserPane(model=self), InfoPane(model=self)] def _selected_projects_changed(self, old, new): if new and self.project_enabled: names = [ni.name for ni in new] self.debug('selected projects={}'.format(names)) # self._load_associated_labnumbers(names) self._load_associated_samples(names) self.dump_browser_selection() def _selected_samples_changed(self, new): if new: self._load_associated_images(new) # def _selected_image_changed(self, new): def _dclicked_changed(self): selected = self.selected_image if selected: db = self.manager.db with db.session_ctx(): dbim = db.get_sample_image(selected.record_id) editor = self.get_editor(selected.record_id, key='record_id') if not editor: model = ImageModel(blob=dbim.image, name=dbim.name, create_date=dbim.create_date, note=dbim.note or '') editor = ImageTabEditor(record_id=selected.record_id, model=model, name=dbim.name) self._open_editor(editor) else: self.activate_editor(editor) def _active_editor_changed(self, new): if new and isinstance(new.model, ImageModel): self.selected_info_model = new.model def _load_associated_images(self, sample_records): db = self.manager.db with db.session_ctx(): images = [] for si in sample_records: sample = db.get_sample(si.name, si.project, si.material, si.identifier) images.extend( [SampleImageRecordView(i) for i in sample.images]) self.images = images def _load_associated_samples(self, names): db = self.manager.db with db.session_ctx(): samples = db.get_samples(names) self.debug('get samples n={}'.format(len(samples))) def func(li, prog, i, n): if prog: prog.change_message('Loading Sample {}'.format(li.name)) if li.labnumbers: return [ SampleRecordView(li, identifier=ll.identifier) for ll in li.labnumbers ] else: return SampleRecordView(li) samples = progress_loader(samples, func) self.samples = samples self.osamples = samples def _default_layout_default(self): return TaskLayout(left=PaneItem(id='pychron.image.browser'), right=PaneItem(id='pychron.image.info'))
class PipelineTask(BaseBrowserTask): name = 'Pipeline Processing' engine = Instance(PipelineEngine) tool_bars = [ SToolBar(ConfigureRecallAction(), ToggleFullWindowAction()), SToolBar(RunAction(), ResumeAction(), RunFromAction(), ResetAction(), ClearAction(), SavePipelineTemplateAction(), name='Pipeline'), SToolBar(SavePDFAction(), SaveFigureAction(), name='Save'), SToolBar(EditAnalysisAction(), name='Edit'), # SToolBar(GitRollbackAction(), label='Git Toolbar'), SToolBar(TagAction(), SetInvalidAction(), SetFilteringTagAction(), SetInterpretedAgeAction(), TabularViewAction(), name='Misc') ] state = Instance(EngineState) resume_enabled = Bool(False) run_enabled = Bool(True) set_interpreted_enabled = Bool(False) # run_to = None modified = False projects = None def activated(self): super(PipelineTask, self).activated() self.engine.dvc = self.dvc self.engine.browser_model = self.browser_model self.engine.interpreted_age_browser_model = self.interpreted_age_browser_model # self.engine.add_data() def _debug(self): self.engine.add_data() if globalv.select_default_data: self.engine.select_default() if globalv.pipeline_template: self.engine.set_template(globalv.pipeline_template) if globalv.run_pipeline: self.run() def prepare_destroy(self): super(PipelineTask, self).prepare_destroy() self.interpreted_age_browser_model.dump_browser() def create_dock_panes(self): panes = [ PipelinePane(model=self.engine), AnalysesPane(model=self.engine), InspectorPane(model=self.engine) ] return panes # toolbar actions def tabular_view(self): self.debug('open tabular view') if not self.has_active_editor(): return ed = self.active_editor from pychron.pipeline.plot.editors.ideogram_editor import IdeogramEditor if isinstance(ed, IdeogramEditor): from pychron.pipeline.editors.fusion.fusion_table_editor import FusionTableEditor ted = FusionTableEditor() ted.items = ed.analyses self._open_editor(ted) def set_filtering_tag(self): ans = self.engine.selected.unknowns refs = self.engine.selected.references ans.extend(refs) omit_ans = [ ai for ai in ans if ai.temp_status == 'omit' and ai.tag != 'omit' ] outlier_ans = [ ai for ai in ans if ai.temp_status == 'outlier' and ai.tag != 'outlier' ] invalid_ans = [ ai for ai in ans if ai.temp_status == 'invalid' and ai.tag != 'invalid' ] self.set_tag('omit', omit_ans, use_filter=False) self.set_tag('outlier', outlier_ans, use_filter=False) self.set_tag('invalid', invalid_ans) def set_tag(self, tag=None, items=None, use_filter=True, warn=True): """ set tag for either analyses selected in unknowns pane or analyses selected in figure e.g temp_status!=0 """ if items is None: items = self._get_selection() if not items: if warn: self.warning_dialog('No analyses selected to Tag') return if items: if tag is None: a = self._get_tagname(items) if a: tag, items, use_filter = a # tags stored as lowercase tag = tag.lower() # set tags for items if tag and items: dvc = self.dvc db = dvc.db key = lambda x: x.repository_identifier for expid, ans in groupby(sorted(items, key=key), key=key): cs = [] with db.session_ctx(): for it in ans: self.debug('setting {} tag= {}'.format( it.record_id, tag)) db.set_analysis_tag(it.uuid, tag) it.set_tag(tag) if dvc.update_tag(it): cs.append(it) # it.refresh_view() if cs: cc = [c.record_id for c in cs] if len(cc) > 1: cstr = '{} - {}'.format(cc[0], cc[-1]) else: cstr = cc[0] dvc.repository_commit( expid, '<TAG> {:<6s} {}'.format(tag, cstr)) for ci in cs: ci.refresh_view() if use_filter: for e in self.editor_area.editors: if isinstance(e, FigureEditor): e.set_items([ ai for ai in e.analyses if ai.tag != 'invalid' ]) # if self.active_editor: self.active_editor.refresh_needed = True self.browser_model.analysis_table.set_tags(tag, items) self.browser_model.analysis_table.remove_invalid() self.browser_model.analysis_table.refresh_needed = True self.engine.refresh_table_needed = True # else: # # edit tags # self._get_tagname([]) def set_invalid(self): items = self._get_selection() self._set_invalid(items) def save_figure(self): self.debug('save figure') if not self.has_active_editor(): return ed = self.active_editor root = paths.figure_dir path = os.path.join(root, 'test.json') obj = self._make_save_figure_object(ed) dvc_dump(obj, path) def save_figure_pdf(self): self.debug('save figure pdf') if not self.has_active_editor(): return ed = self.active_editor sfm = SaveFigureModel(ed.analyses) sfv = SaveFigureView(model=sfm) info = sfv.edit_traits() if info.result: path = sfm.prepare_path(make=True) save_pdf( ed.component, path=path, options=sfm.pdf_options, # path='/Users/ross/Documents/test.pdf', view=True) def run(self): self._run_pipeline() def resume(self): self._resume_pipeline() def run_from(self): self._run_from_pipeline() def set_interpreted_age(self): ias = self.active_editor.get_interpreted_ages() repository_identifiers = self.dvc.get_local_repositories() model = InterpretedAgeFactoryModel(groups=ias) iaf = InterpretedAgeFactoryView( model=model, repository_identifiers=repository_identifiers) info = iaf.edit_traits() if info.result: self._add_interpreted_ages(ias) def git_rollback(self): # select experiment expid = select_experiment_repo() if expid: self.dvc.rollback_repository(expid) def clear(self): self.reset() self.engine.clear() self.close_all() def reset(self): self.run_enabled = True self.resume_enabled = False # self._temp_state = None # self.state = None self.engine.reset() def save_pipeline_template(self): path = self.save_file_dialog( default_directory=paths.user_pipeline_template_dir) # path = '/Users/ross/Sandbox/template.yaml' # path = os.path.join(paths.pipeline_template_dir, 'test.yaml') if path: self.engine.save_pipeline_template(path) # action handlers def freeze_flux(self): ans = self._get_active_analyses() if ans: self.dvc.freeze_flux() else: self._set_action_template('FreezeFlux') def freeze_production_ratios(self): ans = self._get_active_analyses() if ans: self.dvc.freeze_production_ratios(ans) else: self._set_action_template('FreezeProductionRatios') def set_isotope_evolutions_template(self): self._set_action_template('Iso Evo') def set_icfactor_template(self): self._set_action_template('ICFactor') def set_blanks_template(self): self._set_action_template('Blanks') def set_flux_template(self): self._set_action_template('Flux') def set_ideogram_template(self): self._set_action_template('Ideogram') def set_spectrum_template(self): self._set_action_template('Spectrum') def set_isochron_template(self): self._set_action_template('Isochron') def set_inverse_isochron_template(self): self._set_action_template('Inverse Isochron') def set_series_template(self): self._set_action_template('Series') def set_vertical_flux_template(self): self._set_action_template('VerticalFlux') def set_xy_scatter_template(self): self._set_action_template('XYScatter') def set_last_n_analyses_template(self): self.engine.selected_pipeline_template = 'Series' # get n analyses from user n = 10 # get the unknowns node node = self.engine.get_unknowns_node() if node: # get last n analyses as unks # set node.unknowns = unks node.set_last_n_analyses(n) self.run() def set_last_n_hours_template(self): self.engine.selected_pipeline_template = 'Series' # get last n hours from user n = 10 self._set_last_nhours(n) def set_last_day_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24) def set_last_week_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24 * 7) def set_last_month_template(self): self.engine.selected_pipeline_template = 'Series' self._set_last_nhours(24 * 7 * 30.5) # private def _get_active_analyses(self): if self.active_editor: return self.active_editor.analyses def _set_last_nhours(self, n): node = self.engine.get_unknowns_node() if node: node.set_last_n_hours_analyses(n) self.run() def _set_action_template(self, name): self.engine.selected_pipeline_template = name self.run() def _make_save_figure_object(self, editor): po = editor.plotter_options plotter_options = po.to_dict() for k, v in plotter_options.iteritems(): print k, v obj = {} obj['plotter_options'] = plotter_options obj['analyses'] = [ { 'record_id': ai.record_id, 'uuid': ai.uuid, # 'status': ai.temp_status, 'group_id': ai.group_id } for ai in editor.analyses ] return obj def _add_interpreted_ages(self, ias): dvc = self.dvc db = dvc.db with db.session_ctx(): for ia in ias: if ia.use: dvc.add_interpreted_age(ia) def _close_editor(self, editor): for e in self.editor_area.editors: if e.name == editor.name: self.close_editor(e) break def _run(self, message, func, close_all=False): self.debug('{} started'.format(message)) if close_all: self.close_all() if not getattr(self.engine, func)(): self.resume_enabled = True self.run_enabled = False self.debug('false {} {}'.format(message, func)) else: self.run_enabled = True self.resume_enabled = False self.debug('true {} {}'.format(message, func)) for editor in self.engine.state.editors: self._open_editor(editor) self.debug('{} finished'.format(message)) def _run_from_pipeline(self): self._run('run from', 'run_from_pipeline') def _resume_pipeline(self): self._run('resume pipeline', 'resume_pipeline') def _run_pipeline(self): self._run('run pipeline', 'run_pipeline', close_all=True) def _toggle_run(self, v): self.resume_enabled = v self.run_enabled = not v def _sa_factory(self, path, factory, **kw): return SchemaAddition(path=path, factory=factory, **kw) def _set_invalid(self, items): self.set_tag(tag='invalid', items=items, warn=True) # defaults def _default_layout_default(self): return TaskLayout(left=Splitter(Splitter( PaneItem('pychron.pipeline.pane', width=200), PaneItem('pychron.pipeline.analyses', width=200)), PaneItem('pychron.pipeline.inspector'), orientation='vertical')) def _extra_actions_default(self): sas = (('MenuBar/data.menu', RunAction, {}), ) return [ self._sa_factory(path, factory, **kw) for path, factory, kw in sas ] def _help_tips_default(self): return [ 'Use <b>Data>Ideogram</b> to plot an Ideogram', 'Use <b>Data>Spectrum</b> to plot a Spectrum', 'Use <b>Data>Series</b> to plot a Time series of Analyses', # 'Use <b>Data>XY Scatter</b> to plot a XY Scatter plot of ' # 'any Analysis value versus any other Analysis value', # 'Use <b>Data>Recall</b> to view analytical data for individual analyses', ] # handlers @on_trait_change('engine:reset_event') def _handle_reset(self): self.reset() def _active_editor_changed(self, new): if new: self.engine.select_node_by_editor(new) self.set_interpreted_enabled = isinstance(new, InterpretedAgeEditor) # @on_trait_change('active_editor:save_needed') # def _handle_save_needed(self): # self.engine.run_persist(self._temp_state) @on_trait_change('engine:[tag_event, invalid_event, recall_event]') def _handle_analysis_tagging(self, name, new): if name == 'tag_event': self.set_tag(items=new) elif name == 'invalid_event': self._set_invalid(new) elif name == 'recall_event': self.recall(new) @on_trait_change('engine:run_needed') def _handle_run_needed(self, new): self.debug('run needed for {}'.format(new)) self.run() @on_trait_change('engine:recall_analyses_needed') def _handle_recall(self, new): self.recall(new) def _prompt_for_save(self): if globalv.ignore_shareable: return True ret = True ps = self.engine.get_experiment_ids() if ps: changed = repository_has_staged(ps) self.debug('task has changes to {}'.format(changed)) if changed: m = 'You have changes to analyses. Would you like to share them?' ret = self._handle_prompt_for_save(m, 'Share Changes') if ret == 'save': self.dvc.push_repositories(changed) return ret def _opened_hook(self): super(PipelineTask, self)._opened_hook() if globalv.pipeline_debug: self._debug() def _get_selection(self): items = self.engine.selected.unknowns items.extend(self.engine.selected.references) items = [i for i in items if i.temp_selected] items.extend(self.engine.selected_unknowns) items.extend(self.engine.selected_references) return items def _get_tagname(self, items): from pychron.pipeline.tagging.analysis_tags import AnalysisTagModel from pychron.pipeline.tagging.views import AnalysisTagView tv = AnalysisTagView(model=AnalysisTagModel()) db = self.dvc.db with db.session_ctx(): # tv.model.db = db tv.model.items = items # tv.model.load() info = tv.edit_traits() if info.result: tag = tv.model.tag return tag, tv.model.items, tv.model.use_filter # def _get_dr_tagname(self, items): # from pychron.pipeline.tagging.data_reduction_tags import DataReductionTagModel # from pychron.pipeline.tagging.views import DataReductionTagView # # tv = DataReductionTagView(model=DataReductionTagModel(items=items)) # info = tv.edit_traits() # if info.result: # return tv.model def _engine_default(self): e = PipelineEngine(application=self.application) return e
class FigureTask(AnalysisEditTask): name = 'Figure' id = 'pychron.processing.figures' plotter_options_pane = Instance(PlotterOptionsPane) tool_bars = [ SToolBar(SavePDFFigureAction(), SaveFigureAction(), SaveAsFigureAction(), name='Figure'), SToolBar( NewIdeogramAction(), # AppendIdeogramAction(), name='Ideogram'), SToolBar( NewSpectrumAction(), # AppendSpectrumAction(), name='Spectrum'), SToolBar(SetInterpretedAgeTBAction(), BrowseInterpretedAgeTBAction()) # SToolBar(AddTextBoxAction()) ] auto_select_analysis = False figures_help = 'Double-click to open' figure_kind = Enum('All', 'Ideogram', 'Spectrum', 'Inv Iso') delete_figure_button = Button figures = List ofigures = List selected_figures = Any dclicked_figure = Event # # =============================================================================== # task protocol #=============================================================================== def prepare_destroy(self): for ed in self.editor_area.editors: if isinstance(ed, FigureEditor): pom = ed.plotter_options_manager pom.close() super(FigureTask, self).prepare_destroy() def create_dock_panes(self): panes = super(FigureTask, self).create_dock_panes() self.plotter_options_pane = PlotterOptionsPane() self.figure_selector_pane = FigureSelectorPane(model=self) return panes + [self.plotter_options_pane, self.figure_selector_pane] #=============================================================================== # grouping #=============================================================================== def group_by_aliquot(self): key = lambda x: x.aliquot self._group_by(key) def group_by_labnumber(self): key = lambda x: x.labnumber self._group_by(key) def group_selected(self): if self.unknowns_pane.selected: self.active_editor.set_group(self._get_selected_indices(), self._get_unique_group_id()) def clear_grouping(self): """ if selected then set selected group_id to 0 else set all to 0 """ if self.active_editor: sel = self.unknowns_pane.selected if sel: idx = self._get_selected_indices() else: idx = range(len(self.unknowns_pane.items)) self.active_editor.set_group(idx, 0) # self.unknowns_pane.update_needed = True self.unknowns_pane.refresh_needed = True #=============================================================================== # figures #=============================================================================== def new_ideogram(self, ans=None, klass=None, tklass=None, name='Ideo', set_ans=True, add_table=True, add_iso=True): if klass is None: klass = IdeogramEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass # from pychron.processing.tasks.tables.editors.fusion_table_editor \ # import FusionTableEditor as tklass return self._new_figure(ans, name, klass, tklass, set_ans=set_ans, add_iso=add_iso, add_table=add_table) def new_spectrum(self, ans=None, klass=None, tklass=None, name='Spec', add_table=True, add_iso=True): if klass is None: klass = SpectrumEditor if tklass is None: from pychron.processing.tasks.tables.editors.step_heat.step_heat_table_editor import \ StepHeatTableEditor as tklass return self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) def new_inverse_isochron(self, ans=None, name='Inv. Iso.', klass=None, tklass=None, plotter_kw=None): if klass is None: klass = InverseIsochronEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass feditor = self._new_figure(ans, name, klass, tklass, add_iso=False) def new_series(self, ans=None, name='Series', klass=None, tklass=None, add_iso=False, add_table=True): if klass is None: klass = SeriesEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass return self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) #=============================================================================== # actions #=============================================================================== def save_figure(self): sid = self.active_editor.saved_figure_id if sid: self._save_figure() else: self._save_as_figure() def save_as_figure(self): self._save_as_figure() def set_interpreted_age(self): if self.active_editor: self.active_editor.set_interpreted_age() def browse_interpreted_age(self): app = self.application app.open_task('pychron.processing.interpreted_age') def add_text_box(self): ac = self.active_editor if ac and ac.component and hasattr(ac, 'add_text_box'): self.active_editor.add_text_box() at = self.active_editor.annotation_tool if at: at.on_trait_change( self.plot_editor_pane.set_annotation_component, 'component') self.plot_editor_pane.set_annotation_tool(at) def tb_new_ideogram(self): if isinstance(self.active_editor, IdeogramEditor) and \ not self.unknowns_pane.items: self.append_ideogram() else: self.new_ideogram() def tb_new_spectrum(self): if isinstance(self.active_editor, SpectrumEditor) and \ not self.unknowns_pane.items: self.append_spectrum() else: self.new_spectrum() #=============================================================================== # #=============================================================================== #=============================================================================== # private #=============================================================================== def _new_figure(self, ans, name, klass, tklass=None, add_table=True, add_iso=True, set_ans=True): # new figure editor editor = klass(name=name, processor=self.manager) if ans is None: ans = self.unknowns_pane.items if ans: editor.unknowns = ans if set_ans: self.unknowns_pane.items = ans self._open_editor(editor) add_associated = False if not add_associated: self.debug('Not adding associated editors') else: if tklass and add_table: # open table teditor = self._new_table(ans, name, tklass) if teditor: editor.associated_editors.append(weakref.ref(teditor)()) if add_iso: # open associated isochron ieditor = self._new_associated_isochron(ans, name) if ieditor: editor.associated_editors.append(weakref.ref(ieditor)()) ieditor.parent_editor = editor # activate figure editor self.editor_area.activate_editor(editor) return editor def _group_by(self, key): editor = self.active_editor if editor: items = self.unknowns_pane.items group_analyses_by_key(editor, items, key) self.unknowns_pane.refresh_needed = True editor.rebuild() def _add_editor(self, editor, ans): ed = None if ans: if isinstance(editor, FigureEditor): editor.unknowns = ans else: editor.items = ans ed = next( (e for e in self.editor_area.editors if e.name == editor.name), None) if not ed: self.editor_area.add_editor(editor) else: editor = None return editor def _add_unknowns_hook(self, *args, **kw): if self.active_editor: if hasattr(self.active_editor, 'auto_group'): if self.active_editor.auto_group: self.group_by_labnumber() for ai in self.active_editor.associated_editors: if isinstance(ai, FigureEditor): ai.rebuild_graph() def _get_unique_group_id(self): gids = {i.group_id for i in self.unknowns_pane.items} return max(gids) + 1 def _get_selected_indices(self): items = self.unknowns_pane.items return [items.index(si) for si in self.unknowns_pane.selected] def _new_associated_isochron(self, ans, name): name = '{}-isochron'.format(name) editor = InverseIsochronEditor(name=name, processor=self.manager) return self._add_editor(editor, ans) def _new_table(self, ans, name, klass): name = '{}-table'.format(name) editor = klass(name=name) return self._add_editor(editor, ans) def _create_control_pane(self): pass def _load_project_figures(self, new): if new: db = self.manager.db with db.session_ctx(): proj = [p.name for p in new] figs = db.get_project_figures(proj) self.ofigures = [self._dbfigure_factory(f) for f in figs] self.figures = self.ofigures self._figure_kind_changed() def _load_sample_figures(self, new): if new: db = self.manager.db with db.session_ctx(): lns = [p.labnumber for p in new] figs = db.get_labnumber_figures(lns) figs = [self._dbfigure_factory(f) for f in figs] figs = [f for f in figs if f] self.ofigures = figs self.figures = self.ofigures self._figure_kind_changed() def _dbfigure_factory(self, f): if f.preference: dbf = DBFigure( name=f.name or '', project=f.project.name, identifiers=[s.labnumber.identifier for s in f.labnumbers], samples=list( set([s.labnumber.sample.name for s in f.labnumbers])), kind=f.preference.kind, id=f.id) return dbf def _get_sample_obj(self, s): return next((sr for sr in self.samples if sr.labnumber == s), None) def _get_project_obj(self, p): return next((sr for sr in self.projects if sr.name == p), None) def _save_figure(self): """ update preferences update analyses """ if self.active_editor: self.active_editor.update_figure() self.db_save_info() # db=self.manager.db # with db.session_ctx() as sess: # fig=db.get_figure(sid, key='id') # print sid, fig # # pom=self.active_editor.plotter_options_manager # blob = pom.dump_yaml() # fig.preference.options=blob # # dbans=fig.analyses # uuids=[ai.uuid for ai in self.active_editor.analyses] # # for dbai in fig.analyses: # if not dbai.analysis.uuid in uuids: # #remove analysis # sess.delete(dbai) # # for ai in self.active_editor.analyses: # if not next((dbai for dbai in dbans if dbai.analysis.uuid==ai.uuid), None): # #add analysis # ai=db.get_analysis_uuid(ai.uuid) # db.add_figure_analysis(fig, ai) def _save_as_figure(self): """ add a new figure to the database """ db = self.manager.db if not isinstance(self.active_editor, FigureEditor): return with db.session_ctx(): #use dialog to ask user for figure name and associated project dlg = SaveFigureDialog(projects=self.projects, samples=self.samples) # if self.selected_projects: # dlg.selected_project = self.selected_projects[0] # projects = list( set([ai.project for ai in self.active_editor.analyses])) if projects: proj = self._get_project_obj(projects[0]) if proj: dlg.selected_project = proj identifiers = list( set([ai.labnumber for ai in self.active_editor.analyses])) # print samples ss = [self._get_sample_obj(si) for si in identifiers] # # print ss ss = filter(lambda x: not x is None, ss) # # print ss dlg.selected_samples = ss while 1: info = dlg.edit_traits(kind='livemodal') if not info.result: return if dlg.name: break else: if not self.confirmation_dialog( 'Need to set the name of a "figure" to save. Continue?' ): return project = None if dlg.selected_project: project = dlg.selected_project.name identifiers = [si.labnumber for si in dlg.selected_samples] fid = self.active_editor.save_figure(dlg.name, project, identifiers) self._load_sample_figures(dlg.selected_samples) idx = next((i for i, o in enumerate(self.ofigures) if o.id == fid), None) if idx is not None: self.active_editor.saved_figure_id = idx def _delete_figures(self, figs): db = self.manager.db with db.session_ctx() as sess: for fi in figs: dbfig = db.get_figure(fi.id, key='id') sess.delete(dbfig.preference) for si in dbfig.labnumbers: sess.delete(si) for ai in dbfig.analyses: sess.delete(ai) sess.delete(dbfig) #=============================================================================== # handlers #=============================================================================== def _selected_projects_changed(self, new): self._load_project_figures(new) super(FigureTask, self)._selected_projects_changed(new) def _selected_samples_changed(self, new): self._load_sample_figures(new) super(FigureTask, self)._selected_samples_changed(new) def _delete_figure_button_fired(self): if self.selected_figures: if self.confirmation_dialog( 'Are you sure you want to delete the selected figures?'): self._delete_figures(self.selected_figures) if self.selected_samples: self._load_sample_figures(self.selected_samples) else: self._load_project_figures(self.selected_projects) def _figure_kind_changed(self): self.selected_figures = [] if self.figure_kind: if self.figure_kind == 'All': self.figures = self.ofigures else: kind = self.figure_kind[:4].lower() self.figures = filter(lambda x: x.kind == kind, self.ofigures) def _dclicked_sample_changed(self): if self.active_editor: self.active_editor.saved_figure_id = 0 super(FigureTask, self)._dclicked_sample_changed() def _dclicked_figure_changed(self): sf = self.selected_figures if sf: db = self.manager.db with db.session_ctx(): sf = sf[0] db_fig = db.get_figure(sf.id, key='id') blob = db_fig.preference.options kind = db_fig.preference.kind open_editor_needed = True if self.active_editor: open_editor_needed = self.active_editor.basename != kind if open_editor_needed: #open new editor of this kind if kind == 'spec': if self.active_editor: self.active_editor.close() self.new_spectrum() elif kind == 'ideo': if self.active_editor: self.active_editor.close() self.new_ideogram() if self.active_editor: self.active_editor.plotter_options_manager.load_yaml(blob) self.active_editor.saved_figure_id = int(sf.id) self.active_editor.set_items( [a.analysis for a in db_fig.analyses]) for ai, dbai in zip(self.active_editor.analyses, db_fig.analyses): ai.group_id = int(dbai.group or 0) ai.graph_id = int(dbai.graph or 0) self.active_editor.rebuild() @on_trait_change( 'plotter_options_pane:pom:plotter_options:[+, refresh_plot_needed, aux_plots:+]' ) def _options_update(self, obj, name, old, new): if name == 'initialized': return if self.plotter_options_pane.pom.plotter_options.auto_refresh or name == 'refresh_plot_needed': self.active_editor.rebuild() def _active_editor_changed(self): if self.active_editor: if isinstance(self.active_editor, FigureEditor): self.plotter_options_pane.pom = self.active_editor.plotter_options_manager super(FigureTask, self)._active_editor_changed() @on_trait_change('active_editor:refresh_unknowns_table') def _ac_refresh_table(self): if self.unknowns_pane: self.unknowns_pane.refresh_needed = True @on_trait_change('active_editor:tag') def _handle_graph_tag(self, new): self.set_tag() @on_trait_change('active_editor:save_db_figure') def _handle_save_db_figure(self): self._save_as_figure() #=========================================================================== # browser protocol #=========================================================================== #=============================================================================== # defaults #=============================================================================== def _default_layout_default(self): return TaskLayout( id='pychron.processing', left=HSplitter( PaneItem('pychron.browser'), Tabbed(PaneItem('pychron.processing.figures.saved_figures'), PaneItem('pychron.processing.unknowns'), PaneItem('pychron.processing.figures.plotter_options'), PaneItem('pychron.plot_editor')))) #============= EOF ============================================= #@classmethod # def group_by(cls, editor, items, key): # ids = [] # for it in items: # v = key(it) # if not v in ids: # ids.append(v) # # sitems = sorted(items, key=key) # for k, analyses in groupby(sitems, key=key): # gid = ids.index(k) # idxs = [items.index(ai) for ai in analyses] # editor.set_group(idxs, gid, refresh=False) # def _append_figure(self, klass): # """ # if selected_samples append all analyses # else append selected analyses # # """ # return # # if isinstance(self.active_editor, klass): # sa = self.analysis_table.selected # if sa: # ts = self.manager.make_analyses(sa) # else: # ts = [ai for si in self.selected_sample # for ai in self._get_sample_analyses(si)] # # ans = self.manager.make_analyses(ts) # if ans: # pans = self.active_editor.analyses # uuids = [p.uuid for p in pans] # fans = [ai for ai in ans if ai.uuid not in uuids] # # pans.extend(fans) # self.active_editor.trait_set(unknowns=pans) # # gid = 0 # for _, gans in groupby(self.active_editor.unknowns, key=lambda x: x.sample): # for ai in gans: # ai.group_id = gid # gid += 1 # # self.active_editor.rebuild(compress_groups=False)
class BrowserTask(BaseBrowserTask): name = 'Analysis Browser' model = Instance('pychron.envisage.browser.browser_model.BrowserModel') tool_bars = [ SToolBar(ConfigureRecallAction(), ConfigureAnalysesTableAction(), name='Configure'), SToolBar(ToggleFullWindowAction(), LoadReviewStatusAction(), DiffViewAction(), name='View'), SToolBar(EditAnalysisAction(), name='Edit') ] diff_enabled = Bool def activated(self): if self.application.get_plugin('pychron.mass_spec.plugin'): self.diff_enabled = True super(BrowserTask, self).activated() def _opened_hook(self): super(BrowserTask, self)._opened_hook() self.browser_model.activated() self._activate_sample_browser() if globalv.browser_debug: if self.browser_model.analysis_table.analyses: r = self.browser_model.analysis_table.analyses[0] self.recall(r) # menu actions def open_time_view_browser(self): self.debug('open time view') v = AnalysisRangeSelector() v.load() db = self.dvc.db spec_names = db.get_mass_spectrometer_names() v.set_mass_spectrometers(spec_names) # open a time view selector info = v.edit_traits(kind='livemodal') if info.result: v.dump() sms = v.selected_mass_spectrometers ants = v.selected_analysis_types # with db.session_ctx(): # if v.use_date_range: # h, l = v.high_post, v.low_post # ans = db.get_analyses_date_range(l, h, # analysis_type=ants, # mass_spectrometers=sms) # else: # # get analyses # ans, h, l = db.get_last_nhours_analyses(v.nhours, # return_limits=True, # analysis_types=ants, # mass_spectrometers=sms) # # def func(x, prog, i, n): # return x.record_views # # records = progress_loader(ans, func) # # # set analysis_table.analyses # bm.analysis_table.set_analyses(records) # bm.analysis_table.scroll_to_row = len(records) if v.use_date_range: h, l = v.high_post, v.low_post else: now = datetime.now() h, l = now, now - timedelta(hours=v.nhours) bm = self.browser_model if sms: bm.mass_spectrometers_enabled = True bm.mass_spectrometer_includes = v.selected_mass_spectrometers if ants: bm.use_analysis_type_filtering = True bm._analysis_include_types = ants bm._low_post = l.date() bm.use_low_post = True bm._high_post = h.date() bm.use_high_post = True bm.do_filter() bm.select_all() at = bm.analysis_table end = len(at.analyses) at.scroll_to_row = end # toolbar actions def diff_analysis(self): self.debug('diff analysis') if not self.has_active_editor(): return active_editor = self.active_editor if not isinstance(active_editor, RecallEditor): self.warning_dialog('Active tab must be a Recall tab') return left = active_editor.analysis recaller = self.application.get_service( 'pychron.mass_spec.mass_spec_recaller.MassSpecRecaller') if recaller is None: self.warning_dialog('Could not access MassSpec database') return if not recaller.connect(): self.warning_dialog( 'Could not connect to MassSpec database. {}'.format( recaller.db.datasource_url)) return from pychron.pipeline.editors.diff_editor import DiffEditor editor = DiffEditor(recaller=recaller) # left.set_stored_value_states(True, save=True) if not left.check_has_n(): left.load_raw_data(n_only=True) if editor.setup(left): editor.set_diff(left) self._open_editor(editor) else: self.warning_dialog( 'Failed to locate analysis {} in MassSpec database'.format( left.record_id)) # left.revert_use_stored_values() def create_dock_panes(self): return [BrowserPane(model=self.browser_model)] def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.browser.pane'))
class LoadingTask(BaseManagerTask): name = 'Loading' load_pane = Any dirty = False control_pane = Any canvas = Any _positions = List save_directory = Str tool_bars = [SToolBar(SaveLoadingAction(), image_size=(32, 32))] def activated(self): # self.manager.tray = 'A' # self.manager.irradiation = 'NM-251' # self.manager.level = 'H' # self.manager.labnumber = '61311' if self.manager.setup(): bind_preference(self, 'save_directory', 'pychron.loading.save_directory') else: do_later(self.window.close) # def _manager_default(self): # return LoadingManager() def _default_layout_default(self): return TaskLayout(left=PaneItem('pychron.loading.controls'), bottom=PaneItem('pychron.loading.positions')) def prepare_destroy(self): pass def create_dock_panes(self): self.control_pane = LoadControlPane(model=self.manager) self.table_pane = LoadTablePane(model=self.manager) # self.irradiation_pane = LoadIrradiationPane(model=self.manager) return [ self.control_pane, self.table_pane, # self.irradiation_pane ] def create_central_pane(self): self.load_pane = LoadPane() return self.load_pane def save(self): self.manager.save() def save_loading(self): p = LoadingPDFWriter() root = self.save_directory if not root or not os.path.isdir(root): root = paths.loading_dir positions = self.manager.positions ln = self.manager.load_name un = self.manager.loader_name dt = datetime.now() date_str = dt.strftime("%Y-%m-%d %H:%M:%S") meta = dict(load_name=ln, username=un, load_date=date_str, projects='Ross, Test') path = os.path.join(root, '{}.pdf'.format(ln)) p.build(path, positions, self.canvas, meta) # @on_trait_change('manager:load_name') # def _load_changed(self, new): # if new: # self.manager.tray = '' # self.manager.load_load(new) @on_trait_change('manager:tray') def _tray_changed(self, new): if new: c = LoadingCanvas( view_x_range=(-2.2, 2.2), view_y_range=(-2.2, 2.2), ) c.load_scene(new, show_hole_numbers=self.manager.show_hole_numbers) self.canvas = c self.load_pane.component = c self.manager.canvas = c self.manager.positions = [] @on_trait_change('window:closing') def _prompt_on_close(self, event): ''' Prompt the user to save when exiting. ''' if self.dirty: result = self._confirmation('ffoo') if result in (CANCEL, NO): event.veto = True else: self._save()
class RecallTask(AnalysisEditTask): name = 'Recall' tool_bars = [ SToolBar(AddIsoEvoAction(), AddDiffAction(), image_size=(16, 16)) ] auto_select_analysis = False def append_unknown_analyses(self, ans): for i, ai in enumerate(ans): if not (i == 0 and self.active_editor): self.new_editor() self._set_selected_analysis(ai) def replace_unkonwn_analyses(self, ans): for ei in self.editor_area.editors: ei.close() self.append_unknown_analyses(ans) # def activated(self, load=False): # self.load_projects() # # if load: # # editor = RecallEditor() # # self._open_editor(editor) # # #db = self.manager.db # #db.selector.limit = 100 # #db.selector.load_recent() # # super(RecallTask, self).activated() def new_editor(self): editor = RecallEditor() self._open_editor(editor) # def _set_selected_analysis(self, an): # if an and isinstance(self.active_editor, RecallEditor): # if hasattr(an, '__iter__'): # an=an[0] # # an = self.manager.make_analysis(an, calculate_age=True) # self.active_editor.analysis_view = an.analysis_view # self.controls_pane.tool = an.analysis_view.selection_tool # self.active_editor.model = an def _active_editor_changed(self): if self.active_editor: self.controls_pane.tool = self.active_editor.analysis_view.selection_tool def _dclicked_sample_changed(self): pass def _default_layout_default(self): return TaskLayout(id='pychron.recall', left=HSplitter( Tabbed(PaneItem('pychron.browser')), PaneItem('pychron.processing.controls'))) def create_dock_panes(self): self.controls_pane = ControlsPane() self.plot_editor_pane = PlotEditorPane() panes = [ self.controls_pane, self.plot_editor_pane, self._create_browser_pane() ] return panes def add_iso_evo(self, name=None, rec=None): if rec is None: if self.active_editor is not None: rec = self.active_editor.model name = self.active_editor.name if rec is None: return from pychron.processing.tasks.isotope_evolution.isotope_evolution_editor import IsotopeEvolutionEditor ieditor = IsotopeEvolutionEditor(name='IsoEvo {}'.format(name), processor=self.manager) ieditor.set_items([rec]) self.editor_area.add_editor(ieditor) def add_diff(self): left = None if self.active_editor: left = self.active_editor.model if left: editor = DiffEditor() editor.set_diff(left) self.editor_area.add_editor(editor)
class FigureTask(AnalysisEditTask): name = 'Figure' default_task_name = 'Ideogram' id = 'pychron.processing.figures' plotter_options_pane = Instance(PlotterOptionsPane) figure_selector_pane = Instance(FigureSelectorPane) tool_bars = [ SToolBar(ToggleFullWindowAction()), SToolBar(RefreshActiveEditorAction(), # AddIsoEvoAction(), # TagAction() ), SToolBar( SavePDFFigureAction(), # SaveFigureAction(), # SaveAsFigureAction(), name='Figure'), # SToolBar(NewIdeogramAction(), # NewSpectrumAction(), # NewIsochronAction(), # NewTableAction()), # SToolBar(SetInterpretedAgeTBAction(), # BrowseInterpretedAgeTBAction()), # SToolBar(GroupSelectedAction(name='Selected'), # GroupbyAliquotAction(name='by Aliquot'), # GroupbyLabnumberAction(name='by Labnumber'), # GroupbySampleAction(name='by Sample'), # ClearGroupAction(name='Clear')) ] # auto_select_analysis = False figures_help = 'Double-click to open' figure_kind = Enum('All', 'Ideogram', 'Spectrum', 'Inv Iso') delete_figure_button = Button figures = List ofigures = List selected_figures = Any dclicked_figure = Event def activate_spectrum_editor(self): self._activate_editor('spectrum') def activate_ideogram_editor(self): self._activate_editor('ideogram') # =============================================================================== # task protocol # =============================================================================== def activated(self): # if globalv.recall_debug: # self.manager.set_xml_dataset() super(FigureTask, self).activated() def prepare_destroy(self): for ed in self.editor_area.editors: if isinstance(ed, FigureEditor): pom = ed.plotter_options_manager pom.close() super(FigureTask, self).prepare_destroy() def create_dock_panes(self): panes = super(FigureTask, self).create_dock_panes() self.plotter_options_pane = PlotterOptionsPane() self.figure_selector_pane = FigureSelectorPane(model=self) return panes + [self.plotter_options_pane, self.figure_selector_pane] # =============================================================================== # context menu handler # =============================================================================== def plot_selected_grouped(self): self.debug('plot selected grouped') if self.has_active_editor(): self._clear_group() self._append_replace_unknowns(False, self.browser_model.analysis_table.analyses) def plot_selected(self): self.debug('plot selected') ac = self.has_active_editor() if ac: pane = self.unknowns_pane # remember original setting oauto_group1 = ac.auto_group oauto_group2 = pane.auto_group # turn off auto grouping ac.auto_group = False pane.auto_group = False self._clear_group() self._append_replace_unknowns(False, self.browser_model.analysis_table.analyses) # return to original settings ac.auto_group = oauto_group1 pane.auto_group = oauto_group2 # =============================================================================== # graph grouping # =============================================================================== def graph_group_selected(self): if self.unknowns_pane.selected: idxs = self._get_selected_indices() # all_idxs = range(len(self.unknowns_pane.items)) # selection = list(set(all_idxs) - set(idxs)) self.clear_grouping(refresh=False, selection_idxs=idxs) self.active_editor.set_graph_group( idxs, self._get_unique_graph_id()) self.active_editor.compress_analyses() self.active_editor.rebuild() def graph_group_by_sample(self): ans = self.active_editor.analyses for i, (si, gi) in enumerate(groupby(ans, key=lambda x: x.sample)): idxs = [ans.index(ai) for ai in gi] self.active_editor.set_graph_group(idxs, i) # self._get_unique_graph_id() # self.active_editor.compress_analyses() self.active_editor.rebuild() # =============================================================================== # grouping # =============================================================================== def group_by_aliquot(self): if self.unknowns_pane and self.unknowns_pane.items: self.unknowns_pane.group_by_aliquot() def group_by_labnumber(self): if self.unknowns_pane and self.unknowns_pane.items: self.debug('group by labnumber') self.unknowns_pane.group_by_labnumber() def group_selected(self): if self.unknowns_pane and self.unknowns_pane.items: self.unknowns_pane.group_by_selected() def clear_grouping(self, refresh=True, selection_idxs=None): """ if selected then set selected group_id to 0 else set all to 0 """ if self.unknowns_pane and self.unknowns_pane.items: self.unknowns_pane.clear_grouping(refresh_plot=refresh, idxs=selection_idxs) # =============================================================================== # figures # =============================================================================== def new_ideogram(self, ans=None, klass=None, tklass=None, name='Ideo', set_ans=True, add_table=True, add_iso=True): if klass is None: klass = IdeogramEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass # from pychron.processing.tasks.tables.editors.fusion_table_editor \ # import FusionTableEditor as tklass editor = self._new_figure(ans, name, klass, tklass, set_ans=set_ans, add_iso=add_iso, add_table=add_table) self._debug_add() return editor def new_composite(self, ans=None, klass=None, tklass=None, name='Comp', add_table=True, add_iso=True): if klass is None: klass = CompositeEditor if tklass is None: from pychron.processing.tasks.tables.editors.step_heat.step_heat_table_editor import \ StepHeatTableEditor as tklass return self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) def new_spectrum(self, ans=None, klass=None, tklass=None, name='Spec', add_table=True, add_iso=True): if klass is None: klass = SpectrumEditor if tklass is None: from pychron.processing.tasks.tables.editors.step_heat.step_heat_table_editor import \ StepHeatTableEditor as tklass editor = self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) self._debug_add() return editor def new_inverse_isochron(self, ans=None, name='Inv. Iso.', klass=None, tklass=None, plotter_kw=None): if klass is None: klass = InverseIsochronEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass feditor = self._new_figure(ans, name, klass, tklass, add_iso=False) ans = self.browser_model.analysis_table.analyses if ans: self.unknowns_pane.items = ans def new_series(self, ans=None, name='Series', klass=None, tklass=None, add_iso=False, add_table=False): if klass is None: from pychron.processing.tasks.figures.editors.series_editor import SeriesEditor klass = SeriesEditor if tklass is None: from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import \ FusionTableEditor as tklass return self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) def new_xy_scatter(self, ans=None, name='XYScatter', klass=None, tklass=None, add_iso=False, add_table=False): if klass is None: klass = XYScatterEditor return self._new_figure(ans, name, klass, tklass, add_iso=add_iso, add_table=add_table) def new_ideogram_from_file(self): p = '/Users/ross/Programming/git/dissertation/data/minnabluff/interpreted_ages/gee_sample_ages7.txt' p = '/Users/ross/Programming/git/dissertation/data/minnabluff/dryvalleys_comp.txt' p = '/Users/ross/Programming/git/dissertation/data/minnabluff/dryvalleys_comp2.txt' p = os.path.join(paths.data_dir, 'ideogram_template.txt') if not os.path.isfile(p): self.open_file_dialog(default_directory=paths.data_dir) self.new_ideogram(add_iso=False, add_table=False) self.active_editor.set_items_from_file(p) self.active_editor.rebuild() def new_spectrum_from_file(self): p = '/Users/ross/Sandbox/spectrum_file.txt' if not os.path.isfile(p): self.open_file_dialog(default_directory=paths.data_dir) self.new_spectrum(add_iso=False, add_table=False) self.active_editor.set_items_from_file(p) self.active_editor.rebuild() # =============================================================================== # actions # =============================================================================== def new_table(self, ans=None): if self.has_active_editor(): if isinstance(self.active_editor, IdeogramEditor): from pychron.processing.tasks.tables.editors.fusion.fusion_table_editor import FusionTableEditor klass = FusionTableEditor elif isinstance(self.active_editor, SpectrumEditor): from pychron.processing.tasks.tables.editors.step_heat.step_heat_table_editor import StepHeatTableEditor klass = StepHeatTableEditor else: return name = self.active_editor.name.replace(self.active_editor.basename, '') return self._new_table(ans, name, klass) def refresh_active_editor(self): if self.has_active_editor(): self.active_editor.rebuild() def save_figure(self): if not self.has_active_editor(): return if self.active_editor: if not isinstance(self.active_editor, RecallEditor): sid = self.active_editor.saved_figure_id if sid >= 0: self._save_figure() else: self._save_as_figure() else: self.warning_dialog('You are trying to save a figure from a Recall Editor. ' 'Select a Figure Editor instead.') def save_as_figure(self): self._save_as_figure() def set_interpreted_age(self): if self.active_editor: if not isinstance(self.active_editor, RecallEditor): self.active_editor.set_interpreted_age() else: self.warning_dialog('You are trying to set an interpreted age from Recall Editor. ' 'Select a Figure Editor instead') def browse_interpreted_age(self): app = self.application app.open_task('pychron.processing.interpreted_age') def add_text_box(self): ac = self.active_editor if ac and ac.component and hasattr(ac, 'add_text_box'): self.active_editor.add_text_box() at = self.active_editor.annotation_tool if at: at.on_trait_change(self.plot_editor_pane.set_annotation_component, 'component') self.plot_editor_pane.set_annotation_tool(at) # def tb_new_ideogram(self): # self.new_ideogram() # # # if isinstance(self.active_editor, IdeogramEditor) and \ # # not self.unknowns_pane.items: # # self.append_ideogram() # # else: # # self.new_ideogram() # # def tb_new_spectrum(self): # self.new_spectrum() # # if isinstance(self.active_editor, SpectrumEditor) and \ # # not self.unknowns_pane.items: # # self.append_spectrum() # # else: # # self.new_spectrum() # # def tb_new_xy_scatter(self): # self.new_xy_scatter() # # def tb_new_isochron(self): # self.new_inverse_isochron() # # =============================================================================== # # =============================================================================== # =============================================================================== # private # =============================================================================== def _clear_group(self): for i in self.unknowns_pane.items: i.group_id = 0 i.graph_id = 0 self.unknowns_pane.refresh_needed = True def _debug_add(self): from pychron.globals import globalv self.debug('debug add figure_debug: {}'.format(globalv.figure_debug)) if globalv.figure_debug: if self.browser_model: ans = self.browser_model.analysis_table.analyses if ans: self.active_editor.set_items(ans) # with no_update(self.unknowns_pane): # self.unknowns_pane.items = ans def _activate_editor(self, kind): func = getattr(self, 'new_{}'.format(kind)) klass = globals()['{}Editor'.format(kind.capitalize())] if self.active_editor is None: print 'new editor' func() else: for editor in self.editor_area.editors: if isinstance(editor, klass): self.activate_editor(editor) break else: print 'new editor' func() def _new_figure(self, ans, name, klass, tklass=None, add_table=True, add_iso=True, set_ans=True): # with no_update(self): # if klass == IdeogramEditor: # self.browser_model.current_task_name = 'Ideogram' # else: # self.browser_model.current_task_name = 'Spectrum' # new figure editor editor = klass( name=name, processor=self.manager) if ans is None: ans = self.unknowns_pane.items if ans: editor.analyses = ans editor.set_name() editor.rebuild() # if set_ans: # self.unknowns_pane.items = ans self._open_editor(editor) # add_associated = False # if not add_associated: # self.debug('Not adding associated editors') # else: # if tklass and add_table: # # open table # teditor = self._new_table(ans, name, tklass) # if teditor: # editor.associated_editors.append(weakref.ref(teditor)()) # # if add_iso: # # open associated isochron # ieditor = self._new_associated_isochron(ans, name) # if ieditor: # editor.associated_editors.append(weakref.ref(ieditor)()) # ieditor.parent_editor = editor # activate figure editor # self.editor_area.activate_editor(editor) return editor def _add_editor(self, editor, ans): ed = None if ans: if isinstance(editor, FigureEditor): editor.unknowns = ans else: editor.items = ans ed = next((e for e in self.editor_area.editors if e.name == editor.name), None) if not ed: self.editor_area.add_editor(editor) else: editor = None return editor def _add_unknowns_hook(self, *args, **kw): if self.active_editor: # if hasattr(self.active_editor, 'auto_group'): # if self.active_editor.auto_group: if self.unknowns_pane.auto_group and self.active_editor.auto_group: self.group_by_labnumber() # for ai in self.active_editor.associated_editors: # if isinstance(ai, FigureEditor): # ai.rebuild_graph() # def _get_unique_group_id(self): # gids = {i.group_id for i in self.unknowns_pane.items} # return max(gids) + 1 def _get_unique_graph_id(self): gids = {i.graph_id for i in self.unknowns_pane.items} return max(gids) + 1 def _get_selected_indices(self): items = self.unknowns_pane.items return [items.index(si) for si in self.unknowns_pane.selected] def _new_associated_isochron(self, ans, name): name = '{}-isochron'.format(name) editor = InverseIsochronEditor(name=name, processor=self.manager) return self._add_editor(editor, ans) def _new_table(self, ans, name, klass): if ans is None: ans = self.unknowns_pane.items name = '{}-table'.format(name) editor = klass(name=name) return self._add_editor(editor, ans) def _load_project_figures(self, new): if new: db = self.manager.db with db.session_ctx(): proj = [p.name for p in new] figs = db.get_project_figures(proj) self.ofigures = [self._dbfigure_factory(f) for f in figs] self.figures = self.ofigures self._figure_kind_changed() def _load_sample_figures(self, new): if new: lns = [p.labnumber for p in new] self.debug('loading sample figures for {}'.format(','.join(lns))) db = self.manager.db with db.session_ctx(): figs = db.get_labnumber_figures(lns) # figs = [self._dbfigure_factory(f) for f in figs] def gen(): for f in figs: fig = self._dbfigure_factory(f) if fig: yield fig figs = list(gen()) self.ofigures = figs[:] self.figures = figs self._figure_kind_changed() def _dbfigure_factory(self, f): if f.preference: try: dbf = DBFigure(name=f.name or '', project=f.project.name if f.project else '', identifiers=[s.labnumber.identifier for s in f.labnumbers], samples=list(set([s.labnumber.sample.name for s in f.labnumbers])), kind=f.preference.kind, id=f.id) return dbf except AttributeError: self.debug_exception() self.debug('failed making dbfigure {}'.format(f.name)) def _get_sample_obj(self, s): return next((sr for sr in self.browser_model.samples if sr.labnumber == s), None) def _get_project_obj(self, p): return next((sr for sr in self.browser_model.projects if sr.name == p), None) def _save_figure(self): """ update preferences update analyses """ if self.active_editor: self.active_editor.update_figure() self.db_save_info() # db=self.manager.db # with db.session_ctx() as sess: # fig=db.get_figure(sid, key='id') # print sid, fig # # pom=self.active_editor.plotter_options_manager # blob = pom.dump_yaml() # fig.preference.options=blob # # dbans=fig.analyses # uuids=[ai.uuid for ai in self.active_editor.analyses] # # for dbai in fig.analyses: # if not dbai.analysis.uuid in uuids: # #remove analysis # sess.delete(dbai) # # for ai in self.active_editor.analyses: # if not next((dbai for dbai in dbans if dbai.analysis.uuid==ai.uuid), None): # #add analysis # ai=db.get_analysis_uuid(ai.uuid) # db.add_figure_analysis(fig, ai) def _save_as_figure(self): """ add a new figure to the database """ db = self.manager.db if not isinstance(self.active_editor, FigureEditor): return with db.session_ctx(): #use dialog to ask user for figure name and associated project dlg = SaveFigureDialog(projects=self.projects, samples=self.samples) # if self.selected_projects: # dlg.selected_project = self.selected_projects[0] # projects = list(set([ai.project for ai in self.active_editor.analyses])) if projects: proj = self._get_project_obj(projects[0]) if proj: dlg.selected_project = proj identifiers = list(set([ai.labnumber for ai in self.active_editor.analyses])) # print samples ss = [self._get_sample_obj(si) for si in identifiers] # # print ss ss = filter(lambda x: not x is None, ss) # # print ss dlg.selected_samples = ss while 1: info = dlg.edit_traits(kind='livemodal') if not info.result: return if dlg.name: break else: if not self.confirmation_dialog('Need to set the name of a "figure" to save. Continue?'): return project = None if dlg.selected_project: project = dlg.selected_project.name identifiers = [si.labnumber for si in dlg.selected_samples] fid = self.active_editor.save_figure(dlg.name, project, identifiers) self._load_sample_figures(dlg.selected_samples) idx = next((i for i, o in enumerate(self.ofigures) if o.id == fid), None) if idx is not None: self.active_editor.saved_figure_id = idx def _delete_figures(self, figs): db = self.manager.db with db.session_ctx() as sess: for fi in figs: dbfig = db.get_figure(fi.id, key='id') sess.delete(dbfig.preference) for si in dbfig.labnumbers: sess.delete(si) for ai in dbfig.analyses: sess.delete(ai) sess.delete(dbfig) # =============================================================================== # handlers # =============================================================================== # def _selected_projects_changed(self, old, new): # # self._load_project_figures(new) # super(FigureTask, self)._selected_projects_changed(new) @on_trait_change('browser_model:plot_selected') def _handle_plot_selected(self, new): if new: self.plot_selected_grouped() else: self.plot_selected() @on_trait_change('browser_model:selected_samples') def _selected_samples_changed(self, new): self._load_sample_figures(new) # super(FigureTask, self)._selected_samples_changed(new) def _delete_figure_button_fired(self): if self.selected_figures: if self.confirmation_dialog('Are you sure you want to delete the selected figures?'): self._delete_figures(self.selected_figures) if self.browser_model.selected_samples: self._load_sample_figures(self.browser_model.selected_samples) else: self._load_project_figures(self.browser_model.selected_projects) def _figure_kind_changed(self): self.selected_figures = [] if self.figure_kind: if self.figure_kind == 'All': self.figures = self.ofigures else: kind = self.figure_kind[:4].lower() self.figures = filter(lambda x: x.kind == kind, self.ofigures) # def _dclicked_sample_changed(self, new): def _dclicked_sample_hook(self): if not self.has_active_editor(): return editor = self.active_editor if isinstance(editor, FigureEditor): editor.saved_figure_id = -1 editor.clear_aux_plot_limits() editor.enable_aux_plots() # super(FigureTask, self)._dclicked_sample_changed() super(FigureTask, self)._dclicked_sample_hook() def _dclicked_figure_changed(self, new): if not new: return sf = self.selected_figures if sf: # and isinstance(self.active_editor, FigureEditor): db = self.manager.db with db.session_ctx(): sf = sf[0] db_fig = db.get_figure(sf.id, key='id') blob = db_fig.preference.options kind = db_fig.preference.kind open_editor_needed = True editor = self.active_editor if editor: open_editor_needed = editor.basename != kind if open_editor_needed: # open new editor of this kind if kind == 'spec': if editor: editor.close() self.new_spectrum() elif kind == 'ideo': if editor: editor.close() self.new_ideogram() if editor: editor.enable_aux_plots() editor.saved_figure_id = int(sf.id) editor.plotter_options_manager.deinitialize() editor.set_items([a.analysis for a in db_fig.analyses]) for ai, dbai in zip(editor.analyses, db_fig.analyses): ai.group_id = int(dbai.group or 0) ai.graph_id = int(dbai.graph or 0) editor.plotter_options_manager.load_yaml(blob) editor.rebuild() @on_trait_change('plotter_options_pane:pom:plotter_options:[+, refresh_plot_needed, aux_plots:+]') def _options_update(self, obj, name, old, new): if name == 'initialized' or not obj.initialized: return # print obj, name if self.has_active_editor(): if name == 'refresh_plot_needed': # if self.plotter_options_pane.pom.plotter_options.auto_refresh or name == 'refresh_plot_needed': # print 'plotter options rebuild' if not isinstance(self.active_editor, RecallEditor): self.active_editor.rebuild() self.active_editor.dump_tool() self._refresh_plot_hook() def _refresh_plot_hook(self): pass def _set_current_task(self): with no_update(self): if isinstance(self.active_editor, IdeogramEditor): self.browser_model.current_task_name = 'Ideogram' elif isinstance(self.active_editor, SpectrumEditor): self.browser_model.current_task_name = 'Spectrum' else: super(FigureTask, self)._set_current_task() def _active_editor_changed(self, new): editor = self.active_editor if editor: if isinstance(editor, (FigureEditor, XYScatterEditor)): self.plotter_options_pane.pom = pom = editor.plotter_options_manager colors = pom.plotter_options.get_group_colors() if colors: self.unknowns_pane.adapter.colors = colors # self._set_current_task() super(FigureTask, self)._active_editor_changed(new) @on_trait_change('plotter_options_pane:pom:plotter_options:groups:color') def _handle_colors(self): pom = self.plotter_options_pane.pom colors = pom.plotter_options.get_group_colors() self.unknowns_pane.adapter.colors = colors self.unknowns_pane.refresh_needed = True @on_trait_change('active_editor:refresh_unknowns_table') def _ac_refresh_table(self): if self.unknowns_pane: self.unknowns_pane.refresh_needed = True @on_trait_change('active_editor:tag') def _handle_graph_tag(self): self.set_tag() @on_trait_change('active_editor:save_db_figure') def _handle_save_db_figure(self): self._save_as_figure() @on_trait_change('active_editor:invalid') def _handle_invalid(self): self.set_tag(Tag(name='invalid')) # =========================================================================== # browser protocol # =========================================================================== # =============================================================================== # defaults # =============================================================================== def _default_layout_default(self): a = Tabbed(browser_pane_item(), PaneItem('pychron.processing.figures.plotter_options')) b = PaneItem('pychron.processing.unknowns') left = HSplitter(a, b) # HSplitter(VSplitter( # Tabbed(browser_pane_item(), # PaneItem('pychron.processing.figures.plotter_options'), # PaneItem('pychron.plot_editor'))), # PaneItem('pychron.processing.unknowns')) return TaskLayout(id='pychron.processing', left=left) # return TaskLayout( # id='pychron.processing', # left=HSplitter( # browser_pane_item(), # Tabbed( # # PaneItem('pychron.processing.figures.saved_figures'), # PaneItem('pychron.processing.unknowns'), # PaneItem('pychron.processing.figures.plotter_options'), # PaneItem('pychron.plot_editor')))) # ============= EOF ============================================= #@classmethod # def group_by(cls, editor, items, key): # ids = [] # for it in items: # v = key(it) # if not v in ids: # ids.append(v) # # sitems = sorted(items, key=key) # for k, analyses in groupby(sitems, key=key): # gid = ids.index(k) # idxs = [items.index(ai) for ai in analyses] # editor.set_group(idxs, gid, refresh=False) # def _append_figure(self, klass): # """ # if selected_samples append all analyses # else append selected analyses # # """ # return # # if isinstance(self.active_editor, klass): # sa = self.analysis_table.selected # if sa: # ts = self.manager.make_analyses(sa) # else: # ts = [ai for si in self.selected_sample # for ai in self._get_sample_analyses(si)] # # ans = self.manager.make_analyses(ts) # if ans: # pans = self.active_editor.analyses # uuids = [p.uuid for p in pans] # fans = [ai for ai in ans if ai.uuid not in uuids] # # pans.extend(fans) # self.active_editor.trait_set(unknowns=pans) # # gid = 0 # for _, gans in groupby(self.active_editor.unknowns, key=lambda x: x.sample): # for ai in gans: # ai.group_id = gid # gid += 1 # # self.active_editor.rebuild(compress_groups=False) # # new figure editor # editor = klass( # name=name, # processor=self.manager) # # if ans is None: # ans = self.unknowns_pane.items # # if ans: # editor.analyses = ans # editor.set_name() # editor.rebuild() # # if set_ans: # # self.unknowns_pane.items = ans # # self._open_editor(editor) # # # add_associated = False # # if not add_associated: # # self.debug('Not adding associated editors') # # else: # # if tklass and add_table: # # # open table # # teditor = self._new_table(ans, name, tklass) # # if teditor: # # editor.associated_editors.append(weakref.ref(teditor)()) # # # # if add_iso: # # # open associated isochron # # ieditor = self._new_associated_isochron(ans, name) # # if ieditor: # # editor.associated_editors.append(weakref.ref(ieditor)()) # # ieditor.parent_editor = editor # # # activate figure editor # # self.editor_area.activate_editor(editor) # return editor
class SpectrometerTask(EditorTask): scan_manager = Any name = 'Scan' id = 'pychron.spectrometer' _scan_editor = Instance(ScanEditor) tool_bars = [SToolBar(StopScanAction(), )] def info(self, msg, *args, **kw): super(SpectrometerTask, self).info(msg) def spy_position_magnet(self, *args, **kw): self.scan_manager.position_magnet(*args, **kw) def spy_peak_center(self, name): peak_kw = dict(confirm_save=False, warn=True, new_thread=False, message='spectrometer script peakcenter', on_end=self._on_peak_center_end) setup_kw = dict(config_name=name) return self._peak_center(setup_kw=setup_kw, peak_kw=peak_kw) def populate_mftable(self): sm = self.scan_manager cfg = sm.setup_populate_mftable() if cfg: def func(): refiso = cfg.isotope ion = sm.ion_optics_manager ion.backup_mftable() odefl = [] dets = cfg.get_detectors() self.debug('setting deflections') for det, defl in dets: odefl.append((det, sm.spectrometer.get_deflection(det))) sm.spectrometer.set_deflection(det, defl) for di in dets: ion.setup_peak_center( detector=[di.name], isotope=refiso, config_name=cfg.peak_center_config.active_item.name, standalone_graph=False, new=True, show_label=True, use_configuration_dac=False) ion.peak_center.update_others = False name = 'Pop MFTable {}-{}'.format(di.name, refiso) invoke_in_main_thread( self._open_editor, PeakCenterEditor(model=ion.peak_center, name=name)) self._on_peak_center_start() ion.do_peak_center(new_thread=False, save=True, warn=True) self._on_peak_center_end() if not ion.peak_center.isAlive(): break self.debug('unset deflections') for det, defl in odefl: sm.spectrometer.set_deflection(det, defl) fp = cfg.get_finish_position() self.debug('move to end position={}'.format(fp)) if fp: iso, det = fp if iso and det: ion.position(iso, det) t = Thread(target=func) t.start() def stop_scan(self): self.debug('stop scan fired') editor = self.active_editor self.debug('active editor {}'.format(editor)) if editor: if isinstance(editor, (ScanEditor, PeakCenterEditor, CoincidenceEditor)): self.debug('editor stop') editor.stop() def do_coincidence(self): es = [ int(e.name.split(' ')[-1]) for e in self.editor_area.editors if isinstance(e, CoincidenceEditor) ] i = max(es) + 1 if es else 1 man = self.scan_manager.ion_optics_manager name = 'Coincidence {:02d}'.format(i) if man.setup_coincidence(): self._open_editor( CoincidenceEditor(model=man.coincidence, name=name)) man.do_coincidence_scan() def do_peak_center(self): peak_kw = dict(confirm_save=True, warn=True, message='manual peakcenter', on_end=self._on_peak_center_end) self._peak_center(peak_kw=peak_kw) def define_peak_center(self): from pychron.spectrometer.ion_optics.define_peak_center_view import DefinePeakCenterView man = self.scan_manager.ion_optics_manager spec = man.spectrometer dets = spec.detector_names isos = spec.isotopes dpc = DefinePeakCenterView(detectors=dets, isotopes=isos, detector=dets[0], isotope=isos[0]) info = dpc.edit_traits() if info.result: det = dpc.detector isotope = dpc.isotope dac = dpc.dac self.debug('manually setting mftable to {}:{}:{}'.format( det, isotope, dac)) message = 'manually define peak center {}:{}:{}'.format( det, isotope, dac) man.spectrometer.magnet.update_field_table(det, isotope, dac, message) def _on_peak_center_start(self): self.scan_manager.log_events_enabled = False self.scan_manager.scan_enabled = False def _on_peak_center_end(self): self.scan_manager.log_events_enabled = True self.scan_manager.scan_enabled = True def send_configuration(self): self.scan_manager.spectrometer.send_configuration() def prepare_destroy(self): for e in self.editor_area.editors: if hasattr(e, 'stop'): e.stop() self.scan_manager.prepare_destroy() super(SpectrometerTask, self).prepare_destroy() # def activated(self): # self.scan_manager.activate() # self._scan_factory() # super(SpectrometerTask, self).activated() def create_dock_panes(self): panes = [ ControlsPane(model=self.scan_manager), RecordControlsPane(model=self.scan_manager), MassScannerPane(model=self.scan_manager), DACScannerPane(model=self.scan_manager), ReadoutPane(model=self.scan_manager), IntensitiesPane(model=self.scan_manager) ] panes = self._add_canvas_pane(panes) return panes # def _active_editor_changed(self, new): # if not new: # try: # self._scan_factory() # except AttributeError: # pass # private def _peak_center(self, setup_kw=None, peak_kw=None): if setup_kw is None: setup_kw = {} if peak_kw is None: peak_kw = {} es = [] for e in self.editor_area.editors: if isinstance(e, PeakCenterEditor): try: es.append(int(e.name.split(' ')[-1])) except ValueError: pass i = max(es) + 1 if es else 1 ret = -1 ion = self.scan_manager.ion_optics_manager self._peak_center_start_hook() time.sleep(2) name = 'Peak Center {:02d}'.format(i) if ion.setup_peak_center(new=True, **setup_kw): self._on_peak_center_start() invoke_in_main_thread( self._open_editor, PeakCenterEditor(model=ion.peak_center, name=name)) ion.do_peak_center(**peak_kw) ret = ion.peak_center_result self._peak_center_stop_hook() return ret def _peak_center_start_hook(self): pass def _peak_center_stop_hook(self): pass def _scan_factory(self): sim = self.scan_manager.spectrometer.simulation name = 'Scan (Simulation)' if sim else 'Scan' # self._open_editor(ScanEditor(model=self.scan_manager, name=name)) # print 'asdfas', self.editor_area.control # print [e for e in self.editor_area.control.children() if isinstance(e, EditorWidget)] # super(SpectrometerTask, self).activated() se = ScanEditor(model=self.scan_manager, name=name) self._open_editor(se) def _default_layout_default(self): return TaskLayout( left=Splitter(PaneItem('pychron.spectrometer.controls'), orientation='vertical'), right=VSplitter(PaneItem('pychron.spectrometer.intensities'), PaneItem('pychron.spectrometer.readout'))) # def create_central_pane(self): # g = ScanPane(model=self.scan_manager) # return g @on_trait_change('scan_manager:mass_scanner:new_scanner') def _handle_mass_scan_event(self): self._scan_event(self.scan_manager.mass_scanner) @on_trait_change('scan_manager:dac_scanner:new_scanner') def _handle_dac_scan_event(self): self._scan_event(self.scan_manager.dac_scanner) def _scan_event(self, scanner): sim = self.scan_manager.spectrometer.simulation name = 'Magnet Scan (Simulation)' if sim else 'Magnet Scan' editor = next( (e for e in self.editor_area.editors if e.id == 'pychron.scanner'), None) if editor is not None: scanner.reset() else: editor = ScannerEditor(model=scanner, name=name, id='pychron.scanner') self._open_editor(editor, activate=False) self.split_editors(0, 1, h2=300, orientation='vertical') self.activate_editor(editor) @on_trait_change('window:opened') def _opened(self): self.scan_manager.activate() self._scan_factory() ee = [ e for e in self.editor_area.control.children() if isinstance(e, EditorWidget) ][0]