def remote_status_item(label=None): grp = HGroup( Item("remote", label="Name"), test_connection_item(), CustomLabel("_remote_status", width=50, color_name="_remote_status_color"), ) if label: grp.label = label grp.show_border = True return grp
def remote_status_item(label=None): grp = HGroup(Item('remote', label='Name'), test_connection_item(), CustomLabel('_remote_status', width=50, color_name='_remote_status_color')) if label: grp.label = label grp.show_border = True return grp
class Kit2FiffFrame(HasTraits): """GUI for interpolating between two KIT marker files.""" model = Instance(Kit2FiffModel) scene = Instance(MlabSceneModel, ()) headview = Instance(HeadViewController) marker_panel = Instance(CombineMarkersPanel) kit2fiff_panel = Instance(Kit2FiffPanel) view = View(HGroup( VGroup(Item('marker_panel', style='custom'), show_labels=False), VGroup( Item('scene', editor=SceneEditor(scene_class=MayaviScene), dock='vertical', show_label=False), VGroup(Item('headview', style='custom'), show_labels=False), ), VGroup(Item('kit2fiff_panel', style='custom'), show_labels=False), show_labels=False, ), handler=Kit2FiffFrameHandler(), height=700, resizable=True, buttons=NoButtons) def __init__(self, *args, **kwargs): # noqa: D102 logger.debug("Initializing Kit2fiff-GUI with %s backend", ETSConfig.toolkit) HasTraits.__init__(self, *args, **kwargs) # can't be static method due to Traits def _model_default(self): # load configuration values and make sure they're valid config = get_config(home_dir=os.environ.get('_MNE_FAKE_HOME_DIR')) stim_threshold = 1. if 'MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD' in config: try: stim_threshold = float( config['MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD']) except ValueError: warn("Ignoring invalid configuration value for " "MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD: %r (expected " "float)" % (config['MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD'], )) stim_slope = config.get('MNE_KIT2FIFF_STIM_CHANNEL_SLOPE', '-') if stim_slope not in '+-': warn("Ignoring invalid configuration value for " "MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD: %s (expected + or -)" % stim_slope) stim_slope = '-' stim_coding = config.get('MNE_KIT2FIFF_STIM_CHANNEL_CODING', '>') if stim_coding not in ('<', '>', 'channel'): warn("Ignoring invalid configuration value for " "MNE_KIT2FIFF_STIM_CHANNEL_CODING: %s (expected <, > or " "channel)" % stim_coding) stim_coding = '>' return Kit2FiffModel(stim_chs=config.get('MNE_KIT2FIFF_STIM_CHANNELS', ''), stim_coding=stim_coding, stim_slope=stim_slope, stim_threshold=stim_threshold, show_gui=True) def _headview_default(self): return HeadViewController(scene=self.scene, scale=160, system='RAS') def _kit2fiff_panel_default(self): return Kit2FiffPanel(scene=self.scene, model=self.model) def _marker_panel_default(self): return CombineMarkersPanel(scene=self.scene, model=self.model.markers, trans=als_ras_trans) def save_config(self, home_dir=None): """Write configuration values.""" set_config('MNE_KIT2FIFF_STIM_CHANNELS', self.model.stim_chs, home_dir, set_env=False) set_config('MNE_KIT2FIFF_STIM_CHANNEL_CODING', self.model.stim_coding, home_dir, set_env=False) set_config('MNE_KIT2FIFF_STIM_CHANNEL_SLOPE', self.model.stim_slope, home_dir, set_env=False) set_config('MNE_KIT2FIFF_STIM_CHANNEL_THRESHOLD', str(self.model.stim_threshold), home_dir, set_env=False)
class MayaviViewer(HasTraits): """ This class represents a Mayavi based viewer for the particles. They are queried from a running solver. """ particle_arrays = List(Instance(ParticleArrayHelper), []) pa_names = List(Str, []) interpolator = Instance(InterpolatorView) # The default scalar to load up when running the viewer. scalar = Str("rho") scene = Instance(MlabSceneModel, ()) ######################################## # Traits to pull data from a live solver. live_mode = Bool(False, desc='if data is obtained from a running solver ' 'or from saved files') shell = Button('Launch Python Shell') host = Str('localhost', desc='machine to connect to') port = Int(8800, desc='port to use to connect to solver') authkey = Password('pysph', desc='authorization key') host_changed = Bool(True) client = Instance(MultiprocessingClient) controller = Property(depends_on='live_mode, host_changed') ######################################## # Traits to view saved solver output. files = List(Str, []) directory = Directory() current_file = Str('', desc='the file being viewed currently') update_files = Button('Refresh') file_count = Range(low='_low', high='_n_files', value=0, desc='the file counter') play = Bool(False, desc='if all files are played automatically') play_delay = Float(0.2, desc='the delay between loading files') loop = Bool(False, desc='if the animation is looped') # This is len(files) - 1. _n_files = Int(0) _low = Int(0) ######################################## # Timer traits. timer = Instance(Timer) interval = Range(0.5, 20.0, 2.0, desc='frequency in seconds with which plot is updated') ######################################## # Solver info/control. current_time = Float(0.0, desc='the current time in the simulation') time_step = Float(0.0, desc='the time-step of the solver') iteration = Int(0, desc='the current iteration number') pause_solver = Bool(False, desc='if the solver should be paused') ######################################## # Movie. record = Bool(False, desc='if PNG files are to be saved for animation') frame_interval = Range(1, 100, 5, desc='the interval between screenshots') movie_directory = Str # internal counters. _count = Int(0) _frame_count = Int(0) _last_time = Float _solver_data = Any _file_name = Str _particle_array_updated = Bool ######################################## # The layout of the dialog created view = View(HSplit( Group( Group( Group( Item(name='directory'), Item(name='current_file'), Item(name='file_count'), HGroup(Item(name='play'), Item(name='play_delay', label='Delay', resizable=True), Item(name='loop'), Item(name='update_files', show_label=False), padding=0), padding=0, label='Saved Data', selected=True, enabled_when='not live_mode', ), Group( Item(name='live_mode'), Group( Item(name='host'), Item(name='port'), Item(name='authkey'), enabled_when='live_mode', ), label='Connection', ), layout='tabbed' ), Group( Group( Item(name='current_time'), Item(name='time_step'), Item(name='iteration'), Item(name='pause_solver', enabled_when='live_mode' ), Item(name='interval', enabled_when='not live_mode' ), label='Solver', ), Group( Item(name='record'), Item(name='frame_interval'), Item(name='movie_directory'), label='Movie', ), layout='tabbed', ), Group( Item(name='particle_arrays', style='custom', show_label=False, editor=ListEditor(use_notebook=True, deletable=False, page_name='.name' ) ), Item(name='interpolator', style='custom', show_label=False), layout='tabbed' ), Item(name='shell', show_label=False), ), Group( Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=400, width=600, show_label=False), ) ), resizable=True, title='PySPH Particle Viewer', height=640, width=1024, handler=ViewerHandler ) ###################################################################### # `MayaviViewer` interface. ###################################################################### def on_close(self): self._handle_particle_array_updates() @on_trait_change('scene:activated') def start_timer(self): if not self.live_mode: # No need for the timer if we are rendering files. return # Just accessing the timer will start it. t = self.timer if not t.IsRunning(): t.Start(int(self.interval*1000)) @on_trait_change('scene:activated') def update_plot(self): # No need to do this if files are being used. if not self.live_mode: return # do not update if solver is paused if self.pause_solver: return if self.client is None: self.host_changed = True controller = self.controller if controller is None: return self.current_time = t = controller.get_t() self.time_step = controller.get_dt() self.iteration = controller.get_count() arrays = [] for idx, name in enumerate(self.pa_names): pa = controller.get_named_particle_array(name) arrays.append(pa) pah = self.particle_arrays[idx] pah.set(particle_array=pa, time=t) self.interpolator.particle_arrays = arrays if self.record: self._do_snap() def run_script(self, path): """Execute a script in the namespace of the viewer. """ with open(path) as fp: data = fp.read() ns = self._get_shell_namespace() exec(compile(data, path, 'exec'), ns) ###################################################################### # Private interface. ###################################################################### def _do_snap(self): """Generate the animation.""" p_arrays = self.particle_arrays if len(p_arrays) == 0: return if self.current_time == self._last_time: return if len(self.movie_directory) == 0: controller = self.controller output_dir = controller.get_output_directory() movie_dir = os.path.join(output_dir, 'movie') self.movie_directory = movie_dir else: movie_dir = self.movie_directory if not os.path.exists(movie_dir): os.mkdir(movie_dir) interval = self.frame_interval count = self._count if count % interval == 0: fname = 'frame%06d.png' % (self._frame_count) p_arrays[0].scene.save_png(os.path.join(movie_dir, fname)) self._frame_count += 1 self._last_time = self.current_time self._count += 1 @on_trait_change('host,port,authkey') def _mark_reconnect(self): if self.live_mode: self.host_changed = True @cached_property def _get_controller(self): ''' get the controller, also sets the iteration count ''' if not self.live_mode: return None reconnect = self.host_changed if not reconnect: try: c = self.client.controller except Exception as e: logger.info('Error: no connection or connection closed: ' 'reconnecting: %s' % e) reconnect = True self.client = None else: try: self.client.controller.get_count() except IOError: self.client = None reconnect = True if reconnect: self.host_changed = False try: if MultiprocessingClient.is_available((self.host, self.port)): self.client = MultiprocessingClient( address=(self.host, self.port), authkey=self.authkey ) else: logger.info( 'Could not connect: Multiprocessing Interface' ' not available on %s:%s' % (self.host, self.port) ) return None except Exception as e: logger.info('Could not connect: check if solver is ' 'running:%s' % e) return None c = self.client.controller self.iteration = c.get_count() if self.client is None: return None else: return self.client.controller def _client_changed(self, old, new): if not self.live_mode: return self._clear() if new is None: return else: self.pa_names = self.client.controller.get_particle_array_names() self.particle_arrays = [ self._make_particle_array_helper(self.scene, x) for x in self.pa_names ] self.interpolator = InterpolatorView(scene=self.scene) # Turn on the legend for the first particle array. if len(self.particle_arrays) > 0: self.particle_arrays[0].set(show_legend=True, show_time=True) def _timer_event(self): # catch all Exceptions else timer will stop try: self.update_plot() except Exception as e: logger.info('Exception: %s caught in timer_event' % e) def _interval_changed(self, value): t = self.timer if t is None: return if t.IsRunning(): t.Stop() t.Start(int(value*1000)) def _timer_default(self): return Timer(int(self.interval*1000), self._timer_event) def _pause_solver_changed(self, value): if self.live_mode: c = self.controller if c is None: return if value: c.pause_on_next() else: c.cont() def _record_changed(self, value): if value: self._do_snap() def _files_changed(self, value): if len(value) == 0: return else: d = os.path.dirname(os.path.abspath(value[0])) self.movie_directory = os.path.join(d, 'movie') self.set(directory=d, trait_change_notify=False) self._n_files = len(value) - 1 self._frame_count = 0 self._count = 0 self.frame_interval = 1 fc = self.file_count self.file_count = 0 if fc == 0: # Force an update when our original file count is 0. self._file_count_changed(fc) t = self.timer if not self.live_mode: if t.IsRunning(): t.Stop() else: if not t.IsRunning(): t.Stop() t.Start(self.interval*1000) def _file_count_changed(self, value): # Save out any updates for the previous file if needed. self._handle_particle_array_updates() # Load the new file. fname = self.files[value] self._file_name = fname self.current_file = os.path.basename(fname) # Code to read the file, create particle array and setup the helper. data = load(fname) solver_data = data["solver_data"] arrays = data["arrays"] self._solver_data = solver_data self.current_time = t = float(solver_data['t']) self.time_step = float(solver_data['dt']) self.iteration = int(solver_data['count']) names = list(arrays.keys()) pa_names = self.pa_names if len(pa_names) == 0: self.interpolator = InterpolatorView(scene=self.scene) self.pa_names = names pas = [] for name in names: pa = arrays[name] pah = self._make_particle_array_helper(self.scene, name) # Must set this after setting the scene. pah.set(particle_array=pa, time=t) pas.append(pah) self.particle_arrays = pas else: for idx, name in enumerate(pa_names): pa = arrays[name] pah = self.particle_arrays[idx] pah.set(particle_array=pa, time=t) self.interpolator.particle_arrays = list(arrays.values()) if self.record: self._do_snap() def _loop_changed(self, value): if value and self.play: self._play_changed(self.play) def _play_changed(self, value): t = self.timer if value: t.Stop() t.callable = self._play_event t.Start(1000*self.play_delay) else: t.Stop() t.callable = self._timer_event def _clear(self): self.pa_names = [] self.scene.mayavi_scene.children[:] = [] def _play_event(self): nf = self._n_files pc = self.file_count pc += 1 if pc > nf: if self.loop: pc = 0 else: self.timer.Stop() pc = nf self.file_count = pc self._handle_particle_array_updates() def _play_delay_changed(self): if self.play: self._play_changed(self.play) def _scalar_changed(self, value): for pa in self.particle_arrays: pa.scalar = value def _update_files_fired(self): fc = self.file_count files = glob_files(self.files[fc]) sort_file_list(files) self.files = files self.file_count = fc if self.play: self._play_changed(self.play) def _shell_fired(self): ns = self._get_shell_namespace() obj = PythonShellView(ns=ns) obj.edit_traits() def _get_shell_namespace(self): pas = {} for i, x in enumerate(self.particle_arrays): pas[i] = x pas[x.name] = x return dict(viewer=self, particle_arrays=pas, interpolator=self.interpolator, scene=self.scene, mlab=self.scene.mlab) def _directory_changed(self, d): ext = os.path.splitext(self.files[-1])[1] files = glob.glob(os.path.join(d, '*' + ext)) if len(files) > 0: self._clear() sort_file_list(files) self.files = files self.file_count = min(self.file_count, len(files)) else: pass config_file = os.path.join(d, 'mayavi_config.py') if os.path.exists(config_file): self.run_script(config_file) def _live_mode_changed(self, value): if value: self._file_name = '' self.client = None self._clear() self._mark_reconnect() self.start_timer() else: self.client = None self._clear() self.timer.Stop() def _particle_array_helper_updated(self, value): self._particle_array_updated = True def _handle_particle_array_updates(self): # Called when the particle array helper fires an updated event. if self._particle_array_updated and self._file_name: sd = self._solver_data arrays = [x.particle_array for x in self.particle_arrays] detailed = self._requires_detailed_output(arrays) dump(self._file_name, arrays, sd, detailed_output=detailed, only_real=False) self._particle_array_updated = False def _requires_detailed_output(self, arrays): detailed = False for pa in arrays: props = set(pa.properties.keys()) output = set(pa.output_property_arrays) diff = props - output for prop in diff: array = pa.get(prop) if (array.max() - array.min()) > 0: detailed = True break if detailed: break return detailed def _make_particle_array_helper(self, scene, name): pah = ParticleArrayHelper(scene=scene, name=name, scalar=self.scalar) pah.on_trait_change(self._particle_array_helper_updated, 'updated') return pah
class MayaviGrid(HasTraits): ''' This class is used to plot the data in a vlsv file as a mayavi grid The following will bring up a new window and plot the grid in the vlsv file: .. code-block:: python grid = pt.grid.MayaviGrid(vlsvReader=f, variable="rho", operator='pass', threaded=False) Once you have the window open you can use the picker tool in the right-upper corner and use various point-click tools for analyzing data. Picker options: **None** Does nothing upon clicking somewhere in the grid **Velocity_space** Plots the velocity space at a specific position upon clicking somewhere in the grid Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work **Velocity_space_iso_surface** Plots the velocity space at a specific position upon clicking somewhere in the grid in iso-surface plotting style Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work **Velocity_space_nearest_cellid** Plots the velocity space of the closest cell id to the picking point Note: If the vlsv file does not have velocity space saved at all, this will not work **Velocity_space_nearest_cellid_iso_surface** Plots the velocity space of the closest cell id to the picking point in iso-surface plotting style Note: If the vlsv file does not have velocity space saved at all, this will not work **Pitch_angle** Plots the pitch angle distribution at the clicking position Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work **Gyrophase_angle** Plots the gyrophase angle distribution at the clicking position Note: If the vlsv file does not have the velocity space at the position where you are clicking, this will not work **Cut_through** Is used to plot or save the cut-through between two clicking points. This option requires you to use the args section at top-left. To use the args section to plot variables you must write for example: **plot rho B,x E,y** Upon clicking at two points a new window would open with a cut-through plot of rho, x-component of B and y-component of E Alternatively, you can save the cut-through to a variable in the MayaviGrid class by typing instead: **rho B,x E,y** and then going to the terminal and typing .. code-block:: python cut_through_data = grid.cut_through print cut_through_data ''' picker = Enum('None', 'Velocity_space', "Velocity_space_nearest_cellid", 'Velocity_space_iso_surface', 'Velocity_space_nearest_cellid_iso_surface', "Pitch_angle", "Gyrophase_angle", "Cut_through") args = "" variable_plotted = "" labels = [] cut_through = [] plot = [] scene = Instance(MlabSceneModel, ()) engine_view = Instance(EngineView) current_selection = Property dataset = [] # Define the view: view = View( HGroup( Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=250, width=300, show_label=False, resizable=True), Group( #'cell_pick', 'picker', 'args', show_labels=True), ), resizable=True, ) def __init__(self, vlsvReader, variable, operator="pass", threaded=True, **traits): ''' Initializes the class and loads the mayavi grid :param vlsvReader: Some vlsv reader with a file open :type vlsvReader: :class:`vlsvfile.VlsvReader` :param variable: Name of the variable :param operator: Operator for the variable :param threaded: Boolean value for using threads or not using threads to draw the grid (threads enable interactive mode) ''' HasTraits.__init__(self, **traits) self.__vlsvReader = vlsvReader self.engine_view = EngineView(engine=self.scene.engine) self.__engine = self.scene.engine self.__picker = [] self.__mins = [] self.__maxs = [] self.__cells = [] self.__last_pick = [] self.__structured_figures = [] self.__unstructured_figures = [] self.__thread = [] self.__load_grid(variable=variable, operator=operator, threaded=threaded) self.variable_plotted = variable def __module_manager(self): import mayavi.core.module_manager as MM module_manager = self.scene.mayavi_scene # Find the module manager: while (True): module_manager = module_manager.children[0] if type(module_manager) == type(MM.ModuleManager()): break return module_manager def __add_label(self, cellid): # Add dataset: from mayavi.modules.labels import Labels indices = self.__vlsvReader.get_cell_indices(cellid) self.labels = Labels() self.labels.number_of_labels = 1 self.labels.mask.filter.random_mode = False self.labels.mask.filter.offset = int( indices[0] + (self.__cells[0] + 1) * indices[1] + (self.__cells[0] + 1) * (self.__cells[1] + 1) * (indices[2] + 1)) module_manager = self.__module_manager() # Add the label / marker: self.__engine.add_filter(self.labels, module_manager) #module_manager = engine.scenes[0].children[0].children[0] #engine.add_filter(labels1, module_manager) #self.labels = self.scene.mlab.pipeline.labels( self.dataset ) def __add_normal_labels(self, point1, point2): # Get spatial grid sizes: xcells = (int)(self.__vlsvReader.read_parameter("xcells_ini")) ycells = (int)(self.__vlsvReader.read_parameter("ycells_ini")) zcells = (int)(self.__vlsvReader.read_parameter("zcells_ini")) xmin = self.__vlsvReader.read_parameter("xmin") ymin = self.__vlsvReader.read_parameter("ymin") zmin = self.__vlsvReader.read_parameter("zmin") xmax = self.__vlsvReader.read_parameter("xmax") ymax = self.__vlsvReader.read_parameter("ymax") zmax = self.__vlsvReader.read_parameter("zmax") dx = (xmax - xmin) / (float)(xcells) dy = (ymax - ymin) / (float)(ycells) dz = (zmax - zmin) / (float)(zcells) # Get normal vector from point2 and point1 point1 = np.array(point1) point2 = np.array(point2) normal_vector = (point2 - point1) / np.linalg.norm(point2 - point1) normal_vector = np.dot(rotation_matrix_2d( -0.5 * np.pi), (point2 - point1)) / np.linalg.norm(point2 - point1) normal_vector = normal_vector * np.array([1, 1, 0]) point1_shifted = point1 + 0.5 * (point2 - point1) - normal_vector * (8 * dx) point2_shifted = point1 + 0.5 * (point2 - point1) + normal_vector * (8 * dx) point1 = np.array(point1_shifted) point2 = np.array(point2_shifted) cellid1 = self.__vlsvReader.get_cellid(point1) cellid2 = self.__vlsvReader.get_cellid(point2) # Input label: self.__add_label(cellid1) self.__add_label(cellid2) def __load_grid(self, variable, operator="pass", threaded=True): ''' Creates a grid and inputs scalar variables from a vlsv file :param variable: Name of the variable to plot :param operator: Operator for the variable :param threaded: Boolean value for using threads or not using threads to draw the grid (threads enable interactive mode) ''' # Get the cell params: mins = np.array([ self.__vlsvReader.read_parameter("xmin"), self.__vlsvReader.read_parameter("ymin"), self.__vlsvReader.read_parameter("zmin") ]) cells = np.array([ self.__vlsvReader.read_parameter("xcells_ini"), self.__vlsvReader.read_parameter("ycells_ini"), self.__vlsvReader.read_parameter("zcells_ini") ]) maxs = np.array([ self.__vlsvReader.read_parameter("xmax"), self.__vlsvReader.read_parameter("ymax"), self.__vlsvReader.read_parameter("zmax") ]) # Get the variables: index_for_cellid_dict = self.__vlsvReader.get_cellid_locations() variable_array = self.__vlsvReader.read_variable(name=variable, operator=operator) # Sort the dictionary by cell id import operator as oper sorted_index_for_cellid_dict = sorted( index_for_cellid_dict.iteritems(), key=oper.itemgetter(0)) # Add the variable values: variable_array_sorted = [] for i in sorted_index_for_cellid_dict: variable_array_sorted.append(variable_array[i[1]]) # Store the mins and maxs: self.__mins = mins self.__maxs = maxs self.__cells = cells # Draw the grid: if threaded == True: thread = threading.Thread(target=self.__generate_grid, args=(mins, maxs, cells, variable_array_sorted, variable)) thread.start() else: self.__generate_grid(mins=mins, maxs=maxs, cells=cells, datas=variable_array_sorted, names=variable) def __picker_callback(self, picker): """ This gets called when clicking on a cell """ if (self.picker != "Cut_through"): # Make sure the last pick is null (used in cut_through) self.__last_pick = [] coordinates = picker.pick_position coordinates = np.array( [coordinates[0], coordinates[1], coordinates[2]]) # For numerical inaccuracy epsilon = 80 # Check for numerical inaccuracy for i in xrange(3): if (coordinates[i] < self.__mins[i]) and (coordinates[i] + epsilon > self.__mins[i]): # Correct the numberical inaccuracy coordinates[i] = self.__mins[i] + 1 if (coordinates[i] > self.__maxs[i]) and (coordinates[i] - epsilon < self.__maxs[i]): # Correct the values coordinates[i] = self.__maxs[i] - 1 print "COORDINATES:" + str(coordinates) cellid = self.__vlsvReader.get_cellid(coordinates) print "CELL ID: " + str(cellid) # Check for an invalid cell id if cellid == 0: print "Invalid cell id" return if (self.picker == "Velocity_space"): # Set label to give out the location of the cell: self.__add_label(cellid) # Generate velocity space self.__generate_velocity_grid(cellid) elif (self.picker == "Velocity_space_nearest_cellid"): # Find the nearest cell id with distribution: # Read cell ids with velocity distribution in: cell_candidates = self.__vlsvReader.read("SpatialGrid", "CELLSWITHBLOCKS") # Read in the coordinates of the cells: cell_candidate_coordinates = [ self.__vlsvReader.get_cell_coordinates(cell_candidate) for cell_candidate in cell_candidates ] # Read in the cell's coordinates: pick_cell_coordinates = self.__vlsvReader.get_cell_coordinates( cellid) # Find the nearest: from operator import itemgetter norms = np.sum( (cell_candidate_coordinates - pick_cell_coordinates)**2, axis=-1)**(1. / 2) norm, i = min((norm, idx) for (idx, norm) in enumerate(norms)) # Get the cell id: cellid = cell_candidates[i] # Set label to give out the location of the cell: self.__add_label(cellid) # Generate velocity grid self.__generate_velocity_grid(cellid) elif (self.picker == "Velocity_space_iso_surface"): # Set label to give out the location of the cell: self.__add_label(cellid) self.__generate_velocity_grid(cellid, True) elif (self.picker == "Velocity_space_nearest_cellid_iso_surface"): # Find the nearest cell id with distribution: # Read cell ids with velocity distribution in: cell_candidates = self.__vlsvReader.read("SpatialGrid", "CELLSWITHBLOCKS") # Read in the coordinates of the cells: cell_candidate_coordinates = [ self.__vlsvReader.get_cell_coordinates(cell_candidate) for cell_candidate in cell_candidates ] # Read in the cell's coordinates: pick_cell_coordinates = self.__vlsvReader.get_cell_coordinates( cellid) # Find the nearest: from operator import itemgetter norms = np.sum( (cell_candidate_coordinates - pick_cell_coordinates)**2, axis=-1)**(1. / 2) norm, i = min((norm, idx) for (idx, norm) in enumerate(norms)) # Get the cell id: cellid = cell_candidates[i] # Set label to give out the location of the cell: self.__add_label(cellid) # Generate velocity grid self.__generate_velocity_grid(cellid, True) elif (self.picker == "Pitch_angle"): # Set label to give out the location of the cell: self.__add_label(cellid) # Plot pitch angle distribution: from pitchangle import pitch_angles result = pitch_angles(vlsvReader=self.__vlsvReader, cellid=cellid, cosine=True, plasmaframe=True) # plot: pl.hist(result[0].data, weights=result[1].data, bins=50, log=False) pl.show() elif (self.picker == "Gyrophase_angle"): # Plot gyrophase angle distribution: from gyrophaseangle import gyrophase_angles_from_file result = gyrophase_angles_from_file(vlsvReader=self.__vlsvReader, cellid=cellid) # plot: pl.hist(result[0].data, weights=result[1].data, bins=36, range=[-180.0, 180.0], log=True, normed=1) pl.show() elif (self.picker == "Cut_through"): if len(self.__last_pick) == 3: from cutthrough import cut_through # Get a cut-through self.cut_through = cut_through(self.__vlsvReader, point1=self.__last_pick, point2=coordinates) # Get cell ids and distances separately cellids = self.cut_through[0].data distances = self.cut_through[1] # Get any arguments from the user: args = self.args.split() if len(args) == 0: #Do nothing print "Bad args" self.__last_pick = [] return plotCut = False plotRankine = False # Optimize file read: self.__vlsvReader.optimize_open_file() variables = [] # Save variables for i in xrange(len(args)): # Check if the user has given the plot argument if args[i] == "plot": plotCut = True elif args[i] == "rankine": # set labels: self.__add_normal_labels(point1=self.__last_pick, point2=coordinates) fig = plot_rankine(self.__vlsvReader, point1=self.__last_pick, point2=coordinates) #pl.show() self.__last_pick = [] self.plot = fig return else: if args[i].find(",") != -1: _variable = args[i].split(',')[0] _operator = args[i].split(',')[1] variable_info = self.__vlsvReader.read_variable_info( name=_variable, cellids=cellids, operator=_operator) variables.append(variable_info) self.cut_through.append(variable_info) else: variable_info = self.__vlsvReader.read_variable_info( name=args[i], cellids=cellids) variables.append(variable_info) self.cut_through.append(variable_info) if plotCut == True: # Set label to give out the location of the cell: self.__add_label(cellids[0]) self.__add_label(cellids[len(cellids) - 1]) if plotRankine == True: # Plot Rankine-Hugoniot jump conditions: normal_vector = (coordinates - self.__last_pick ) / np.linalg.norm(coordinates - self.__last_pick) # Read V, B, T and rho V = self.__vlsvReader.read_variable("v", cellids=cellids[0]) B = self.__vlsvReader.read_variable("B", cellids=cellids[0]) T = self.__vlsvReader.read_variable("Temperature", cellids=cellids[0]) rho = self.__vlsvReader.read_variable( "rho", cellids=cellids[0]) # Get parallel and perpendicular components: Vx = np.dot(V, normal_vector) Vy = np.linalg.norm(V - Vx * normal_vector) Bx = np.dot(B, normal_vector) By = np.linalg.norm(B - Bx * normal_vector) # Calculate jump conditions conditions = oblique_shock(Vx, Vy, Bx, By, T, rho) rankine_variables = [] for i in xrange(len(get_data(distances))): if i < len(get_data(distances)) * 0.5: rankine_variables.append(rho) else: rankine_variables.append(conditions[5]) variables.append(rankine_variables) from plot import plot_multiple_variables fig = plot_multiple_variables( [distances for i in xrange(len(args) - 1)], variables, figure=[]) pl.show() # Close the optimized file read: self.__vlsvReader.optimize_close_file() # Read in the necessary variables: self.__last_pick = [] else: self.__last_pick = coordinates def __generate_grid(self, mins, maxs, cells, datas, names): ''' Generates a grid from given data :param mins: An array of minimum coordinates for the grid for ex. [-100, 0, 0] :param maxs: An array of maximum coordinates for the grid for ex. [-100, 0, 0] :param cells: An array of number of cells in x, y, z direction :param datas: Scalar data for the grid e.g. array([ cell1Rho, cell2Rho, cell3Rho, cell4Rho, .., cellNRho ]) :param names: Name for the scalar data ''' # Create nodes x, y, z = mgrid[mins[0]:maxs[0]:(cells[0] + 1) * complex(0, 1), mins[1]:maxs[1]:(cells[1] + 1) * complex(0, 1), mins[2]:maxs[2]:(cells[2] + 1) * complex(0, 1)] # Create points for the nodes: pts = empty(z.shape + (3, ), dtype=float) pts[..., 0] = x pts[..., 1] = y pts[..., 2] = z # Input scalars scalars = np.array(datas) # We reorder the points, scalars and vectors so this is as per VTK's # requirement of x first, y next and z last. pts = pts.transpose(2, 1, 0, 3).copy() pts.shape = pts.size / 3, 3 scalars = scalars.T.copy() # Create the dataset. sg = tvtk.StructuredGrid(dimensions=x.shape, points=pts) sg.cell_data.scalars = ravel(scalars.copy()) sg.cell_data.scalars.name = names # Visualize the data d = self.scene.mlab.pipeline.add_dataset(sg) iso = self.scene.mlab.pipeline.surface(d) # Add labels: # from mayavi.modules.labels import Labels # testlabels = self.scene.mlab.pipeline.labels(d) self.dataset = d # Configure traits self.configure_traits() # Note: This is not working properly -- it seemingly works out at first but it eventually causes segmentation faults in some places #self.__thread = threading.Thread(target=self.configure_traits, args=()) #self.__thread.start() def __generate_velocity_grid(self, cellid, iso_surface=False): '''Generates a velocity grid from a given spatial cell id :param cellid: The spatial cell's ID :param iso_surface: If true, plots the iso surface ''' # Create nodes # Get velocity blocks and avgs: blocksAndAvgs = self.__vlsvReader.read_blocks(cellid) if len(blocksAndAvgs) == 0: print "CELL " + str(cellid) + " HAS NO VELOCITY BLOCK" return False # Create a new scene self.__engine.new_scene() mayavi.mlab.set_engine(self.__engine) #CONTINUE # Create a new figure figure = mayavi.mlab.gcf(engine=self.__engine) figure.scene.disable_render = True blocks = blocksAndAvgs[0] avgs = blocksAndAvgs[1] # Get nodes: nodesAndKeys = self.__vlsvReader.construct_velocity_cell_nodes(blocks) # Create an unstructured grid: points = nodesAndKeys[0] tets = nodesAndKeys[1] tet_type = tvtk.Voxel().cell_type #VTK_VOXEL ug = tvtk.UnstructuredGrid(points=points) # Set up the cells ug.set_cells(tet_type, tets) # Input data values = np.ravel(avgs) ug.cell_data.scalars = values ug.cell_data.scalars.name = 'avgs' # Plot B if possible: # Read B vector and plot it: if self.__vlsvReader.check_variable("B") == True: B = self.__vlsvReader.read_variable(name="B", cellids=cellid) elif self.__vlsvReader.check_variable("B_vol") == True: B = self.__vlsvReader.read_variable(name="B_vol", cellids=cellid) else: B = self.__vlsvReader.read_variable( name="background_B", cellids=cellid) + self.__vlsvReader.read_variable( name="perturbed_B", cellids=cellid) points2 = np.array([[0, 0, 0]]) ug2 = tvtk.UnstructuredGrid(points=points2) ug2.point_data.vectors = [B / np.linalg.norm(B)] ug2.point_data.vectors.name = 'B_vector' #src2 = VTKDataSource(data = ug2) d2 = mayavi.mlab.pipeline.add_dataset(ug2) #mayavi.mlab.add_module(Vectors()) vec = mayavi.mlab.pipeline.vectors(d2) vec.glyph.mask_input_points = True vec.glyph.glyph.scale_factor = 1e6 vec.glyph.glyph_source.glyph_source.center = [0, 0, 0] # Visualize d = mayavi.mlab.pipeline.add_dataset(ug) if iso_surface == False: iso = mayavi.mlab.pipeline.surface(d) else: ptdata = mayavi.mlab.pipeline.cell_to_point_data(d) iso = mayavi.mlab.pipeline.iso_surface( ptdata, contours=[1e-15, 1e-14, 1e-12], opacity=0.3) figure.scene.disable_render = False self.__unstructured_figures.append(figure) # Name the figure figure.name = str(cellid) + ", " + self.variable_plotted + " = " + str( self.__vlsvReader.read_variable(self.variable_plotted, cellids=cellid)) from mayavi.modules.axes import Axes axes = Axes() axes.name = 'Axes' axes.axes.fly_mode = 'none' axes.axes.number_of_labels = 8 axes.axes.font_factor = 0.5 #module_manager = self.__module_manager() # Add the label / marker: self.__engine.add_filter(axes) from mayavi.modules.outline import Outline outline = Outline() outline.name = 'Outline' self.__engine.add_filter(outline) return True def generate_diff_grid(self, cellid1, cellid2): ''' Generates a diff grid of given cell ids (shows avgs diff) :param cellid1: The first cell id :param cellid2: The second cell id .. code-block:: python # Example: grid.generate_diff_grid( 29219, 2910 ) .. note:: If the cell id does not have a certain velocity cell, it is assumed that the avgs value of that cell is 0 ''' # Create nodes # Get velocity blocks and avgs (of cellid 1) blocksAndAvgs1 = self.__vlsvReader.read_blocks(cellid1) if len(blocksAndAvgs1) == 0: print "CELL " + str(cellid1) + " HAS NO VELOCITY BLOCK" return False blocks1 = blocksAndAvgs1[0] avgs1 = blocksAndAvgs1[1] # Get velocity blocks and avgs (of cellid 2) blocksAndAvgs2 = self.__vlsvReader.read_blocks(cellid2) if len(blocksAndAvgs2) == 0: print "CELL " + str(cellid2) + " HAS NO VELOCITY BLOCK" return False blocks2 = blocksAndAvgs2[0] avgs2 = blocksAndAvgs2[1] print len(avgs2) print len(blocks2) # Compare blocks and create a new avgs array values: avgs_same = [] avgs_cellid1 = [] avgs_cellid2 = [] blocks_same = [] blocks_cellid1 = [] blocks_cellid2 = [] print np.shape(avgs1[0]) for i in xrange(len(blocks1)): b = blocks1[i] # Get index of block i2 = np.where(blocks2 == b)[0] if len(i2) != 0: # Fetch the block: #print avgs1[64*i:64*(i+1)] #print avgs2[64*i2[0]:64*(i2[0]+1)] avgs_same.append(avgs1[i:(i + 1)] - avgs2[i2[0]:(i2[0] + 1)]) blocks_same.append(b) else: avgs_cellid1.append(avgs1[i:(i + 1)]) blocks_cellid1.append(b) for i in xrange(len(blocks2)): b = blocks2[i] if (b in blocks1) == False: avgs_cellid2.append(avgs2[i:(i + 1)]) blocks_cellid2.append(b) # Make a list for the avgs etc avgs = np.zeros( 64 * (len(avgs_same) + len(avgs_cellid1) + len(avgs_cellid2))) #avgs = np.reshape(avgs, (len(avgs_same)+len(avgs_cellid1)+len(avgs_cellid2), 64)) print np.shape(avgs_same) blocks = np.zeros( len(blocks_same) + len(blocks_cellid1) + len(blocks_cellid2)) index = 0 avgs[64 * index:64 * (index + len(blocks_same))] = np.ravel( np.array(avgs_same)) blocks[index:index + len(blocks_same)] = np.array(blocks_same) index = index + len(blocks_same) avgs[64 * index:64 * (index + len(blocks_cellid1))] = np.ravel( np.array(avgs_cellid1)) blocks[index:index + len(blocks_cellid1)] = np.array(blocks_cellid1) index = index + len(blocks_cellid1) avgs[64 * index:64 * (index + len(blocks_cellid2))] = np.ravel( np.array(avgs_cellid2)) blocks[index:index + len(blocks_cellid2)] = np.array(blocks_cellid2) blocks = blocks.astype(int) # Get nodes: nodesAndKeys = self.__vlsvReader.construct_velocity_cell_nodes(blocks) # Create an unstructured grid: points = nodesAndKeys[0] tets = nodesAndKeys[1] # Create a new scene self.__engine.new_scene() mayavi.mlab.set_engine(self.__engine) #CONTINUE # Create a new figure figure = mayavi.mlab.gcf(engine=self.__engine) figure.scene.disable_render = True tet_type = tvtk.Voxel().cell_type #VTK_VOXEL ug = tvtk.UnstructuredGrid(points=points) #Thissetsupthecells. ug.set_cells(tet_type, tets) #Attributedata. values = np.ravel(avgs) ug.cell_data.scalars = values ug.cell_data.scalars.name = 'avgs' d = mayavi.mlab.pipeline.add_dataset(ug) iso = mayavi.mlab.pipeline.surface(d) figure.scene.disable_render = False self.__unstructured_figures.append(figure) # Name the figure figure.name = str(cellid1) + " " + str(cellid2) mayavi.mlab.show() return True def __do_nothing(self, picker): return # Trait events: @on_trait_change('scene.activated') def set_mouse_click(self): # Temporary bug fix (MayaVi needs a dummy pick to be able to remove cells callbacks from picker.. ) #self.figure.on_mouse_pick( self.__do_nothing, type='world' self.figure = self.scene.mlab.gcf() # Cell picker func = self.__picker_callback typeid = 'world' click = 'Left' picker = self.figure.on_mouse_pick(func, type='world') self.__picker = [func, typeid, click] #picker.tolerance = 0 # Show legend bar manager = self.figure.children[0].children[0] manager.scalar_lut_manager.show_scalar_bar = True manager.scalar_lut_manager.show_legend = True
def _info_grp(self): return HGroup( Readonly('local_commit', label='Your Version'), Readonly('latest_remote_commit', label='Latest Version'), Readonly('n', label='Commits Behind', visible_when='show_behind'))
class DoubleSview(HasTraits): ''' Container for two instances of scatter view. Takes in full Sview objects, so that composite plots can be built up using these ''' scatt1 = Instance(ScatterView) scatt2 = Instance(ScatterView) implements(ICompositeView) datanames = ['Scattering', 'Absorbance', 'Extinction'] hideplots = List( editor=CheckListEditor( values=['Scattering', 'Absorbance', 'Extinction'], cols=3) ) #THESE ARE KEYS USED TO SETDATA IN SVIEW OBJECT (DON'T ALTER IN EITHER CODE) #Following is used to keep keys in plot objects separate (e.g. Absorbance is a plot key for scatt1 and scatt2# #These will turn it into Absorbance%s1 and Absorbance%s2# delimiter = Str('%') s1_id = Str('s1') s2_id = Str('s2') s1_color = Str('blue') s2_color = Str('red') alldata = Instance(ArrayPlotData) doubleplot = Instance(Plot) def _alldata_default(self): """ Default ArrayPlotData with reserved names which will be updated when individual plot data objects are changed. names for the ArrayPlotData objects based on datanames (sig, absorb) plus the id and delimiter. I reserve only one instance of 'x' """ alldata = ArrayPlotData() for name in self.datanames: alldata.set_data(name + self.delimiter + self.s1_id, []) alldata.set_data(name + self.delimiter + self.s2_id, []) alldata.set_data('x', []) return alldata def _doubleplot_default(self): ''' I add all the plots in one go, then use hide/show functions to change them''' plot = Plot(self.alldata) for name in self.alldata.list_data(): if name != 'x': if name.split(self.delimiter)[1] == self.s1_id: color = self.s1_color elif name.split(self.delimiter)[1] == self.s2_id: color = self.s2_color plot.plot(('x', name), name=name, linewidth=5, color=color) return plot @on_trait_change('scatt1.data.arrays, scatt2.data.arrays') def update_alldata(self): ''' This is how the plots update in real time, by listening to data.arrays. I extract 'x' from the first plot, assuming it is the same between plots ''' if self.scatt1 is not None: for name in self.scatt1.data.arrays: if name == 'x': self.alldata.set_data((str(name)), self.scatt1.data.arrays[name]) else: self.alldata.set_data( (str(name) + self.delimiter + self.s1_id), self.scatt1.data.arrays[name]) if self.scatt2 is not None: for name in self.scatt2.data.arrays: if name != 'x': self.alldata.set_data( (str(name) + self.delimiter + self.s2_id), self.scatt2.data.arrays[name]) @on_trait_change('hideplots') def update_lines(self): ''' Allows users to hide or show plots by first plotting all the lines. Note that since there are two plots, there are actually two matches to name. EG if name is "abs" then its going to hide or show abs%1 and abs%2, that is why I only need to put one call below ''' for name in self.doubleplot.plots: if name.split(self.delimiter)[0] in self.hideplots: self.doubleplot.hideplot(name) else: self.doubleplot.showplot(name) self.doubleplot.request_redraw() #Necessary traits_view = View(VGroup(HGroup(Item('scatt1', style='custom', show_label=False), Item('scatt2', style='custom', show_label=False), label="Separate"), VGroup(Item('hideplots', style='custom', label='Hide Plot'), Item('doubleplot', editor=ComponentEditor(size=(200, 100)), show_label=False), label="Combined"), layout='tabbed'), resizable=True)
from traits.api import Str, Bool, Float, Range, List, Instance, HasTraits, DelegatesTo, Button from traitsui.api import View, Group, Item, HGroup,spring from labtools.agilent.funcgen import AgilentFuncGen, INITCMD, LOGLEVEL, find_address from labtools.utils.instrui import BaseInstrumentUI, instrument_group, status_group from labtools.log import create_logger logger = create_logger(__name__, LOGLEVEL) output_group = HGroup(Item('voltage'), spring,Item('output_button',show_label = False, enabled_when = '_initialized==True'),show_border = True, label = 'Output') class IOSettings(HasTraits): """IO Settings for Keithley. defines port (instrument) name, communication timeout and initialization commands. """ timeout = Range(0.,100.,10., desc = 'communication timeout') instr = Str(desc = 'instrument name') initcmd = Str(INITCMD, desc = 'initialization command') view = View('timeout', 'instr', Item('initcmd', style = 'custom'), buttons = ['OK', 'Cancel']) class OutputSettings(HasTraits): voltage = Float(10.) frequency = Float(40.) offset = Float(0.)
class Visualization(HasTraits): engine1 = Instance(Engine, args=()) sceneView1 = Instance(MlabSceneModel, ()) # The scene model # Initialize the GUI Values GUI_OBJECT_NAME = Str("") GUI_ID = Str("") GUI_MATERIAL_ID = Str("") GUI_MATERIAL_NAME = Str("") GUI_CHANGE_REPRESENTATION = Bool GUI_CHANGE_MATERIAL = Str GUI_MATERIAL_LIBRARY = List(['']) # Initialize the picker @on_trait_change('sceneView1.activated') def initializePicker(self): picker = self.sceneView1.mayavi_scene.on_mouse_pick( self.picker_callback, type='cell') picker.tolerance = 0.01 # Perform an action depending if an AMF object was picked or not def picker_callback(self, picker): global LIST_AMF_OBJECTS, CURRENT_SELECTED_OBJECT, DICT_MATERIAL # Catch the errors here output = vtk.vtkFileOutputWindow() output.SetFileName("log.txt") vtk.vtkOutputWindow().SetInstance(output) picker_outside = True # Check if the object picked belongs to our LIST_AMF_OBJECTS for i in range(len(LIST_AMF_OBJECTS)): if picker.actor in LIST_AMF_OBJECTS[i].geometry.actor.actors: # The user picked an object in our LIST_AMF_OBJECTS picker_outside = False # Update the visualization LIST_AMF_OBJECTS[ i].geometry.actor.mapper.scalar_visibility = False # Disable the scalar colors assigned to the object LIST_AMF_OBJECTS[i].geometry.actor.property.color = ( 1, 0, 0) # Color the picked object in red LIST_AMF_OBJECTS[ i].geometry.actor.property.line_width = 8 # Increase slighly the size of the wireframe edges # Update the GUI self.GUI_OBJECT_NAME = LIST_AMF_OBJECTS[i].name self.GUI_ID = LIST_AMF_OBJECTS[i].xmlObjectID self.GUI_MATERIAL_ID = LIST_AMF_OBJECTS[i].materialId self.GUI_MATERIAL_NAME = DICT_MATERIAL[ LIST_AMF_OBJECTS[i].materialId] CURRENT_SELECTED_OBJECT = i # LIST_AMF_OBJECTS[i].geometry.actor.actor.scale = (1,1,2) # Just a placeholder in case we want to slightly increase the height of the selected object else: # The object was not picked - Reapply the original Scalar Color and line width LIST_AMF_OBJECTS[ i].geometry.actor.mapper.scalar_visibility = True LIST_AMF_OBJECTS[i].geometry.actor.property.line_width = 2 # LIST_AMF_OBJECTS[i].geometry.actor.actor.scale = (1,1,1) # Just a placeholder to assign the orignal height to the object if picker_outside: # The picker did not select an object belonging to our LIST_AMF_OBJECTS self.GUI_MATERIAL_ID = "" self.GUI_OBJECT_NAME = "" self.GUI_ID = "No Object Selected" self.GUI_MATERIAL_NAME = "" CURRENT_SELECTED_OBJECT = -1 # When clicked, change the objects in the visualizer from wireframe to surface representation and vice-versa # TODO: No real purpose now but could be useful if we plan to apply material textures @on_trait_change('GUI_CHANGE_REPRESENTATION') def switchSurfaceWireframe(self): global LIST_AMF_OBJECTS # Update the rendering if self.GUI_CHANGE_REPRESENTATION: # Apply Surface for i in range(len(LIST_AMF_OBJECTS)): # Placeholder code to apply texture # LIST_AMF_OBJECTS[i].surface.actor.actor.property.representation = 'surface' # textureFile = tvtk.JPEGReader() # textureFile.file_name= TextureFolder + str(LIST_AMF_OBJECTS[i].materialId) + ".jpg" #any jpeg file # wallTexture1 = tvtk.Texture(input_connection=textureFile.output_port, interpolate=0) # LIST_AMF_OBJECTS[i].surface.actor.enable_texture = True # LIST_AMF_OBJECTS[i].surface.actor.tcoord_generator_mode = 'plane' # LIST_AMF_OBJECTS[i].surface.actor.actor.texture = wallTexture1 LIST_AMF_OBJECTS[ i].geometry.actor.actor.property.representation = 'surface' else: # Apply Wireframe for i in range(len(LIST_AMF_OBJECTS)): LIST_AMF_OBJECTS[ i].geometry.actor.actor.property.representation = 'wireframe' LIST_AMF_OBJECTS[i].geometry.actor.enable_texture = False # Update the rendering force_render() self.sceneView1.render() self.sceneView1.mayavi_scene.render() # Handle new material assigmment @on_trait_change('GUI_CHANGE_MATERIAL') def update_material_test(self): global CURRENT_SELECTED_OBJECT, LIST_AMF_OBJECTS, AMF_ROOT, AMF_TREE if CURRENT_SELECTED_OBJECT != -1: # Apply the new color corresponding to the newly material assigned to the selected object dataset = mlab.pipeline.get_vtk_src( LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].geometry ) # Get the dataset associated with the object currentScalar = dataset[0].point_data.scalars.to_array( ) # Get the scalars, i.e, the material ID color newScalar = np.full_like( currentScalar, self.GUI_CHANGE_MATERIAL) # Create the new scalar color LIST_AMF_OBJECTS[ CURRENT_SELECTED_OBJECT].geometry.mlab_source.trait_set( scalars=newScalar) # Apply the color to the object LIST_AMF_OBJECTS[ CURRENT_SELECTED_OBJECT].geometry.actor.mapper.scalar_visibility = True LIST_AMF_OBJECTS[ CURRENT_SELECTED_OBJECT].materialId = self.GUI_CHANGE_MATERIAL # Update the object material ID # Update the GUI with the material Name and Material ID self.GUI_MATERIAL_ID = LIST_AMF_OBJECTS[ CURRENT_SELECTED_OBJECT].materialId self.GUI_MATERIAL_NAME = DICT_MATERIAL[ LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].materialId] # Update the AMF File of the selected object with the new material selected idObject = LIST_AMF_OBJECTS[CURRENT_SELECTED_OBJECT].xmlObjectID pathToUpdate = "./object/[@id=\"" + idObject + "\"]/mesh/volume" volumesToUpdate = AMF_ROOT.findall( pathToUpdate ) # Get all the volumes corresponding to the selected object for i in range(len(volumesToUpdate)): volumesToUpdate[i].attrib[ "materialid"] = self.GUI_CHANGE_MATERIAL # Save a new AMF file incuding the changes of Material amfFileToSave = AMF_SAVED_PREFIX + AMF_FILE amfFileToSave = str(Path(AMF_FOLDER) / amfFileToSave) AMF_TREE.write(amfFileToSave) force_render() self.sceneView1.render() self.sceneView1.mayavi_scene.render() ################################################################ ########## INITIALIZE THE VISUALIZATION ################ ################################################################ # Parse the AMF file and create the visualization def __init__(self): global LIST_AMF_OBJECTS, AMF_TREE, AMF_ROOT, DICT_MATERIAL self.engine1.start() amfFileToParse = str(Path(AMF_FOLDER) / AMF_FILE) try: AMF_TREE = ET.parse(amfFileToParse) except OSError as e: print("Error:", e) exit() AMF_ROOT = AMF_TREE.getroot() objectsDict = {} # By default, we add a material with ID 0 that corresponds to the case where no material is assigned to a volume # Obviously, this choice imposes to use Material ID in the library with an ID greater than 0 TODO: Check if it's the case once we know how to manage the material library noMaterialID = "0" DICT_MATERIAL[noMaterialID] = "No Material" # Start by handling the material in the AMF file to build the material library for tMaterial in AMF_ROOT.iter('material'): # Iterate through all the material in the scenario materialID = tMaterial.attrib['id'] for tName in tMaterial.iter('metadata'): materialName = tName.text # Get the material Name DICT_MATERIAL[ materialID] = materialName # Add the material to the material dictionary # Handle the case where no Material exists in the AMF file - For example NISTGaithersburg.xml # Here is just a placeholder for the default material library # In this implementation, we will create a fake material made of 100 materials (completely arbitrary choice) if len(DICT_MATERIAL) == 1: # No Material defined nbMaterial = 100 for i in range(1, nbMaterial + 1): DICT_MATERIAL[str(i)] = "FakematerialName" + str(i) for tObject in AMF_ROOT.iter('object'): # Iterate through all the objects in the AMF File coordinateX = [] coordinateY = [] coordinateZ = [] DONOTADD = False xmlObjectID = tObject.attrib['id'] # Get the Object ID for tName in tObject.iter('metadata'): xmlObjectName = tName.text # Get the object Name # There is a bug in the way geodata scenario are generated # It includes twice every object so we handle that here # TODO: Fix the geodata scenarios generation and update the code accordingly if xmlObjectName in objectsDict: # If an object with the same name has already been parsed, flag it DONOTADD = True else: # The object does not exist in the object dictionnary, just add it to the objects dictionary objectsDict[xmlObjectName] = True # Get the X, Y, Z coordinates corresponding to an object for tcoordinatesX in tObject.iter('x'): # Get x coordinates coordinateX.append(float(tcoordinatesX.text)) for tcoordinatesY in tObject.iter('y'): # Get y coordinates coordinateY.append(float(tcoordinatesY.text)) for tcoordinatesZ in tObject.iter('z'): # Get z coordinates coordinateZ.append(float(tcoordinatesZ.text)) for tVolume in tObject.iter('volume'): # Iterate over the volume, i.e., the triangles connections and material # Please note that an object can be defined with more than one volume try: materialId = tVolume.attrib[ 'materialid'] # Get the material ID associated to the triangles connections except KeyError: # It's possible that a volume is not having any material assigned - Handle it # print("Warning: Object :", xmlObjectName, " is not having any material associated to it") TODO Commented for now materialId = None v1 = [] # First vertex v2 = [] # Second vertex v3 = [] # Third vertex for tTriangles in tVolume.iter('triangle'): # Iterate over the triangles of a volume for tFirstPoint in tTriangles.iter('v1'): # Get First vertex v1.append(int(tFirstPoint.text)) for tSecondPoint in tTriangles.iter('v2'): # Get Second vertex v2.append(int(tSecondPoint.text)) for tThirdPoint in tTriangles.iter('v3'): # Get Third vertex v3.append(int(tThirdPoint.text)) # Get the final triangles coordinates by connecting the vertices to their associated coordinates finalX = [] finalY = [] finalZ = [] for index in range(len(v1)): finalX.append([ coordinateX[v1[index]], coordinateX[v2[index]], coordinateX[v3[index]] ]) finalY.append([ coordinateY[v1[index]], coordinateY[v2[index]], coordinateY[v3[index]] ]) finalZ.append([ coordinateZ[v1[index]], coordinateZ[v2[index]], coordinateZ[v3[index]] ]) # Create the triangles connections triangles = [(i * 3, (i * 3) + 1, (i * 3) + 2) for i in range(0, len(finalX))] # Manage automatically the color of each volume depending on the material ID # The colormap is having 0:nbMaterial+1 possible values # We define a scalar that we associate with the volume if materialId == None: # Assign the No Material ID in case no material was assigned to a volume materialId = noMaterialID color = np.ones(np.asarray(finalX).shape) * int(materialId) if DONOTADD == False: # Add the volume to the visualization only it it was not added previously # Create the volume to visualize volume = mlab.triangular_mesh( finalX, finalY, finalZ, triangles, scalars=color, vmin=0, vmax=len(DICT_MATERIAL) - 1, colormap='Spectral', representation='wireframe', name="volume:" + xmlObjectName, figure=self.sceneView1.mayavi_scene, reset_zoom=False) volume.module_manager.scalar_lut_manager.lut.number_of_colors = 256 # Create a label for each volume labels = Labels() vtk_data_source = volume self.engine1.add_filter(labels, vtk_data_source) labels.mapper.label_format = (xmlObjectName) labels.number_of_labels = 1 labels.mask.filter.random_mode = False # Store the objects currentObject = ObjectGeometry(xmlObjectID, xmlObjectName, volume, materialId) LIST_AMF_OBJECTS.append(currentObject) # Present the Material ID library ordered in the GUI materialIDSorted = sorted(list(DICT_MATERIAL.keys()), key=int) self.GUI_MATERIAL_LIBRARY = materialIDSorted HasTraits.__init__(self) # GUI Definition view = View( HSplit( Group( Item('sceneView1', editor=SceneEditor(scene_class=MayaviScene), height=800, width=700, show_label=False, resizable=True), # Group used to inspect the different objects of the scenario HGroup( Group(Item(name='GUI_CHANGE_REPRESENTATION', label='Wireframe/Surface'), Item(name='GUI_ID', label='ID', style='readonly'), Item(name='GUI_OBJECT_NAME', label='Name', style='readonly'), Item(name='GUI_MATERIAL_ID', label='Material ID', style='readonly'), Item(name='GUI_MATERIAL_NAME', label='Material Name', style='readonly'), label='Object Inspector', show_border=True), # visible_when='GUI_ID != "1"', #TODO Can allow to hide or display the group ), # Group used to edit the objects material (TODO: On-Hold as no convergence for the material ID library management) HGroup( Group(Item( name='GUI_CHANGE_MATERIAL', editor=CheckListEditor(name='GUI_MATERIAL_LIBRARY'), label='Change Material'), label='Object Editor', show_border=True), )), ), resizable=True, )
class SolutionView(HasTraits): python_console_cmds = Dict() # we need to doubleup on Lists to store the psuedo absolutes separately # without rewriting everything lats = List() lngs = List() alts = List() """ logging_v : toggle logging for velocity files directory_name_v : location and name of velocity files logging_p : toggle logging for position files directory_name_p : location and name of velocity files """ logging_v = Bool(False) directory_name_v = File logging_p = Bool(False) directory_name_p = File lats_psuedo_abs = List() lngs_psuedo_abs = List() alts_psuedo_abs = List() table_spp = List() table_psuedo_abs = List() dops_table = List() pos_table_spp = List() vel_table = List() rtk_pos_note = Str( "It is necessary to enter the \"Surveyed Position\" settings for the base station in order to view the psuedo-absolute RTK Positions in this tab." ) plot = Instance(Plot) plot_data = Instance(ArrayPlotData) # Store plots we care about for legend running = Bool(True) zoomall = Bool(False) position_centered = Bool(False) clear_button = SVGButton(label='', tooltip='Clear', filename=os.path.join(determine_path(), 'images', 'iconic', 'x.svg'), width=16, height=16) zoomall_button = SVGButton(label='', tooltip='Zoom All', toggle=True, filename=os.path.join(determine_path(), 'images', 'iconic', 'fullscreen.svg'), width=16, height=16) center_button = SVGButton(label='', tooltip='Center on Solution', toggle=True, filename=os.path.join(determine_path(), 'images', 'iconic', 'target.svg'), width=16, height=16) paused_button = SVGButton(label='', tooltip='Pause', toggle_tooltip='Run', toggle=True, filename=os.path.join(determine_path(), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join( determine_path(), 'images', 'iconic', 'play.svg'), width=16, height=16) traits_view = View( HSplit( Tabbed( VGroup(Item('', label='Single Point Position (SPP)', emphasized=True), Item('table_spp', style='readonly', editor=TabularEditor(adapter=SimpleAdapter()), show_label=False, width=0.3), label='Single Point Position'), VGroup(Item('', label='RTK Position', emphasized=True), Item('table_psuedo_abs', style='readonly', editor=TabularEditor(adapter=SimpleAdapter()), show_label=False, width=0.3, height=0.9), Item('rtk_pos_note', show_label=False, resizable=True, editor=MultilineTextEditor( TextEditor(multi_line=True)), style='readonly', width=0.3, height=-40), label='RTK Position')), VGroup( HGroup( Item('paused_button', show_label=False), Item('clear_button', show_label=False), Item('zoomall_button', show_label=False), Item('center_button', show_label=False), ), Item('plot', show_label=False, editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8))), ))) def _zoomall_button_fired(self): self.zoomall = not self.zoomall def _center_button_fired(self): self.position_centered = not self.position_centered def _paused_button_fired(self): self.running = not self.running def _clear_button_fired(self): self.lats = [] self.lngs = [] self.alts = [] self.lats_psuedo_abs = [] self.lngs_psuedo_abs = [] self.alts_psuedo_abs = [] self.plot_data.set_data('lat', []) self.plot_data.set_data('lng', []) self.plot_data.set_data('alt', []) self.plot_data.set_data('t', []) self.plot_data.set_data('lat_ps', []) self.plot_data.set_data('lng_ps', []) self.plot_data.set_data('alt_ps', []) self.plot_data.set_data('t_ps', []) def _pos_llh_callback(self, sbp_msg, **metadata): # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so # actually perform the update in the UI thread. if self.running: GUI.invoke_later(self.pos_llh_callback, sbp_msg) def mode_string(self, msg): if msg: if (msg.flags & 0xff) == 0: return 'SPP (single point position)' elif (msg.flags & 0xff) == 1: return 'Fixed RTK' elif (msg.flags & 0xff) == 2: return 'Float RTK' return 'None' def update_table(self): self._table_list = self.table_spp.items() def auto_survey(self): if self.counter < 1000: self.counter = self.counter + 1 self.latitude_list.append(self.last_soln.lat) self.longitude_list.append(self.last_soln.lon) self.altitude_list.append(self.last_soln.height) self.latitude_list = self.latitude_list[-1000:] self.longitude_list = self.longitude_list[-1000:] self.altitude_list = self.altitude_list[-1000:] self.latitude = (sum(self.latitude_list)) / self.counter self.altitude = (sum(self.altitude_list)) / self.counter self.longitude = (sum(self.longitude_list)) / self.counter def pos_llh_callback(self, sbp_msg, **metadata): self.last_stime_update = time.time() soln = MsgPosLLH(sbp_msg) self.last_soln = soln masked_flag = soln.flags & 0x7 if masked_flag == 0: psuedo_absolutes = False else: psuedo_absolutes = True pos_table = [] tow = soln.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 if self.week is not None: t = datetime.datetime(1980, 1, 6) + \ datetime.timedelta(weeks=self.week) + \ datetime.timedelta(seconds=tow) pos_table.append(('GPS Time', t)) pos_table.append(('GPS Week', str(self.week))) if (self.directory_name_p == ''): filepath_p = time.strftime("position_log_%Y%m%d-%H%M%S.csv") else: filepath_p = os.path.join( self.directory_name_p, time.strftime("position_log_%Y%m%d-%H%M%S.csv")) if self.logging_p == False: self.log_file = None if self.logging_p: if self.log_file is None: self.log_file = open(filepath_p, 'w') self.log_file.write( "time,latitude(degrees),longitude(degrees),altitude(meters),n_sats,flags\n" ) self.log_file.write('%s,%.10f,%.10f,%.4f,%d,%d\n' % (str(t), soln.lat, soln.lon, soln.height, soln.n_sats, soln.flags)) self.log_file.flush() pos_table.append(('GPS ToW', tow)) pos_table.append(('Num. sats', soln.n_sats)) pos_table.append(('Lat', soln.lat)) pos_table.append(('Lng', soln.lon)) pos_table.append(('Alt', soln.height)) pos_table.append(('Flags', '0x%02x' % soln.flags)) pos_table.append(('Mode', self.mode_string(soln))) self.auto_survey() if psuedo_absolutes: # setup_plot variables self.lats_psuedo_abs.append(soln.lat) self.lngs_psuedo_abs.append(soln.lon) self.alts_psuedo_abs.append(soln.height) self.lats_psuedo_abs = self.lats_psuedo_abs[-1000:] self.lngs_psuedo_abs = self.lngs_psuedo_abs[-1000:] self.alts_psuedo_abs = self.alts_psuedo_abs[-1000:] self.plot_data.set_data('lat_ps', self.lats_psuedo_abs) self.plot_data.set_data('lng_ps', self.lngs_psuedo_abs) self.plot_data.set_data('alt_ps', self.alts_psuedo_abs) self.plot_data.set_data('cur_lat_ps', [soln.lat]) self.plot_data.set_data('cur_lng_ps', [soln.lon]) t_psuedo_abs = range(len(self.lats)) if t is not None: self.plot_data.set_data('t', t) self.plot_data.set_data('t_ps', t_psuedo_abs) # set-up table variables self.table_psuedo_abs = pos_table else: # setup_plot variables self.lats.append(soln.lat) self.lngs.append(soln.lon) self.alts.append(soln.height) self.lats = self.lats[-1000:] self.lngs = self.lngs[-1000:] self.alts = self.alts[-1000:] self.plot_data.set_data('lat', self.lats) self.plot_data.set_data('lng', self.lngs) self.plot_data.set_data('alt', self.alts) self.plot_data.set_data('cur_lat', [soln.lat]) self.plot_data.set_data('cur_lng', [soln.lon]) t = range(len(self.lats)) self.plot_data.set_data('t', t) # set-up table variables self.pos_table_spp = pos_table self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table # TODO: figure out how to center the graph now that we have two separate messages # when we selectivtely send only SPP, the centering function won't work anymore if self.position_centered: d = (self.plot.index_range.high - self.plot.index_range.low) / 2. self.plot.index_range.set_bounds(soln.lon - d, soln.lon + d) d = (self.plot.value_range.high - self.plot.value_range.low) / 2. self.plot.value_range.set_bounds(soln.lat - d, soln.lat + d) if self.zoomall: plot_square_axes(self.plot, 'lng', 'lat') def dops_callback(self, sbp_msg, **metadata): dops = MsgDops(sbp_msg) self.dops_table = [('PDOP', '%.1f' % (dops.pdop * 0.01)), ('GDOP', '%.1f' % (dops.gdop * 0.01)), ('TDOP', '%.1f' % (dops.tdop * 0.01)), ('HDOP', '%.1f' % (dops.hdop * 0.01)), ('VDOP', '%.1f' % (dops.vdop * 0.01))] self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table def vel_ned_callback(self, sbp_msg, **metadata): vel_ned = MsgVelNED(sbp_msg) tow = vel_ned.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 if self.week is not None: t = datetime.datetime(1980, 1, 6) + \ datetime.timedelta(weeks=self.week) + \ datetime.timedelta(seconds=tow) if self.directory_name_v == '': filepath_v = time.strftime("velocity_log_%Y%m%d-%H%M%S.csv") else: filepath_v = os.path.join( self.directory_name_v, time.strftime("velocity_log_%Y%m%d-%H%M%S.csv")) if self.logging_v == False: self.vel_log_file = None if self.logging_v: if self.vel_log_file is None: self.vel_log_file = open(filepath_v, 'w') self.vel_log_file.write( 'time,north(m/s),east(m/s),down(m/s),speed(m/s),num_sats\n' ) self.vel_log_file.write( '%s,%.6f,%.6f,%.6f,%.6f,%d\n' % (str(t), vel_ned.n * 1e-3, vel_ned.e * 1e-3, vel_ned.d * 1e-3, math.sqrt(vel_ned.n * vel_ned.n + vel_ned.e * vel_ned.e) * 1e-3, vel_ned.n_sats)) self.vel_log_file.flush() self.vel_table = [ ('Vel. N', '% 8.4f' % (vel_ned.n * 1e-3)), ('Vel. E', '% 8.4f' % (vel_ned.e * 1e-3)), ('Vel. D', '% 8.4f' % (vel_ned.d * 1e-3)), ] self.table_spp = self.pos_table_spp + self.vel_table + self.dops_table def gps_time_callback(self, sbp_msg, **metadata): self.week = MsgGPSTime(sbp_msg).wn self.nsec = MsgGPSTime(sbp_msg).ns def __init__(self, link, dirname=''): super(SolutionView, self).__init__() self.log_file = None self.directory_name_v = dirname self.directory_name_p = dirname self.vel_log_file = None self.last_stime_update = 0 self.last_soln = None self.counter = 0 self.latitude_list = [] self.longitude_list = [] self.altitude_list = [] self.altitude = 0 self.longitude = 0 self.latitude = 0 self.plot_data = ArrayPlotData(lat=[], lng=[], alt=[], t=[], cur_lat=[], cur_lng=[], cur_lat_ps=[], cur_lng_ps=[], lat_ps=[], lng_ps=[], alt_ps=[], t_ps=[]) self.plot = Plot(self.plot_data) # 1000 point buffer self.plot.plot(('lng', 'lat'), type='line', name='', color=(0, 0, 0.9, 0.1)) self.plot.plot(('lng', 'lat'), type='scatter', name='', color='blue', marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_ps', 'lat_ps'), type='line', name='', color=(1, 0.4, 0, 0.1)) self.plot.plot(('lng_ps', 'lat_ps'), type='scatter', name='', color='orange', marker='diamond', line_width=0.0, marker_size=1.0) # current values spp = self.plot.plot(('cur_lng', 'cur_lat'), type='scatter', name='SPP', color='blue', marker='plus', line_width=1.5, marker_size=5.0) rtk = self.plot.plot(('cur_lng_ps', 'cur_lat_ps'), type='scatter', name='RTK', color='orange', marker='plus', line_width=1.5, marker_size=5.0) plot_labels = ['SPP', 'RTK'] plots_legend = dict(zip(plot_labels, [spp, rtk])) self.plot.legend.plots = plots_legend self.plot.legend.visible = True self.plot.index_axis.tick_label_position = 'inside' self.plot.index_axis.tick_label_color = 'gray' self.plot.index_axis.tick_color = 'gray' self.plot.index_axis.title = 'Longitude (degrees)' self.plot.index_axis.title_spacing = 5 self.plot.value_axis.tick_label_position = 'inside' self.plot.value_axis.tick_label_color = 'gray' self.plot.value_axis.tick_color = 'gray' self.plot.value_axis.title = 'Latitude (degrees)' self.plot.value_axis.title_spacing = 5 self.plot.padding = (25, 25, 25, 25) self.plot.tools.append(PanTool(self.plot)) zt = ZoomTool(self.plot, zoom_factor=1.1, tool_mode="box", always_on=False) self.plot.overlays.append(zt) self.link = link self.link.add_callback(self._pos_llh_callback, SBP_MSG_POS_LLH) self.link.add_callback(self.vel_ned_callback, SBP_MSG_VEL_NED) self.link.add_callback(self.dops_callback, SBP_MSG_DOPS) self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME) self.week = None self.nsec = 0 self.python_console_cmds = { 'solution': self, }
class TravelsensorGraph(HasTraits): plotview = Instance(PlotView, ()) checkable_sensors = List() cycol = cycle('bgrcmky') force = [] x_axis = Instance(Combobox, ()) y_axis = Instance(Combobox, ()) def update_sensors(self, sensors): del self.checkable_sensors[:] for s in sensors: c = next(self.cycol) s.parent = self s.plot_color = c self.checkable_sensors.append(s) def plot(self, index): self.update_axis_properties() self.update_plot() self.configure_traits() def get_recorded_values(self, axis): res = [] for i in range(len(self.recorded_values)): val = self.recorded_values[i] if axis.selected_key == val: arr = load(join(recorder_dir, recording_file)) res.append((None, arr[:, i])) return res def get_dic_values(self, axis): res = [] for i in range(len(self.dic_properties)): val = self.dic_properties[i] if axis.selected_key == val: for t in self.checkable_sensors: if t.is_checked: arr = load( join(travel_sensor_sensors_dir, t.name + ".npy")) res.append((t, arr[:, i])) return res def update_axis_properties(self): self.recorded_values = ["Time [s]"] ports = MeasuringCard.load_input_ports_as_dict() for key in ports: self.recorded_values.append(key) for val in self.recorded_values: self.x_axis.add_item(val, self.get_recorded_values) self.y_axis.add_item(val, self.get_recorded_values) self.dic_properties = [ "U-displacement [mm]", "V-displacement [mm]", "Strain exx", "Strain exy", "Strain eyy" ] for dic in self.dic_properties: self.x_axis.add_item(dic, self.get_dic_values) self.y_axis.add_item(dic, self.get_dic_values) self.x_axis.selected_key = self.recorded_values[0] self.y_axis.selected_key = self.dic_properties[0] def update_plot(self): self.x_arr = self.x_axis.get_selected_value()(self.x_axis) self.y_arr = self.y_axis.get_selected_value()(self.y_axis) self.plotview.reset_subplots("SmartRecord") self.plotview.set_labels(self.x_axis.selected_key, self.y_axis.selected_key, "SmartRecord") for x_val in self.x_arr: xt, xvals = x_val for y_val in self.y_arr: yt, yvals = y_val if xt == None: self.plotview.plot_graph(0, xvals, yvals, yt.plot_color) else: self.plotview.plot_graph(0, xvals, yvals, xt.plot_color) icon = Image(ImageResource("../../../../icons/smrc_icon.png")) smrc = Str("SmartRecord") update_button = Button("Update plot") def _update_button_fired(self): self.update_plot() view = View(VGroup( HGroup( UItem('smrc', style_sheet="*{font: bold; font-size:32px;\ color:" + toolbar_background + ";}", style='readonly'), UItem('icon')), HGroup( VGroup( VGroup(Item('x_axis', style='custom'), Item('y_axis', style='custom'), UItem('update_button'), label="Axis"), VGroup( UItem('checkable_sensors', style='readonly', editor=ListEditor(editor=InstanceEditor(), style='custom')), label='Sensors', ), ), UItem('plotview', style='custom'))), title="Sensors", resizable=True, handler=GraphHandler())
class ResultViewer(HasTraits): sensor_graph = Instance(TravelsensorGraph, ()) result_options = Instance(Combobox, ()) show_result = Button("Show") show_index = Int() cur_image = Image() logger = getLogger("Application") def __init__(self, recorder): self.recorder = recorder self.result_options.add_item('recorded_image', self.show_recorded_image) self.result_options.add_item('strain-exx', self.show_strain_exx) self.result_options.add_item('strain-exy', self.show_strain_exy) self.result_options.add_item('strain-eyy', self.show_strain_eyy) self.result_options.selected_key = 'recorded_image' def show_recorded_image(self, index): if not self.recorder.show_images: self.result_options.add_listener(self) self.recorder.show_images = True self.show_images = True try: fname = self.recorder.images[index] except IndexError: fname = 'None' self.fpath = join(images_dir, fname) self.cur_image = ImageResource(join(resized_images_dir, fname)) def show_strain_exx(self, index): fname = strain_exx_img_file.format(convert_number(index)) self.fpath = join(result_normal_dir, fname) self.cur_image = ImageResource(join(result_resized_dir, fname)) def show_strain_exy(self, index): fname = strain_exy_img_file.format(convert_number(index)) self.fpath = join(result_normal_dir, fname) self.cur_image = ImageResource(join(result_resized_dir, fname)) def show_strain_eyy(self, index): fname = strain_eyy_img_file.format(convert_number(index)) self.fpath = join(result_normal_dir, fname) self.cur_image = ImageResource(join(result_resized_dir, fname)) def update_image(self, index): self.index = index self.result_options.get_selected_value()(index) def selected_changed(self, selected_key): for key in self.result_options.values: if key == selected_key: self.update_image(self.index) def _sensor_fired(self): files = get_all_files(travel_sensor_sensors_dir) sensors = [] for f in files: if ".npy" in f: sensor = Sensor.load(join(travel_sensor_sensors_dir, f)) sensors.append(sensor) self.sensor_graph.update_sensors(sensors) self.sensor_graph.plot(0) def _show_result_fired(self): img = imread(self.fpath) namedWindow('image', WINDOW_NORMAL) imshow('image', img) waitKey(0) destroyAllWindows() sensor = Button('Show Sensors') show_images = Bool(False) view = View( VGroup(VGroup( UItem('cur_image', width=300, height=225), label="Recorded image:", ), HGroup( UItem('result_options', style='custom'), UItem('show_result', label='Show details'), UItem('sensor'), ), visible_when='show_images'))
class FunctionPlotter(HasTraits): figure = Instance(Figure, ()) #❶ code = Code() #❷ points = List(Instance(Point), []) #❸ draw_button = Button("Plot") view = View( VSplit( Item("figure", editor=MPLFigureEditor(toolbar=True), show_label=False), #❶ HSplit( VGroup( Item("code", style="custom"), #❷ HGroup(Item("draw_button", show_label=False), ), show_labels=False), Item("points", editor=point_table_editor, show_label=False) #❸ )), width=800, height=600, title="Function Plotter", resizable=True) ###2### ###3### def __init__(self, **kw): super(FunctionPlotter, self).__init__(**kw) self.figure.canvas_events = [ #❶ ("button_press_event", self.memory_location), ("button_release_event", self.update_location) ] self.button_press_status = None #保存鼠标按键按下时的状态 self.lines = [] #保存所有曲线 self.functions = [] #保存所有的曲线函数 self.env = {} #代码的执行环境 self.axe = self.figure.add_subplot(1, 1, 1) self.axe.callbacks.connect('xlim_changed', self.update_data) #❷ self.axe.set_xlim(0, 1) self.axe.set_ylim(0, 1) self.points_line, = self.axe.plot([], [], "kx", ms=8, zorder=1000) #数据点 ###3### ###6### def update_data(self, axe): xmin, xmax = axe.get_xlim() x = np.linspace(xmin, xmax, 500) for line, func in zip(self.lines, self.functions): y = func(x) line.set_data(x, y) self.update_figure() ###6### ###4### def memory_location(self, evt): if evt.button in (1, 3): self.button_press_status = time.clock(), evt.x, evt.y else: self.button_press_status = None def update_location(self, evt): if evt.button in (1, 3) and self.button_press_status is not None: last_clock, last_x, last_y = self.button_press_status if time.clock() - last_clock > 0.5: #❶ return if ((evt.x - last_x)**2 + (evt.y - last_y)**2)**0.5 > 4: #❷ return if evt.button == 1: if evt.xdata is not None and evt.ydata is not None: point = Point(x=evt.xdata, y=evt.ydata) #❸ self.points.append(point) elif evt.button == 3: if self.points: self.points.pop() #❹ ###4### ###5### @on_trait_change("points[]") def _points_changed(self, obj, name, new): for point in new: point.on_trait_change(self.update_points, name="x, y") #❶ self.update_points() def update_points(self): #❷ arr = np.array([(point.x, point.y) for point in self.points]) if arr.shape[0] > 0: self.points_line.set_data(arr[:, 0], arr[:, 1]) else: self.points_line.set_data([], []) self.update_figure() def update_figure(self): #❸ if self.figure.canvas is not None: #❹ self.figure.canvas.draw_idle() ###5### ###7### def _draw_button_fired(self): self.plot_lines() def plot_lines(self): xmin, xmax = self.axe.get_xlim() #❶ x = np.linspace(xmin, xmax, 500) self.env = { "points": np.array([(point.x, point.y) for point in self.points]) } #❷ exec self.code in self.env results = [] for line in self.lines: line.remove() self.axe.set_color_cycle(None) #重置颜色循环 self.functions = [] self.lines = [] for name, value in self.env.items(): #❸ if name.startswith("_"): #忽略以_开头的名字 continue if callable(value): try: y = value(x) if y.shape != x.shape: #输出数组应该与输入数组的形状一致 raise ValueError( "the return shape is not the same as x") except Exception as ex: import traceback print "failed when call function {}\n".format(name) traceback.print_exc() continue results.append((name, y)) self.functions.append(value) for (name, y), function in zip(results, self.functions): #如果函数有plot_parameters属性,则用其作为plot()的参数 kw = getattr(function, "plot_parameters", {}) #❹ label = kw.get("label", name) line, = self.axe.plot(x, y, label=label, **kw) self.lines.append(line) points = self.env.get("points", None) #❺ if points is not None: self.points = [ Point(x=x, y=y) for x, y in np.asarray(points).tolist() ] self.axe.legend() self.update_figure()
Group( Item(name='number_of_labels'), enabled_when='show_scalar_bar==True', ), Group( Item(name='shadow'), Item(name='use_default_name'), Item(name='data_name', enabled_when='not object.use_default_name'), HGroup( Item(name='_title_text_property', show_label=False, editor=InstanceEditor( label='Edit bar Title', id='mayavi.core.lut_manager.bar_title_text')), Item(name='_label_text_property', show_label=False, editor=InstanceEditor( label='Edit bar Text', id='mayavi.core.lut_manager.bar_label_text'), label='Edit bar Text'), ), HGroup( Item( name='scalar_bar', show_label=False, editor=InstanceEditor( label='Edit bar Actor', id='mayavi.core.lut_manager.bar_actor'), ), Item(
mrk_out_wildcard = ["Tab separated values file (*.txt)|*.txt"] else: mrk_wildcard = ["*.sqd;*.mrk;*.txt;*.pickled"] mrk_out_wildcard = "*.txt" out_ext = '.txt' use_editor_v = CheckListEditor(cols=1, values=[(i, str(i)) for i in range(5)]) use_editor_h = CheckListEditor(cols=5, values=[(i, str(i)) for i in range(5)]) mrk_view_editable = View( VGroup('file', Item('name', show_label=False, style='readonly'), HGroup( Item('use', editor=use_editor_v, enabled_when="enabled", style='custom'), 'points', ), HGroup(Item('clear', enabled_when="can_save", show_label=False), Item('save_as', enabled_when="can_save", show_label=False)), )) mrk_view_basic = View( VGroup('file', Item('name', show_label=False, style='readonly'), Item('use', editor=use_editor_h, enabled_when="enabled", style='custom'), HGroup(Item('clear', enabled_when="can_save", show_label=False), Item('edit', show_label=False), Item('save_as', enabled_when="can_save",
class SolutionView(HasTraits): python_console_cmds = Dict() pdop = Float() gdop = Float() tdop = Float() hdop = Float() vdop = Float() pos_llh = Array(dtype=float, shape=(3,)) pos_ned = Array(dtype=float, shape=(3,)) ns = List() mean_ns = Float() es = List() mean_es = Float() ds = List() mean_ds = Float() mean_len = Int(50) mean_dist = Float() n_used = Int() dist = Float() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) clear = Button() pr_plot = Instance(Plot) pr_plot_data = Instance(ArrayPlotData) prs = List() pred_prs = List() traits_view = View( HGroup( Item('pdop', label='PDOP', format_str='%.1f'), Item('gdop', label='GDOP', format_str='%.1f'), Item('tdop', label='TDOP', format_str='%.1f'), Item('hdop', label='HDOP', format_str='%.1f'), Item('vdop', label='VDOP', format_str='%.1f'), ), Item('clear'), HGroup( Item('pos_llh'), Item('pos_ned'), VGroup( Item('dist'), Item('mean_len'), Item('mean_dist'), ), VGroup( Item('mean_ns'), Item('mean_es'), Item('mean_ds'), ), Item('n_used') ), Item( 'plot', editor = ComponentEditor(bgcolor = (0.8,0.8,0.8)), ) ) prs_view = View( Item( 'pr_plot', editor = ComponentEditor(bgcolor = (0.8,0.8,0.8)), show_label = False, ) ) def _clear_fired(self): self.ns = [] self.es = [] self.ds = [] def prs_callback(self, data): fmt = '<' + str(TRACK_N_CHANNELS) + 'd' self.prs.append(struct.unpack(fmt, data)) prs = np.transpose(self.prs[-500:]) t = range(len(prs[0])) self.pr_plot_data.set_data('t', t) for n in range(TRACK_N_CHANNELS): self.pr_plot_data.set_data('prs'+str(n), prs[n]) def pred_prs_callback(self, data): return fmt = '<' + str(TRACK_N_CHANNELS) + 'd' self.pred_prs.append(struct.unpack(fmt, data)) pred_prs = np.array(np.transpose(self.pred_prs[-500:])) prs = np.array(np.transpose(self.prs[-500:])) t = range(len(pred_prs[0])) self.pr_plot_data.set_data('t', t) for n in range(TRACK_N_CHANNELS): err = prs[n]-pred_prs[n] #err = err - (sum(err)/len(err)) self.pr_plot_data.set_data('pred_prs'+str(n), err) def solution_callback(self, data): soln = struct.unpack('<3d3d3d3d3d7ddBB', data) self.pos_llh = [soln[0]*(180/math.pi), soln[1]*(180/math.pi), soln[2]] pos_xyz = soln[3:6] self.pos_ned = soln[6:9] vel_xyz = soln[9:12] vel_ned = soln[12:15] err_cov = soln[15:22] time = soln[22] soln_valid = soln[23] self.n_used = soln[24] self.dist = math.sqrt(self.pos_ned[0]**2 + self.pos_ned[1]**2 + self.pos_ned[2]**2) if self.dist < 3000: self.ns.append(self.pos_ned[0]) self.es.append(self.pos_ned[1]) self.ds.append(self.pos_ned[2]) else: print "Whacky solution detected!" self.mean_ns = sum(self.ns[:self.mean_len])/len(self.ns[:self.mean_len]) self.mean_es = sum(self.es[:self.mean_len])/len(self.es[:self.mean_len]) self.mean_ds = sum(self.ds[:self.mean_len])/len(self.ds[:self.mean_len]) self.mean_dist = math.sqrt(self.mean_ns**2 + self.mean_es**2 + self.mean_ds**2) self.plot_data.set_data('n', self.ns) self.plot_data.set_data('e', self.es) self.plot_data.set_data('h', self.ds) self.plot_data.set_data('ref_n', [0.0, self.mean_ns]) self.plot_data.set_data('ref_e', [0.0, self.mean_es]) t = range(len(self.ds)) self.plot_data.set_data('t', t) def dops_callback(self, data): self.pdop, self.dgop, self.tdop, self.hdop, self.vdop = struct.unpack('<ddddd', data) def __init__(self, link): super(SolutionView, self).__init__() self.link = link self.link.add_callback(MSG_SOLUTION, self.solution_callback) self.link.add_callback(MSG_SOLUTION_DOPS, self.dops_callback) self.link.add_callback(MSG_SOLUTION_PRS, self.prs_callback) self.link.add_callback(MSG_SOLUTION_PRED_PRS, self.pred_prs_callback) self.plot_data = ArrayPlotData(n=[0.0], e=[0.0], h=[0.0], t=[0.0], ref_n=[0.0], ref_e=[0.0]) self.plot = Plot(self.plot_data) #, auto_colors=colours_list) self.plot.plot(('n', 'e'), type='scatter', color='blue', marker='plus') self.plot.plot(('ref_n', 'ref_e'), type='scatter', color='red', marker='cross', marker_size=10, line_width=1.5 ) #self.plot.plot(('h', 'e'), type='line', color='red') self.pr_plot_data = ArrayPlotData(t=[0.0]) self.pr_plot = Plot(self.pr_plot_data, auto_colors=colours_list) self.pr_plot.value_range.tight_bounds = False #self.pr_plot.value_range.low_setting = 0.0 for n in range(TRACK_N_CHANNELS): self.pr_plot_data.set_data('prs'+str(n), [0.0]) self.pr_plot.plot(('t', 'prs'+str(n)), type='line', color='auto') #self.pr_plot_data.set_data('pred_prs'+str(n), [0.0]) #self.pr_plot.plot(('t', 'pred_prs'+str(n)), type='line', color='auto') self.python_console_cmds = { 'solution': self }
class VolumeSlicer(HasTraits): # The data to plot data = Array() # The 4 views displayed scene3d = Instance(MlabSceneModel, ()) scene_x = Instance(MlabSceneModel, ()) scene_y = Instance(MlabSceneModel, ()) scene_z = Instance(MlabSceneModel, ()) # The data source data_src3d = Instance(Source) # The image plane widgets of the 3D scene ipw_3d_x = Instance(PipelineBase) ipw_3d_y = Instance(PipelineBase) ipw_3d_z = Instance(PipelineBase) _axis_names = dict(x=0, y=1, z=2) #--------------------------------------------------------------------------- def __init__(self, **traits): super(VolumeSlicer, self).__init__(**traits) # Force the creation of the image_plane_widgets: self.ipw_3d_x self.ipw_3d_y self.ipw_3d_z #--------------------------------------------------------------------------- # Default values #--------------------------------------------------------------------------- def _data_src3d_default(self): return mlab.pipeline.scalar_field(self.data, figure=self.scene3d.mayavi_scene) def make_ipw_3d(self, axis_name): ipw = mlab.pipeline.image_plane_widget( self.data_src3d, figure=self.scene3d.mayavi_scene, plane_orientation='%s_axes' % axis_name) return ipw def _ipw_3d_x_default(self): return self.make_ipw_3d('x') def _ipw_3d_y_default(self): return self.make_ipw_3d('y') def _ipw_3d_z_default(self): return self.make_ipw_3d('z') #--------------------------------------------------------------------------- # Scene activation callbaks #--------------------------------------------------------------------------- @on_trait_change('scene3d.activated') def display_scene3d(self): outline = mlab.pipeline.outline( self.data_src3d, figure=self.scene3d.mayavi_scene, ) self.scene3d.mlab.view(40, 50) # Interaction properties can only be changed after the scene # has been created, and thus the interactor exists for ipw in (self.ipw_3d_x, self.ipw_3d_y, self.ipw_3d_z): # Turn the interaction off ipw.ipw.interaction = 0 self.scene3d.scene.background = (0, 0, 0) # Keep the view always pointing up self.scene3d.scene.interactor.interactor_style = \ tvtk.InteractorStyleTerrain() def make_side_view(self, axis_name): scene = getattr(self, 'scene_%s' % axis_name) # To avoid copying the data, we take a reference to the # raw VTK dataset, and pass it on to mlab. Mlab will create # a Mayavi source from the VTK without copying it. # We have to specify the figure so that the data gets # added on the figure we are interested in. outline = mlab.pipeline.outline( self.data_src3d.mlab_source.dataset, figure=scene.mayavi_scene, ) ipw = mlab.pipeline.image_plane_widget(outline, plane_orientation='%s_axes' % axis_name) setattr(self, 'ipw_%s' % axis_name, ipw) # Synchronize positions between the corresponding image plane # widgets on different views. ipw.ipw.sync_trait('slice_position', getattr(self, 'ipw_3d_%s' % axis_name).ipw) # Make left-clicking create a crosshair ipw.ipw.left_button_action = 0 # Add a callback on the image plane widget interaction to # move the others def move_view(obj, evt): position = obj.GetCurrentCursorPosition() for other_axis, axis_number in self._axis_names.items(): if other_axis == axis_name: continue ipw3d = getattr(self, 'ipw_3d_%s' % other_axis) ipw3d.ipw.slice_position = position[axis_number] ipw.ipw.add_observer('InteractionEvent', move_view) ipw.ipw.add_observer('StartInteractionEvent', move_view) # Center the image plane widget ipw.ipw.slice_position = 0.5 * self.data.shape[ self._axis_names[axis_name]] # Position the view for the scene views = dict( x=(0, 90), y=(90, 90), z=(0, 0), ) scene.mlab.view(*views[axis_name]) # 2D interaction: only pan and zoom scene.scene.interactor.interactor_style = \ tvtk.InteractorStyleImage() scene.scene.background = (0, 0, 0) @on_trait_change('scene_x.activated') def display_scene_x(self): return self.make_side_view('x') @on_trait_change('scene_y.activated') def display_scene_y(self): return self.make_side_view('y') @on_trait_change('scene_z.activated') def display_scene_z(self): return self.make_side_view('z') #--------------------------------------------------------------------------- # The layout of the dialog created #--------------------------------------------------------------------------- view = View( HGroup( Group( Item('scene_y', editor=SceneEditor(scene_class=Scene), height=250, width=300), Item('scene_z', editor=SceneEditor(scene_class=Scene), height=250, width=300), show_labels=False, ), Group( Item('scene_x', editor=SceneEditor(scene_class=Scene), height=250, width=300), Item('scene3d', editor=SceneEditor(scene_class=MayaviScene), height=250, width=300), show_labels=False, ), ), resizable=True, title='Volume Slicer', )
class PlotApp2(HasTraits): numPcaScores = PCA.nums plotdata = Instance(ArrayPlotData) Y_PCA = Str YPCA = List(Str) X_PCA = Str XPCA = List(Str) Color = Str Colordropdownlist = List(Str) colors = List(str) Shape = Str Shapedropdownlist = List(Str) Size = Str Sizedropdownlist = List(Str) shapes_name = List(Str) colors_name = List(Str) sizes_name = List(Str) active_scores_combobox = Enum(['Post Scores', 'Pre Scores']) start_selection = Button(label='Start Selection') stop_selection = Button(label='Stop Selection') RightPlot = Instance(OverlayPlotContainer) LeftPlot = Instance(OverlayPlotContainer) button_editor = ButtonEditor() table = List(Instance(MyData)) columns = [ObjectColumn(name='name')] columns.append(ObjectColumn(name="Value")) table_editor = TableEditor(columns=columns, deletable=True, sortable=False, sort_model=False, show_lines=True, line_color="black", editable=False, show_column_labels=False) shape_table = List(Instance(ShapeTable)) shape_columns = List(Instance(ObjectColumn)) color_table = List(Instance(ColorTable)) color_columns = List(Instance(ObjectColumn)) size_table = List(Instance(SizeTable)) size_columns = List(Instance(ObjectColumn)) traits_view = View(VSplit( HSplit( VGroup( VGroup( Item( 'Y_PCA', editor=EnumEditor( name='YPCA', evaluate=validate_choice, ), ), Item( 'X_PCA', editor=EnumEditor( name='XPCA', evaluate=validate_choice, ), ), Item('active_scores_combobox', width=225, label="Score"), HGroup( Item('start_selection', editor=button_editor, show_label=False, width=0.5), Item('stop_selection', editor=button_editor, show_label=False, width=0.5)), ), Item('LeftPlot', editor=ComponentEditor(), show_label=False, width=590, height=800), ), VSplit( HGroup( VGroup( Item( 'Shape', editor=EnumEditor( name='Shapedropdownlist', evaluate=validate_choice, ), ), Item('shape_table', editor=TableEditor(columns_name='shape_columns', deletable=True, sortable=False, sort_model=False, show_lines=True, line_color="black", editable=False, show_column_labels=False), show_label=False, width=0.3, padding=5)), VGroup( Item( 'Color', editor=EnumEditor( name='Colordropdownlist', evaluate=validate_choice, ), ), Item('color_table', editor=TableEditor(columns_name='color_columns', deletable=True, sortable=False, sort_model=False, show_lines=True, line_color="black", editable=False, show_column_labels=False), show_label=False, width=0.3, padding=5)), VGroup( Item( 'Size', editor=EnumEditor( name='Sizedropdownlist', evaluate=validate_choice, ), ), Item('size_table', editor=TableEditor(columns_name='size_columns', deletable=True, sortable=False, sort_model=False, show_lines=True, line_color="black", editable=False, show_column_labels=False), show_label=False, width=0.3, padding=5)), ), Item('RightPlot', editor=ComponentEditor(), show_label=False, height=640), )), Item('table', editor=table_editor, show_label=False, padding=15)), width=1100, height=700, resizable=True, title="Principal Components Visualizer") def __init__(self, PCAData): super(PlotApp2, self).__init__() #self.phenotypes, self.pheno_dict = readPhenotypesFromCSVFile('..\..\IOdata\pca_phenotypes.csv') self.phenotypes, self.pheno_dict = readPhenotypesFromCSVFile_pd( '..\IOdata\phenotypes_table_2.csv') print(self.phenotypes, self.pheno_dict) self.shapes_name = self.pheno_dict[self.phenotypes[1]] self.colors_name = self.pheno_dict[self.phenotypes[2]] self.sizes_name = self.pheno_dict[self.phenotypes[3]] self.colors = get_colors(len(self.colors_name)) #print('self.color=',self.colors) self.table_editor.columns = [ObjectColumn(name='name')] for i in range(len(PCAData) - 1): self.table_editor.columns.append(ObjectColumn(name="PCA" + str(i))) self.PCAData = PCAData self.YPCA = [str(i) for i in range(len(PCAData) - 1)] self.XPCA = [str(i) for i in range(len(PCAData) - 1)] self.Shapedropdownlist = self.phenotypes self.Colordropdownlist = self.phenotypes self.Sizedropdownlist = self.phenotypes self.X_PCA = '0' self.Y_PCA = '0' self.Shape = self.phenotypes[1] self.Color = self.phenotypes[2] self.Size = self.phenotypes[3] self.activeScore = 'Pre Scores' self._updateTable() self._updateShapeTable() self._updateColorTable() self._updateSizeTable() self._update_Both_graph() return def _getPCAArray(self, pcaIndex): x0 = [] for batch in self.PCAData.batchs: if (self.active_scores_combobox == "Post Scores"): x0.append(batch.postscores[pcaIndex]) else: x0.append(batch.prescores[pcaIndex]) return x0 def _create_1D1_plot(self): index = 0 plot0 = Plot(self.plotdata, padding=0) plot0.padding_left = 5 plot0.padding_bottom = 5 Container = OverlayPlotContainer(padding=50, fill_padding=True, bgcolor="lightgray", use_backbuffer=True) y1 = range(len(self.PCAData.batchs[0].prescores)) points = [] for batch in self.PCAData.batchs: if (self.active_scores_combobox == "Post Scores"): x1 = self.PCAData.batchs[index].postscores else: x1 = self.PCAData.batchs[index].prescores if (self.Shape == self.phenotypes[0]): a = 1 elif (self.Shape == self.phenotypes[1]): a = batch.number elif (self.Shape == self.phenotypes[2]): a = batch.type else: a = 0 if (self.Color == self.phenotypes[0]): b = 0 elif (self.Color == self.phenotypes[1]): b = batch.number elif (self.Color == self.phenotypes[2]): b = batch.type else: b = 0 tmarker = shapes[a] bcolor = self.colors[b] for i in range(len(x1)): points.append((x1[i], y1[i])) plot0 = create_scatter_plot((x1, y1), marker=tmarker, color=getColor(bcolor)) if batch.isSelected: plot0.alpha = 1 else: plot0.alpha = 0.2 plot0.bgcolor = "white" plot0.border_visible = True if index == 0: value_mapper = plot0.value_mapper index_mapper = plot0.index_mapper add_default_grids(plot0) add_default_axes(plot0, vtitle='PCA Indices', htitle='PCA Scores') plot0.index_range.tight_bounds = False plot0.index_range.refresh() plot0.value_range.tight_bounds = False plot0.value_range.refresh() plot0.tools.append(PanTool(plot0)) zoom = ZoomTool(plot0, tool_mode="box", always_on=False, maintain_aspect_ratio=False) plot0.overlays.append(zoom) dragzoom = DragZoom(plot0, drag_button="right", maintain_aspect_ratio=False) plot0.tools.append(dragzoom) else: plot0.value_mapper = value_mapper value_mapper.range.add(plot0.value) plot0.index_mapper = index_mapper index_mapper.range.add(plot0.index) Container.add(plot0) index = index + 1 self.RightPlot = Container def _create_2D_plot(self): index = 0 secContainer = OverlayPlotContainer(padding=50, fill_padding=True, bgcolor="lightgray", use_backbuffer=True) try: pcaPoints = [] for batch in self.PCAData.batchs: if (self.active_scores_combobox == "Post Scores"): y = [batch.postscores[int(self.Y_PCA)]] x = [batch.postscores[int(self.X_PCA)]] else: x = [batch.prescores[int(self.X_PCA)]] y = [batch.prescores[int(self.Y_PCA)]] for i in range(len(x)): pcaPoints.append((x[i], y[i])) if (self.Shape == self.phenotypes[0]): a = 1 elif (self.Shape == self.phenotypes[1]): a = batch.number elif (self.Shape == self.phenotypes[2]): a = batch.type else: a = 0 if (self.Color == self.phenotypes[0]): b = 0 elif (self.Color == self.phenotypes[1]): b = batch.number elif (self.Color == self.phenotypes[2]): b = batch.type else: b = 0 tmarker = shapes[a] bcolor = self.colors[b] plot = create_scatter_plot((x, y), marker=tmarker, color=getColor(bcolor)) if batch.isSelected: plot.alpha = 1 else: plot.fill_alpha = 0.2 plot.bgcolor = "white" plot.border_visible = True if index == 0: value_mapper = plot.value_mapper index_mapper = plot.index_mapper add_default_grids(plot) add_default_axes(plot, vtitle='PCA ' + self.Y_PCA, htitle='PCA ' + self.X_PCA) plot.index_range.tight_bounds = False plot.index_range.refresh() plot.value_range.tight_bounds = False plot.value_range.refresh() plot.tools.append(PanTool(plot)) zoom = ZoomTool(plot, tool_mode="box", always_on=False) plot.overlays.append(zoom) dragzoom = DragZoom(plot, drag_button="right") plot.tools.append(dragzoom) else: plot.value_mapper = value_mapper value_mapper.range.add(plot.value) plot.index_mapper = index_mapper index_mapper.range.add(plot.index) secContainer.add(plot) index = index + 1 lineDraw = LineDrawer2D(plot) lineDraw.setPCAData(self, self.PCAData) plot.overlays.append(lineDraw) self.LeftPlot = secContainer except ValueError: pass def _Y_PCA_changed(self, selectedValue): self.Y_PCA = selectedValue self._create_2D_plot() def _X_PCA_changed(self, selectedValue): self.X_PCA = selectedValue self._create_2D_plot() def _Color_changed(self, selectedValue): self.pcolor = selectedValue self.colors_name = self.pheno_dict[self.pcolor] self.colors = get_colors(len(self.colors_name)) #print(self.Color, self.colors_name, self.colors) self._updateColorTable() self._update_Both_graph() def _Size_changed(self, selectedValue): self.psize = selectedValue self.sizes_name = self.pheno_dict[self.psize] self._updateSizeTable() self._update_Both_graph() def _Shape_changed(self, selectedValue): self.pshape = selectedValue self.shapes_name = self.pheno_dict[self.pshape] self._updateShapeTable() self._update_Both_graph() def _active_scores_combobox_changed(self): self._update_Both_graph() def _start_selection_fired(self): for batch in self.PCAData.batchs: batch.isSelected = False self._create_1D1_plot() self._create_2D_plot() def _stop_selection_fired(self): for batch in self.PCAData.batchs: batch.isSelected = True self._create_1D1_plot() self._create_2D_plot() def _updateShapeTable(self): del (self.shape_table) columns = [ObjectColumn(name='name')] for i in range(len(self.shapes_name)): columns.append(ObjectColumn(name='s' + self.shapes_name[i])) data = ShapeTable() self.shape_table.append(data) self.shape_columns = columns self.shape_table.remove(data) data = ShapeTable() data.name = self.pshape for i in range(len(self.shapes_name)): exec('data.s' + self.shapes_name[i] + '="' + self.shapes_name[i] + '"') self.shape_table.append(data) data = ShapeTable() data.name = "Shape" for i in range(len(self.shapes_name)): exec('data.s' + self.shapes_name[i] + '="' + shapes[i] + '"') self.shape_table.append(data) def _updateColorTable(self): del (self.color_table) columns = [ObjectColumn(name='name')] for i in range(len(self.colors_name)): columns.append( ObjectColumn(name='s' + self.colors_name[i], cell_color=getColor(self.colors[i]))) data = ColorTable() self.color_table.append(data) self.color_columns = columns self.color_table.remove(data) data = ColorTable() data.name = self.pcolor for i in range(len(self.colors_name)): exec('data.s' + self.colors_name[i] + '="' + self.colors_name[i] + '"') self.color_table.append(data) data = ColorTable() data.name = "Color" for i in range(len(self.colors_name)): exec('data.s' + self.colors_name[i] + '=""') self.color_table.append(data) def _updateSizeTable(self): del (self.size_table) columns = [ObjectColumn(name='name')] for i in range(len(self.sizes_name)): columns.append(ObjectColumn(name='s' + self.sizes_name[i])) data = SizeTable() self.size_table.append(data) self.size_columns = columns self.size_table.remove(data) data = SizeTable() data.name = self.psize for i in range(len(self.sizes_name)): exec('data.s' + self.sizes_name[i] + '="' + self.sizes_name[i] + '"') self.size_table.append(data) data = SizeTable() data.name = "Size" for i in range(len(self.sizes_name)): exec('data.s' + self.sizes_name[i] + '="' + sizes[i] + '"') self.size_table.append(data) def _updateTable(self): numPcaScores = len(self.PCAData) - 1 pca_vars = [] sumVar = 0.0 sumPercent = 0.0 del (self.table) data = MyData() data.name = 'PCA Index' for i in range(numPcaScores): exec('data.PCA' + str(i) + '=' + str(i)) self.table.append(data) data = MyData() data.name = 'Percentage Power' for i in range(numPcaScores): pca = self._getPCAArray(i) temp = var(pca) pca_vars.append(temp) sumVar = sumVar + temp for i in range(numPcaScores): percent = 100 * pca_vars[i] / sumVar exec('data.PCA' + str(i) + ('=%0.2f' % percent)) self.table.append(data) data = MyData() data.name = 'Cumulative Percentage Power' for i in range(numPcaScores): percent = 100 * pca_vars[i] / sumVar sumPercent = sumPercent + percent exec('data.PCA' + str(i) + ('=%0.2f' % sumPercent)) self.table.append(data) def _update_Both_graph(self): self.activeScore = self.active_scores_combobox self._create_2D_plot() self._create_1D1_plot() self._updateTable()
def traits_view(self): irrad_grp = VGroup( HGroup(UItem('irradiation_enabled', tooltip='Enable Irradiation filter'), UItem('irradiation', enabled_when='irradiation_enabled', editor=EnumEditor(name='irradiations'))), UItem('level', enabled_when='irradiation_enabled', editor=EnumEditor(name='levels')), visible_when='irradiation_visible', show_border=True, label='Irradiations') pgrp = UItem('projects', height=-150, editor=FilterTabularEditor(editable=False, enabled_cb='project_enabled', refresh='refresh_needed', selected='selected_projects', adapter=ProjectAdapter(), multi_select=True)) project_grp = Group(pgrp, springy=False, visible_when='project_visible', show_border=True, label='Projects') analysis_type_group = HGroup( UItem('use_analysis_type_filtering', tooltip='Enable Analysis Type filter', label='Enabled'), spring, UItem('_analysis_include_types', enabled_when='use_analysis_type_filtering', style='custom', editor=CheckListEditor(cols=5, name='available_analysis_types')), visible_when='analysis_types_visible', show_border=True, label='Analysis Types') date_grp = HGroup(UItem('use_low_post'), UItem('low_post', enabled_when='use_low_post'), UItem('use_high_post'), UItem('high_post', enabled_when='use_high_post'), UItem('use_named_date_range'), UItem('named_date_range'), icon_button_editor('date_configure_button', 'calendar'), label='Date', visible_when='date_visible', show_border=True) ms_grp = HGroup(UItem('use_mass_spectrometers', tooltip='Enable Mass Spectrometer filter'), spring, UItem('mass_spectrometer_includes', style='custom', enabled_when='use_mass_spectrometers', editor=CheckListEditor(name='available_mass_spectrometers', cols=10)), visible_when='mass_spectrometer_visible', label='Mass Spectrometer', show_border=True) ln_grp = HGroup( UItem('identifier'), label='Identifier', show_border=True, visible_when='identifier_visible') top_level_filter_grp = VGroup( CustomLabel('filter_label', style='custom', width=-1.0, visible_when='not filter_focus'), HGroup(ms_grp, ln_grp), HGroup(project_grp, irrad_grp), analysis_type_group, date_grp) g1 = UItem('controller.tableview', style='custom') grp = VGroup(top_level_filter_grp, g1) return View(grp)
def traits_view(self): v = View( HGroup(UItem('use'), UItem('det', editor=EnumEditor(name='detectors')), Item('value'), Label(PLUSMINUS), UItem('error'))) return v
class TitleEditorDemo(HasTraits): # Define the selection of titles that can be displayed: title = Enum( 'Select a new title from the drop down list below', 'This is the TitleEditor demonstration', 'Acme Widgets Sales for Each Quarter', 'This is Not Intended to be a Real Application' ) # A user settable version of the title: title_2 = Str('Type into the text field below to change this title') # A title driven by the result of a calculation: title_3 = Property(depends_on='value') # The number used to drive the calculation: value = Float # Define the test view: view = View( VGroup( VGroup( HGroup( Item('title', show_label=False, springy=True, editor=TitleEditor() ) ), Item('title'), show_border=True ), VGroup( HGroup( Item('title_2', show_label=False, springy=True, editor=TitleEditor() ) ), Item('title_2', label='Title'), show_border=True ), VGroup( HGroup( Item('title_3', show_label=False, springy=True, editor=TitleEditor() ) ), Item('value'), show_border=True ) ), width=0.4 ) #-- Property Implementations --------------------------------------------- @cached_property def _get_title_3(self): try: return ('The square root of %s is %s' % (self.value, self.value ** 0.5)) except: return ('The square root of %s is %si' % (self.value, (-self.value) ** 0.5))
class DataSourceWizardView(DataSourceWizard): #---------------------------------------------------------------------- # Private traits #---------------------------------------------------------------------- _top_label = Str('Describe your data') _info_text = Str('Array size do not match') _array_label = Str('Available arrays') _data_type_text = Str("What does your data represents?") _lines_text = Str("Connect the points with lines") _scalar_data_text = Str("Array giving the value of the scalars") _optional_scalar_data_text = Str("Associate scalars with the data points") _connectivity_text = Str("Array giving the triangles") _vector_data_text = Str("Associate vector components") _position_text = Property(depends_on="position_type_") _position_text_dict = {'explicit': 'Coordinnates of the data points:', 'orthogonal grid': 'Position of the layers along each axis:', } def _get__position_text(self): return self._position_text_dict.get(self.position_type_, "") _shown_help_text = Str _data_sources_wrappers = Property(depends_on='data_sources') def _get__data_sources_wrappers(self): return [ ArrayColumnWrapper(name=name, shape=repr(self.data_sources[name].shape)) for name in self._data_sources_names ] # A traits pointing to the object, to play well with traitsUI _self = Instance(DataSourceWizard) _suitable_traits_view = Property(depends_on="data_type_") def _get__suitable_traits_view(self): return "_%s_data_view" % self.data_type_ ui = Any(False) _preview_button = Button(label='Preview structure') def __preview_button_fired(self): if self.ui: self.build_data_source() self.preview() _ok_button = Button(label='OK') def __ok_button_fired(self): if self.ui: self.ui.dispose() self.build_data_source() _cancel_button = Button(label='Cancel') def __cancel_button_fired(self): if self.ui: self.ui.dispose() _is_ok = Bool _is_not_ok = Bool def _anytrait_changed(self): """ Validates if the OK button is enabled. """ if self.ui: self._is_ok = self.check_arrays() self._is_not_ok = not self._is_ok _preview_window = Instance(PreviewWindow, ()) _info_image = Instance(ImageResource, ImageLibrary.image_resource('@std:alert16',)) #---------------------------------------------------------------------- # TraitsUI views #---------------------------------------------------------------------- _coordinates_group = \ HGroup( Item('position_x', label='x', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('position_y', label='y', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('position_z', label='z', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), ) _position_group = \ Group( Item('position_type'), Group( Item('_position_text', style='readonly', resizable=False, show_label=False), _coordinates_group, visible_when='not position_type_=="image data"', ), Group( Item('grid_shape_source_', label='Grid shape', editor=EnumEditor( name='_grid_shape_source_labels', invalid='_is_not_ok')), HGroup( spring, Item('grid_shape', style='custom', editor=ArrayEditor(width=-60), show_label=False), enabled_when='grid_shape_source==""', ), visible_when='position_type_=="image data"', ), label='Position of the data points', show_border=True, show_labels=False, ), _connectivity_group = \ Group( HGroup( Item('_connectivity_text', style='readonly', resizable=False), spring, Item('connectivity_triangles', editor=EnumEditor(name='_data_sources_names'), show_label=False, ), show_labels=False, ), label='Connectivity information', show_border=True, show_labels=False, enabled_when='position_type_=="explicit"', ), _scalar_data_group = \ Group( Item('_scalar_data_text', style='readonly', resizable=False, show_label=False), HGroup( spring, Item('scalar_data', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), show_labels=False, ), label='Scalar value', show_border=True, show_labels=False, ) _optional_scalar_data_group = \ Group( HGroup( 'has_scalar_data', Item('_optional_scalar_data_text', resizable=False, style='readonly'), show_labels=False, ), Item('_scalar_data_text', style='readonly', resizable=False, enabled_when='has_scalar_data', show_label=False), HGroup( spring, Item('scalar_data', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok'), enabled_when='has_scalar_data'), show_labels=False, ), label='Scalar data', show_border=True, show_labels=False, ), _vector_data_group = \ VGroup( HGroup( Item('vector_u', label='u', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_v', label='v', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_w', label='w', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), ), label='Vector data', show_border=True, ), _optional_vector_data_group = \ VGroup( HGroup( Item('has_vector_data', show_label=False), Item('_vector_data_text', style='readonly', resizable=False, show_label=False), ), HGroup( Item('vector_u', label='u', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_v', label='v', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), Item('vector_w', label='w', editor=EnumEditor(name='_data_sources_names', invalid='_is_not_ok')), enabled_when='has_vector_data', ), label='Vector data', show_border=True, ), _array_view = \ View( Item('_array_label', editor=TitleEditor(), show_label=False), Group( Item('_data_sources_wrappers', editor=TabularEditor( adapter=ArrayColumnAdapter(), ), ), show_border=True, show_labels=False )) _questions_view = View( Item('_top_label', editor=TitleEditor(), show_label=False), HGroup( Item('_data_type_text', style='readonly', resizable=False), spring, 'data_type', spring, show_border=True, show_labels=False, ), HGroup( Item('_self', style='custom', editor=InstanceEditor( view_name='_suitable_traits_view'), ), Group( # FIXME: Giving up on context sensitive help # because of lack of time. #Group( # Item('_shown_help_text', editor=HTMLEditor(), # width=300, # label='Help', # ), # show_labels=False, # label='Help', #), #Group( Item('_preview_button', enabled_when='_is_ok'), Item('_preview_window', style='custom', label='Preview structure'), show_labels=False, #label='Preview structure', #), #layout='tabbed', #dock='tab', ), show_labels=False, show_border=True, ), ) _point_data_view = \ View(Group( Group(_coordinates_group, label='Position of the data points', show_border=True, ), HGroup( 'lines', Item('_lines_text', style='readonly', resizable=False), label='Lines', show_labels=False, show_border=True, ), _optional_scalar_data_group, _optional_vector_data_group, # XXX: hack to have more vertical space Label('\n'), Label('\n'), Label('\n'), )) _surface_data_view = \ View(Group( _position_group, _connectivity_group, _optional_scalar_data_group, _optional_vector_data_group, )) _vector_data_view = \ View(Group( _vector_data_group, _position_group, _optional_scalar_data_group, )) _volumetric_data_view = \ View(Group( _scalar_data_group, _position_group, _optional_vector_data_group, )) _wizard_view = View( Group( HGroup( Item('_self', style='custom', show_label=False, editor=InstanceEditor(view='_array_view'), width=0.17, ), '_', Item('_self', style='custom', show_label=False, editor=InstanceEditor(view='_questions_view'), ), ), HGroup( Item('_info_image', editor=ImageEditor(), visible_when="_is_not_ok"), Item('_info_text', style='readonly', resizable=False, visible_when="_is_not_ok"), spring, '_cancel_button', Item('_ok_button', enabled_when='_is_ok'), show_labels=False, ), ), title='Import arrays', resizable=True, ) #---------------------------------------------------------------------- # Public interface #---------------------------------------------------------------------- def __init__(self, **traits): DataSourceFactory.__init__(self, **traits) self._self = self def view_wizard(self): """ Pops up the view of the wizard, and keeps the reference it to be able to close it. """ # FIXME: Workaround for traits bug in enabled_when self.position_type_ self.data_type_ self._suitable_traits_view self.grid_shape_source self._is_ok self.ui = self.edit_traits(view='_wizard_view') def preview(self): """ Display a preview of the data structure in the preview window. """ self._preview_window.clear() self._preview_window.add_source(self.data_source) data = lambda name: self.data_sources[name] g = Glyph() g.glyph.glyph_source.glyph_source = \ g.glyph.glyph_source.glyph_list[0] g.glyph.scale_mode = 'data_scaling_off' if not (self.has_vector_data or self.data_type_ == 'vector'): g.glyph.glyph_source.glyph_source.glyph_type = 'cross' g.actor.property.representation = 'points' g.actor.property.point_size = 3. self._preview_window.add_module(g) if not self.data_type_ in ('point', 'vector') or self.lines: s = Surface() s.actor.property.opacity = 0.3 self._preview_window.add_module(s) if not self.data_type_ == 'point': self._preview_window.add_filter(ExtractEdges()) s = Surface() s.actor.property.opacity = 0.2 self._preview_window.add_module(s)
class UpdateView(HasTraits): piksi_hw_rev = String('piksi_multi') is_v2 = Bool(False) piksi_stm_vers = String('Waiting for Piksi to send settings...', width=COLUMN_WIDTH) newest_stm_vers = String('Downloading Latest Firmware info...') piksi_nap_vers = String('Waiting for Piksi to send settings...') newest_nap_vers = String('Downloading Latest Firmware info...') local_console_vers = String('v' + CONSOLE_VERSION) newest_console_vers = String('Downloading Latest Console info...') download_directory_label = String('Firmware Download Directory:') update_stm_firmware = Button(label='Update Firmware') updating = Bool(False) update_stm_en = Bool(False) download_firmware = Button(label='Download Latest Firmware') download_directory = String() choose_dir = Button(label='...', padding=-1) download_stm = Button(label='Download', height=HT) downloading = Bool(False) download_fw_en = Bool(False) stm_fw = Instance(FirmwareFileDialog) stream = Instance(OutputStream) view = View( VGroup(Item('piksi_hw_rev', label='Hardware Revision', editor_args={'enabled': False}, resizable=True), HGroup( VGroup(Item('piksi_stm_vers', label='Current', resizable=True, editor_args={'enabled': False}), Item('newest_stm_vers', label='Latest', resizable=True, editor_args={ 'enabled': False, 'readonly_allow_selection': True }), Item('stm_fw', style='custom', show_label=True, label="Local File"), Item('update_stm_firmware', show_label=False, enabled_when='update_stm_en'), show_border=True, label="Firmware Version"), VGroup(Item('local_console_vers', label='Current', resizable=True, editor_args={'enabled': False}), Item('newest_console_vers', label='Latest', editor_args={'enabled': False}), label="Swift Console Version", show_border=True), ), HGroup( VGroup(HGroup( Item('download_directory', label="Directory", resizable=True), UItem('choose_dir', width=-0.1), ), HGroup( Spring(width=50, springy=False), Item('download_firmware', enabled_when='download_fw_en', show_label=False, resizable=True, springy=True)), label="Firmware Download", show_border=True), VGroup(Item( 'stream', style='custom', editor=InstanceEditor(), show_label=False, ), show_border=True, label="Firmware Upgrade Status"), ), show_border=True), ) def __init__(self, link, download_dir=None, prompt=True, connection_info={'mode': 'unknown'}): """ Traits tab with UI for updating Piksi firmware. Parameters ---------- link : sbp.client.handler.Handler Link for SBP transfer to/from Piksi. prompt : bool Prompt user to update console/firmware if out of date. """ self.link = link self.connection_info = connection_info self.settings = {} self.prompt = prompt self.python_console_cmds = {'update': self} self.download_directory = download_dir try: self.update_dl = UpdateDownloader(root_dir=self.download_directory) except RuntimeError: self.update_dl = None self.stm_fw = FirmwareFileDialog(self.download_directory) self.stm_fw.on_trait_change(self._manage_enables, 'status') self.stream = OutputStream() self.stream.max_len = 1000 self.last_call_fw_version = None self.link.add_callback(self.log_cb, SBP_MSG_LOG) def _choose_dir_fired(self): dialog = DirectoryDialog(label='Choose Download location', action='open', default_directory=self.download_directory) dialog.open() if dialog.return_code == OK: self.download_directory = dialog.path else: self._write('Error while selecting firmware download location') def _manage_enables(self): """ Manages whether traits widgets are enabled in the UI or not. """ if self.updating or self.downloading: self.update_stm_en = False self.download_fw_en = False else: if getattr(self.stm_fw, 'blob', None) is not None: self.update_stm_en = True else: self.update_stm_en = False if self.download_directory != '': self.download_fw_en = True def _download_directory_changed(self): if getattr(self, 'update_dl', None): self.update_dl.set_root_path(self.download_directory) self._manage_enables() def _updating_changed(self): """ Handles self.updating trait being changed. """ self._manage_enables() def _downloading_changed(self): """ Handles self.downloading trait being changed. """ self._manage_enables() def _clear_stream(self): self.stream.reset() def _write(self, text): """ Stream style write function. Allows flashing debugging messages to be routed to embedded text console. Parameters ---------- text : string Text to be written to screen. """ self.stream.write(text) self.stream.write('\n') self.stream.flush() def _update_stm_firmware_fired(self): """ Handle update_stm_firmware button. Starts thread so as not to block the GUI thread. """ ins_settings = self.settings.get('ins', None) ins_output_mode = None if ins_settings is not None: ins_output_mode = ins_settings.get('output_mode').value if (ins_output_mode is not None) and not (ins_output_mode.startswith('Disabled') or ins_output_mode.startswith('disabled')): ins_disable_prompt = \ prompt.CallbackPrompt( title="Unsupported Update Request", actions=[prompt.close_button], ) ins_disable_prompt.text = \ "\n\n" + \ "Updating firmware is not supported when INS is active.\n\n" + \ "Please change the 'output mode' INS setting to 'Disabled'\n" + \ "before updating firmware.\n\n" ins_disable_prompt.run(block=False) return if self.connection_info['mode'] != 'TCP/IP': self._write( "\n" "-----------------------------------------------\n" "USB Flashdrive Upgrade Procedure\n" "-----------------------------------------------\n" "\n" "1.\tInsert the USB flash drive provided with your Piksi Multi into your computer.\n" " \tSelect the flash drive root directory as the firmware download destination using the directory chooser above.\n" " \tPress the \"Download Latest Firmware\" button. This will download the latest Piksi Multi firmware file onto\n" " \tthe USB flashdrive.\n" "2.\tEject the drive from your computer and plug it into the USB Host port of the Piksi Multi evaluation board.\n" "3.\tReset your Piksi Multi and it will upgrade to the version on the USB flash drive.\n" " \tThis should take less than 5 minutes.\n" "4.\tWhen the upgrade completes you will be prompted to remove the USB flash drive and reset your Piksi Multi.\n" "5.\tVerify that the firmware version has upgraded via inspection of the Current Firmware Version box\n" " \ton the Update Tab of the Swift Console.\n") confirm_prompt = prompt.CallbackPrompt( title="Update device over serial connection?", actions=[ prompt.close_button, prompt.continue_via_serial_button ], callback=self._update_stm_firmware_fn) confirm_prompt.text = "\n" \ + " Upgrading your device via UART / RS232 may take up to 30 minutes. \n" \ + " \n" \ + " If the device you are upgrading has an accessible USB host port, it \n" \ " is recommended to instead follow the \'USB Flashdrive Upgrade \n" \ " Procedure\' that now appears in the Firmware upgrade status box. \n" \ + "\n" \ + " Are you sure you want to continue upgrading over serial?" confirm_prompt.run(block=False) else: self._update_stm_firmware_fn() def _replace_with_version_2(self): self.downloading = True self._write('Downloading Multi firmware v2.0.0') filepath = self.update_dl._download_file_from_url(V2_LINK) self._write('Saved file to %s' % filepath) self.stm_fw.load_bin(filepath) self.downloading = False def _update_stm_firmware_fn(self): try: if self._firmware_update_thread.is_alive(): return except AttributeError: pass current_fw_version = parse_version(self.piksi_stm_vers) re_result = re.search('[a-zA-Z0-9]*-(v[0-9]*\.[0-9]*\.[0-9])', self.stm_fw.status) intended_version = parse_version(re_result.group(1)) # If the current firmware is not yet beyond 2.0.0, and we are loading beyond 2.0.0 # warn the user that this upgrade is not possible if (current_fw_version < pkparse_version("v2.0.0") and intended_version > pkparse_version("v2.0.0")): confirm_prompt = prompt.CallbackPrompt( title="Update to v2.0.0", actions=[prompt.close_button, prompt.ok_button], callback=self._replace_with_version_2) confirm_prompt.text = "\n" \ + " Upgrading to firmware v2.1.0 or later requires that the device be \n" \ + " running firmware v2.0.0 or later. Please upgrade to firmware \n" \ + " version 2.0.0. \n" \ + " \n" \ + " Would you like to download firmware version v2.0.0 now? \n" \ + " \n" confirm_prompt.run(block=False) return self._firmware_update_thread = Thread( target=self.manage_firmware_updates, args=("STM", )) self._firmware_update_thread.start() def _download_firmware(self): """ Download latest firmware from swiftnav.com. """ self._write('') # Check that we received the index file from the website. if self.update_dl is None or self.update_dl.index is None: self._write("Error: Can't download firmware files") return self.downloading = True status = 'Downloading Latest Firmware...' self.stm_fw.clear(status) self._write(status) # Get firmware files from Swift Nav's website, save to disk, and load. if 'fw' in self.update_dl.index[self.piksi_hw_rev]: try: self._write('Downloading Latest Multi firmware') filepath = self.update_dl.download_multi_firmware( self.piksi_hw_rev) self._write('Saved file to %s' % filepath) self.stm_fw.load_bin(filepath) except AttributeError: self._write( "Error downloading firmware: index file not downloaded yet" ) except RuntimeError as e: self._write( "RunTimeError: unable to download firmware to path {0}: {1}" .format(self.download_directory, e)) except IOError as e: if e.errno == errno.EACCES or e.errno == errno.EPERM: self._write("IOError: unable to write to path %s. " "Verify that the path is writable." % self.download_directory) else: raise (e) except KeyError: self._write( "Error downloading firmware: URL not present in index") except URLError: self.nap_fw.clear("Error downloading firmware") self._write( "Error: Failed to download latest NAP firmware from Swift Navigation's website" ) self.downloading = False return def _download_firmware_fired(self): """ Handle download_firmware button. Starts thread so as not to block the GUI thread. """ try: if self._download_firmware_thread.is_alive(): return except AttributeError: pass self._download_firmware_thread = Thread(target=self._download_firmware) self._download_firmware_thread.start() def compare_versions(self): """ To be called after latest Piksi firmware info has been received from device, to decide if current firmware on Piksi is out of date. Also informs user if the firmware was successfully upgraded. Starts a thread so as not to block GUI thread. """ try: if self._compare_versions_thread.is_alive(): return except AttributeError: pass self._compare_versions_thread = Thread(target=self._compare_versions) self._compare_versions_thread.start() def _compare_versions(self): """ Compares version info between received firmware version / current console and firmware / console info from website to decide if current firmware or console is out of date. Prompt user to update if so. Informs user if firmware successfully upgraded. """ # Check that settings received from Piksi contain FW versions. try: self.piksi_hw_rev = HW_REV_LOOKUP[self.settings['system_info'] ['hw_revision'].value] self.piksi_stm_vers = self.settings['system_info'][ 'firmware_version'].value except KeyError: self._write( "\nError: Settings received from Piksi don't contain firmware version keys. Please contact Swift Navigation.\n" ) return self.is_v2 = self.piksi_hw_rev.startswith('piksi_v2') self._get_latest_version_info() # Check that we received the index file from the website. if self.update_dl is None: self._write( "Error: No website index to use to compare versions with local firmware" ) return # Get local stm version local_stm_version = None local_serial_number = None try: local_stm_version = self.settings['system_info'][ 'firmware_version'].value local_serial_number = self.settings['system_info'][ 'serial_number'].value except: # noqa pass # Check if console is out of date and notify user if so. if self.prompt: local_console_version = parse_version(CONSOLE_VERSION) remote_console_version = parse_version(self.newest_console_vers) self.console_outdated = remote_console_version > local_console_version # we want to warn users using v2 regardless of version logic if self.console_outdated or self.is_v2: if not self.is_v2: console_outdated_prompt = \ prompt.CallbackPrompt( title="Swift Console Outdated", actions=[prompt.close_button], ) console_outdated_prompt.text = \ "Your console is out of date and may be incompatible\n" + \ "with current firmware. We highly recommend upgrading to\n" + \ "ensure proper behavior.\n\n" + \ "Please visit http://support.swiftnav.com to\n" + \ "download the latest version.\n\n" + \ "Local Console Version :\n\t" + \ "v" + CONSOLE_VERSION + \ "\nLatest Console Version :\n\t" + \ self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n" else: console_outdated_prompt = \ prompt.CallbackPrompt( title="Swift Console Incompatible", actions=[prompt.close_button], ) console_outdated_prompt.text = \ "Your console is incompatible with your hardware revision.\n" + \ "We highly recommend using a compatible console version\n" + \ "to ensure proper behavior.\n\n" + \ "Please visit http://support.swiftnav.com to\n" + \ "download the latest compatible version.\n\n" + \ "Current Hardware revision :\n\t" + \ self.piksi_hw_rev + \ "\nLast supported Console Version: \n\t" + \ self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n" console_outdated_prompt.run() # For timing aesthetics between windows popping up. sleep(0.5) # Check if firmware is out of date and notify user if so. remote_stm_version = self.newest_stm_vers self.fw_outdated = remote_stm_version > local_stm_version if local_stm_version.startswith('DEV'): self.fw_outdated = False if self.fw_outdated: fw_update_prompt = \ prompt.CallbackPrompt( title='Firmware Update', actions=[prompt.close_button] ) if 'fw' in self.update_dl.index[self.piksi_hw_rev]: fw_update_prompt.text = \ "New Piksi firmware available.\n\n" + \ "Please use the Update tab to update.\n\n" + \ "Newest Firmware Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['fw']['version'] else: fw_update_prompt.text = \ "New Piksi firmware available.\n\n" + \ "Please use the Update tab to update.\n\n" + \ "Newest STM Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['stm_fw']['version'] + \ "Newest SwiftNAP Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['nap_fw']['version'] fw_update_prompt.run() # Check if firmware successfully upgraded and notify user if so. if ((self.last_call_fw_version is not None and self.last_call_fw_version != local_stm_version) and (self.last_call_sn is None or local_serial_number is None or self.last_call_sn == local_serial_number)): fw_success_str = "Firmware successfully upgraded from %s to %s." % \ (self.last_call_fw_version, local_stm_version) print(fw_success_str) self._write(fw_success_str) # Record firmware version reported each time this callback is called. self.last_call_fw_version = local_stm_version self.last_call_sn = local_serial_number def _get_latest_version_info(self): """ Get latest firmware / console version from website. """ try: self.update_dl = UpdateDownloader(root_dir=self.download_directory) except RuntimeError: self._write( "\nError: Failed to download latest file index from Swift Navigation's website. Please visit our website to check that you're running the latest Piksi firmware and Piksi console.\n" ) self.update_dl = None return # Make sure index contains all keys we are interested in. try: if 'fw' in self.update_dl.index[self.piksi_hw_rev]: self.newest_stm_vers = self.update_dl.index[ self.piksi_hw_rev]['fw']['version'] else: self.newest_stm_vers = self.update_dl.index[ self.piksi_hw_rev]['stm_fw']['version'] self.newest_nap_vers = self.update_dl.index[ self.piksi_hw_rev]['nap_fw']['version'] self.newest_console_vers = self.update_dl.index[ self.piksi_hw_rev]['console']['version'] except KeyError: self._write( "\nError: Index downloaded from Swift Navigation's website (%s) doesn't contain all keys. Please contact Swift Navigation.\n" % INDEX_URL) return def file_transfer_progress_cb(self, arg): new_pcent = float(arg) / float(self.blob_size) * 100 if new_pcent - self.pcent_complete > 0.1: self.pcent_complete = new_pcent self.stream.scrollback_write( "{:2.1f} % of {:2.1f} MB transferred.".format( self.pcent_complete, self.blob_size * 1e-6)) def log_cb(self, msg, **kwargs): for regex in UPGRADE_WHITELIST: if re.match(regex, msg.text): text = msg.text.replace("\r", "\n").strip().split("\n") if len(text) > 1: # upgrade tool deliminates lines in stoud with \r, we want penultimate line that is complete to show text = text[-2] else: # If there is only one line, we show that text = text[-1] self.stream.scrollback_write(text) def manage_multi_firmware_update(self): self.blob_size = float(len(self.stm_fw.blob)) self.pcent_complete = 0 # Set up progress dialog and transfer file to Piksi using SBP FileIO self._clear_stream() self._write( "Transferring image to device...\n\n00.0 of {:2.1f} MB trasnferred" .format(self.blob_size * 1e-6)) try: FileIO(self.link).write("upgrade.image_set.bin", self.stm_fw.blob, progress_cb=self.file_transfer_progress_cb) except Exception as e: self._write("Failed to transfer image file to Piksi: %s\n" % e) self._write("Upgrade Aborted.") import traceback print(traceback.format_exc()) return -1 self.stream.scrollback_write( "Image transfer complete: {:2.1f} MB transferred.\n".format( self.blob_size * 1e-6)) # Setup up pulsed progress dialog and commit to flash self._write("Committing file to Flash...\n") self.link.add_callback(self.log_cb, SBP_MSG_LOG) code = shell_command(self.link, "upgrade_tool upgrade.image_set.bin", 200) self.link.remove_callback(self.log_cb, SBP_MSG_LOG) if code != 0: self._write('Failed to perform upgrade (code = %d)' % code) if code == -255: self._write('Shell command timed out. Please try again.') return self._write("Upgrade Complete.") self._write('Resetting Piksi...') self.link(MsgReset(flags=0)) # Executed in GUI thread, called from Handler. def manage_firmware_updates(self, device): """ Update Piksi firmware. Erase entire STM flash (other than bootloader) if so directed. Flash NAP only if new firmware is available. """ self.updating = True self._write('') if not self.is_v2: self.manage_multi_firmware_update() else: self._write( 'Unable to upgrade piksi v2; please use the last supported v2 console version.' ) self._write("") self.updating = False
Menu( ActionGroup(new_item_action, name='list_group'), name=_('Edit'), ), ) # ---------------------------------------------------------------------------- # TraitsUI Views # ---------------------------------------------------------------------------- #: Stripped down view for use in list editor to_do_item_view = View( HGroup( Item('completed', show_label=False), Item('creation_time', show_label=False, style='readonly', editor=TextEditor(format_func=format_date, )), Item('description', show_label=False, springy=True), Item('controller.delete', show_label=False, editor=ButtonEditor(label=_('Delete')))), ) #: View for main model view todo_list_view = View( VGroup( HGroup( Item('remaining', style='readonly', show_label=False), Spring(), Item('display_selection', label=_('Show'), editor=EnumEditor(values={ 'all': _('All'),
class PolygonPlotDemo(HasTraits): # The main plot container. plot = Instance(Plot) # Data holder for `plot`. apd = Instance(ArrayPlotData) # The polygon plot renderer. polygon_plot = Instance(PolygonPlot) # Assorted styles that will be set on `polygon_plot`. edge_style = LineStyle edge_width = Range(value=1, low=0, high=8) edge_alpha = Range(value=1.0, low=0.0, high=1.0) face_alpha = Range(value=0.4, low=0.0, high=1.0) alpha = Range(value=1.0, low=0.0, high=1.0) traits_view = \ View( VGroup( Group( UItem('plot', editor=ComponentEditor(), style='custom'), ), VGroup( HGroup( Item('edge_style'), spring, ), Item('edge_width'), Item('edge_alpha'), Item('face_alpha'), Item('alpha'), ), ), resizable=True, ) #---------------------------------------------------------------------- # Default values #---------------------------------------------------------------------- def _apd_default(self): # Create the data to plot. px = np.array([0.5, 1.0, 2.0, 2.5, 2.0, 1.5, 0.5, 0.0]) py = np.array([0.0, 0.8, 0.5, 3.0, 3.5, 2.0, 3.0, 0.5]) # Create the ArrayPlotData container used by the Plot. apd = ArrayPlotData(px=px, py=py) return apd def _plot_default(self): plot = Plot(self.apd, title='PolygonPlot Demo') return plot def _polygon_plot_default(self): p = self.plot.plot(('px', 'py'), type='polygon', face_color=(0, 0.8, 1) + (self.face_alpha, ), edge_color=(0, 0, 0) + (self.edge_alpha, ), edge_style=self.edge_style, alpha=self.alpha) return p[0] #---------------------------------------------------------------------- # Trait change handlers #---------------------------------------------------------------------- def _edge_style_changed(self): self.polygon_plot.edge_style = self.edge_style def _edge_width_changed(self): self.polygon_plot.edge_width = self.edge_width def _edge_alpha_changed(self): self.polygon_plot.edge_color = self.polygon_plot.edge_color[:3] + ( self.edge_alpha, ) def _face_alpha_changed(self): self.polygon_plot.face_color = self.polygon_plot.face_color[:3] + ( self.face_alpha, ) def _alpha_changed(self): self.polygon_plot.alpha = self.alpha
class UpdateView(HasTraits): piksi_hw_rev = String('piksi_multi') is_v2 = Bool(False) piksi_stm_vers = String('Waiting for Piksi to send settings...', width=COLUMN_WIDTH) newest_stm_vers = String('Downloading Latest Firmware info...') piksi_nap_vers = String('Waiting for Piksi to send settings...') newest_nap_vers = String('Downloading Latest Firmware info...') local_console_vers = String('v' + CONSOLE_VERSION) newest_console_vers = String('Downloading Latest Console info...') erase_stm = Bool(True) erase_en = Bool(True) update_stm_firmware = Button(label='Update FW') update_nap_firmware = Button(label='Update NAP') update_full_firmware = Button(label='Update Piksi STM and NAP Firmware') updating = Bool(False) update_stm_en = Bool(False) update_nap_en = Bool(False) update_en = Bool(False) serial_upgrade = Bool(False) upgrade_steps = String("Firmware upgrade steps:") download_firmware = Button(label='Download Latest Firmware') download_directory = Directory( " Please choose a directory for downloaded firmware files...") download_stm = Button(label='Download', height=HT) download_nap = Button(label='Download', height=HT) downloading = Bool(False) download_fw_en = Bool(True) stm_fw = Instance(FirmwareFileDialog) nap_fw = Instance(FirmwareFileDialog) stream = Instance(OutputStream) view = View( VGroup( Item('piksi_hw_rev', label='Hardware Revision', editor_args={'enabled': False}, resizable=True), HGroup( VGroup(Item('piksi_stm_vers', label='Current', resizable=True, editor_args={'enabled': False}), Item('newest_stm_vers', label='Latest', resizable=True, editor_args={ 'enabled': False, 'readonly_allow_selection': True }), Item('stm_fw', style='custom', show_label=True, label="Local File", enabled_when='download_fw_en', visible_when='serial_upgrade', editor_args={'enabled': False}), HGroup( Item('update_stm_firmware', show_label=False, enabled_when='update_stm_en', visible_when='serial_upgrade'), Item('erase_stm', label='Erase STM flash\n(recommended)', enabled_when='erase_en', show_label=True, visible_when='is_v2')), show_border=True, label="Firmware Version"), VGroup(Item('piksi_nap_vers', label='Current', resizable=True, editor_args={'enabled': False}), Item('newest_nap_vers', label='Latest', resizable=True, editor_args={'enabled': False}), Item('nap_fw', style='custom', show_label=True, label="Local File", enabled_when='download_fw_en', editor_args={'enabled': False}), HGroup( Item('update_nap_firmware', show_label=False, enabled_when='update_nap_en', visible_when='serial_upgrade'), Item(width=50, label=" ")), show_border=True, label="NAP Version", visible_when='is_v2'), VGroup(Item('local_console_vers', label='Current', resizable=True, editor_args={'enabled': False}), Item('newest_console_vers', label='Latest', editor_args={'enabled': False}), label="Swift Console Version", show_border=True), ), UItem('download_directory', enabled_when='download_fw_en'), UItem('download_firmware', enabled_when='download_fw_en'), UItem('update_full_firmware', enabled_when='update_en', visible_when='is_v2'), VGroup( UItem('upgrade_steps', visible_when='not serial_upgrade', style='readonly'), Item( 'stream', style='custom', editor=InstanceEditor(), show_label=False, ), show_border=True, ))) def __init__(self, link, download_dir=None, prompt=True, serial_upgrade=False): """ Traits tab with UI for updating Piksi firmware. Parameters ---------- link : sbp.client.handler.Handler Link for SBP transfer to/from Piksi. prompt : bool Prompt user to update console/firmware if out of date. """ self.link = link self.settings = {} self.prompt = prompt self.python_console_cmds = {'update': self} try: self.update_dl = UpdateDownloader() if download_dir: self.update_dl.set_root_path(download_dir) except URLError: self.update_dl = None self.erase_en = True self.stm_fw = FirmwareFileDialog('bin') self.stm_fw.on_trait_change(self._manage_enables, 'status') self.nap_fw = FirmwareFileDialog('M25') self.nap_fw.on_trait_change(self._manage_enables, 'status') self.stream = OutputStream() self.serial_upgrade = serial_upgrade self.last_call_fw_version = None if not self.serial_upgrade: self._write( "1. Insert the USB flash drive provided with your Piki Multi into " "your computer. Select the flash drive root directory as the " "firmware download destination using the \"Please " "choose a directory for downloaded firmware files\" directory " "chooser above. Press the \"Download Latest Firmware\" button. " "This will download the latest Piksi Multi firmware file onto the " "USB flashdrive.\n" "2. Eject the drive from your computer and plug it " "into the Piksi Multi evaluation board.\n" "3. Reset your Piksi Multi and it will upgrade to the version " "on the USB flash drive. This should take less than 5 minutes.\n" "4. When the upgrade completes you will be prompted to remove the " "USB flash drive and reset your Piksi Multi.\n" "5. Verify that the firmware version has upgraded via inspection " "of the Current Firmware Version box on the Firmware Update Tab " "of the Swift Console.\n") def _manage_enables(self): """ Manages whether traits widgets are enabled in the UI or not. """ if self.updating or self.downloading: self.update_stm_en = False self.update_nap_en = False self.update_en = False self.download_fw_en = False self.erase_en = False else: self.download_fw_en = True self.erase_en = True if self.stm_fw.ihx is not None or self.stm_fw.blob is not None: self.update_stm_en = True else: self.update_stm_en = False self.update_en = False if self.nap_fw.ihx is not None: self.update_nap_en = True else: self.update_nap_en = False self.update_en = False if self.nap_fw.ihx is not None and self.stm_fw.ihx is not None: self.update_en = True def _download_directory_changed(self): if self.update_dl: self.update_dl.set_root_path(self.download_directory) def _updating_changed(self): """ Handles self.updating trait being changed. """ self._manage_enables() def _downloading_changed(self): """ Handles self.downloading trait being changed. """ self._manage_enables() def _write(self, text): """ Stream style write function. Allows flashing debugging messages to be routed to embedded text console. Parameters ---------- text : string Text to be written to screen. """ self.stream.write(text) self.stream.write('\n') self.stream.flush() def _update_stm_firmware_fired(self): """ Handle update_stm_firmware button. Starts thread so as not to block the GUI thread. """ try: if self._firmware_update_thread.is_alive(): return except AttributeError: pass self._firmware_update_thread = Thread( target=self.manage_firmware_updates, args=("STM", )) self._firmware_update_thread.start() def _update_nap_firmware_fired(self): """ Handle update_nap_firmware button. Starts thread so as not to block the GUI thread. """ try: if self._firmware_update_thread.is_alive(): return except AttributeError: pass self._firmware_update_thread = Thread( target=self.manage_firmware_updates, args=("M25", )) self._firmware_update_thread.start() def _update_full_firmware_fired(self): """ Handle update_full_firmware button. Starts thread so as not to block the GUI thread. """ try: if self._firmware_update_thread.is_alive(): return except AttributeError: pass self._firmware_update_thread = Thread( target=self.manage_firmware_updates, args=("ALL", )) self._firmware_update_thread.start() def _download_firmware(self): """ Download latest firmware from swiftnav.com. """ self._write('') # Check that we received the index file from the website. if self.update_dl is None: self._write("Error: Can't download firmware files") return self.downloading = True status = 'Downloading Latest Firmware...' self.nap_fw.clear(status) self.stm_fw.clear(status) self._write(status) # Get firmware files from Swift Nav's website, save to disk, and load. if 'fw' in self.update_dl.index[self.piksi_hw_rev]: try: self._write('Downloading Latest Multi firmware') filepath = self.update_dl.download_multi_firmware( self.piksi_hw_rev) self._write('Saved file to %s' % filepath) self.stm_fw.load_bin(filepath) except AttributeError: self.nap_fw.clear("Error downloading firmware") self._write( "Error downloading firmware: index file not downloaded yet" ) except IOError: self.nap_fw.clear( "IOError: unable to write to path %s. " "Verify that the path exists and is writable." % self.download_directory) self._write("IOError: unable to write to path %s. " "Verify that the path exists and is writable." % self.download_directory) except KeyError: self.nap_fw.clear("Error downloading firmware") self._write( "Error downloading firmware: URL not present in index") except URLError: self.nap_fw.clear("Error downloading firmware") self._write( "Error: Failed to download latest NAP firmware from Swift Navigation's website" ) self.downloading = False return def _download_firmware_fired(self): """ Handle download_firmware button. Starts thread so as not to block the GUI thread. """ try: if self._download_firmware_thread.is_alive(): return except AttributeError: pass self._download_firmware_thread = Thread(target=self._download_firmware) self._download_firmware_thread.start() def compare_versions(self): """ To be called after latest Piksi firmware info has been received from device, to decide if current firmware on Piksi is out of date. Also informs user if the firmware was successfully upgraded. Starts a thread so as not to block GUI thread. """ try: if self._compare_versions_thread.is_alive(): return except AttributeError: pass self._compare_versions_thread = Thread(target=self._compare_versions) self._compare_versions_thread.start() def _compare_versions(self): """ Compares version info between received firmware version / current console and firmware / console info from website to decide if current firmware or console is out of date. Prompt user to update if so. Informs user if firmware successfully upgraded. """ # Check that settings received from Piksi contain FW versions. try: self.piksi_hw_rev = \ HW_REV_LOOKUP[self.settings['system_info'] ['hw_revision'].value] self.piksi_stm_vers = \ self.settings['system_info']['firmware_version'].value except KeyError: self._write( "\nError: Settings received from Piksi don't contain firmware version keys. Please contact Swift Navigation.\n" ) return self.is_v2 = self.piksi_hw_rev.startswith('piksi_v2') if self.is_v2: self.stm_fw.set_flash_type('STM') self.serial_upgrade = True else: self.stm_fw.set_flash_type('bin') self._get_latest_version_info() # Check that we received the index file from the website. if self.update_dl is None: self._write( "Error: No website index to use to compare versions with local firmware" ) return # Get local stm version local_stm_version = None try: local_stm_version = self.settings['system_info'][ 'firmware_version'].value except: pass # Check if console is out of date and notify user if so. if self.prompt: local_console_version = parse_version(CONSOLE_VERSION) remote_console_version = parse_version(self.newest_console_vers) self.console_outdated = remote_console_version > local_console_version # we want to warn users using v2 regardless of version logic if self.console_outdated or self.is_v2: if not self.is_v2: console_outdated_prompt = \ prompt.CallbackPrompt( title="Swift Console Outdated", actions=[prompt.close_button], ) console_outdated_prompt.text = \ "Your console is out of date and may be incompatible\n" + \ "with current firmware. We highly recommend upgrading to\n" + \ "ensure proper behavior.\n\n" + \ "Please visit http://support.swiftnav.com to\n" + \ "download the latest version.\n\n" + \ "Local Console Version :\n\t" + \ "v" + CONSOLE_VERSION + \ "\nLatest Console Version :\n\t" + \ self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n" else: console_outdated_prompt = \ prompt.CallbackPrompt( title="Swift Console Incompatible", actions=[prompt.close_button], ) console_outdated_prompt.text = \ "Your console is incompatible with your hardware revision.\n" + \ "We highly recommend using a compatible console version\n" + \ "to ensure proper behavior.\n\n" + \ "Please visit http://support.swiftnav.com to\n" + \ "download the latest compatible version.\n\n" + \ "Current Hardware revision :\n\t" + \ self.piksi_hw_rev + \ "\nLast supported Console Version: \n\t" + \ self.update_dl.index[self.piksi_hw_rev]['console']['version'] + "\n" console_outdated_prompt.run() # For timing aesthetics between windows popping up. sleep(0.5) # Check if firmware is out of date and notify user if so. remote_stm_version = self.newest_stm_vers self.fw_outdated = remote_stm_version > local_stm_version if self.fw_outdated: fw_update_prompt = \ prompt.CallbackPrompt( title='Firmware Update', actions=[prompt.close_button] ) if 'fw' in self.update_dl.index[self.piksi_hw_rev]: fw_update_prompt.text = \ "New Piksi firmware available.\n\n" + \ "Please use the Firmware Update tab to update.\n\n" + \ "Newest Firmware Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['fw']['version'] else: fw_update_prompt.text = \ "New Piksi firmware available.\n\n" + \ "Please use the Firmware Update tab to update.\n\n" + \ "Newest STM Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['stm_fw']['version'] + \ "Newest SwiftNAP Version :\n\t%s\n\n" % \ self.update_dl.index[self.piksi_hw_rev]['nap_fw']['version'] fw_update_prompt.run() # Check if firmware successfully upgraded and notify user if so. if self.last_call_fw_version is not None and \ self.last_call_fw_version != local_stm_version: fw_success_str = "Firmware successfully upgraded from %s to %s." % \ (self.last_call_fw_version, local_stm_version) print(fw_success_str) self._write(fw_success_str) # Record firmware version reported each time this callback is called. self.last_call_fw_version = local_stm_version def _get_latest_version_info(self): """ Get latest firmware / console version from website. """ try: self.update_dl = UpdateDownloader() except URLError: self._write( "\nError: Failed to download latest file index from Swift Navigation's website. Please visit our website to check that you're running the latest Piksi firmware and Piksi console.\n" ) return # Make sure index contains all keys we are interested in. try: if 'fw' in self.update_dl.index[self.piksi_hw_rev]: self.newest_stm_vers = self.update_dl.index[ self.piksi_hw_rev]['fw']['version'] else: self.newest_stm_vers = self.update_dl.index[ self.piksi_hw_rev]['stm_fw']['version'] self.newest_nap_vers = self.update_dl.index[ self.piksi_hw_rev]['nap_fw']['version'] self.newest_console_vers = self.update_dl.index[ self.piksi_hw_rev]['console']['version'] except KeyError: self._write( "\nError: Index downloaded from Swift Navigation's website (%s) doesn't contain all keys. Please contact Swift Navigation.\n" % INDEX_URL) return def manage_stm_firmware_update(self): # Erase all of STM's flash (other than bootloader) if box is checked. if self.erase_stm: text = "Erasing STM" self._write(text) self.create_flash("STM") sectors_to_erase = set(range(self.pk_flash.n_sectors)).difference( set(self.pk_flash.restricted_sectors)) progress_dialog = PulsableProgressDialog(len(sectors_to_erase), False) progress_dialog.title = text GUI.invoke_later(progress_dialog.open) erase_count = 0 for s in sorted(sectors_to_erase): progress_dialog.progress(erase_count) self._write('Erasing %s sector %d' % (self.pk_flash.flash_type, s)) self.pk_flash.erase_sector(s) erase_count += 1 self.stop_flash() self._write("") try: progress_dialog.close() except AttributeError: pass # Flash STM. text = "Updating STM" self._write(text) self.create_flash("STM") stm_n_ops = self.pk_flash.ihx_n_ops(self.stm_fw.ihx, erase=not self.erase_stm) progress_dialog = PulsableProgressDialog(stm_n_ops, True) progress_dialog.title = text GUI.invoke_later(progress_dialog.open) # Don't erase sectors if we've already done so above. self.pk_flash.write_ihx(self.stm_fw.ihx, self.stream, mod_print=0x40, elapsed_ops_cb=progress_dialog.progress, erase=not self.erase_stm) self.stop_flash() self._write("") try: progress_dialog.close() except AttributeError: pass def manage_nap_firmware_update(self, check_version=False): # Flash NAP if out of date. try: local_nap_version = parse_version( self.settings['system_info']['nap_version'].value) remote_nap_version = parse_version(self.newest_nap_vers) nap_out_of_date = local_nap_version != remote_nap_version except KeyError: nap_out_of_date = True if nap_out_of_date or not check_version: text = "Updating NAP" self._write(text) self.create_flash("M25") nap_n_ops = self.pk_flash.ihx_n_ops(self.nap_fw.ihx) progress_dialog = PulsableProgressDialog(nap_n_ops, True) progress_dialog.title = text GUI.invoke_later(progress_dialog.open) self.pk_flash.write_ihx(self.nap_fw.ihx, self.stream, mod_print=0x40, elapsed_ops_cb=progress_dialog.progress) self.stop_flash() self._write("") try: progress_dialog.close() except AttributeError: pass return True else: text = "NAP is already to latest version, not updating!" self._write(text) self._write("") return False def manage_multi_firmware_update(self): # Set up progress dialog and transfer file to Piksi using SBP FileIO progress_dialog = PulsableProgressDialog(len(self.stm_fw.blob)) progress_dialog.title = "Transferring image file" GUI.invoke_later(progress_dialog.open) self._write("Transferring image file...") try: FileIO(self.link).write("upgrade.image_set.bin", self.stm_fw.blob, progress_cb=progress_dialog.progress) except Exception as e: self._write("Failed to transfer image file to Piksi: %s\n" % e) progress_dialog.close() return try: progress_dialog.close() except AttributeError: pass # Setup up pulsed progress dialog and commit to flash progress_dialog = PulsableProgressDialog(100, True) progress_dialog.title = "Committing to flash" GUI.invoke_later(progress_dialog.open) self._write("Committing file to flash...") def log_cb(msg, **kwargs): self._write(msg.text) self.link.add_callback(log_cb, SBP_MSG_LOG) code = shell_command(self.link, "upgrade_tool upgrade.image_set.bin", 600, progress_cb=progress_dialog.progress) self.link.remove_callback(log_cb, SBP_MSG_LOG) progress_dialog.close() if code != 0: self._write('Failed to perform upgrade (code = %d)' % code) if code == -255: self._write('Shell command timed out. Please try again.') return self._write('Resetting Piksi...') self.link(MsgReset(flags=0)) # Executed in GUI thread, called from Handler. def manage_firmware_updates(self, device): """ Update Piksi firmware. Erase entire STM flash (other than bootloader) if so directed. Flash NAP only if new firmware is available. """ self.updating = True update_nap = False self._write('') if not self.is_v2: self.manage_multi_firmware_update() self.updating = False return elif device == "STM": self.manage_stm_firmware_update() elif device == "M25": update_nap = self.manage_nap_firmware_update() else: self.manage_stm_firmware_update() update_nap = self.manage_nap_firmware_update(check_version=True) # Must tell Piksi to jump to application after updating firmware. if device == "STM" or update_nap: self.link(MsgBootloaderJumpToApp(jump=0)) self._write("Firmware update finished.") self._write("") self.updating = False def create_flash(self, flash_type): """ Create flash.Flash instance and set Piksi into bootloader mode, prompting user to reset if necessary. Parameter --------- flash_type : string Either "STM" or "M25". """ # Reset device if the application is running to put into bootloader mode. self.link(MsgReset(flags=0)) self.pk_boot = bootload.Bootloader(self.link) self._write("Waiting for bootloader handshake message from Piksi ...") reset_prompt = None handshake_received = self.pk_boot.handshake(1) # Prompt user to reset Piksi if we don't receive the handshake message # within a reasonable amount of tiime (firmware might be corrupted). while not handshake_received: reset_prompt = \ prompt.CallbackPrompt( title="Please Reset Piksi", actions=[prompt.close_button], ) reset_prompt.text = \ "You must press the reset button on your Piksi in order\n" + \ "to update your firmware.\n\n" + \ "Please press it now.\n\n" reset_prompt.run(block=False) while not reset_prompt.closed and not handshake_received: handshake_received = self.pk_boot.handshake(1) reset_prompt.kill() reset_prompt.wait() self._write("received bootloader handshake message.") self._write("Piksi Onboard Bootloader Version: " + self.pk_boot.version) self.pk_flash = flash.Flash(self.link, flash_type, self.pk_boot.sbp_version) def stop_flash(self): """ Stop Flash and Bootloader instances (removes callback from SerialLink). """ self.pk_flash.stop() self.pk_boot.stop()
class Kit2FiffPanel(HasPrivateTraits): """Control panel for kit2fiff conversion.""" model = Instance(Kit2FiffModel) # model copies for view use_mrk = DelegatesTo('model') sqd_file = DelegatesTo('model') hsp_file = DelegatesTo('model') fid_file = DelegatesTo('model') stim_coding = DelegatesTo('model') stim_chs = DelegatesTo('model') stim_chs_ok = DelegatesTo('model') stim_chs_comment = DelegatesTo('model') stim_slope = DelegatesTo('model') stim_threshold = DelegatesTo('model') # info can_save = DelegatesTo('model') sqd_fname = DelegatesTo('model') hsp_fname = DelegatesTo('model') fid_fname = DelegatesTo('model') misc_chs_desc = DelegatesTo('model') can_test_stim = DelegatesTo('model') test_stim = Button(label="Find Events") plot_raw = Button(label="Plot Raw") # Source Files reset_dig = Button # Visualization scene = Instance(MlabSceneModel) fid_obj = Instance(PointObject) elp_obj = Instance(PointObject) hsp_obj = Instance(PointObject) # Output save_as = Button(label='Save FIFF...') clear_all = Button(label='Clear All') queue = Instance(queue.Queue, ()) queue_feedback = Str('') queue_current = Str('') queue_len = Int(0) queue_len_str = Property(Str, depends_on=['queue_len']) error = Str('') view = View( VGroup( VGroup(Item('sqd_file', label="Data", tooltip=tooltips['sqd_file']), Item('sqd_fname', show_label=False, style='readonly'), Item('hsp_file', label='Digitizer\nHead Shape', tooltip=tooltips['hsp_file']), Item('hsp_fname', show_label=False, style='readonly'), Item('fid_file', label='Digitizer\nFiducials', tooltip=tooltips['fid_file']), Item('fid_fname', show_label=False, style='readonly'), Item('reset_dig', label='Clear Digitizer Files', show_label=False), Item('use_mrk', editor=use_editor, style='custom', tooltip=tooltips['use_mrk']), label="Sources", show_border=True), VGroup(Item('misc_chs_desc', label='MISC Channels', style='readonly'), Item('stim_slope', label="Event Onset", style='custom', tooltip=tooltips['stim_slope'], editor=EnumEditor(values={ '+': '2:Peak (0 to 5 V)', '-': '1:Trough (5 to 0 V)' }, cols=2)), Item('stim_coding', label="Value Coding", style='custom', editor=EnumEditor(values={ '>': '1:little-endian', '<': '2:big-endian', 'channel': '3:Channel#' }, cols=3), tooltip=tooltips["stim_coding"]), Item('stim_chs', label='Channels', style='custom', tooltip=tooltips["stim_chs"], editor=TextEditor(evaluate_name='stim_chs_ok', auto_set=True)), Item('stim_chs_comment', label='Evaluation', style='readonly', show_label=False), Item('stim_threshold', label='Threshold', tooltip=tooltips['stim_threshold']), HGroup(Item('test_stim', enabled_when='can_test_stim', show_label=False), Item('plot_raw', enabled_when='can_test_stim', show_label=False), show_labels=False), label='Events', show_border=True), HGroup(Item('save_as', enabled_when='can_save'), spring, 'clear_all', show_labels=False), Item('queue_feedback', show_label=False, style='readonly'), Item('queue_current', show_label=False, style='readonly'), Item('queue_len_str', show_label=False, style='readonly'))) def __init__(self, *args, **kwargs): # noqa: D102 super(Kit2FiffPanel, self).__init__(*args, **kwargs) # setup save worker def worker(): # noqa: D102 while True: raw, fname = self.queue.get() basename = os.path.basename(fname) self.queue_len -= 1 self.queue_current = 'Processing: %s' % basename # task try: raw.save(fname, overwrite=True) except Exception as err: self.error = str(err) res = "Error saving: %s" else: res = "Saved: %s" # finalize self.queue_current = '' self.queue_feedback = res % basename self.queue.task_done() t = Thread(target=worker) t.daemon = True t.start() # setup mayavi visualization self.fid_obj = PointObject(scene=self.scene, color=(0.1, 1., 0.1), point_scale=5e-3, name='Fiducials') self._update_fid() self.elp_obj = PointObject(scene=self.scene, color=(0.196, 0.196, 0.863), point_scale=1e-2, opacity=.2, name='ELP') self._update_elp() self.hsp_obj = PointObject(scene=self.scene, color=(0.784, ) * 3, point_scale=2e-3, name='HSP') self._update_hsp() self.scene.camera.parallel_scale = 0.15 self.scene.mlab.view(0, 0, .15) @on_trait_change('model:fid,model:head_dev_trans') def _update_fid(self): if self.fid_obj is not None: self.fid_obj.points = apply_trans(self.model.head_dev_trans, self.model.fid) @on_trait_change('model:hsp,model:head_dev_trans') def _update_hsp(self): if self.hsp_obj is not None: self.hsp_obj.points = apply_trans(self.model.head_dev_trans, self.model.hsp) @on_trait_change('model:elp,model:head_dev_trans') def _update_elp(self): if self.elp_obj is not None: self.elp_obj.points = apply_trans(self.model.head_dev_trans, self.model.elp) def _clear_all_fired(self): self.model.clear_all() @cached_property def _get_queue_len_str(self): if self.queue_len: return "Queue length: %i" % self.queue_len else: return '' def _plot_raw_fired(self): self.model.raw.plot() def _reset_dig_fired(self): self.reset_traits(['hsp_file', 'fid_file']) def _save_as_fired(self): # create raw try: raw = self.model.get_raw() except Exception as err: error(None, str(err), "Error Creating KIT Raw") raise # find default path stem, _ = os.path.splitext(self.sqd_file) if not stem.endswith('raw'): stem += '-raw' default_path = stem + '.fif' # save as dialog dlg = FileDialog(action="save as", wildcard="fiff raw file (*.fif)|*.fif", default_path=default_path) dlg.open() if dlg.return_code != OK: return fname = dlg.path if not fname.endswith('.fif'): fname += '.fif' if os.path.exists(fname): answer = confirm( None, "The file %r already exists. Should it " "be replaced?", "Overwrite File?") if answer != YES: return self.queue.put((raw, fname)) self.queue_len += 1 def _test_stim_fired(self): try: events = self.model.get_event_info() except Exception as err: error( None, "Error reading events from SQD data file: %s (Check " "the terminal output for details)" % str(err), "Error Reading events from SQD file") raise if len(events) == 0: information(None, "No events were found with the current " "settings.", "No Events Found") else: lines = ["Events found (ID: n events):"] for id_ in sorted(events): lines.append("%3i: \t%i" % (id_, events[id_])) information(None, '\n'.join(lines), "Events in SQD File")
class FirmwareFileDialog(HasTraits): file_wildcard = String("Intel HEX File (*.hex)|*.hex|All files|*") status = String('Please choose a file') choose_fw = Button(label='...', padding=-1) view = View( HGroup(UItem('status', resizable=True), UItem('choose_fw', width=-0.1)), ) def __init__(self, flash_type): """ Pop-up file dialog to choose an IntelHex file, with status and button to display in traitsui window. """ self.set_flash_type(flash_type) def set_flash_type(self, flash_type): """ Parameters ---------- flash_type : string Which Piksi flash to interact with ("M25" or "STM"). """ if flash_type not in ('bin', 'M25', 'STM'): raise ValueError("flash_type must be 'bin', 'M25' or 'STM'") if flash_type == 'bin': self.file_wildcard = "Binary image set (*.bin)|*.bin|All files|*" else: self.file_wildcard = "Intel HEX File (*.hex)|*.hex|All files|*" self._flash_type = flash_type self.ihx = None self.blob = None def clear(self, status): """ Set text of status box and clear IntelHex file. Parameters ---------- status : string Error text to replace status box text with. """ self.ihx = None self.blob = None self.status = status def load_ihx(self, filepath): """ Load IntelHex file and set status to indicate if file was successfully loaded. Parameters ---------- filepath : string Path to IntelHex file. """ if self._flash_type not in ('M25', 'STM'): self.clear("Error: Can't load Intel HEX File as image set binary") return try: self.ihx = IntelHex(filepath) self.status = os.path.split(filepath)[1] except HexRecordError: self.clear('Error: File is not a valid Intel HEX File') # Check that address ranges are valid for self._flash_type. ihx_addrs = flash.ihx_ranges(self.ihx) if self._flash_type == "M25": try: sectors = flash.sectors_used(ihx_addrs, flash.m25_addr_sector_map) except IndexError: self.clear('Error: HEX File contains restricted address ' + '(STM Firmware File Chosen?)') elif self._flash_type == "STM": try: sectors = flash.sectors_used(ihx_addrs, flash.stm_addr_sector_map) except: self.clear('Error: HEX File contains restricted address ' + '(NAP Firmware File Chosen?)') def load_bin(self, filepath): if self._flash_type != 'bin': self.clear("Error: Can't load binary file for M25 or STM flash") return try: self.blob = open(filepath, 'rb').read() self.status = os.path.split(filepath)[1] except: self.clear('Error: Failed to read binary file') def _choose_fw_fired(self): """ Activate file dialog window to choose IntelHex firmware file. """ dialog = FileDialog(label='Choose Firmware File', action='open', wildcard=self.file_wildcard) dialog.open() if dialog.return_code == OK: filepath = os.path.join(dialog.directory, dialog.filename) if self._flash_type == 'bin': self.load_bin(filepath) else: self.load_ihx(filepath) else: self.clear('Error while selecting file')
class SolutionView(HasTraits): python_console_cmds = Dict() lats = List() lngs = List() alts = List() table = List() dops_table = List() pos_table = List() vel_table = List() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) running = Bool(True) position_centered = Bool(False) clear_button = SVGButton( label='', tooltip='Clear', filename=os.path.join(os.path.dirname(__file__), 'images', 'iconic', 'x.svg'), width=16, height=16 ) zoomall_button = SVGButton( label='', tooltip='Zoom All', filename=os.path.join(os.path.dirname(__file__), 'images', 'iconic', 'fullscreen.svg'), width=16, height=16 ) center_button = SVGButton( label='', tooltip='Center on Solution', toggle=True, filename=os.path.join(os.path.dirname(__file__), 'images', 'iconic', 'target.svg'), width=16, height=16 ) paused_button = SVGButton( label='', tooltip='Pause', toggle_tooltip='Run', toggle=True, filename=os.path.join(os.path.dirname(__file__), 'images', 'iconic', 'pause.svg'), toggle_filename=os.path.join(os.path.dirname(__file__), 'images', 'iconic', 'play.svg'), width=16, height=16 ) traits_view = View( HSplit( Item('table', style = 'readonly', editor = TabularEditor(adapter=SimpleAdapter()), show_label=False, width=0.3), VGroup( HGroup( Item('paused_button', show_label=False), Item('clear_button', show_label=False), Item('zoomall_button', show_label=False), Item('center_button', show_label=False), ), Item( 'plot', show_label = False, editor = ComponentEditor(bgcolor = (0.8,0.8,0.8)), ) ) ) ) def _zoomall_button_fired(self): self.plot.index_range.low_setting = 'auto' self.plot.index_range.high_setting = 'auto' self.plot.value_range.low_setting = 'auto' self.plot.value_range.high_setting = 'auto' def _center_button_fired(self): self.position_centered = not self.position_centered def _paused_button_fired(self): self.running = not self.running def _clear_button_fired(self): self.lats = [] self.lngs = [] self.alts = [] self.plot_data.set_data('lat', []) self.plot_data.set_data('lng', []) self.plot_data.set_data('alt', []) self.plot_data.set_data('t', []) def _pos_llh_callback(self, data): # Updating an ArrayPlotData isn't thread safe (see chaco issue #9), so # actually perform the update in the UI thread. if self.running: GUI.invoke_later(self.pos_llh_callback, data) def update_table(self): self._table_list = self.table.items() def pos_llh_callback(self, data): soln = sbp_messages.PosLLH(data) self.pos_table = [] if self.log_file is None: self.log_file = open(time.strftime("position_log_%Y%m%d-%H%M%S.csv"), 'w') self.log_file.write('%.2f,%.4f,%.4f,%.4f,%d\n' % (soln.tow * 1e3, soln.lat, soln.lon, soln.height, soln.n_sats)) self.log_file.flush() if self.week is not None: t = datetime.datetime(1980, 1, 6) + \ datetime.timedelta(weeks=self.week) + \ datetime.timedelta(seconds=soln.tow/1e3) self.pos_table.append(('GPS Time', t)) self.pos_table.append(('GPS Week', str(self.week))) tow = soln.tow*1e-3 + self.nsec*1e-9 if self.nsec is not None: tow += self.nsec*1e-9 self.pos_table.append(('GPS ToW', tow)) self.pos_table.append(('Num. sats', soln.n_sats)) self.pos_table.append(('Lat', soln.lat)) self.pos_table.append(('Lng', soln.lon)) self.pos_table.append(('Alt', soln.height)) self.lats.append(soln.lat) self.lngs.append(soln.lon) self.alts.append(soln.height) self.lats = self.lats[-1000:] self.lngs = self.lngs[-1000:] self.alts = self.alts[-1000:] self.plot_data.set_data('lat', self.lats) self.plot_data.set_data('lng', self.lngs) self.plot_data.set_data('alt', self.alts) t = range(len(self.lats)) self.plot_data.set_data('t', t) self.table = self.pos_table + self.vel_table + self.dops_table if self.position_centered: d = (self.plot.index_range.high - self.plot.index_range.low) / 2. self.plot.index_range.set_bounds(soln.pos_llh[0] - d, soln.pos_llh[0] + d) d = (self.plot.value_range.high - self.plot.value_range.low) / 2. self.plot.value_range.set_bounds(soln.pos_llh[1] - d, soln.pos_llh[1] + d) def dops_callback(self, data): dops = sbp_messages.Dops(data) self.dops_table = [ ('PDOP', '%.1f' % (dops.pdop * 0.01)), ('GDOP', '%.1f' % (dops.gdop * 0.01)), ('TDOP', '%.1f' % (dops.tdop * 0.01)), ('HDOP', '%.1f' % (dops.hdop * 0.01)), ('VDOP', '%.1f' % (dops.vdop * 0.01)) ] self.table = self.pos_table + self.vel_table + self.dops_table def vel_ned_callback(self, data): vel_ned = sbp_messages.VelNED(data) if self.vel_log_file is None: self.vel_log_file = open(time.strftime("velocity_log_%Y%m%d-%H%M%S.csv"), 'w') self.vel_log_file.write('%.2f,%.4f,%.4f,%.4f,%.4f,%d\n' % (vel_ned.tow * 1e3, vel_ned.n, vel_ned.e, vel_ned.d, math.sqrt(vel_ned.n*vel_ned.n + vel_ned.e*vel_ned.e),vel_ned.n_sats)) self.vel_log_file.flush() self.vel_table = [ ('Vel. N', '% 8.4f' % (vel_ned.n * 1e-3)), ('Vel. E', '% 8.4f' % (vel_ned.e * 1e-3)), ('Vel. D', '% 8.4f' % (vel_ned.d * 1e-3)), ] self.table = self.pos_table + self.vel_table + self.dops_table def gps_time_callback(self, data): self.week = sbp_messages.GPSTime(data).wn self.nsec = sbp_messages.GPSTime(data).ns def __init__(self, link): super(SolutionView, self).__init__() self.log_file = None self.vel_log_file = None self.plot_data = ArrayPlotData(lat=[0.0], lng=[0.0], alt=[0.0], t=[0.0], ref_lat=[0.0], ref_lng=[0.0], region_lat=[0.0], region_lng=[0.0]) self.plot = Plot(self.plot_data) self.plot.plot(('lng', 'lat'), type='line', name='line', color=(0, 0, 0, 0.1)) self.plot.plot(('lng', 'lat'), type='scatter', name='points', color='blue', marker='dot', line_width=0.0, marker_size=1.0) self.plot.index_axis.tick_label_position = 'inside' self.plot.index_axis.tick_label_color = 'gray' self.plot.index_axis.tick_color = 'gray' self.plot.value_axis.tick_label_position = 'inside' self.plot.value_axis.tick_label_color = 'gray' self.plot.value_axis.tick_color = 'gray' self.plot.padding = (0, 1, 0, 1) self.plot.tools.append(PanTool(self.plot)) zt = ZoomTool(self.plot, zoom_factor=1.1, tool_mode="box", always_on=False) self.plot.overlays.append(zt) self.link = link self.link.add_callback(sbp_messages.SBP_POS_LLH, self._pos_llh_callback) self.link.add_callback(sbp_messages.SBP_VEL_NED, self.vel_ned_callback) self.link.add_callback(sbp_messages.SBP_DOPS, self.dops_callback) self.link.add_callback(sbp_messages.SBP_GPS_TIME, self.gps_time_callback) self.week = None self.nsec = 0 self.python_console_cmds = { 'solution': self }
class ViewHandlerMixin(HasTraits): """ Useful bits for view handlers. """ # the view for the current plot current_plot_view = \ View( HGroup( Item('plot_names_by', editor = TextEditor(), style = "readonly", show_label = False), Item('current_plot', editor = TabListEditor(name = 'plot_names'), style = 'custom', show_label = False))) plot_params_traits = View(Item('plot_params', editor = InstanceEditor(), style = 'custom', show_label = False)) context = Instance(WorkflowItem) conditions_names = Property(depends_on = "context.conditions") previous_conditions_names = Property(depends_on = "context.previous_wi.conditions") statistics_names = Property(depends_on = "context.statistics") numeric_statistics_names = Property(depends_on = "context.statistics") # MAGIC: gets value for property "conditions_names" def _get_conditions_names(self): if self.context and self.context.conditions: return sorted(list(self.context.conditions.keys())) else: return [] # MAGIC: gets value for property "previous_conditions_names" def _get_previous_conditions_names(self): if self.context and self.context.previous_wi and self.context.previous_wi.conditions: return sorted(list(self.context.previous_wi.conditions.keys())) else: return [] # MAGIC: gets value for property "statistics_names" def _get_statistics_names(self): if self.context and self.context.statistics: return sorted(list(self.context.statistics.keys())) else: return [] # MAGIC: gets value for property "numeric_statistics_names" def _get_numeric_statistics_names(self): if self.context and self.context.statistics: return sorted([x for x in list(self.context.statistics.keys()) if util.is_numeric(self.context.statistics[x])]) else: return [] @on_trait_change('context.view_error_trait', dispatch = 'ui', post_init = True) def _view_trait_error(self): # check if we're getting called on the local or remote process if self.info is None or self.info.ui is None: return for ed in self.info.ui._editors: if ed.name == self.context.view_error_trait: err_state = True else: err_state = False if not ed.label_control: continue item = ed.label_control if not err_state and not hasattr(item, '_ok_color'): continue pal = QtGui.QPalette(item.palette()) # @UndefinedVariable if err_state: setattr(item, '_ok_color', QtGui.QColor(pal.color(item.backgroundRole()))) # @UndefinedVariable pal.setColor(item.backgroundRole(), QtGui.QColor(255, 145, 145)) # @UndefinedVariable item.setAutoFillBackground(True) item.setPalette(pal) else: pal.setColor(item.backgroundRole(), item._ok_color) delattr(item, '_ok_color') item.setAutoFillBackground(False) item.setPalette(pal)
def traits_view(self): c_grp = VGroup( # HGroup(Item('setpoint'), # UItem('water_flow_state', editor=LEDEditor(label='H2O Flow')), # spring, icon_button_editor('pane.disable_button', 'cancel')), VGroup(UItem('output_percent_readback', editor=LCDEditor())), icon_button_editor('start_record_button', 'media-record', tooltip='Start recording', enabled_when='not _recording'), icon_button_editor('stop_record_button', 'media-playback-stop', tooltip='Stop recording', enabled_when='_recording'), label='Controller', show_border=True) power_grp = HGroup(UItem('pane.extract_value', width=50, enabled_when='furnace_enabled', tooltip='Power setting for furnace (0-100%)'), UItem('pane.extract_button', enabled_when='furnace_enabled', tooltip='Send the value to the furnace'), show_border=True, label='Furnace Power') # jitter_grp = HGroup(UItem('pane.jitter_button', editor=ButtonEditor(label_value='pane.jitter_label')), # icon_button_editor('pane.configure_jitter_button', 'cog', tooltip='Configure Jitter'), # show_border=True, label='Jitter') dump_grp = HGroup(UItem('pane.dump_sample_number', width=50, enabled_when='dump_sample_enabled', tooltip='Sample number to dump'), UItem('pane.dump_sample_button', enabled_when='dump_sample_enabled', tooltip='Execute the complete sample loading procedure'), UItem('pane.clear_sample_states_button'), show_border=True, label='Dump') # status_grp = HGroup(CustomLabel('status_txt', size=14)) d1 = VGroup( power_grp, dump_grp) d2 = VGroup( # UItem('pane.refresh_states_button'), UItem('dumper_canvas', editor=ComponentEditor())) d_grp = HGroup(d1, d2, label='Dumper', show_border=True) # v_grp = VGroup(UItem('video_canvas', editor=VideoComponentEditor()), # visible_when='video_enabled', # label='Camera') g_grp = VGroup(Item('graph_scan_width', label='Scan Width (mins)'), HGroup(Item('graph_scale', label='Scale'), Item('graph_y_auto', label='Autoscale Y'), Item('graph_ymax', label='Max', format_str='%0.3f', enabled_when='not graph_y_auto'), Item('graph_ymin', label='Min', format_str='%0.3f', enabled_when='not graph_y_auto')), HGroup(icon_button_editor('clear_button', 'clear', tooltip='Clear and reset graph'), spring), HGroup(icon_button_editor('start_record_button', 'media-record', tooltip='Start recording', enabled_when='not _recording'), icon_button_editor('stop_record_button', 'media-playback-stop', tooltip='Stop recording', enabled_when='_recording'), icon_button_editor('add_marker_button', 'flag', enabled_when='_recording'), show_border=True, label='Record Scan'), label='Graph') v = View(VGroup(c_grp, HGroup(Tabbed(d_grp, g_grp)))) return v
HGroup( VGroup( HGroup( # Simulation Control VGroup( Item( name="bit_rate", label="Bit Rate (Gbps)", tooltip="bit rate", show_label=True, enabled_when="True", editor=TextEditor(auto_set=False, enter_set=True, evaluate=float), ), Item( name="nbits", label="Nbits", tooltip="# of bits to run", editor=TextEditor(auto_set=False, enter_set=True, evaluate=int), ), Item( name="nspb", label="Nspb", tooltip="# of samples per bit", editor=TextEditor(auto_set=False, enter_set=True, evaluate=int), ), Item( name="mod_type", label="Modulation", tooltip="line signalling/modulation scheme", editor=CheckListEditor(values=[(0, "NRZ"), (1, "Duo-binary"), (2, "PAM-4")]), ), ), VGroup( Item(name="do_sweep", label="Do Sweep", tooltip="Run parameter sweeps."), Item( name="sweep_aves", label="SweepAves", tooltip="# of trials, per sweep, for averaging.", enabled_when="do_sweep == True", ), Item( name="pattern_len", label="PatLen", tooltip="length of random pattern to use to construct bit stream", editor=TextEditor(auto_set=False, enter_set=True, evaluate=int), ), Item( name="eye_bits", label="EyeBits", tooltip="# of bits to use to form eye diagrams", editor=TextEditor(auto_set=False, enter_set=True, evaluate=int), ), ), VGroup( Item(name="vod", label="Vod (V)", tooltip="Tx output voltage into matched load"), Item(name="rn", label="Rn (V)", tooltip="standard deviation of random noise"), Item(name="pn_mag", label="Pn (V)", tooltip="peak magnitude of periodic noise"), Item(name="pn_freq", label="f(Pn) (MHz)", tooltip="frequency of periodic noise"), ), ), label="Simulation Control", show_border=True, ), VGroup( Item( name="thresh", label="Pj Threshold (sigma)", tooltip="Threshold for identifying periodic jitter spectral elements. (sigma)", ), Item( name="impulse_length", label="Impulse Response Length (ns)", tooltip="Manual impulse response length override", ), Item(name="debug", label="Debug", tooltip="Enable to log extra information to console."), label="Analysis Parameters", show_border=True, ), ),