Ejemplo n.º 1
0
    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]
Ejemplo n.º 2
0
 def _tool_bars_default(self):
     tb = SToolBar(
         SampleLoadingAction(),
         # IsolateChamberAction(),
         # EvacuateChamberAction(),
         # FinishChamberChangeAction(),
         image_size=(16, 16))
     tb2 = SToolBar(AutoReloadAction())
     return [tb, tb2]
Ejemplo n.º 3
0
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'))
Ejemplo n.º 4
0
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')))
Ejemplo n.º 5
0
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'))
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
 def _tool_bars_default(self):
     tb = SToolBar(IsolateChamberAction(),
                   EvacuateChamberAction(),
                   FinishChamberChangeAction(),
                   image_size=(16, 16))
     return [
         tb,
     ]
Ejemplo n.º 8
0
    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'))
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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)
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
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)
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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'))))
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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]
Ejemplo n.º 18
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
Ejemplo n.º 19
0
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 =============================================
Ejemplo n.º 20
0
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
Ejemplo n.º 21
0
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'))
Ejemplo n.º 22
0
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'))
Ejemplo n.º 23
0
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'))
Ejemplo n.º 24
0
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
Ejemplo n.º 25
0
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)
Ejemplo n.º 26
0
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'))
Ejemplo n.º 27
0
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()
Ejemplo n.º 28
0
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)
Ejemplo n.º 29
0
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
Ejemplo n.º 30
0
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]