Пример #1
0
class SceneController(HasTraits):
    n_meridional    = CInt(10)
    n_longitudinal  = CInt(10)

    scene = Instance(MlabSceneModel, ())

    plot = Instance(PipelineBase)

    # When the scene is activated, or when the parameters are changed, we
    # update the plot.
    @on_trait_change('n_meridional,n_longitudinal,scene.activated')
    def update_plot(self):
        x, y, z, t = self.get_data()
        if self.plot is None:
            self.plot = self.scene.mlab.plot3d(x, y, z, t,
                                tube_radius=0.025, colormap='Spectral')
        else:
            self.plot.mlab_source.set(x=x, y=y, z=z, scalars=t)

    def get_data(self):
        """ Obtain the x,y,z,t data for the domain equation and given values of
        n_meridional and n_longitudinal
        """
        from numpy import arange, pi, cos, sin
        phi = arange(0.0, 2*pi + 0.5*pi/1000, pi/1000, 'd')

        mu = phi*self.n_meridional
        x = cos(mu) * (1 + cos(self.n_longitudinal * mu/self.n_meridional)*0.5)
        y = sin(mu) * (1 + cos(self.n_longitudinal * mu/self.n_meridional)*0.5)
        z = 0.5 * sin(self.n_longitudinal*mu/self.n_meridional)
        t = sin(mu)

        return x, y, z, t

    def create_scene_widget(self):
        """ Factory method to create the QWidget for the Mayavi scene.

        This follows the same approach as the Chaco example i.e. create a hidden
        traitsui view based on the mayavi SceneEditor and return it's 'control'
        to obtain the required QWidget.
        """
        from traitsui.api import View, Item
        from mayavi.core.ui.api import MayaviScene, SceneEditor
        view = View(Item('scene', show_label=False,
                         editor=SceneEditor(scene_class=MayaviScene)),
                         resizable=True)
        ui = self.edit_traits(view=view, parent=None, kind='subpanel')

        return ui.control
Пример #2
0
class ExportPane(TraitsDockPane):

    id = 'edu.mit.synbio.cytoflowgui.export_pane'
    name = 'Export'

    # the task serving as the dock pane's controller
    task = Instance(Task)

    closable = False
    dock_area = 'right'
    floatable = False
    movable = False
    visible = True

    # the dinky little model that this pane displays
    width = CFloat(11)
    height = CFloat(8.5)
    dpi = CInt(96)

    do_exit = Event
    do_export = Event

    def default_traits_view(self):
        return View(
            Item('width', editor=TextEditor(auto_set=False)),
            Item('height', editor=TextEditor(auto_set=False)),
            Item('dpi', editor=TextEditor(auto_set=False)),
            Item('do_export',
                 editor=ButtonEditor(value=True, label="Export figure..."),
                 show_label=False),
            Item('do_exit',
                 editor=ButtonEditor(value=True, label="Return to Cytoflow"),
                 show_label=False))
Пример #3
0
class ViolinPlotParams(Data1DPlotParams):
    bw = Enum('scott', 'silverman')
    scale_plot = Enum('area', 'count', 'width')
    scale_hue = Bool(False)
    gridsize = CInt(100)
    inner = Enum("box", "quartile", None)
    split = Bool(False)
Пример #4
0
class Dataset(HasTraits):
    scan_id = Str("")
    subject_id = Str("")
    scan_gender = List(["female", "male"])
    scan_age = CInt(22)
    study = Str("")
    scan_group = Str("")

    software = List(["DSI Studio", "DTK"])
    smoothing = Range(low=0., high=1., default=0.)
    cutoff_angle = Range(low=0., high=180., default=55.)
    qa_threshold = Range(low=0., high=1., default=0.)
    gfa_threshold = Range(low=0., high=1., default=0.)
    length_min = Range(low=0., high=100., default=10.)
    length_max = Range(low=0., high=1000., default=400.)

    institution = List(["UCSB", "CMU"])
    reconstruction = Enum("dsi", "gqi", "qsdr")
    scanner = List(["SIEMENS TIM TRIO"])
    n_directions = Range(low=8, high=516, default=512)
    max_b_value = List([5000, 1000])
    bvals = List()
    bvecs = List()

    def __init__(self, **traits):
        super(Dataset, self).__init__(**traits)
Пример #5
0
class RsyncMixin(HasTraits):
    rsync_user = Str
    rsync_port = CInt(22)
    rsync_remote = Str
    rsync_options = Str
    lpath = Str
    rpath = Str

    def _bind_preferences(self):
        prefid = 'pychron.dvc'
        for r in ('rsync_user', 'rsync_remote', 'rsync_port', 'rsync_options'):
            bind_preference(self, r, '{}.{}'.format(prefid, r))

    def push(self):
        rsync_push(self.lpath,
                   self.rpath,
                   True,
                   remote=self.rsync_remote,
                   user=self.rsync_user)

    def pull(self):
        rsync_pull(self.lpath,
                   self.rpath,
                   False,
                   remote=self.rsync_remote,
                   user=self.rsync_user)
Пример #6
0
class Model(HasTraits):
    npts_x = CInt(256)
    npts_y = CInt(256)
    npts_z = CInt(109)

    min_x = CFloat(-2 * pi)
    max_x = CFloat(2 * pi)
    min_y = CFloat(-2 * pi)
    max_y = CFloat(2 * pi)
    min_z = CFloat(-pi)
    max_z = CFloat(pi)

    xs = Array
    ys = Array
    vals = Array

    minval = Float
    maxval = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    @on_trait_change("npts_+", "min_+", "max_+")
    def compute_model(self):
        def vfunc(x, y, z):
            return sin(x * z) * cos(y) * sin(z) + sin(0.5 * z)

        # Create the axes
        self.xs = linspace(self.min_x, self.max_x, self.npts_x)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y)
        self.zs = linspace(self.min_z, self.max_z, self.npts_z)

        # Generate a cube of values by using newaxis to span new dimensions
        self.vals = vfunc(self.xs[:, newaxis, newaxis],
                          self.ys[newaxis, :, newaxis], self.zs[newaxis,
                                                                newaxis, :])

        self.minval = nanmin(self.vals)
        self.maxval = nanmax(self.vals)
        self.model_changed = True
Пример #7
0
class TubeFactory(PipeFactory):
    """Applies the Tube mayavi filter to the given VTK object."""

    _target = Instance(filters.Tube, ())

    tube_sides = CInt(6, adapts='filter.number_of_sides',
                        desc="""number of sides of the tubes used to
                        represent the lines.""")

    tube_radius = CFloat(0.05, adapts='filter.radius',
                        desc="""radius of the tubes used to represent the
                        lines.""")
Пример #8
0
class ArduinoServoActuator(AbstractArduinoActuator):
    """
        Float-valued actuator object for Arduino output pins that can be configured in Servo mode
        Status is servo angle (0-360).
    """

    _status = CFloat(transient=True)

    #: Minimum pulse time (in microseconds)
    min_pulse = CInt(544)

    #: Maximum pulse time (in microseconds)
    max_pulse = CInt(2400)

    def _min_pulse_changed(self):
        if self.traits_inited():
            self.setup()

    def _max_pulse_changed(self):
        if self.traits_inited():
            self.setup()

    def setup(self, *args, **kwargs):
        super().setup(*args, **kwargs)
        self.logger.debug("setup_servo %s %s %s %s %s %s", self, self.service,
                          self.pin, self.min_pulse, self.max_pulse,
                          int(round(self._status)))
        self._arduino.setup_servo(self.pin, self.min_pulse, self.max_pulse,
                                  int(round(self._status)))

    def _status_changed(self):
        self.logger.debug("change_servo %s %s %s", self.pin,
                          int(round(self._status)))
        self._arduino.change_digital(self.pin, int(round(self._status)))

    def cleanup(self):
        self._arduino.cleanup_digital_actuator(self.pin)
Пример #9
0
class ImagePlaneWidgetFactory(DataModuleFactory):
    """ Applies the ImagePlaneWidget mayavi module to the given data
        source (Mayavi source, or VTK dataset).
    """
    _target = Instance(modules.ImagePlaneWidget, ())

    slice_index = CInt(0, adapts='ipw.slice_index',
                        help="""The index along wich the
                                            image is sliced.""")

    plane_opacity = Range(0.0, 1.0, 1.0, adapts='ipw.plane_property.opacity',
                    desc="""the opacity of the plane actor.""")

    plane_orientation = Enum('x_axes', 'y_axes', 'z_axes',
                        adapts='ipw.plane_orientation',
                        desc="""the orientation of the plane""")
