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
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))
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)
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)
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)
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
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.""")
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)
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""")
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)
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", )
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))
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))
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)
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)
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()
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))
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:]
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)
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')
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
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
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
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))
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
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()
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())
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()
class UserIntSensor(AbstractNumericSensor): """Integer-valued user-editable sensor""" user_editable = CBool(True) _status = CInt(0)