def on_step_routes_complete(self, start_time, electrode_ids):
        '''
        Callback function executed when all concurrent routes for a step have
        completed a single run.

        If repeats are requested, either through repeat counts or a repeat
        duration, *cycle* routes (i.e., routes that terminate at the start
        electrode) will repeat as necessary.
        '''
        step_options = self.get_step_options()
        step_duration_s = (datetime.now() -
                           self.step_start_time).total_seconds()
        if ((step_options['repeat_duration_s'] > 0 and step_duration_s <
             step_options['repeat_duration_s']) or
            (self.repeat_i + 1 < step_options['route_repeats'])):
            # Either repeat duration has not been met, or the specified number
            # of repetitions has not been met.  Execute another iteration of
            # the routes.
            self.repeat_i += 1
            df_routes = self.get_routes()
            self.route_controller.execute_routes(
                df_routes, step_options['transition_duration_ms'],
                trail_length=step_options['trail_length'],
                cyclic=True, acyclic=False,
                on_complete=self.on_step_routes_complete,
                on_error=self.on_error)
        else:
            logger.info('Completed routes (%s repeats in %ss)', self.repeat_i +
                        1, si_format(step_duration_s))
            # Transitions along all droplet routes have been processed.
            # Signal step has completed and reset plugin step state.
            emit_signal('on_step_complete', [self.name, None])
Exemple #2
0
    def on_step_run(self):
        """"
        Handler called whenever a step is executed. Note that this signal
        is only emitted in realtime mode or if a protocol is running.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.

        return_value can be one of:
            None
            'Repeat' - repeat the step
            or 'Fail' - unrecoverable error (stop the protocol)
        """
        app = get_app()
        logger.info('[SyringePumpPlugin] on_step_run(): step #%d',
                    app.protocol.current_step_number)
        app_values = self.get_app_values()
        options = self.get_step_options()

        if (self.proxy != None and (app.realtime_mode or app.running)):
            microsteps = self.proxy.microstep_setting
            steps = (app_values['steps_per_microliter'] *
                     options['microliters'] * microsteps)
            steps_per_second = (app_values['steps_per_microliter'] *
                                microsteps * options['microliters_per_min'] /
                                60.0)
            self.proxy.move(steps, steps_per_second)
            print 'move(steps=%d, steps_per_second=%d)' % (steps,
                                                           steps_per_second)
            while self.proxy.steps_remaining:
                gtk.main_iteration()
        return_value = None
        emit_signal('on_step_complete', [self.name, return_value])