Пример #10
0
class ViolinPlotParams(Data1DPlotParams):

    bw = Enum('scott', 'silverman')
    scale_plot = Enum('area', 'count', 'width')
    scale_hue = Bool(False)
    gridsize = CInt(100)
    inner = Enum("box", "quartile", None)
    split = Bool(False)

    def default_traits_view(self):
        base_view = Data1DPlotParams.default_traits_view(self)

        return View(Item('bw', label='Bandwidth'),
                    Item('scale_plot', label="Plot scale"), Item('scale_hue'),
                    Item('gridsize', editor=TextEditor(auto_set=False)),
                    Item('inner'), Item('split'), base_view.content)
Пример #11
0
class Camera(HasTraits):
    """Camera object"""

    gain = Enum(
        1,
        2,
        3,
        desc="the gain index of the camera",
        label="gain",
    )

    exposure = CInt(
        10,
        desc="the exposure time, in ms",
        label="Exposure",
    )
Пример #12
0
class AngleControl(HasTraits):
    '''
    Euler angle UI elements:

    Angles in the UI can be set by
    1. initial:     Typing the desired angle
    2. add_diff:    Once the first angle is chosen, the camera can be moved using a slider

    final = angle + d_angle will be displayed and is intended to be used in subsequent actions
    '''

    definition = Instance(ElementalRotationDefinition, ())

    # Large scale rotation angle
    initial = CInt(0)

    # Small scale rotation angle slider
    add_diff = Range(-50, 50, 0)

    # Resulting rotation angle
    final = Property(observe='initial, add_diff')

    def _get_final(self):
        return self.initial + self.add_diff

    # UI elements
    label = Property(depends_on='definition.name')

    def _get_label(self):
        return self.definition.angle_name + ": "

    view_label = Item('label', show_label=False, style="readonly")
    view_initial = Item('initial', show_label=False)
    view_add_diff = HGroup(Item('', label="+"),
                           Item('add_diff', show_label=False, width=200))
    view_final = HGroup(
        Item('', label="="),
        Item('final', show_label=False, style="readonly", width=40))

    view = View(
        HGroup(view_label,
               view_initial,
               view_add_diff,
               view_final,
               show_border=True,
               springy=True))
Пример #13
0
class Camera(HasTraits):
    """Camera object"""

    gain = Enum(
        1,
        2,
        3,
        desc="the gain index of the camera",
        label="gain",
    )
    exposure = CInt(
        10,
        desc="the exposure time, in ms",
        label="Exposure",
    )

    def capture(self):
        """Captures an image on the camera and returns it"""
        print("capturing an image at %i ms exposure, gain: %i" %
              (self.exposure, self.gain))
Пример #14
0
class AbstractArduinoSensor(AbstractSensor):
    """
        Abstract base class for Arduino sensors
    """

    history_frequency = CFloat(1.0)
    user_editable = CBool(False)

    #: Arduino service number (specify, if more than 1 ArduinoServices are configured in system)
    service = CInt(0)

    #: Arduino pin number
    pin = CInt

    _arduino = Instance(AbstractSystemService, transient=True)

    def setup(self, *args, **kwargs):
        super().setup(*args, **kwargs)
        self.logger.debug('Arduino sensor setup')
        self._arduino = self.system.request_service('ArduinoService',
                                                    self.service)
Пример #15
0
class AbstractArduinoActuator(AbstractActuator):
    """
        Abstract base class for Arduino actuators
    """

    #: Arduino service number (specify, if more than 1 ArduinoService are configured in the system)
    service = CInt(0)

    #: Arduino pin number
    pin = CInt

    _arduino = Instance(AbstractSystemService, transient=True)

    view = AbstractActuator.view + ["pin"]
    simple_view = AbstractActuator.simple_view + ["pin"]

    def setup(self, *args, **kwargs):
        super().setup(*args, **kwargs)
        self.logger.debug('Arduino actuator setup')
        self._arduino = self.system.request_service('ArduinoService',
                                                    self.service)
Пример #16
0
class FileChangeSensor(AbstractSensor):
    """ Sensor that detects file changes on filesystem.
        Integer valued status is incremented by each change.
    """
    _status = CInt(0)

    #: Name of file or directory to monitor
    filename = CUnicode

    #: PyInotify flags to configure what file change events to monitor
    watch_flags = Int(pyinotify.IN_MODIFY | pyinotify.IN_CREATE
                      | pyinotify.IN_DELETE)

    _notifier = Any(transient=True)

    class InotifyEventHandler(pyinotify.ProcessEvent):
        def __init__(self, func, *args, **kwargs):
            self.func = func
            super().__init__(*args, **kwargs)

        def process_default(self, event):
            self.func()

    def notify(self):
        self.status += 1

    def setup(self):
        if self._notifier:
            self._notifier.stop()
        wm = pyinotify.WatchManager()
        handler = self.InotifyEventHandler(self.notify)
        self._notifier = pyinotify.ThreadedNotifier(wm,
                                                    default_proc_fun=handler)

        wm.add_watch(self.filename, self.watch_flags, rec=True)
        self._notifier.start()

    def cleanup(self):
        self._notifier.stop()
Пример #17
0
class BeadCalibrationPluginOp(PluginOpMixin, BeadCalibrationOp):
    handler_factory = Callable(BeadCalibrationHandler)

    beads_name = Str(estimate=True)
    beads = Dict(Str, List(Float), transient=True)

    beads_file = File(filter=["*.fcs"], estimate=True)
    units_list = List(_Unit, estimate=True)
    units = Dict(Str, Str, transient=True)

    bead_peak_quantile = CInt(80, estimate=True)
    bead_brightness_threshold = CFloat(100.0, estimate=True)
    bead_brightness_cutoff = util.CFloatOrNone(None, estimate=True)

    @on_trait_change('units_list_items,units_list.+', post_init=True)
    def _controls_changed(self, obj, name, old, new):
        self.changed = (Changed.ESTIMATE, ('units_list', self.units_list))

    def default_view(self, **kwargs):
        return BeadCalibrationPluginView(op=self, **kwargs)

    def apply(self, experiment):

        if not self.beads_name:
            raise util.CytoflowOpError(
                "Specify which beads to calibrate with.")

        for i, unit_i in enumerate(self.units_list):
            for j, unit_j in enumerate(self.units_list):
                if unit_i.channel == unit_j.channel and i != j:
                    raise util.CytoflowOpError(
                        "Channel {0} is included more than once".format(
                            unit_i.channel))

        self.units = {}
        for unit in self.units_list:
            self.units[unit.channel] = unit.unit

        self.beads = self.BEADS[self.beads_name]
        return BeadCalibrationOp.apply(self, experiment)

    def estimate(self, experiment):
        if not self.beads_name:
            raise util.CytoflowOpError(
                "Specify which beads to calibrate with.")

        for i, unit_i in enumerate(self.units_list):
            for j, unit_j in enumerate(self.units_list):
                if unit_i.channel == unit_j.channel and i != j:
                    raise util.CytoflowOpError(
                        "Channel {0} is included more than once".format(
                            unit_i.channel))

        self.units = {}
        for unit in self.units_list:
            self.units[unit.channel] = unit.unit

        self.beads = self.BEADS[self.beads_name]
        BeadCalibrationOp.estimate(self, experiment)
        self.changed = (Changed.ESTIMATE_RESULT, self)

    def should_clear_estimate(self, changed, payload):
        if changed == Changed.ESTIMATE:
            return True

        return False

    def clear_estimate(self):
        self._calibration_functions.clear()
        self._peaks.clear()
        self._mefs.clear()
        self._histograms.clear()
        self.changed = (Changed.ESTIMATE_RESULT, self)

    def get_notebook_code(self, idx):
        op = BeadCalibrationOp()
        op.copy_traits(self, op.copyable_trait_names())

        for unit in self.units_list:
            op.units[unit.channel] = unit.unit

        op.beads = self.BEADS[self.beads_name]

        return dedent("""
        # Beads: {beads}
        op_{idx} = {repr}
        
        op_{idx}.estimate(ex_{prev_idx})
        ex_{idx} = op_{idx}.apply(ex_{prev_idx})
        """.format(beads=self.beads_name,
                   repr=repr(op),
                   idx=idx,
                   prev_idx=idx - 1))