Exemple #3
0
    def on_step_run(self):
        """
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.

        .. versionchanged:: 0.14
            Schedule update of control board status label in main GTK thread.
        """
        logger.debug('[DropBotPlugin] on_step_run()')
        self._kill_running_step()
        app = get_app()
        options = self.get_step_options()

        if (self.control_board and (app.realtime_mode or app.running)):
            max_channels = self.control_board.number_of_channels
            # All channels should default to off.
            channel_states = np.zeros(max_channels, dtype=int)
            # Set the state of any channels that have been set explicitly.
            channel_states[self.channel_states.index.values.tolist(
            )] = self.channel_states

            emit_signal("set_frequency",
                        options['frequency'],
                        interface=IWaveformGenerator)
            emit_signal("set_voltage",
                        options['voltage'],
                        interface=IWaveformGenerator)
            if not self.control_board.hv_output_enabled:
                self.control_board.hv_output_enabled = True

            label = (
                self.connection_status +
                ', Voltage: %.1f V' % self.control_board.measure_voltage())

            # Schedule update of control board status label in main GTK thread.
            gobject.idle_add(
                app.main_window_controller.label_control_board_status.
                set_markup, label)

            self.control_board.set_state_of_channels(channel_states)

        # if a protocol is running, wait for the specified minimum duration
        if app.running:
            logger.debug('[DropBotPlugin] on_step_run: '
                         'timeout_add(%d, _callback_step_completed)' %
                         options['duration'])
            self.timeout_id = gobject.timeout_add(
                options['duration'], self._callback_step_completed)
            return
        else:
            self.step_complete()
    def update_grid(self, protocol=None):
        app = get_app()
        if protocol is None:
            protocol = app.protocol
        if protocol is None:
            return
        logging.debug('[ProtocolGridController].update_grid:')
        logging.debug('[ProtocolGridController]   plugin_fields=%s',
                      protocol.plugin_fields)
        forms = emit_signal('get_step_form_class')

        steps = protocol.steps
        logging.debug('[ProtocolGridController]   forms=%s steps=%s', forms,
                      steps)

        if self.enabled_fields is None:
            # Assign directly to _enabled_fields to avoid recursive call into
            # update_grid()
            self._enabled_fields = dict([(form_name,
                                          set(form.field_schema_mapping
                                              .keys()))
                                         for form_name, form in forms.items()])

        # The step ID column can be hidden by changing show_ids to False
        combined_fields = ProtocolGridView(forms, self.enabled_fields,
                                           show_ids=True)
        combined_fields.connect('fields-filter-request',
                                self.set_fields_filter)

        for i, step in enumerate(steps):
            values = emit_signal('get_step_values', [i])
            logging.debug('[ProtocolGridController]   Step[%d]=%s values=%s',
                          i, step, values)

            attributes = dict()
            for form_name, form in combined_fields.forms.iteritems():
                attr_values = values[form_name]
                logging.debug('[CombinedRow] attr_values=%s' % attr_values)
                attributes[form_name] = RowFields(**attr_values)
            c = CombinedRow(combined_fields, attributes=attributes)
            combined_fields.append(c)
        if self.widget:
            self.window.remove(self.widget)
            del self.widget
        self.widget = combined_fields
        if self.widget:
            self.widget.show_all()
            self.widget.select_row(app.protocol.current_step_number)
            self._register_shortcuts()
            self.window.add(self.widget)