Пример #18
0
class VectorsFactory(DataModuleFactory):
    """Applies the Vectors mayavi module to the given data object
        source (Mayavi source, or VTK dataset).
    """

    _target = Instance(modules.Vectors, ())

    scale_factor = CFloat(1., adapts='glyph.glyph.scale_factor',
                            desc="""the scaling applied to the glyphs. The
                                    size of the glyph is by default in drawing
                                    units.""")

    scale_mode = Trait('vector', {'none':'data_scaling_off',
                                'scalar':'scale_by_scalar',
                                'vector':'scale_by_vector'},
                            help="""the scaling mode for the glyphs
                            ('vector', 'scalar', or 'none').""")

    resolution = CInt(8, desc="The resolution of the glyph created. For "
                        "spheres, for instance, this is the number of "
                        "divisions along theta and phi.")

    mask_points = Either(None, CInt,
                        desc="If supplied, only one out of 'mask_points' "
                        "data point is displayed. This option is useful "
                        "to reduce the number of points displayed "
                        "on large datasets")

    def _resolution_changed(self):
        glyph = self._target.glyph.glyph_source.glyph_source
        if hasattr(glyph, 'theta_resolution'):
            glyph.theta_resolution = self.resolution
        if hasattr(glyph, 'phi_resolution'):
            glyph.phi_resolution = self.resolution
        if hasattr(glyph, 'resolution'):
            glyph.resolution = self.resolution
        if hasattr(glyph, 'shaft_resolution'):
            glyph.shaft_resolution = self.resolution
        if hasattr(glyph, 'tip_resolution'):
            glyph.tip_resolution = self.resolution

    def _mask_points_changed(self):
        if self.mask_points is not None:
            self._target.glyph.mask_input_points = True
            self._target.glyph.mask_points.on_ratio = self.mask_points

    def _scale_mode_changed(self):
        self._target.glyph.scale_mode = self.scale_mode_

    mode = Trait('2darrow', glyph_mode_dict,
                    desc="""the mode of the glyphs.""")

    def _mode_changed(self):
        v = self._target
        # Workaround for different version of VTK:
        if hasattr(v.glyph.glyph_source, 'glyph_source'):
            g = v.glyph.glyph_source
        else:
            g = v.glyph
        if self.mode == 'point':
            g.glyph_source = tvtk.PointSource(radius=0, number_of_points=1)
        else:
            g.glyph_source = g.glyph_list[self.mode_]
        if self.mode_ == 0:
            g.glyph_source.glyph_type = self.mode[2:]
Пример #19
0
class TextClassifier(HasTraits):
    '''
    Class for implementing sklean text classifiers in the editor.
    '''
    
    # The text vectorizer from sklearn.feature_extraction.text
    vectorizer = Instance(TfidfVectorizer)
    
    # The training data
    x_train = Instance(csr_matrix)
    
    # The testing data
    x_test = Instance(csr_matrix)
    
    # The average performance score of the classifier
    classifier_score = Float
    
    # Length of the selected column that should be considered as training data
    train_length = CInt(0)
    
    # The column index that should be considered as containing the targets
    target_col_no = CInt(0)
    
    # The DataFrame instance containing the data
    data_frame = Instance(DataFrame)
    
    # The selection_handler object for the tableview
    selection_handler = Instance(SelectionHandler)
    
    # The string representation of the selected classifier
    classifier_select = String
    
    # A dictionary that maps classifier_string into sklearn classifier
    # instances
    classifier_dict = Dict

    
    def __init__(self, vectorizer=None, data_frame=None):

        if vectorizer is not None:
            self.vectorizer = vectorizer
        else:
            self.vectorizer = TfidfVectorizer()
        if data_frame is not None:
            self.data_frame = data_frame
        self.selection_handler = SelectionHandler()
        self.classifier_dict = {
            'LinearSVC':LinearSVC(),
            'Perceptron':Perceptron(),
            'RidgeClassifier':RidgeClassifier(),
            'SGDClassifier':SGDClassifier(),
            'BernoulliNB':BernoulliNB(),
            'MultinomialNB':MultinomialNB(),
            'KneighborsClassifier':KNeighborsClassifier(),
            'NearestCentroid':NearestCentroid()
        }
    
    def select_classifier(self):
        '''
        Sets the classifier as per the selection from the user.
        '''
        self.classifier = self.classifier_dict[self.classifier_select]
    
    def create_dataset(self):
        '''
        Splits the data frame into training data, testing data and targets.
        '''
        
        self.selection_handler.create_selection()
        column = self.selection_handler.selected_indices[0][1]
        column_name = self.data_frame.columns[column]
        data = self.data_frame[column_name]
        self.training_data = data[:self.train_length]
        self.testing_data = data[self.train_length:]
        
        column_name = self.data_frame.columns[self.target_col_no]
        target_data = self.data_frame[column_name]
        self.train_targets = np.array(target_data[:self.train_length]).astype(float)
        self.test_targets = target_data[self.train_length:]
        
        self.selection_handler.flush()
    
    def text_vectorize(self):
        '''
        Vectorizes the text input.
        '''
        self.x_train = self.vectorizer.fit_transform(self.training_data)
        #self.x_test = self.vectorizer.transform(self.testing_data)
    
    def train_classifier(self):
        '''
        Trains the selected classifier.
        '''
        self.classifier.fit(self.x_train, self.train_targets)
    
    def test_classifier(self):
        '''
        Tests the selected classifier to generate the prediction score.
        '''
        self.x_test = self.vectorizer.transform(self.testing_data)
        self.prediction = self.classifier.predict(self.x_test)
        self.classifier_score = self.classifier.score(self.x_test,
                                                      self.test_targets)
    
    def save_classifier(self, pickle_filename):
        '''
        Saves the classifier and vectorizer objects as a pickle file.
        '''
        op = open(pickle_filename, 'w')
        pickle.dump(self.classifier, op)
        pickle.dump(self.vectorizer, op)
        op.close()
    
    def load_classifier(self, pickle_filename):
        '''
        Loads a classifier and a vectorizer from a pickle file.
        '''
        op = open(pickle_filename, 'r')
        self.classifier = pickle.load(op)
        self.vectorizer = pickle.load(op)
        op.close()
    
    def make_prediction(self):
        '''
        Makes prediction considering the selected column as test input.
        '''
        self.selection_handler.create_selection()
        pred_data_index = self.selection_handler.selected_indices[0][1]
        pred_column_name = self.data_frame.columns[pred_data_index]
        self.testing_data = self.data_frame[pred_column_name]
        self.x_test = self.vectorizer.transform(self.testing_data)
        self.prediction = self.classifier.predict(self.x_test)
Пример #20
0
class AbstractService(HasTraits):
    """
        Base class for System and UserServices
    """

    #: If set to *True*, service is loaded automatically (if not explicitly prevented
    #: in :attr:`automate.system.System.exclude_services`). Overwrite this in subclasses,
    autoload = False
    system = Instance(SystemBase)
    logger = Instance(logging.Logger, transient=True)
    log_level = CInt(logging.INFO)
    is_mocked = CBool(False, transient=True)
    _id = 0

    @property
    def id(self):
        return id(self)

    @property
    def name(self):
        return '%s.%s' % (self.__class__.__name__, self._id)

    def _log_level_changed(self, new_value):
        if self.logger:
            self.logger.setLevel(new_value)

    @property
    def initialized(self):
        return bool(self.system)

    def setup_system(self, system, name=None, id=0):
        self.system = system
        self._id = id
        self.logger = self.system.logger.getChild(self.name)
        self.logger.setLevel(self.log_level)
        self.logger.info('Setup')
        self.system.register_service(self)
        self.setup()

    def cleanup_system(self):
        if self.system:
            self.logger.info('Cleaning up')
            self.cleanup()

    def setup(self):
        """
            Initialize service here. Define in subclasses.
        """

    def cleanup(self):
        """
            Cleanup actions must be performed here. This must be blocking until service is
            fully cleaned up.

            Define in subclasses.
        """

    def reload(self):
        self.cleanup()
        self.setup()
        self.logger.info('Reloading %s ready!', self)

    def __repr__(self):
        return '<' + self.__class__.__name__ + ' instance%s>' % (
            '' if self.system else ' not initialized')
Пример #21
0
class PlotGrid(AbstractOverlay):
    """ An overlay that represents a grid.

    A grid is a set of parallel lines, horizontal or vertical. You can use
    multiple grids with different settings for the horizontal and vertical
    lines in a plot.
    """

    #------------------------------------------------------------------------
    # Data-related traits
    #------------------------------------------------------------------------

    #: The mapper (and associated range) that drive this PlotGrid.
    mapper = Instance(AbstractMapper)

    #: The dataspace interval between grid lines.
    grid_interval = Trait('auto', 'auto', Float)

    #: The dataspace value at which to start this grid.  If None, then
    #: uses the mapper.range.low.
    data_min = Trait(None, None, Float)

    #: The dataspace value at which to end this grid.  If None, then uses
    #: the mapper.range.high.
    data_max = Trait(None, None, Float)

    #: A callable that implements the AbstractTickGenerator Interface.
    tick_generator = Instance(AbstractTickGenerator)

    #------------------------------------------------------------------------
    # Layout traits
    #------------------------------------------------------------------------

    #: The orientation of the grid lines.  "horizontal" means that the grid
    #: lines are parallel to the X axis and the ticker and grid interval
    #: refer to the Y axis.
    orientation = Enum('horizontal', 'vertical')

    #: Draw the ticks starting at the end of the mapper range? If False, the
    #: ticks are drawn starting at 0. This setting can be useful to keep the
    #: grid from from "flashing" as the user resizes the plot area.
    flip_axis = Bool(False)

    #: Optional specification of the grid bounds in the dimension transverse
    #: to the ticking/gridding dimension, i.e. along the direction specified
    #: by self.orientation.  If this is specified but transverse_mapper is
    #: not specified, then there is no effect.
    #:
    #:   None : use self.bounds or self.component.bounds (if overlay)
    #:   Tuple : (low, high) extents, used for every grid line
    #:   Callable : Function that takes an array of dataspace grid ticks
    #:              and returns either an array of shape (N,2) of (starts,ends)
    #:              for each grid point or a single tuple (low, high)
    transverse_bounds = Trait(None, Tuple, Callable)

    #: Mapper in the direction corresponding to self.orientation, i.e. transverse
    #: to the direction of self.mapper.  This is used to compute the screen
    #: position of transverse_bounds.  If this is not specified, then
    #: transverse_bounds has no effect, and vice versa.
    transverse_mapper = Instance(AbstractMapper)

    #: Dimensions that the grid is resizable in (overrides PlotComponent).
    resizable = "hv"

    #------------------------------------------------------------------------
    # Appearance traits
    #------------------------------------------------------------------------

    #: The color of the grid lines.
    line_color = black_color_trait

    #: The style (i.e., dash pattern) of the grid lines.
    line_style = LineStyle('solid')

    #: The thickness, in pixels, of the grid lines.
    line_width = CInt(1)
    line_weight = Alias("line_width")

    #: Default Traits UI View for modifying grid attributes.
    traits_view = GridView

    #------------------------------------------------------------------------
    # Private traits; mostly cached information
    #------------------------------------------------------------------------

    _cache_valid = Bool(False)
    _tick_list = Any
    _tick_positions = Any

    # An array (N,2) of start,end positions in the transverse direction
    # i.e. the direction corresponding to self.orientation
    _tick_extents = Any

    #_length = Float(0.0)

    #------------------------------------------------------------------------
    # Public methods
    #------------------------------------------------------------------------

    def __init__(self, **traits):
        # TODO: change this back to a factory in the instance trait some day
        self.tick_generator = DefaultTickGenerator()
        super(PlotGrid, self).__init__(**traits)
        self.bgcolor = "none"  #make sure we're transparent
        return

    @on_trait_change("bounds,bounds_items,position,position_items")
    def invalidate(self):
        """ Invalidate cached information about the grid.
        """
        self._reset_cache()
        return

    #------------------------------------------------------------------------
    # PlotComponent and AbstractOverlay interface
    #------------------------------------------------------------------------

    def do_layout(self, *args, **kw):
        """ Tells this component to do layout at a given size.

        Overrides PlotComponent.
        """
        if self.use_draw_order and self.component is not None:
            self._layout_as_overlay(*args, **kw)
        else:
            super(PlotGrid, self).do_layout(*args, **kw)
        return

    #------------------------------------------------------------------------
    # Private methods
    #------------------------------------------------------------------------

    def _do_layout(self):
        """ Performs a layout.

        Overrides PlotComponent.
        """
        return

    def _layout_as_overlay(self, size=None, force=False):
        """ Lays out the axis as an overlay on another component.
        """
        if self.component is not None:
            self.position = self.component.position
            self.bounds = self.component.bounds
        return

    def _reset_cache(self):
        """ Clears the cached tick positions.
        """
        self._tick_positions = array([], dtype=float)
        self._tick_extents = array([], dtype=float)
        self._cache_valid = False
        return

    def _compute_ticks(self, component=None):
        """ Calculates the positions for the grid lines.
        """
        if (self.mapper is None):
            self._reset_cache()
            self._cache_valid = True
            return

        if self.data_min is None:
            datalow = self.mapper.range.low
        else:
            datalow = self.data_min
        if self.data_max is None:
            datahigh = self.mapper.range.high
        else:
            datahigh = self.data_max

        # Map the low and high data points
        screenhigh = self.mapper.map_screen(datalow)
        screenlow = self.mapper.map_screen(datahigh)

        if (datalow == datahigh) or (screenlow == screenhigh) or \
           (datalow in [inf, -inf]) or (datahigh in [inf, -inf]):
            self._reset_cache()
            self._cache_valid = True
            return

        if component is None:
            component = self.component

        if component is not None:
            bounds = component.bounds
            position = component.position
        else:
            bounds = self.bounds
            position = self.position

        if isinstance(self.mapper, LogMapper):
            scale = 'log'
        else:
            scale = 'linear'

        ticks = self.tick_generator.get_ticks(datalow,
                                              datahigh,
                                              datalow,
                                              datahigh,
                                              self.grid_interval,
                                              use_endpoints=False,
                                              scale=scale)
        tick_positions = self.mapper.map_screen(array(ticks, float64))

        if self.orientation == 'horizontal':
            self._tick_positions = around(
                column_stack((zeros_like(tick_positions) + position[0],
                              tick_positions)))
        elif self.orientation == 'vertical':
            self._tick_positions = around(
                column_stack((tick_positions,
                              zeros_like(tick_positions) + position[1])))
        else:
            raise self.NotImplementedError

        # Compute the transverse direction extents
        self._tick_extents = zeros((len(ticks), 2), dtype=float)
        if self.transverse_bounds is None or self.transverse_mapper is None:
            # No mapping needed, just use the extents
            if self.orientation == 'horizontal':
                extents = (position[0], position[0] + bounds[0])
            elif self.orientation == 'vertical':
                extents = (position[1], position[1] + bounds[1])
            self._tick_extents[:] = extents
        elif callable(self.transverse_bounds):
            data_extents = self.transverse_bounds(ticks)
            tmapper = self.transverse_mapper
            if isinstance(data_extents, tuple):
                self._tick_extents[:] = tmapper.map_screen(
                    asarray(data_extents))
            else:
                extents = array([
                    tmapper.map_screen(data_extents[:, 0]),
                    tmapper.map_screen(data_extents[:, 1])
                ]).T
                self._tick_extents = extents
        else:
            # Already a tuple
            self._tick_extents[:] = self.transverse_mapper.map_screen(
                asarray(self.transverse_bounds))

        self._cache_valid = True

    def _draw_overlay(self, gc, view_bounds=None, mode='normal'):
        """ Draws the overlay layer of a component.

        Overrides PlotComponent.
        """
        self._draw_component(gc, view_bounds, mode)
        return

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        """ Draws this component overlaid on another component.

        Overrides AbstractOverlay.
        """
        if not self.visible:
            return
        self._compute_ticks(other_component)
        self._draw_component(gc, view_bounds, mode)
        self._cache_valid = False
        return

    def _draw_component(self, gc, view_bounds=None, mode="normal"):
        """ Draws the component.

        This method is preserved for backwards compatibility. Overrides
        PlotComponent.
        """
        # What we're really trying to do with a grid is plot contour lines in
        # the space of the plot.  In a rectangular plot, these will always be
        # straight lines.
        if not self.visible:
            return

        if not self._cache_valid:
            self._compute_ticks()

        if len(self._tick_positions) == 0:
            return

        with gc:
            gc.set_line_width(self.line_weight)
            gc.set_line_dash(self.line_style_)
            gc.set_stroke_color(self.line_color_)
            gc.set_antialias(False)

            if self.component is not None:
                gc.clip_to_rect(*(self.component.position +
                                  self.component.bounds))
            else:
                gc.clip_to_rect(*(self.position + self.bounds))

            gc.begin_path()
            if self.orientation == "horizontal":
                starts = self._tick_positions.copy()
                starts[:, 0] = self._tick_extents[:, 0]
                ends = self._tick_positions.copy()
                ends[:, 0] = self._tick_extents[:, 1]
            else:
                starts = self._tick_positions.copy()
                starts[:, 1] = self._tick_extents[:, 0]
                ends = self._tick_positions.copy()
                ends[:, 1] = self._tick_extents[:, 1]
            if self.flip_axis:
                starts, ends = ends, starts
            gc.line_set(starts, ends)
            gc.stroke_path()
        return

    def _mapper_changed(self, old, new):
        if old is not None:
            old.on_trait_change(self.mapper_updated, "updated", remove=True)
        if new is not None:
            new.on_trait_change(self.mapper_updated, "updated")
        self.invalidate()
        return

    def mapper_updated(self):
        """
        Event handler that is bound to this mapper's **updated** event.
        """
        self.invalidate()
        return

    def _position_changed_for_component(self):
        self.invalidate()

    def _position_items_changed_for_component(self):
        self.invalidate()

    def _bounds_changed_for_component(self):
        self.invalidate()

    def _bounds_items_changed_for_component(self):
        self.invalidate()

    #------------------------------------------------------------------------
    # Event handlers for visual attributes.  These mostly just call request_redraw()
    #------------------------------------------------------------------------

    @on_trait_change("visible,line_color,line_style,line_weight")
    def visual_attr_changed(self):
        """ Called when an attribute that affects the appearance of the grid
        is changed.
        """
        if self.component:
            self.component.invalidate_draw()
            self.component.request_redraw()
        else:
            self.invalidate_draw()
            self.request_redraw()

    def _grid_interval_changed(self):
        self.invalidate()
        self.visual_attr_changed()

    def _orientation_changed(self):
        self.invalidate()
        self.visual_attr_changed()
        return

    ### Persistence ###########################################################
    #_pickles = ("orientation", "line_color", "line_style", "line_weight",
    #            "grid_interval", "mapper")

    def __getstate__(self):
        state = super(PlotGrid, self).__getstate__()
        for key in [
                '_cache_valid', '_tick_list', '_tick_positions',
                '_tick_extents'
        ]:
            if key in state:
                del state[key]

        return state

    def _post_load(self):
        super(PlotGrid, self)._post_load()
        self._mapper_changed(None, self.mapper)
        self._reset_cache()
        self._cache_valid = False
        return