Exemple #5
0
    def on_step_run(self):
        '''
        Handler called whenever a step is executed.

        Plugins that handle this signal **MUST** emit the ``on_step_complete``
        signal once they have completed the step.  The protocol controller will
        wait until all plugins have completed the current step before
        proceeding.
        '''
        # Get latest step field values for this plugin.
        options = self.get_step_options()
        # Apply step options
        self.apply_step_options(options)

        emit_signal('on_step_complete', [self.name])
    def on_step_run(self):
        """
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.
        """
        logger.debug('[OpenDropPlugin] on_step_run()')
        self._kill_running_step()
        app = get_app()
        options = self.get_step_options()
        dmf_options = app.dmf_device_controller.get_step_options()
        logger.debug('[OpenDropPlugin] options=%s dmf_options=%s' %
                     (options, dmf_options))
        app_values = self.get_app_values()

        if (self.control_board.connected() and (app.realtime_mode or
                                                app.running)):

            state = dmf_options.state_of_channels
            max_channels = self.control_board.number_of_channels()
            if len(state) > max_channels:
                state = state[0:max_channels]
            elif len(state) < max_channels:
                state = np.concatenate([state, np.zeros(max_channels -
                                                        len(state), int)])
                assert(len(state) == max_channels)

            emit_signal("set_frequency",
                        options['frequency'],
                        interface=IWaveformGenerator)
            emit_signal("set_voltage", options['voltage'],
                        interface=IWaveformGenerator)

            self.control_board.set_state_of_all_channels(state)

        # if a protocol is running, wait for the specified minimum duration
        if app.running:
            logger.debug('[OpenDropPlugin] on_step_run: '
                         'timeout_add(%d, _callback_step_completed)' %
                         options['duration'])
            self.timeout_id = gobject.timeout_add(
                options['duration'], self._callback_step_completed)
            return
        else:
            self.step_complete()
    def update_protocol(self, protocol):
        app = get_app()

        for i, s in enumerate(protocol):

            step = app.protocol.steps[i]
            prevData = step.get_data(self.plugin_name)
            values = {}

            for k,v in prevData.iteritems():
                if k in s:
                    values[k] = s[k]

            step.set_data(self.plugin_name, values)
            emit_signal('on_step_options_changed', [self.plugin_name, i],
                        interface=IPlugin)
    def update_protocol(self, protocol):
        app = get_app()

        for i, s in enumerate(protocol):

            step = app.protocol.steps[i]
            prevData = step.get_data(self.plugin_name)
            values = {}

            for k, v in prevData.iteritems():
                if k in s:
                    values[k] = s[k]

            step.set_data(self.plugin_name, values)
            emit_signal('on_step_options_changed', [self.plugin_name, i],
                        interface=IPlugin)
    def on_step_run(self):
        """
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.
        """
        logger.debug('[TestPlugin] on_step_run()')
        app = get_app()

        if (self.proxy and app.realtime_mode or app.running):
            options = self.get_step_options()
            self.proxy.digital_write(pin=13, value=options['led_on'])

        emit_signal('on_step_complete', [self.name, None])
    def on_step_run(self):
        """
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.
        """
        logger.debug('[TestPlugin] on_step_run()')
        app = get_app()

        if (self.proxy and app.realtime_mode or app.running):
            options = self.get_step_options()
            self.proxy.digital_write(pin=13, value=options['led_on'])
        
        emit_signal('on_step_complete', [self.name, None])
    def on_step_run(self):
        '''
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete signal
        once they have completed the step. The protocol controller will wait
        until all plugins have completed the current step before proceeding.
        '''
        app = get_app()

        if (app.realtime_mode or app.running) and self.gui_process is not None:
            step_options = self.get_step_options()
            if not step_options['video_enabled']:
                hub_execute(self.name, 'disable_video',
                            wait_func=lambda *args: refresh_gui(), timeout_s=5,
                            silent=True)
            else:
                hub_execute(self.name, 'enable_video',
                            wait_func=lambda *args: refresh_gui(), timeout_s=5,
                            silent=True)
        emit_signal('on_step_complete', [self.name, None])
    def on_step_run(self):
        '''
        Handler called whenever a step is executed.

        Plugins that handle this signal must emit the on_step_complete signal
        once they have completed the step. The protocol controller will wait
        until all plugins have completed the current step before proceeding.
        '''
        app = get_app()
        # TODO: Migrate video commands to mqtt!!
        # if (app.realtime_mode or app.running) and self.gui_process is not None:
        #     step_options = self.get_step_options()
        #     if not step_options['video_enabled']:
        #         hub_execute(self.name, 'disable_video',
        #                     wait_func=lambda *args: refresh_gui(), timeout_s=5,
        #                     silent=True)
        #     else:
        #         hub_execute(self.name, 'enable_video',
        #                     wait_func=lambda *args: refresh_gui(), timeout_s=5,
        #                     silent=True)
        emit_signal('on_step_complete', [self.name, None])
    def on_step_run(self):
        """
        Handler called whenever a step is executed. Note that this signal
        is only emitted in realtime mode or if a protocol is running.

        Plugins that handle this signal must emit the on_step_complete
        signal once they have completed the step. The protocol controller
        will wait until all plugins have completed the current step before
        proceeding.

        return_value can be one of:
            None
            'Repeat' - repeat the step
            or 'Fail' - unrecoverable error (stop the protocol)
        """
        app = get_app()
        logger.info('[AnalystRemotePlugin] on_step_run(): step #%d',
                    app.protocol.current_step_number)
        # If `acquire` is `True`, start acquisition
        options = self.get_step_options()
        if options['acquire']:
            app_values = self.get_app_values()
            try:
                if self.timeout_id is not None:
                    # Timer was already set, so cancel previous timer.
                    gobject.source_remove(self.timeout_id)
                self.remote = AnalystRemoteControl(app_values['subscribe_uri'],
                                                   app_values['request_uri'])
                self.remote.start_acquisition()
                self.timeout_id = gobject.timeout_add(100,
                                                      self.remote_check_tick)
            except:
                print "Exception in user code:"
                print '-'*60
                traceback.print_exc(file=sys.stdout)
                print '-'*60
                # An error occurred while initializing Analyst remote control.
                emit_signal('on_step_complete', [self.name, 'Fail'])
        else:
            emit_signal('on_step_complete', [self.name, None])
 def remote_check_tick(self):
     if self.remote is not None:
         try:
             if self.remote.acquisition_complete():
                 # Acquisition is complete so notify step complete.
                 self.remote.reset()
                 emit_signal('on_step_complete', [self.name, None])
                 self.timeout_id = None
                 self.remote = None
                 return False
             else:
                 print "Waiting for acquisition to complete..."
         except:
             print "Exception in user code:"
             print '-'*60
             traceback.print_exc(file=sys.stdout)
             print '-'*60
             emit_signal('on_step_complete', [self.name, 'Fail'])
             self.timeout_id = None
             self.remote = None
             return False
     return True
 def __init__(self):
     gobject.GObject.__init__(self)
     super(MetadataPlugin, self).__init__()
     self.name = self.plugin_name
     self.timeout_id = None
     self.start_time = None
     self.menu_item = None
     self.menu = None
     self.video_config_menu = None
     self.metadata_menu = None
     self.connect('metadata-changed', lambda obj, original_metadata,
                  metadata: pm.emit_signal('on_metadata_changed',
                                           args=[obj.schema,
                                                 original_metadata,
                                                 metadata]))
    def update_grid(self, protocol=None):
        app = get_app()
        if protocol is None:
            protocol = app.protocol
        if protocol is None:
            return
        _L().debug('plugin_fields=%s', protocol.plugin_fields)
        forms = dict([
            (k, f) for k, f in emit_signal('get_step_form_class').iteritems()
            if f is not None
        ])

        steps = protocol.steps
        _L().debug('forms=%s steps=%s', forms, steps)

        if self.enabled_fields is None:
            # Assign directly to _enabled_fields to avoid recursive call into
            # update_grid()
            self._enabled_fields = dict([
                (form_name, set(form.field_schema_mapping.keys()))
                for form_name, form in forms.items()
            ])

        # The step ID column can be hidden by changing show_ids to False
        combined_fields = ProtocolGridView(forms,
                                           self.enabled_fields,
                                           show_ids=True)
        combined_fields.connect('fields-filter-request',
                                self.set_fields_filter)

        for i, step in enumerate(steps):
            values = emit_signal('get_step_values', [i])

            attributes = dict()
            for form_name, form in combined_fields.forms.iteritems():
                attr_values = values[form_name]
                attributes[form_name] = RowFields(**attr_values)
            combined_row = CombinedRow(combined_fields, attributes=attributes)
            combined_fields.append(combined_row)

        if self.widget:
            # Replacing a previously rendered widget.  Maintain original column
            # order.

            # Store the position of each column, keyed by column title.
            column_positions = dict([
                (_get_title(c), i)
                for i, c in enumerate(self.widget.get_columns())
            ])
            # Remove existing widget to replace with new widget.
            self.window.remove(self.widget)
            del self.widget
        else:
            # No previously rendered widget.  Used saved column positions (if
            # available).
            app_values = self.get_app_values()
            column_positions_json = app_values.get('column_positions', '{}')
            column_positions = json.loads(column_positions_json)

        if column_positions:
            # Explicit column positions are available, so reorder columns
            # accordingly.

            # Remove columns so we can reinsert them in an explicit order.
            columns = combined_fields.get_columns()
            for c in columns:
                combined_fields.remove_column(c)

            # Sort columns according to original order.
            ordered_column_info = sorted([
                (column_positions.get(_get_title(c),
                                      len(columns)), _get_title(c), c)
                for c in columns
            ])

            # Re-add columns in order (sorted according to existing column
            # order).
            for i, title_i, column_i in ordered_column_info:
                combined_fields.append_column(column_i)

        self.widget = combined_fields

        app = get_app()
        if self.widget:
            self.widget.show_all()
            self.widget.select_row(app.protocol.current_step_number)
            self.window.add(self.widget)
            self.accel_group = self._create_accel_group(
                app.main_window_controller.view)
            app.main_window_controller.view.add_accel_group(self.accel_group)
        else:
            self.accel_group = None

        # Disable keyboard shortcuts when a cell edit has started.  Without
        # doing so, certain keys may not behave as expected in edit mode.  For
        # example, see [`step_label_plugin`][1].
        #
        # [1]: https://github.com/wheeler-microfluidics/step_label_plugin/issues/1
        self.widget.connect(
            'editing-started', lambda *args: app.main_window_controller.
            disable_keyboard_shortcuts())
        # Re-enable keyboard shortcuts when a cell edit has completed.
        self.widget.connect(
            'editing-done',
            lambda *args: app.main_window_controller.enable_keyboard_shortcuts(
            ))
    def check_dstat_status(self):
        '''
         1. Check to see if acquisition is finished.
         2. If (1), emit `on_step_complete` signal.
        '''
        try:
            completed_timestamp = hub_execute('dstat-interface',
                                              'acquisition_complete',
                                              experiment_id=
                                              self.dstat_experiment_id,
                                              timeout_s=5.)
            if completed_timestamp is not None:
                # ## Acquisition is complete ##

                app = get_app()

                # Increment the number of completed DStat experiments for
                # current step.
                step_i = app.protocol.current_step_number
                count_i = 1 + self.dstat_experiment_count_by_step.get(step_i,
                                                                      0)
                self.dstat_experiment_count_by_step[step_i] = count_i

                # ### Save results data and plot ###
                output_directory = (path(app.experiment_log.get_log_path())
                                    .abspath())
                output_namebase = str(app.protocol.current_step_number)

                step_label = self.get_step_label()
                if step_label is not None:
                    # Replace characters that are not allowed in a filename
                    # with underscore.
                    output_namebase = re.sub(r'[:/\\\?{}]', '_', step_label)

                # Save results to a text file in the experiment log directory.
                output_txt_path = get_unique_path(output_directory
                                                  .joinpath(output_namebase +
                                                            '.txt'))
                logger.info('Save results to: %s', output_txt_path)
                dstat_params = hub_execute('dstat-interface', 'get_params')
                hub_execute('dstat-interface', 'save_text',
                            save_data_path=output_txt_path)
                data_i = hub_execute('dstat-interface', 'get_experiment_data',
                                     experiment_id=self.dstat_experiment_id)
                metadata_i = self.get_step_metadata()
                # Compute (approximate) `utc_timestamp` for each DStat
                # measurement.
                max_time_s = data_i.time_s.max()
                metadata_i['utc_timestamp'] = (completed_timestamp -
                                               data_i.time_s
                                               .map(lambda t:
                                                    timedelta(seconds=
                                                              max_time_s - t)))

                # Step label from step label plugin.
                metadata_i['step_label'] = step_label

                # Compute UTC start time from local experiment start time.
                metadata_i['experiment_start'] = \
                    (dt.datetime.fromtimestamp(app.experiment_log.start_time())
                     + (dt.datetime.utcnow() - dt.datetime.now()))
                # Compute UTC start time from local experiment start time.
                metadata_i['experiment_length_min'] = \
                    (completed_timestamp -
                     metadata_i['experiment_start']).total_seconds() / 60.

                # Record synchronous detection parameters from DStat (if set).
                if dstat_params['sync_true']:
                    metadata_i['target_hz'] = float(dstat_params['sync_freq'])
                else:
                    metadata_i['target_hz'] = None
                metadata_i['sample_frequency_hz'] = float(dstat_params['adc_rate_hz'])

                # Cast metadata `unicode` fields as `str` to enable HDF export.
                for k, v in metadata_i.iteritems():
                    if isinstance(v, types.StringTypes):
                        metadata_i[k] = str(v)

                data_md_i = data_i.copy()

                for i, (k, v) in enumerate(metadata_i.iteritems()):
                    try:
                        data_md_i.insert(i, k, v)
                    except Exception, e:
                        logger.info('Skipping metadata field %s: %s.\n%s', k,
                                    v, e)

                # Set order for known columns.  Unknown columns are ordered
                # last, alphabetically.
                column_order = ['instrument_id', 'experiment_id',
                                'experiment_uuid', 'experiment_start',
                                'experiment_length_min', 'utc_timestamp',
                                'device_id', 'batch_id', 'sample_id',
                                'step_label', 'step_number', 'attempt_number',
                                'temperature_celsius', 'relative_humidity',
                                'target_hz', 'sample_frequency_hz', 'time_s',
                                'current_amps']
                column_index = dict([(k, i) for i, k in
                                     enumerate(column_order)])
                ordered_columns = sorted(data_md_i.columns, key=lambda k:
                                         (column_index
                                          .get(k, len(column_order)), k))
                data_md_i = data_md_i[ordered_columns]

                namebase_i = ('e[{}]-d[{}]-s[{}]'
                              .format(metadata_i['experiment_uuid'][:8],
                                      metadata_i.get('device_id'),
                                      metadata_i.get('sample_id')))

                if self.dstat_experiment_data is None:
                    self.dstat_experiment_data = data_md_i
                else:
                    combined = pd.concat([self.dstat_experiment_data,
                                          data_md_i])
                    self.dstat_experiment_data = combined.reset_index(drop=
                                                                      True)

                # Append DStat experiment data to CSV file.
                csv_output_path = self.data_dir().joinpath(namebase_i + '.csv')
                # Only include header if the file does not exist or is empty.
                include_header = not (csv_output_path.isfile() and
                                      (csv_output_path.size > 0))
                with csv_output_path.open('a') as output:
                    data_md_i.to_csv(output, index=False,
                                     header=include_header)

                df_dstat_summary = self.dstat_summary_frame(numeric=True)
                # Write DStat summary table to CSV file.
                csv_summary_path = self.data_dir().joinpath('dstat-summary'
                                                            '.csv')
                with csv_summary_path.open('w') as output:
                    df_dstat_summary.to_csv(output)

                # Turn light back on after photomultiplier tube (PMT)
                # measurement.
                self.dropbot_dx_remote.light_enabled = True

                # notify step complete.
                emit_signal('on_step_complete', [self.name, None])
                self.dstat_timeout_id = None
                return False
            else:
Exemple #18
0
 def notify(step_number):
     emit_signal('on_step_options_changed', [self.name, step_number],
                 interface=IPlugin)
 def on_error(self, *args):
     logger.error('Error executing routes.', exc_info=True)
     # An error occurred while initializing Analyst remote control.
     emit_signal('on_step_complete', [self.name, 'Fail'])
 def step_complete(self, return_value=None):
     app = get_app()
     if app.running or app.realtime_mode:
         emit_signal('on_step_complete', [self.name, return_value])
    def update_grid(self, protocol=None):
        app = get_app()
        if protocol is None:
            protocol = app.protocol
        if protocol is None:
            return
        logging.debug('[ProtocolGridController].update_grid:')
        logging.debug('[ProtocolGridController]   plugin_fields=%s',
                      protocol.plugin_fields)
        forms = dict([(k, f) for k, f in
                      emit_signal('get_step_form_class').iteritems()
                      if f is not None])

        steps = protocol.steps
        logging.debug('[ProtocolGridController]   forms=%s steps=%s', forms,
                      steps)

        if self.enabled_fields is None:
            # Assign directly to _enabled_fields to avoid recursive call into
            # update_grid()
            self._enabled_fields = dict([(form_name,
                                          set(form.field_schema_mapping
                                              .keys()))
                                         for form_name, form in forms.items()])

        # The step ID column can be hidden by changing show_ids to False
        combined_fields = ProtocolGridView(forms, self.enabled_fields,
                                           show_ids=True)
        combined_fields.connect('fields-filter-request',
                                self.set_fields_filter)

        for i, step in enumerate(steps):
            values = emit_signal('get_step_values', [i])
            #logging.debug('[ProtocolGridController]   Step[%d]=%s values=%s',
                          #i, step, values)

            attributes = dict()
            for form_name, form in combined_fields.forms.iteritems():
                attr_values = values[form_name]
                #logging.debug('[CombinedRow] attr_values=%s' % attr_values)
                attributes[form_name] = RowFields(**attr_values)
            combined_row = CombinedRow(combined_fields, attributes=attributes)
            combined_fields.append(combined_row)

        # Create a shortcut wrapper to lookup column title from each
        # `TreeViewColumn`.  Just makes following code more concise.
        get_title = lambda c: c.get_data('pygtkhelpers::column').title

        if self.widget:
            # Replacing a previously rendered widget.  Maintain original column
            # order.

            # Store the position of each column, keyed by column title.
            column_positions = dict([(get_title(c), i)
                                     for i, c in enumerate(self.widget
                                                           .get_columns())])
            # Remove existing widget to replace with new widget.
            self.window.remove(self.widget)
            del self.widget
        else:
            # No previously rendered widget.  Used saved column positions (if
            # available).
            app_values = self.get_app_values()
            column_positions_json = app_values.get('column_positions', '{}')
            column_positions = json.loads(column_positions_json)

        if column_positions:
            # Explicit column positions are available, so reorder columns
            # accordingly.

            # Remove columns so we can reinsert them in an explicit order.
            columns = combined_fields.get_columns()
            for c in columns:
                combined_fields.remove_column(c)

            # Sort columns according to original order.
            ordered_column_info = sorted([(column_positions.get(get_title(c),
                                                                len(columns)),
                                           get_title(c), c) for c in columns])

            # Re-add columns in order (sorted according to existing column order).
            for i, title_i, column_i in ordered_column_info:
                combined_fields.append_column(column_i)

        self.widget = combined_fields

        app = get_app()
        if self.widget:
            self.widget.show_all()
            self.widget.select_row(app.protocol.current_step_number)
            self.window.add(self.widget)
            self.accel_group = self._create_accel_group(app
                                                        .main_window_controller
                                                        .view)
            app.main_window_controller.view.add_accel_group(self.accel_group)
        else:
            self.accel_group = None

        # Disable keyboard shortcuts when a cell edit has started.  Without
        # doing so, certain keys may not behave as expected in edit mode.  For
        # example, see [`step_label_plugin`][1].
        #
        # [1]: https://github.com/wheeler-microfluidics/step_label_plugin/issues/1
        self.widget.connect('editing-started', lambda *args:
                            app.main_window_controller
                            .disable_keyboard_shortcuts())
        # Re-enable keyboard shortcuts when a cell edit has completed.
        self.widget.connect('editing-done', lambda *args:
                            app.main_window_controller
                            .enable_keyboard_shortcuts())
    def on_step_run(self):
        '''
        Handler called whenever a step is executed. Note that this signal is
        only emitted in realtime mode or if a protocol is running.

        Plugins that handle this signal must emit the `on_step_complete` signal
        once they have completed the step. The protocol controller will wait
        until all plugins have completed the current step before proceeding.

        The `on_step_complete` signal is emitted with following signature:

            emit_signal('on_step_complete', [plugin_name, return_value])

        where `plugin_name` is the name of the emitting plugin, and
        `return_value` can be one of:

         - `None`: Step completed successfully.
         - `'Repeat'`: Repeat the step.
         - `'Fail'`: Unrecoverable error (stop the protocol).
        '''
        app = get_app()
        logger.info('[DropBotDxAccessoriesPlugin] on_step_run(): step #%d',
                    app.protocol.current_step_number)
        options = self.get_step_options()
        app_values = self.get_app_values()
        if self.connected():
            self.dropbot_dx_remote.light_enabled = not options['dstat_enabled']
            self.dropbot_dx_remote.magnet_engaged=options['magnet_engaged']
            try:
                if self.has_environment_data:
                    env = self.get_environment_state().to_dict()
                    logger.info('temp=%.1fC, Rel. humidity=%.1f%%' %
                                (env['temperature_celsius'],
                                 100 * env['relative_humidity']))
                    app.experiment_log.add_data({"environment state": env},
                                                self.name)
            except ValueError:
                self.has_environment_data = False

            if options['dstat_enabled']:
                # D-stat is enabled for step.  Request acquisition.
                try:
                    if 'dstat_params_file' in options:
                        # Load Dstat parameters.
                        hub_execute('dstat-interface', 'load_params',
                                    params_path=options['dstat_params_file'])
                    if self.dstat_timeout_id is not None:
                        # Timer was already set, so cancel previous timer.
                        gobject.source_remove(self.dstat_timeout_id)
                    # Delay before D-stat measurement (e.g., to allow webcam
                    # light to turn off).
                    dstat_delay_s = app_values.get('dstat_delay_s', 0)
                    time.sleep(max(0, dstat_delay_s))
                    step_label = self.get_step_label()
                    # Send Microdrop step label (if available) to provide name
                    # for DStat experiment.
                    metadata = self.metadata.copy()
                    metadata['name'] = (step_label if step_label else
                                        str(app.protocol.current_step_number +
                                            1))
                    metadata['patient_id'] = metadata.get('sample_id', 'None')

                    # Get target path for DStat database directory.
                    dstat_database_path = (path(app.config['data_dir'])
                                           .realpath().joinpath('dstat-db'))
                    self.dstat_experiment_id = \
                        hub_execute('dstat-interface', 'run_active_experiment',
                                    metadata=metadata,
                                    params={'db_path_entry':
                                            str(dstat_database_path),
                                            'db_enable_checkbutton': True})
                    self._dstat_spinner = itertools.cycle(r'-\|/')
                    print ''
                    # Check every 250ms to see if dstat acquisition has
                    # completed.
                    self.dstat_timeout_id = \
                        gobject.timeout_add(250, self.check_dstat_status)
                except:
                    print "Exception in user code:"
                    print '-'*60
                    traceback.print_exc(file=sys.stdout)
                    print '-'*60
                    # An error occurred while initializing Analyst remote
                    # control.
                    emit_signal('on_step_complete', [self.name, 'Fail'])
            else:
                # D-State is not enabled, so step is complete.
                emit_signal('on_step_complete', [self.name, None])
        else:
            # DropBox-DX device is not connected, but allow protocol to
            # continue.
            #
            # N.B., A warning message is display once at the *start* of the
            # protocol if no DropBot-DX connection has been established, but
            # *not* on each step.
            emit_signal('on_step_complete', [self.name, None])
Exemple #23
0
 def step_complete(self, return_value=None):
     app = get_app()
     if app.running or app.realtime_mode:
         emit_signal('on_step_complete', [self.name, return_value])
                df_dstat_summary = self.dstat_summary_frame(numeric=True)
                # Write DStat summary table to CSV file.
                csv_summary_path = self.data_dir().joinpath('dstat-summary'
                                                            '.csv')
                with csv_summary_path.open('w') as output:
                    df_dstat_summary.to_csv(output)

                # Turn light back on after photomultiplier tube (PMT)
                # measurement.
                self.dropbot_dx_remote.light_enabled = True

                # notify step complete.
                emit_signal('on_step_complete', [self.name, None])
                self.dstat_timeout_id = None
                return False
            else:
                print '\rWaiting for Dstat...', self._dstat_spinner.next(),
        except:
            print "Exception in user code:"
            print '-'*60
            traceback.print_exc(file=sys.stdout)
            print '-'*60
            emit_signal('on_step_complete', [self.name, 'Fail'])
            self.dstat_timeout_id = None
            return False
        return True


PluginGlobals.pop_env()