Пример #22
0
class Axis(ConfigLoadable):
    '''
    '''
    id = Int
    #    name = Str
    position = Float
    negative_limit = Float
    positive_limit = Float
    pdir = Str
    parent = Any(transient=True)
    calculate_parameters = Bool(True)
    drive_ratio = Float(1)

    velocity = Property(depends_on='_velocity')
    _velocity = Float(enter_set=True, auto_set=False)

    acceleration = Property(depends_on='_acceleration')
    _acceleration = Float(enter_set=True, auto_set=False)

    deceleration = Property(depends_on='_deceleration')
    _deceleration = Float(enter_set=True, auto_set=False)

    machine_velocity = Float
    machine_acceleration = Float
    machine_deceleration = Float
    # sets handled by child class

    nominal_velocity = Float
    nominal_acceleration = Float
    nominal_deceleration = Float

    sign = CInt(1)

    def _get_velocity(self):
        return self._velocity

    def _get_acceleration(self):
        return self._acceleration

    def _get_deceleration(self):
        return self._deceleration

    def upload_parameters_to_device(self):
        pass

    @on_trait_change('_velocity, _acceleration, _deceleration')
    def update_machine_values(self, obj, name, old, new):
        setattr(self, 'machine{}'.format(name), new)

    def _calibration_changed(self):
        self.parent.update_axes()

    def simple_view(self):
        v = View(
            Item('calculate_parameters'),
            Item('velocity',
                 format_str='%0.3f',
                 enabled_when='not calculate_parameters'),
            Item('acceleration',
                 format_str='%0.3f',
                 enabled_when='not calculate_parameters'),
            Item('deceleration',
                 format_str='%0.3f',
                 enabled_when='not calculate_parameters'), Item('drive_ratio'))
        return v

    def full_view(self):
        return self.simple_view()

    def dump(self):
        '''
        '''
        pass
#        self.loaded = False
#
#        p = os.path.join(self.pdir, '.%s' % self.name)
#        with open(p, 'w') as f:
#            pickle.dump(self, f)
#    def load_parameters_from_config(self, path):
#        self.config_path = path
#        self._load_parameters_from_config(path)
#
#    def load_parameters(self, pdir):
#        '''
#        '''
# #        self.pdir = pdir
# #        p = os.path.join(pdir, '.%s' % self.name)
# #
# #        if os.path.isfile(p):
# #            return p
# #        else:
#        self.load(pdir)

    def save(self):
        pass

    def ask(self, cmd):
        return self.parent.ask(cmd)

    def _get_parameters(self, path):
        '''
  
        '''
        #        cp = ConfigParser.ConfigParser()
        #        cp.read())
        params = []
        #        if path is None:
        if not os.path.isfile(path):
            path = os.path.join(path, '{}axis.cfg'.format(self.name))

        cp = self.get_configuration(path)
        if cp:
            params = [item for s in cp.sections() for item in cp.items(s)]

#        for ai in a:
#            print ai
#
#        for s in cp.sections():
#            for i in cp.items(s):
#                params.append(i)
        return params

    def _validate_float(self, v):
        try:
            v = float(v)
            return v
        except ValueError:
            pass
Пример #23
0
class ExperimentQueueFactory(DVCAble, PersistenceLoggable):
    application = Any

    username = String
    email = Property(depends_on='username, use_email, _email')
    _email = Str
    _emails = Dict

    use_group_email = Bool
    use_email = Bool
    edit_emails = Button

    usernames = Property(depends_on='users_dirty, db_refresh_needed')
    edit_user = Event
    add_user = Event
    users_dirty = Event
    db_refresh_needed = Event

    mass_spectrometer = String('Spectrometer')
    mass_spectrometers = Property(depends_on='db_refresh_needed')

    extract_device = String('Extract Device')
    extract_devices = Property(depends_on='db_refresh_needed')

    queue_conditionals_name = Str
    available_conditionals = List

    delay_between_analyses = Int(30)
    delay_before_analyses = Int(5)
    delay_after_blank = Int(15)
    delay_after_air = Int(15)
    tray = Str
    trays = Property
    note = Str
    default_lighting = CInt(0)

    load_name = Str

    select_existing_load_name_button = Button

    ok_make = Property(depends_on='mass_spectrometer, username')

    persistence_name = 'queue_factory'
    pattributes = ('mass_spectrometer', 'extract_device', 'use_group_email',
                   'delay_between_analyses', 'delay_before_analyses',
                   'delay_after_blank', 'delay_after_air', 'default_lighting',
                   'queue_conditionals_name')

    def activate(self, load_persistence):
        """
            called by ExperimentFactory
        """
        self._load_queue_conditionals()
        if load_persistence:
            self.load()
            self.username = globalv.username

    def deactivate(self):
        """
            called by ExperimentFactory.destroy
        """
        self.dump()

    # persistence
    def _load_queue_conditionals(self):
        root = paths.queue_conditionals_dir
        cs = glob_list_directory(root, remove_extension=True)
        self.available_conditionals = [NULL_STR] + cs

    def _select_existing_load_name_button_fired(self):
        db = self.get_database()
        if db is None or not db.connect():
            self.warning_dialog('Not connected to a database')

        else:
            with db.session_ctx(use_parent_session=False):
                loads = db.get_loads()

                from pychron.database.views.load_view import LoadView
                lv = LoadView(records=loads)
                info = lv.edit_traits()
                if info.result:
                    self.load_name = lv.selected.name
                    self.tray = lv.selected.holderName

    # ===============================================================================
    # property get/set
    # ===============================================================================
    def _get_email(self):
        email = ''
        if self.use_email:
            if self._email:
                email = self._email
            else:
                if self.username in self._emails:
                    email = self._emails[self.username]
        return email

    def _set_email(self, v):
        self._email = v

    @cached_property
    def _get_ok_make(self):
        ms = self.mass_spectrometer.strip()
        un = self.username.strip()
        return bool(ms and ms not in ('Spectrometer', LINE_STR) and un)

    @cached_property
    def _get_trays(self):
        db = self.get_database()
        if db is None or not db.connect():
            return []

        trays = [NULL_STR]
        dbtrays = db.get_load_holders()
        if dbtrays:
            trays.extend(dbtrays)
        return trays

    @cached_property
    def _get_usernames(self):
        db = self.get_database()
        if db is None or not db.connect():
            return []

        us = []
        with db.session_ctx(use_parent_session=False):
            dbus = db.get_users(verbose_query=True)
            if dbus:
                us = [ui.name for ui in dbus]
                self._emails = {ui.name: ui.email or '' for ui in dbus}

        return [''] + us

    @cached_property
    def _get_extract_devices(self):
        """
            look in db first
            then look for a config file
            then use hardcorded defaults
        """
        db = self.get_database()
        cp = os.path.join(paths.setup_dir, 'names')
        if db:
            if not db.connect():
                return []
            with db.session_ctx(use_parent_session=False):
                names = db.get_extraction_device_names()

        elif os.path.isfile(cp):
            names = self._get_names_from_config(cp, 'Extraction Devices')
        else:
            names = ['Fusions Diode', 'Fusions UV', 'Fusions CO2']
        return ['Extract Device', LINE_STR] + names

    @cached_property
    def _get_mass_spectrometers(self):
        """
            look in db first
            then look for a config file
            then use hardcorded defaults
        """
        db = self.get_database()
        cp = os.path.join(paths.setup_dir, 'names')
        if db:
            if not db.connect():
                self.warning('not connected to database')
                return []
            with db.session_ctx(use_parent_session=False):
                ms = db.get_mass_spectrometer_names()
                names = [mi.capitalize() for mi in ms]
        elif os.path.isfile(cp):
            names = self._get_names_from_config(cp, 'Mass Spectrometers')
        else:
            names = ['Jan', 'Obama']

        return ['Spectrometer', LINE_STR] + names

    def _get_names_from_config(self, cp, section):
        config = ConfigParser()
        config.read(cp)
        if config.has_section(section):
            return [
                config.get(section, option)
                for option in config.options(section)
            ]

    # handlers
    def _edit_user_fired(self):
        a = UserEntry(dvc=self.dvc)

        nuser = a.edit(self.username)
        if nuser:
            self.users_dirty = True
            self.username = nuser

    def _mass_spectrometer_changed(self, new):
        self.debug('mass spectrometer ="{}"'.format(new))

    def _edit_emails_fired(self):
        task = self.application.open_task('pychron.users')
        task.auto_save = True
Пример #24
0
class MassSpecExportSpec(Loggable):
    runid = CStr
    labnumber = CStr
    aliquot = Either(CInt, Str)
    step = Str
    irradpos = CStr

    isotopes = Dict

    mass_spectrometer = Str
    extract_device = Str
    tray = Str
    position = Property(depends_on='_position')
    _position = Any

    timestamp = Float
    power_requested = Float(0)
    power_achieved = Float(0)
    extract_value = Float(0)
    duration = Float(0)
    cleanup = Float(0)
    duration_at_request = Float(0)
    first_stage_delay = CInt(0)

    runscript_name = Str
    runscript_text = Str
    comment = Str

    # data_path = Str
    # data_manager = Instance(H5DataManager, ())
    update_rundatetime = Bool
    is_peak_hop = Bool
    peak_hop_detector = 'CDD'
    # ic_factor_v = Float
    # ic_factor_e = Float

    irradiation = Str
    level = Str
    irradiation_position = CInt
    production_ratios = Dict
    chron_dosages = List
    interference_corrections = Dict
    production_name = Str
    j = Any

    shared_logger = True

    @property
    def second_stage_delay(self):
        return self.cleanup

    def load_record(self, record):
        attrs = [('labnumber', 'labnumber'), ('aliquot', 'aliquot'),
                 ('step', 'step'), ('uuid', 'uuid'), ('irradpos', 'labnumber'),
                 ('timestamp', 'timestamp'),
                 ('extract_device', 'extract_device'), ('tray', 'tray'),
                 ('position', 'position'),
                 ('power_requested', 'extract_value'),
                 ('power_achieved', 'extract_value'),
                 ('extract_value', 'extract_value'), ('duration', 'duration'),
                 ('duration_at_request', 'duration'),
                 ('first_stage_delay', 'duration'), ('cleanup', 'cleanup'),
                 ('comment', 'comment'), ('irradiation', 'irradiation'),
                 ('irradiation_position', 'irradiation_pos'),
                 ('irradiation_pos', 'irradiation_pos'),
                 ('level', 'irradiation_level'),
                 ('irradiation_level', 'irradiation_level'),
                 ('isotopes', 'isotopes'), ('tag', 'tag'),
                 ('sample', 'sample'), ('material', 'material'),
                 ('project', 'project'),
                 ('mass_spectrometer', 'mass_spectrometer'), ('age', 'age'),
                 ('age_err', 'age_err'), ('age_err_wo_j', 'age_err_wo_j'),
                 ('age_err_wo_j_irrad', 'age_err_wo_j_irrad'),
                 ('ar39decayfactor', 'ar39decayfactor'),
                 ('ar37decayfactor', 'ar37decayfactor')]

        # if hasattr(record, 'spec'):
        # spec = record.spec
        # else:
        # spec = record

        for exp_attr, run_attr in attrs:
            if hasattr(record, run_attr):
                try:
                    v = getattr(record, run_attr)
                    self.debug('setting {} to {}'.format(exp_attr, v))
                    setattr(self, exp_attr, v)
                except TraitError, e:
                    self.debug(e)

        # if hasattr(record, 'cdd_ic_factor'):
        # ic = record.cdd_ic_factor
        # if ic is None:
        #         self.debug('Using default CDD IC factor 1.0')
        #         ic = ufloat(1, 1.0e-20)
        #
        #     self.ic_factor_v = float(ic.nominal_value)
        #     self.ic_factor_e = float(ic.std_dev)
        # else:
        #     self.debug('{} has no ic_factor attribute'.format(record, ))

        for a in ('chron_dosages', 'production_ratios',
                  'interference_corrections', 'production_name', 'j'):
            if hasattr(record, a):
                setattr(self, a, getattr(record, a))
            else:
                self.debug('no attribute {}'.format(a))
Пример #25
0
class VolumeViewer(HasTraits):
    # The view displayed
    model = Instance(MlabSceneModel, ())

    # The data to plot
    volume_data = Instance(VolumeData)

    # The volume renderer
    volume_renderer = Instance(VolumeRenderer)

    # Clip plane positions
    clip_bounds = List(CInt)

    # The transfer function editor
    ctf_editor = Instance(CtfEditor)

    # Whether to show the histogram on the CTF editor.
    histogram_bins = CInt(0)

    # If True, the Z-axis points down
    flip_z = Bool(False)

    # Additional members of the scene
    scene_members = Dict(Unicode, Instance(ABCVolumeSceneMember))

    # An event fired once the scene has been initialized.
    scene_initialized = Event

    # -------------------------------------------------------------------------
    # Public interface
    # -------------------------------------------------------------------------

    def screenshot(self, magnification=1):
        """ Returns an image of the rendered volume. The image will be the same
        size as the window on screen by default. For high resolution image,
        pass a magnification integer value > 1.
        """
        renderer = self.model.renderer

        image_filter = tvtk.RenderLargeImage()
        image_filter.input = renderer
        image_filter.magnification = magnification
        image_filter.update()

        image_data = image_filter.output
        x, y, _ = image_data.dimensions
        data = image_data.point_data.scalars
        data_array = data.to_array().copy()
        data_array.shape = (y, x, 3)
        data_array = np.flipud(data_array)

        return data_array

    # -------------------------------------------------------------------------
    # Default values
    # -------------------------------------------------------------------------

    def _clip_bounds_default(self):
        return [0, CLIP_MAX, 0, CLIP_MAX, 0, CLIP_MAX]

    def _volume_renderer_default(self):
        function = self.ctf_editor.function
        return VolumeRenderer(data=self.volume_data,
                              colors=function.color,
                              opacities=function.opacity)

    def _ctf_editor_default(self):
        return CtfEditor(prompt_color_selection=get_color)

    # -------------------------------------------------------------------------
    # Traits notifications
    # -------------------------------------------------------------------------

    def _volume_data_changed(self):
        self.volume_renderer.data = self.volume_data

    def _clip_bounds_changed(self):
        self.volume_renderer.clip_bounds = self.clip_bounds[:]

    def _clip_bounds_items_changed(self):
        self.volume_renderer.clip_bounds = self.clip_bounds[:]

    @on_trait_change('ctf_editor.function.updated')
    def ctf_updated(self):
        set_ctf = self.volume_renderer.set_transfer_function
        function = self.ctf_editor.function
        set_ctf(function.color, function.opacity)

    # -------------------------------------------------------------------------
    # Scene activation callbacks
    # -------------------------------------------------------------------------

    @on_trait_change('model.activated')
    def display_model(self):
        # Add the volume to the scene
        self.volume_renderer.add_volume_to_scene(self.model)

        # Add the other members to the scene
        volume_actor = self.volume_renderer.actor
        for member in self.scene_members.values():
            member.add_actors_to_scene(self.model, volume_actor)

        self._setup_camera()
        self.model.scene.background = (0, 0, 0)

        # Keep the view always pointing up
        interactor = self.model.scene.interactor
        interactor.interactor_style = tvtk.InteractorStyleTerrain()

        # Let other code know that the scene is ready.
        self.scene_initialized = True

    # -------------------------------------------------------------------------
    # Private methods
    # -------------------------------------------------------------------------

    def _setup_camera(self):
        if self.flip_z:
            view_up = (0, 0, -1)
            elevation = 100
        else:
            view_up = (0, 0, 1)
            elevation = 80
        self.model.mlab.view(40, elevation)
        self.model.camera.view_up = view_up

    @on_trait_change('histogram_bins,volume_data.raw_data')
    def _new_histogram(self):
        if (self.histogram_bins > 0 and
                self.volume_data is not None and
                self.volume_data.raw_data is not None):
            self.ctf_editor.histogram = np.histogram(self.volume_data.raw_data,
                                                     bins=self.histogram_bins,
                                                     density=False)
        else:
            self.ctf_editor.histogram = None
Пример #26
0
class WebService(TornadoService):
    """
    Web User Interface Service for Automate
    """

    #: Restrict usage to only monitoring statuses (default: ``True``).
    #: If WebService is not in read_only mode, it is possible to run arbitrary Python commands
    #: through eval/exec via web browser. This is, of course, a severe security issue.
    #: Secure SSL configuration HIGHLY recommended, if not operating in ``read_only`` mode.
    read_only = CBool(True)

    #: Default view that is displayed when entering the server.
    #: Can be the name of any view in views.py
    default_view = Str('system')

    #: HTTP port to listen
    http_port = Int(8080)

    #: Authentication for logging into web server. (user,password) pairs in a tuple.
    http_auth = Tuple

    #: Let websocket connection die after ``websocket_timeout`` time of no ping reply from client.
    websocket_timeout = CInt(60 * 5)

    #: Tags that are shown in user defined view
    user_tags = CSet(trait=Str, value={'user'})

    #: Django debugging mode (slower, more info shown when error occurs)
    debug = CBool(False)

    #: User-defined custom pages as a dictionary of form ``{name: template_content}``
    custom_pages = Dict(key_trait=Unicode, value_trait=Unicode)

    #: set to True, if you want to launch multiple servers with same system. Authentication and
    #: other settings are then taken from master service. Only web server settings (http host/port)
    #: are used from slave.
    slave = CBool(False)

    #: In this dictionary you can define your custom Django settings which will override the default ones
    django_settings = Dict()

    #: From /set/object/value and /toggle/object, redirect to /set_ready/object/value after after executing action
    redirect_from_setters = CBool(True)

    #: Show hidden objects in web UI (those prefixed with _)
    show_hidden = CBool(False)

    #: Full exposed url root
    server_url = Unicode()

    _sockets = List(transient=True)

    def get_filehandler_class(service):
        class MyFileHandler(tornado.web.StaticFileHandler):
            def validate_absolute_path(self, *args, **kwargs):
                session_id = getattr(
                    self.request.cookies.get('sessionid', None), 'value', None)
                from django.contrib.sessions.middleware import SessionMiddleware
                mw = SessionMiddleware()
                session_data = mw.SessionStore(session_id)
                if not session_data.get('logged_in', False):
                    raise tornado.web.HTTPError(403, 'not logged in')

                return super().validate_absolute_path(*args, **kwargs)

            def check_etag_header(self):
                """ Disable etag_header checking (checks only modified time). Due to etag caching
                    file changes were not detected at all. """
                return False

        return MyFileHandler

    def get_tornado_handlers(self):
        if self.slave:
            return self.system.request_service(
                'WebService').get_tornado_handlers()
        super_handlers = super().get_tornado_handlers()
        path = os.path.join(os.path.dirname(__file__), 'static')
        static = [('/static/(.*)', tornado.web.StaticFileHandler, {
            'path': path
        })]
        return static + super_handlers

    def setup(self):
        if not self.slave:
            os.environ[
                'DJANGO_SETTINGS_MODULE'] = 'automate.extensions.webui.settings'
            from django.conf import settings
            settings.DEBUG = self.debug
            if not 'SECRET_KEY' in self.django_settings:
                self.logger.warning(
                    'Insecure settings! Please set proper SECRET_KEY in '
                    'WebService.django_settings!')
            if not 'TIME_ZONE' in self.django_settings:
                os.environ.pop(
                    'TZ'
                )  # Django uses America/Chicago as default timezone. Let's clean this up.
                time.tzset()
            if self.server_url:
                self.django_settings['SERVER_URL'] = self.server_url
            if self.system.raven_dsn:
                settings.INSTALLED_APPS.append(
                    'raven.contrib.django.raven_compat')
                settings.RAVEN_CONFIG = {
                    'dsn': self.system.raven_dsn,
                    'release': __version__
                }
            installed_apps = self.django_settings.pop('INSTALLED_APPS', None)
            if installed_apps:
                settings.INSTALLED_APPS.extend(list(installed_apps))

            for key, value in self.django_settings.items():
                setattr(settings, key, value)

            from automate.extensions.webui.djangoapp.views import set_globals
            set_globals(self, self.system)

        super().setup()
        if not self.slave:
            self.system.request_service('LogStoreService').on_trait_change(
                self.push_log, 'most_recent_line')

            self.system.on_trait_change(
                self.update_sockets,
                'objects.status, objects.changing, objects.active, '
                'objects.program_status_items')

    def get_websocket(service):
        if service.slave:
            return service.system.request_service('WebService').get_websocket()

        class WebSocket(WebSocketHandler):
            def data_received(self, chunk):
                pass

            def __init__(self, application, request, **kwargs):
                self.log_requested = False
                self.subscribed_objects = set()
                self.last_message = None
                self.logged_in = False

                super().__init__(application, request, **kwargs)

            def check_origin(self, origin):
                return True

            def write_json(self, **kwargs):
                msg = json.dumps(kwargs)
                service.logger.debug('Sending to client %s', msg)
                self.write_message(msg)

            def open(self):
                self.session_id = session_id = getattr(
                    self.request.cookies.get('sessionid', None), 'value', None)
                from django.contrib.sessions.middleware import SessionMiddleware
                mw = SessionMiddleware()
                session_data = mw.SessionStore(session_id)

                if session_data.get('logged_in',
                                    False) or not service.http_auth:
                    self.logged_in = True
                else:
                    service.logger.warning("Not (yet) logged in %s",
                                           session_id)

                service.logger.debug("WebSocket opened for session %s",
                                     session_id)
                service._sockets.append(self)

            def _authenticate(self, username, password):
                if (username, password) == service.http_auth:
                    self.logged_in = True
                    service.logger.debug('Websocket user %s logged in.',
                                         username)
                else:
                    service.logger.warning(
                        'Authentication failure: user %s with passwd %s != %s ',
                        username, password, service.http_auth)
                    self.close()

            def _ping(self):
                pass

            def _set_status(self, name, status):
                if service.read_only:
                    service.logger.warning(
                        "Could not perform operation: read only mode enabled")
                    return
                obj = service.system.namespace.get(name, None)
                if obj:
                    obj.status = status

            def _subscribe(self, objects):
                self.subscribed_objects.update(objects)

            def _unsubscribe(self, objects):
                self.subscribed_objects -= set(objects)

            def _clear_subscriptions(self):
                self.subscribed_objects.clear()

            def _send_command(self, command):
                if not service.read_only:
                    service.system.cmd_exec(command)
                else:
                    service.logger.warning(
                        "Could not perform operation: read only mode enabled")

            def _fetch_objects(self):
                data = [(i.name, i.get_as_datadict())
                        for i in service.system.objects_sorted]
                self.write_json(action='return', rv=data)

            def _request_log(self):
                self.log_requested = True

            def on_message(self, json_message):
                """
                    Message format: {'action': 'action_name', other_kwargs...)
                """

                message = json.loads(json_message)
                service.logger.debug('Message received from client: %s',
                                     message)

                action = message.pop('action', '')

                if self.logged_in:
                    action_func = getattr(self, '_' + action, None)
                    if action_func:
                        service.logger.debug('Running websocket action %s',
                                             action)
                        action_func(**message)
                    else:
                        service.logger.error(
                            'Not logged in or unknown message %s', message)
                elif action == 'authenticate':
                    return self._authenticate(**message)

                self.last_message = datetime.datetime.now()

            def on_close(self):
                service.logger.debug("WebSocket closed for session %s",
                                     self.session_id)
                service._sockets.remove(self)

        return WebSocket

    def push_log(self, new):
        for s in self._sockets:
            if s.log_requested:
                try:
                    s.write_json(action='log', data=new)
                except WebSocketClosedError:
                    pass

    def update_sockets(self, obj, attribute, old, new):
        from django.template.loader import render_to_string
        if isinstance(obj, StatusObject):
            self.logger.debug('Update_sockets %s %s %s %s', obj, attribute,
                              old, new)
            for s in self._sockets:
                if s.last_message and (
                        s.last_message < datetime.datetime.now() -
                        datetime.timedelta(seconds=self.websocket_timeout)):
                    self.logger.info('Closing connection %s due to timeout',
                                     s.session_id)
                    s.on_close()
                    s.close(code=1000, reason='Timeout')
                    continue
                if obj.name in s.subscribed_objects:
                    if attribute == 'active':
                        s.write_json(action='program_active',
                                     name=obj.name,
                                     active=obj.active)
                    elif attribute in ['status', 'changing']:
                        s.write_json(action='object_status',
                                     name=obj.name,
                                     status=obj.status,
                                     time=int(1000 * time.time()),
                                     display=obj.get_status_display(),
                                     changing=obj.changing)

    def get_wsgi_application(self):
        from django.core.wsgi import get_wsgi_application
        return get_wsgi_application()
class Model(HasTraits):

    #Traits view definitions:
    traits_view = View(
        Group(Item('function'),
              HGroup(Item('npts_x', label="Number X Points"),
                     Item('npts_y', label="Number Y Points")),
              HGroup(Item('min_x', label="Min X value"),
                     Item('max_x', label="Max X value")),
              HGroup(Item('min_y', label="Min Y value"),
                     Item('max_y', label="Max Y value"))),
                     buttons=["OK", "Cancel"])

    function = Str("tanh(x**2+y)*cos(y)*jn(0,x+y*2)")

    npts_x = CInt(400)
    npts_y = CInt(200)

    min_x = CFloat(-2*pi)
    max_x = CFloat(2*pi)
    min_y = CFloat(-1.5*pi)
    max_y = CFloat(1.5*pi)

    xs = Array
    ys = Array
    zs = Array

    minz = Float
    maxz = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    def compute_model(self):
        # The xs and ys used for the image plot range need to be the
        # edges of the cells.
        self.xs = linspace(self.min_x, self.max_x, self.npts_x+1)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y+1)

        # The grid of points at which we will evaluate the 2D function
        # is located at cell centers, so use halfsteps from the
        # min/max values (which are edges)
        xstep = (self.max_x - self.min_x) / self.npts_x
        #ystep = (self.max_y - self.min_y) / self.npts_y
        gridx = linspace(self.min_x+xstep/2, self.max_x-xstep/2, self.npts_x)
        gridy = linspace(self.min_y+xstep/2, self.max_y-xstep/2, self.npts_y)
        x, y = meshgrid(gridx, gridy)
        try:
            d = dict(x=x, y=y)
            exec "from scipy import *" in d
            exec "from scipy.special import *" in d
            self.zs = eval(self.function, d)
            self.minz = nanmin(self.zs)
            self.maxz = nanmax(self.zs)
            self.model_changed = True
            self._function = self.function
        except:
            self.set(function = self._function, trait_change_notify=False)

    def _anytrait_changed(self, name, value):
        if name in ['function', 'npts_x', 'npts_y',
                    'min_x', 'max_x', 'min_y', 'max_y']:
            self.compute_model()
Пример #28
0
class TimedFlag(Flag):
    duration = Float(1)

    display_time = Property(depends_on='_time_remaining')
    _time_remaining = CInt(0)

    _start_time = None
    _uperiod = 1000

    def clear(self):
        super(TimedFlag, self).clear()
        self.pt.Stop()

    def _get_display_time(self):
        return self._time_remaining

    def traits_view(self):
        v = View(
            HGroup(Item('name', style='readonly'),
                   spring,
                   Item('display_time', format_str='%03i', style='readonly'),
                   Item('display_state'),
                   show_labels=False))
        return v

    def set(self, value):
        set_duration = True
        if isinstance(value, bool):
            set_duration = False

        try:
            value = float(value)
        except ValueError:
            return 'Invalid flag value'

        super(TimedFlag, self).set(value)
        if self.isSet():
            if set_duration:
                self.duration = value
                self._time_remaining = value
            else:
                self._time_remaining = self.duration

            self._start_time = time()
            self.pt = PTimer(self._uperiod, self._update_time)
            t = OneShotTimer(self.duration, self.clear)
            t.start()

        return True

    def isStarted(self):
        return self._start_time is not None

    def get(self):
        t = 0
        if self.isSet() and self.isStarted():
            t = max(0, self.duration - (time() - self._start_time))

        return t

    def _update_time(self):
        self._time_remaining = round(self.get())
Пример #29
0
class VolumeRenderer(HasStrictTraits):
    # The data to plot
    data = Instance(VolumeData)

    # The mayavi data source for the volume data
    data_source = Instance(VTKDataSource)

    # The mayavi volume renderer object
    volume = Instance(Volume3D)

    # The tvtk.Actor for `volume`
    actor = Property(Instance(tvtk.Actor), depends_on='volume')

    # The minimum and maximum displayed intensity values.
    vmin = CInt(0)
    vmax = CInt(255)

    # The transfer function components
    opacities = Instance(PiecewiseFunction)
    colors = Instance(PiecewiseFunction)
    global_alpha = Range(0.0, 1.0, value=1.0)

    # Clip plane positions
    clip_bounds = List(CInt)

    # Render quality setting
    render_quality = Enum('default', list(QUALITY_SETTINGS.keys()))

    # -------------------------------------------------------------------------
    # Public interface
    # -------------------------------------------------------------------------

    def add_volume_to_scene(self, scene_model):
        source = add_dataset(self.data.render_data,
                             figure=scene_model.mayavi_scene)
        self.data_source = source
        self.volume = volume3d(source, figure=scene_model.mayavi_scene)
        self._setup_volume()

    def set_transfer_function(self, colors=None, opacities=None):
        """ Update the volume mapper's transfer function.
        """
        lerp = lambda x: self.vmin + x * (self.vmax - self.vmin)  # noqa

        if colors is not None:
            self.colors = colors
        if opacities is not None:
            self.opacities = opacities

        color_tf = tvtk.ColorTransferFunction()
        for color in self.colors.values():
            color_tf.add_rgb_point(lerp(color[0]), *(color[1:]))

        opacity_tf = tvtk.PiecewiseFunction()
        alphas = self.opacities.values()
        for i, alpha in enumerate(alphas):
            x = alpha[0]
            if i > 0:
                # Look back one item. VTK doesn't like exact vertical jumps, so
                # we need to jog a value that is exactly equal by a little bit.
                if alphas[i-1][0] == alpha[0]:
                    x += 1e-8
            opacity_tf.add_point(lerp(x), alpha[1] * self.global_alpha)

        self._set_volume_ctf(color_tf, opacity_tf)

    # -------------------------------------------------------------------------
    # Traits bits
    # -------------------------------------------------------------------------

    def _clip_bounds_default(self):
        return [0, CLIP_MAX, 0, CLIP_MAX, 0, CLIP_MAX]

    @on_trait_change('data.raw_data')
    def _update_data(self):
        self.vmin = self.data.raw_data.min()
        self.vmax = self.data.raw_data.max()
        self._render_data_changed()

    @on_trait_change('data:mask_data')
    def _render_data_changed(self):
        if self.data_source is not None:
            image_data = self.data.render_data
            self.data_source.data = image_data
            self.data_source.update()
            self._setup_volume()

    def _clip_bounds_changed(self):
        self._set_volume_clip_planes()

    def _global_alpha_changed(self):
        self.set_transfer_function()

    def _render_quality_changed(self):
        self._setup_volume()

    def _get_actor(self):
        return self.volume.actors[0]

    # -------------------------------------------------------------------------
    # Private methods
    # -------------------------------------------------------------------------

    def _setup_volume(self):
        render_settings = QUALITY_SETTINGS[self.render_quality]
        self.volume.volume_mapper.trait_set(**render_settings['mapper'])
        self.volume.volume_property.trait_set(**render_settings['property'])
        self._set_volume_clip_planes()
        self.set_transfer_function()

    def _set_volume_clip_planes(self):
        if self.data is None:
            return

        bounds = [b//CLIP_MAX for b in self.data.bounds]
        mn = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[::2])]
        mx = [bounds[i]*pos for i, pos in enumerate(self.clip_bounds[1::2])]
        planes = tvtk.Planes()
        # The planes need to be inside out to serve as clipping planes
        planes.set_bounds(mx[0], mn[0],
                          mx[1], mn[1],
                          mx[2], mn[2])
        # Set them as the clipping planes for the volume mapper
        self.volume.volume.mapper.clipping_planes = planes

    def _set_volume_ctf(self, color_tf, opacity_tf):
        if self.volume is not None:
            vp = self.volume.volume_property
            vp.set_scalar_opacity(opacity_tf)
            vp.set_color(color_tf)
            self.volume._update_ctf_fired()
Пример #30
0
class UserIntSensor(AbstractNumericSensor):
    """Integer-valued user-editable sensor"""
    user_editable = CBool(True)
    _status = CInt(0)