class IMUView(HasTraits): python_console_cmds = Dict() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) imu_temp = Float(0) imu_conf = Int(0) rms_acc_x = Float(0) rms_acc_y = Float(0) rms_acc_z = Float(0) traits_view = View( VGroup( Item( 'plot', editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)), show_label=False, ), HGroup( Item('imu_temp', format_str='%.2f C'), Item('imu_conf', format_str='0x%02X'), Item('rms_acc_x', format_str='%.2f g'), Item('rms_acc_y', format_str='%.2f g'), Item('rms_acc_z', format_str='%.2f g'), ), )) def imu_set_data(self): self.plot_data.set_data('acc_x', self.acc[:, 0]) self.plot_data.set_data('acc_y', self.acc[:, 1]) self.plot_data.set_data('acc_z', self.acc[:, 2]) self.plot_data.set_data('gyr_x', self.gyro[:, 0]) self.plot_data.set_data('gyr_y', self.gyro[:, 1]) self.plot_data.set_data('gyr_z', self.gyro[:, 2]) def imu_aux_callback(self, sbp_msg, **metadata): if sbp_msg.imu_type == 0: self.imu_temp = 23 + sbp_msg.temp / 2.**9 self.imu_conf = sbp_msg.imu_conf else: print("IMU type %d not known" % sbp_msg.imu_type) def imu_raw_callback(self, sbp_msg, **metadata): self.acc[:-1, :] = self.acc[1:, :] self.gyro[:-1, :] = self.gyro[1:, :] self.acc[-1] = (sbp_msg.acc_x, sbp_msg.acc_y, sbp_msg.acc_z) self.gyro[-1] = (sbp_msg.gyr_x, sbp_msg.gyr_y, sbp_msg.gyr_z) if self.imu_conf is not None: acc_range = self.imu_conf & 0xF sf = 2.**(acc_range + 1) / 2.**15 self.rms_acc_x = sf * np.sqrt(np.mean(np.square(self.acc[:, 0]))) self.rms_acc_y = sf * np.sqrt(np.mean(np.square(self.acc[:, 1]))) self.rms_acc_z = sf * np.sqrt(np.mean(np.square(self.acc[:, 2]))) def __init__(self, link): super(IMUView, self).__init__() self.acc = np.zeros((NUM_POINTS, 3)) self.gyro = np.zeros((NUM_POINTS, 3)) self.plot_data = ArrayPlotData(t=np.arange(NUM_POINTS), acc_x=[0.0], acc_y=[0.0], acc_z=[0.0], gyr_x=[0.0], gyr_y=[0.0], gyr_z=[0.0]) self.plot = Plot(self.plot_data, auto_colors=colours_list, emphasized=True) self.plot.title = 'Raw IMU Data' self.plot.title_color = [0, 0, 0.43] self.ylim = self.plot.value_mapper.range self.ylim.low = -32768 self.ylim.high = 32767 # self.plot.value_range.bounds_func = lambda l, h, m, tb: (0, h * (1 + m)) self.plot.value_axis.orientation = 'right' self.plot.value_axis.axis_line_visible = False self.plot.value_axis.title = 'LSB count' call_repeatedly(0.2, self.imu_set_data) self.legend_visible = True self.plot.legend.visible = True self.plot.legend.align = 'll' self.plot.legend.line_spacing = 1 self.plot.legend.font = 'modern 8' self.plot.legend.draw_layer = 'overlay' self.plot.legend.tools.append( LegendTool(self.plot.legend, drag_button="right")) acc_x = self.plot.plot(('t', 'acc_x'), type='line', color='auto', name='Accn. X') acc_x = self.plot.plot(('t', 'acc_y'), type='line', color='auto', name='Accn. Y') acc_x = self.plot.plot(('t', 'acc_z'), type='line', color='auto', name='Accn. Z') acc_x = self.plot.plot(('t', 'gyr_x'), type='line', color='auto', name='Gyro X') acc_x = self.plot.plot(('t', 'gyr_y'), type='line', color='auto', name='Gyro Y') acc_x = self.plot.plot(('t', 'gyr_z'), type='line', color='auto', name='Gyro Z') self.link = link self.link.add_callback(self.imu_raw_callback, SBP_MSG_IMU_RAW) self.link.add_callback(self.imu_aux_callback, SBP_MSG_IMU_AUX) self.python_console_cmds = {'track': self}
class Confocal( ManagedJob, GetSetItemsMixin ): (Item('submit_gsd_button', show_label=False), Item('remove_gsd_button', show_label=False), Item('priority_gsd'), Item('state_gsd', style='readonly'), Item('history_back_gsd', show_label=False), Item('history_forward_gsd', show_label=False), # scanner position x = Range(low=scanner.getXRange()[0], high=scanner.getXRange()[1], value=0.5*(scanner.getXRange()[0]+scanner.getXRange()[1]), desc='x [micron]', label='x [micron]', mode='slider') y = Range(low=scanner.getYRange()[0], high=scanner.getYRange()[1], value=0.5*(scanner.getYRange()[0]+scanner.getYRange()[1]), desc='y [micron]', label='y [micron]', mode='slider') z = Range(low=scanner.getZRange()[0], high=scanner.getZRange()[1], value=0.5*(scanner.getZRange()[0]+scanner.getZRange()[1]), desc='z [micron]', label='z [micron]', mode='slider') # imagging parameters x1 = Range(low=scanner.getXRange()[0], high=scanner.getXRange()[1], value=scanner.getXRange()[0], desc='x1 [micron]', label='x1', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) y1 = Range(low=scanner.getYRange()[0], high=scanner.getYRange()[1], value=scanner.getYRange()[0], desc='y1 [micron]', label='y1', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) z1 = Range(low=scanner.getZRange()[0], high=scanner.getZRange()[1], value=scanner.getZRange()[0], desc='z1 [micron]', label='z1', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) x2 = Range(low=scanner.getXRange()[0], high=scanner.getXRange()[1], value=scanner.getXRange()[1], desc='x2 [micron]', label='x2', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) y2 = Range(low=scanner.getYRange()[0], high=scanner.getYRange()[1], value=scanner.getYRange()[1], desc='y2 [micron]', label='y2', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) z2 = Range(low=scanner.getZRange()[0], high=scanner.getZRange()[1], value=scanner.getZRange()[1], desc='z2 [micron]', label='z2', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%.2f')) resolution = Range(low=1, high=1000, value=100, desc='Number of point in long direction', label='resolution', auto_set=False, enter_set=True) seconds_per_point = Range(low=1e-3, high=10, value=0.005, desc='Seconds per point [s]', label='Seconds per point [s]', mode='text', auto_set=False, enter_set=True) bidirectional = Bool( True ) return_speed = Range(low=1.0, high=100., value=10., desc='Multiplier for return speed of Scanner if mode is monodirectional', label='return speed', mode='text', auto_set=False, enter_set=True) constant_axis = Enum('z', 'x', 'y', label='constant axis', desc='axis that is not scanned when acquiring an image', editor=EnumEditor(values={'x':'1:x','y':'2:y','z':'3:z',},cols=3),) # buttons history_back = Button(label='Back') history_forward = Button(label='Forward') reset_range = Button(label='reset range') reset_cursor = Button(label='reset position') # plot parameters thresh_high = Trait( 'auto', Str('auto'), Float(10000.), desc='High Limit of image plot', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float)) thresh_low = Trait( 'auto', Str('auto'), Float(0.), desc='Low Limit of image plot', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float)) colormap = Enum('Spectral','gray') show_labels = Bool(False) # scan data X = Array() Y = Array() image = Array() # plots plot_data = Instance( ArrayPlotData ) scan_plot = Instance( CMapImagePlot ) cursor = Instance( CursorTool2D ) zoom = Instance( AspectZoomTool ) figure = Instance( Plot ) figure_container = Instance( HPlotContainer, editor=ComponentEditor() ) z_label_text = Str('z:0.0') cursor_position = Property(depends_on=['x','y','z','constant_axis']) get_set_items=['constant_axis', 'X', 'Y', 'thresh_high', 'thresh_low', 'seconds_per_point', 'return_speed', 'bidirectional', 'history', 'image', 'z_label_text', 'resolution', 'x', 'x1', 'x2', 'y', 'y1', 'y2', 'z', 'z1', 'z2'] def __init__(self): super(Confocal, self).__init__() self.X = numpy.linspace(scanner.getXRange()[0], scanner.getXRange()[-1], self.resolution+1) self.Y = numpy.linspace(scanner.getYRange()[0], scanner.getYRange()[-1], self.resolution+1) self.image = numpy.zeros((len(self.X), len(self.Y))) self._create_plot() self.figure.index_range.on_trait_change(self.update_axis_li, '_low_value', dispatch='ui') self.figure.index_range.on_trait_change(self.update_axis_hi, '_high_value', dispatch='ui') self.figure.value_range.on_trait_change(self.update_axis_lv, '_low_value', dispatch='ui') self.figure.value_range.on_trait_change(self.update_axis_hv, '_high_value', dispatch='ui') self.zoom.on_trait_change(self.check_zoom, 'box', dispatch='ui') self.on_trait_change(self.set_mesh_and_aspect_ratio, 'X,Y', dispatch='ui') self.on_trait_change(self.update_image_plot, 'image', dispatch='ui') self.sync_trait('cursor_position', self.cursor, 'current_position') self.sync_trait('thresh_high', self.scan_plot.value_range, 'high_setting') self.sync_trait('thresh_low', self.scan_plot.value_range, 'low_setting') self.on_trait_change(self.scan_plot.request_redraw, 'thresh_high', dispatch='ui') self.on_trait_change(self.scan_plot.request_redraw, 'thresh_low', dispatch='ui') self.history = History(length = 10) self.history.put( self.copy_items(['constant_axis', 'X', 'Y', 'image', 'z_label_text', 'resolution'] ) ) self.labels = {} self.label_list = [] # scanner position @on_trait_change('x,y,z') def _set_scanner_position(self): if self.state != 'run': scanner.setPosition(self.x, self.y, self.z) @cached_property def _get_cursor_position(self): if self.constant_axis == 'x': return self.z, self.y elif self.constant_axis == 'y': return self.x, self.z elif self.constant_axis == 'z': return self.x, self.y def _set_cursor_position(self, position): if self.constant_axis == 'x': self.z, self.y = position elif self.constant_axis == 'y': self.x, self.z = position elif self.constant_axis == 'z': self.x, self.y = position # image acquisition def _run(self): """Acquire a scan""" try: self.state='run' self.update_mesh() X = self.X Y = self.Y XP = X[::-1] self.image=numpy.zeros((len(Y),len(X))) """ if not self.bidirectional: scanner.initImageScan(len(X), len(Y), self.seconds_per_point, return_speed=self.return_speed) else: scanner.initImageScan(len(X), len(Y), self.seconds_per_point, return_speed=None) """ for i,y in enumerate(Y): if threading.current_thread().stop_request.isSet(): break if i%2 != 0 and self.bidirectional: XL = XP else: XL = X YL = y * numpy.ones(X.shape) if self.constant_axis == 'x': const = self.x * numpy.ones(X.shape) Line = numpy.vstack( (const, YL, XL) ) elif self.constant_axis == 'y': const = self.y * numpy.ones(X.shape) Line = numpy.vstack( (XL, const, YL) ) elif self.constant_axis == 'z': const = self.z * numpy.ones(X.shape) Line = numpy.vstack( (XL, YL, const) ) if self.bidirectional: c = scanner.scanLine(Line, self.seconds_per_point) else: c = scanner.scanLine(Line, self.seconds_per_point, return_speed=self.return_speed) if i%2 != 0 and self.bidirectional: self.image[i,:] = c[-1::-1] else: self.image[i,:] = c[:] """ scanner.doImageLine(Line) self.image = scanner.getImage() """ self.trait_property_changed('image', self.image) if self.constant_axis == 'x': self.z_label_text='x:%.2f'%self.x elif self.constant_axis == 'y': self.z_label_text='y:%.2f'%self.y elif self.constant_axis == 'z': self.z_label_text='z:%.2f'%self.z """ # block at the end until the image is ready if not threading.current_thread().stop_request.isSet(): self.image = scanner.getImage(1) self._image_changed() """ scanner.setPosition(self.x, self.y, self.z) #save scan data to history self.history.put( self.copy_items(['constant_axis', 'X', 'Y', 'image', 'z_label_text', 'resolution'] ) ) finally: self.state = 'idle' # plotting def _create_plot(self): plot_data = ArrayPlotData(image=self.image) plot = Plot(plot_data, width=500, height=500, resizable='hv', aspect_ratio=1.0, padding=8, padding_left=32, padding_bottom=32) plot.img_plot('image', colormap=Spectral, xbounds=(self.X[0],self.X[-1]), ybounds=(self.Y[0],self.Y[-1]), name='image') image = plot.plots['image'][0] image.x_mapper.domain_limits = (scanner.getXRange()[0],scanner.getXRange()[1]) image.y_mapper.domain_limits = (scanner.getYRange()[0],scanner.getYRange()[1]) zoom = AspectZoomTool(image, enable_wheel=False) cursor = CursorTool2D(image, drag_button='left', color='blue', marker_size=1.0, line_width=1.0 ) image.overlays.append(cursor) image.overlays.append(zoom) colormap = image.color_mapper colorbar = ColorBar(index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, plot=plot, orientation='v', resizable='v', width=16, height=320, padding=8, padding_left=32) container = HPlotContainer() container.add(plot) container.add(colorbar) z_label = PlotLabel(text='z=0.0', color='red', hjustify='left', vjustify='bottom', position=[10,10]) container.overlays.append(z_label) self.plot_data = plot_data self.scan_plot = image self.cursor = cursor self.zoom = zoom self.figure = plot self.figure_container = container self.sync_trait('z_label_text', z_label, 'text') def set_mesh_and_aspect_ratio(self): self.scan_plot.index.set_data(self.X,self.Y) x1=self.X[0] x2=self.X[-1] y1=self.Y[0] y2=self.Y[-1] self.figure.aspect_ratio = (x2-x1) / float((y2-y1)) self.figure.index_range.low = x1 self.figure.index_range.high = x2 self.figure.value_range.low = y1 self.figure.value_range.high = y2 def check_zoom(self, box): li,lv,hi,hv=box if self.constant_axis == 'x': if not li<self.z<hi: self.z = 0.5*(li+hi) if not lv<self.y<hv: self.y = 0.5*(lv+hv) elif self.constant_axis == 'y': if not li<self.x<hi: self.x = 0.5*(li+hi) if not lv<self.z<hv: self.z = 0.5*(lv+hv) elif self.constant_axis == 'z': if not li<self.x<hi: self.x = 0.5*(li+hi) if not lv<self.y<hv: self.y = 0.5*(lv+hv) def center_cursor(self): i = 0.5 * (self.figure.index_range.low + self.figure.index_range.high) v = 0.5 * (self.figure.value_range.low + self.figure.value_range.high) if self.constant_axis == 'x': self.z = i self.y = v elif self.constant_axis == 'y': self.x = i self.z = v elif self.constant_axis == 'z': self.x = i self.y = v def _constant_axis_changed(self): self.update_mesh() self.image = numpy.zeros((len(self.X), len(self.Y))) self.update_axis() self.set_mesh_and_aspect_ratio() def update_image_plot(self): self.plot_data.set_data('image', self.image) def _colormap_changed(self, new): data = self.figure.datasources['image'] func = getattr(chaco.api,new) self.figure.color_mapper=func(DataRange1D(data)) self.figure.request_redraw() def _show_labels_changed(self, name, old, new): for item in self.scan_plot.overlays: if isinstance(item, DataLabel) and item.label_format in self.labels: item.visible = new self.scan_plot.request_redraw() def get_label_index(self, key): for index, item in enumerate(self.scan_plot.overlays): if isinstance(item, DataLabel) and item.label_format == key: return index return None def set_label(self, key, coordinates, **kwargs): plot = self.scan_plot if self.constant_axis == 'x': point = (coordinates[2],coordinates[1]) elif self.constant_axis == 'y': point = (coordinates[0],coordinates[2]) elif self.constant_axis == 'z': point = (coordinates[0],coordinates[1]) defaults = {'component':plot, 'data_point':point, 'label_format':key, 'label_position':'top right', 'bgcolor':'transparent', 'text_color':'black', 'border_visible':False, 'padding_bottom':8, 'marker':'cross', 'marker_color':'black', 'marker_line_color':'black', 'marker_line_width':1.5, 'marker_size':6, 'arrow_visible':False, 'clip_to_plot':False, 'visible':self.show_labels} defaults.update(kwargs) label = DataLabel(**defaults) index = self.get_label_index(key) if index is None: plot.overlays.append(label) else: plot.overlays[index] = label self.labels[key] = coordinates plot.request_redraw() def remove_label(self, key): plot = self.scan_plot index = self.get_label_index(key) plot.overlays.pop(index) plot.request_redraw() self.labels.pop(key) def remove_all_labels(self): plot = self.scan_plot new_overlays = [] for item in plot.overlays: if not ( isinstance(item, DataLabel) and item.label_format in self.labels ) : new_overlays.append(item) plot.overlays = new_overlays plot.request_redraw() self.labels.clear() @on_trait_change('constant_axis') def relocate_labels(self): for item in self.scan_plot.overlays: if isinstance(item, DataLabel) and item.label_format in self.labels: coordinates = self.labels[item.label_format] if self.constant_axis == 'x': point = (coordinates[2],coordinates[1]) elif self.constant_axis == 'y': point = (coordinates[0],coordinates[2]) elif self.constant_axis == 'z': point = (coordinates[0],coordinates[1]) item.data_point = point def update_axis_li(self): if self.constant_axis == 'x': self.z1 = self.figure.index_range.low elif self.constant_axis == 'y': self.x1 = self.figure.index_range.low elif self.constant_axis == 'z': self.x1 = self.figure.index_range.low def update_axis_hi(self): if self.constant_axis == 'x': self.z2 = self.figure.index_range.high elif self.constant_axis == 'y': self.x2 = self.figure.index_range.high elif self.constant_axis == 'z': self.x2 = self.figure.index_range.high def update_axis_lv(self): if self.constant_axis == 'x': self.y1 = self.figure.value_range.low elif self.constant_axis == 'y': self.z1 = self.figure.value_range.low elif self.constant_axis == 'z': self.y1 = self.figure.value_range.low def update_axis_hv(self): if self.constant_axis == 'x': self.y2 = self.figure.value_range.high elif self.constant_axis == 'y': self.z2 = self.figure.value_range.high elif self.constant_axis == 'z': self.y2 = self.figure.value_range.high def update_axis(self): self.update_axis_li() self.update_axis_hi() self.update_axis_lv() self.update_axis_hv() def update_mesh(self): if self.constant_axis == 'x': x1=self.z1 x2=self.z2 y1=self.y1 y2=self.y2 elif self.constant_axis == 'y': x1=self.x1 x2=self.x2 y1=self.z1 y2=self.z2 elif self.constant_axis == 'z': x1=self.x1 x2=self.x2 y1=self.y1 y2=self.y2 if (x2-x1) >= (y2-y1): self.X = numpy.linspace(x1,x2,self.resolution) self.Y = numpy.linspace(y1,y2,int(self.resolution*(y2-y1)/(x2-x1))) else: self.Y = numpy.linspace(y1,y2,self.resolution) self.X = numpy.linspace(x1,x2,int(self.resolution*(x2-x1)/(y2-y1))) # GUI buttons def _history_back_fired(self): self.stop() self.set_items( self.history.back() ) def _history_forward_fired(self): self.stop() self.set_items( self.history.forward() ) def _reset_range_fired(self): self.x1 = scanner.getXRange()[0] self.x2 = scanner.getXRange()[1] self.y1 = scanner.getYRange()[0] self.y2 = scanner.getYRange()[1] self.z1 = scanner.getZRange()[0] self.z2 = scanner.getZRange()[1] def _reset_cursor_fired(self): self.center_cursor() # saving images def save_image(self, filename=None): self.save_figure(self.figure_container, filename) traits_view = View(VGroup(Hsplit(HGroup(HGroup(Item('submit_button', show_label=False), Item('remove_button', show_label=False), Item('priority'), Item('state', style='readonly'), Item('history_back', show_label=False), Item('history_forward', show_label=False), ), Item('figure_container', show_label=False, resizable=True,enabled_when='state != "run"'), HGroup(Item('thresh_low', width=-80), Item('thresh_high', width=-80), Item('colormap', width=-100), Item('show_labels'), ), ), HGroup(HGroup(Item('submit_gsd_button', show_label=False), Item('remove_button', show_label=False), Item('history_back_gsd', show_label=False), Item('history_forward_gsd', show_label=False), ), Item('figure_container_gsd', show_label=False, resizable=True,enabled_when='state != "run"'), HGroup(Item('thresh_low_gsd', width=-80), Item('thresh_high_gsd', width=-80), Item('colormap_gsd', width=-100), Item('show_labels'), ), ), ), HGroup(Item('resolution', enabled_when='state != "run"', width=-60), Item('x1', width=-60), Item('x2', width=-60), Item('y1', width=-60), Item('y2', width=-60), Item('z1', width=-60), Item('z2', width=-60), Item('reset_range', show_label=False), ), HGroup(Item('constant_axis', style='custom', show_label=False, enabled_when='state != "run"'), Item('bidirectional', enabled_when='state != "run"'), Item('seconds_per_point', width=-80), Item('return_speed', width=-80), Item('reset_cursor', show_label=False), ), Item('x', enabled_when='state != "run" or (state == "run" and constant_axis == "x")'), Item('y', enabled_when='state != "run" or (state == "run" and constant_axis == "y")'), Item('z', enabled_when='state != "run" or (state == "run" and constant_axis == "z")'), ), menubar = MenuBar(Menu(Action(action='save_image', name='Save Image (.png)'), Action(action='save', name='Save (.pyd or .pys)'), Action(action='load', name='Load'), Action(action='_on_close', name='Quit'), name='File'),), title='Confocal', width=880, height=800, buttons=[], resizable=True, x=0, y=0, handler=GetSetSaveImageHandler)
class MandelbrotView(ModelView): """ Traits UI and Chaco view of a Mandelbrot set. """ # The model part of this UI. model = Instance(MandelbrotParameters) # The Chaco plot. mandelbrot_plot = Instance(Plot) def _mandelbrot_plot_default(self): return self._create_mandelbrot_plot() # The Chaco data source for the Mandelbrot set. mandelbrot_plot_data = Instance(ArrayPlotData) def _mandelbrot_plot_data_default(self): plot_data = ArrayPlotData() self._set_plot_data(plot_data) return plot_data # The Chaco plot renderer. mandelbrot_renderer = Instance(AbstractPlotRenderer) # A button that resets the view to the default one. reset_view = Button def _reset_view_fired(self): self.model.set(xmin=-2, xmax=1, ymin=-1.5, ymax=1.5) # The colormap of the plot. colormap = Enum(dc.color_map_name_dict.keys()) @on_trait_change('colormap') def set_colormap(self): data_range = DataRange1D(low=-1.0, high=200) colormap = dc.color_map_name_dict[self.colormap](data_range) self.mandelbrot_renderer.color_mapper = colormap self.mandelbrot_renderer.invalidate_and_redraw() @on_trait_change('model:xmin,model:xmax,model:ymin,model:ymax') def _update_plot_data_and_bounds(self): """ Update the image data and the plot bounds when the bounds change. """ self._set_plot_data(self.mandelbrot_plot_data) self.mandelbrot_plot = self._create_mandelbrot_plot() def _create_mandelbrot_plot(self): plot = Plot(self.mandelbrot_plot_data) self.mandelbrot_renderer = plot.img_plot( 'mandelbrot', xbounds=self.model.x_coords, ybounds=self.model.y_coords, name='mandelbrot_plot')[0] plot.aspect_ratio = 1.0 plot.tools.append(MandelzoomTool(component=plot, params=self.model)) self.set_colormap() return plot def _set_plot_data(self, plot_data): mandelbrot = mandelbrot_grid( self.model.x_bounds, self.model.y_bounds, self.model.grid_size ) plot_data.set_data('mandelbrot', mandelbrot) # Traits UI definition of the UI. traits_view = View( VGroup( Item('mandelbrot_plot', editor=ComponentEditor(), show_label=False), HGroup( Item('colormap'), Item('reset_view', show_label=False) ), ), resizable=True, )
class GSODDataPlotterView(HasTraits): """ Application of the zoom tool to the GSOD plotting tool. Load a HDF file containing one or more timeseries and plot the entire data inside. The zoom tool allows to explore a subset of it. The legend allows to (de)select some timeseries. """ data_file = File() ts_data = Dict() ts_plot = Instance(ToolbarPlot) index_is_dates = Bool() traits_view = View( VGroup( Item('data_file', style='simple', label="HDF file to load"), Item('ts_plot', editor=ComponentEditor(size=(800, 600)), show_label=False), ), title='Chaco Plot with file loader and legend highlighter', width=900, height=800, resizable=True) def __init__(self, pandas_list=[], array_dict={}, *args, **kw): """ If a (list of) pandas or a dict of arrays is passed, load them up. """ ts_data = {} super(GSODDataPlotterView, self).__init__(*args, **kw) if not isinstance(pandas_list, list): pandas_list = [pandas_list] if pandas_list: array_dict, self.index_is_dates = pandas2array_dict(pandas_list) ts_data.update(array_dict) if array_dict: ts_data.update(ts_dict) self.ts_data = ts_data # Now trigger the plot redraw def _data_file_changed(self): """ Update the data from the HDF5 file. """ ts_data, self.index_is_dates = pandas_hdf_to_data_dict2(self.data_file) assert ("index" in ts_data) self.ts_data = ts_data def _ts_data_changed(self): """ Dataset has changed: update the plot. ENH: add the possibility to pass a dict to ArrayPlotData. """ print "data changed: updating the plot..." arr_data = ArrayPlotData() for k, v in self.ts_data.items(): arr_data.set_data(k, v) self.ts_plot = ToolbarPlot(arr_data) for i, k in enumerate([k for k in self.ts_data.keys() if k != "index"]): self.ts_plot.plot(("index", k), name=k, color=colors[i % len(colors)]) if self.index_is_dates: # Index was an array of datetime: overwrite the x axis self.ts_plot.x_axis = None x_axis = PlotAxis(self.ts_plot, orientation="bottom", tick_generator=ScalesTickGenerator( scale=CalendarScaleSystem())) self.ts_plot.overlays.append(x_axis) self.ts_plot.x_grid.tick_generator = x_axis.tick_generator if self.data_file: self.ts_plot.title = "Time series visualization from %s" % self.data_file else: self.ts_plot.title = "Time series visualization" attach_tools(self.ts_plot)
class App(HasTraits): audio_stream = Instance(AudioStream, ()) timer = Instance(Timer) decoder = Instance(SpeechDecoder) data_queue = Instance(Collapsible, ()) results_queue = Instance(queue.Queue, ()) decoder_thread = Instance(threading.Thread) spectrum_data = Instance(ArrayPlotData) time_data = Instance(ArrayPlotData) spectrogram_plotdata = Instance(ArrayPlotData) text = Str plot = Instance(Component) traits_view = View( VGroup( Group(Item('plot', editor=ComponentEditor(size=(900, 500)), show_label=False), orientation="vertical"), UItem('text', style='custom'), ), resizable=True, title="Audio Spectrum", width=900, height=500, ) def start(self): self.audio_stream.start() self.decoder_thread.start() self.timer = Timer(20, self.update) def stop(self): self.timer.Stop() self.data_queue.put(DONE) self.decoder_thread.join() self.audio_stream.stop() def update(self): audio_data = self.audio_stream.get_audio_data() normalized_time = audio_data / 32768.0 spectrum = np.abs(scipy.fft(normalized_time))[:NUM_SAMPLES // 2] # Update plot data self.spectrum_data.set_data('amplitude', spectrum) self.time_data.set_data('amplitude', normalized_time) spectrogram_data = self.spectrogram_plotdata.get_data('imagedata') spectrogram_data = np.hstack( (spectrogram_data[:, 1:], np.transpose([spectrum]))) self.spectrogram_plotdata.set_data('imagedata', spectrogram_data) # Update decoder self.data_queue.put(audio_data) try: self.text += self.results_queue.get_nowait() except queue.Empty: pass def _decoder_default(self): return SpeechDecoder.from_paths( model="deepspeech-0.5.1-models/output_graph.pbmm", alphabet="deepspeech-0.5.1-models/alphabet.txt", lm="deepspeech-0.5.1-models/lm.binary", trie="deepspeech-0.5.1-models/trie") def _decoder_thread_default(self): return threading.Thread(target=self._transcribe) def _transcribe(self): self.decoder.start() done = False while not done: for _ in range(8): data = self.data_queue.get() if data is DONE: done = True break self.decoder.update_content(data) result = self.decoder.decode() self.results_queue.put(result) self.decoder.stop() def _spectrum_data_default(self): frequencies = np.linspace(0.0, SAMPLING_RATE / 2, num=NUM_SAMPLES // 2) spectrum_data = ArrayPlotData(frequency=frequencies) empty_amplitude = np.zeros(NUM_SAMPLES // 2) spectrum_data.set_data('amplitude', empty_amplitude) return spectrum_data def _time_data_default(self): ts = np.linspace(0.0, NUM_SAMPLES / SAMPLING_RATE, num=NUM_SAMPLES) time_data = ArrayPlotData(time=ts) empty_amplitude = np.zeros(NUM_SAMPLES) time_data.set_data('amplitude', empty_amplitude) return time_data def _spectrogram_plotdata_default(self): spectrogram_data = np.zeros((NUM_SAMPLES // 2, SPECTROGRAM_LENGTH)) spectrogram_plotdata = ArrayPlotData() spectrogram_plotdata.set_data('imagedata', spectrogram_data) return spectrogram_plotdata def _plot_default(self): # Set up the spectrum plot spectrum_plot = Plot(self.spectrum_data) spectrum_plot.plot(("frequency", "amplitude"), name="Spectrum", color="red") spectrum_plot.padding = 50 spectrum_plot.title = "Spectrum" spec_range = list( spectrum_plot.plots.values())[0][0].value_mapper.range # noqa spec_range.low = 0.0 spec_range.high = 5.0 spectrum_plot.index_axis.title = 'Frequency (Hz)' spectrum_plot.value_axis.title = 'Amplitude' # Time series plot time_plot = Plot(self.time_data) time_plot.plot(("time", "amplitude"), name="Time", color="blue") time_plot.padding = 50 time_plot.title = "Time" time_plot.index_axis.title = 'Time (seconds)' time_plot.value_axis.title = 'Amplitude' time_range = list(time_plot.plots.values())[0][0].value_mapper.range time_range.low = -0.2 time_range.high = 0.2 # Spectrogram plot spectrogram_plot = Plot(self.spectrogram_plotdata) max_time = SPECTROGRAM_LENGTH * NUM_SAMPLES / SAMPLING_RATE max_freq = SAMPLING_RATE / 2 spectrogram_plot.img_plot( 'imagedata', name='Spectrogram', xbounds=(0, max_time), ybounds=(0, max_freq), colormap=hot, ) range_obj = spectrogram_plot.plots['Spectrogram'][0].value_mapper.range range_obj.high = 5 range_obj.low = 0.0 spectrogram_plot.title = 'Spectrogram' container = HPlotContainer() container.add(spectrum_plot) container.add(time_plot) container.add(spectrogram_plot) return container
class TimeTrace( GetSetItemsMixin ): number_of_points = Int(200, desc='Length of Count Trace', label='Number of points', mode='text', auto_set=False, enter_set=True) seconds_per_point = Float(0.05, desc='Seconds per point [s]', label='Seconds per point [s]', mode='text', auto_set=False, enter_set=True) # trace data count_rate = Array() time = Array() enable_0 = Bool(True, label='channel 0', desc='enable channel 0') enable_1 = Bool(False, label='channel 1', desc='enable channel 1') enable_2 = Bool(False, label='channel 2', desc='enable channel 2') enable_3 = Bool(False, label='channel 3', desc='enable channel 3') enable_4 = Bool(False, label='channel 4', desc='enable channel 4') enable_5 = Bool(False, label='channel 5', desc='enable channel 5') enable_6 = Bool(False, label='channel 6', desc='enable channel 6') enable_7 = Bool(False, label='channel 7', desc='enable channel 7') channels = Instance( list, factory=list ) plot = Instance( Plot ) plot_data = Instance( ArrayPlotData ) start_button = Button(label='start', show_label=False) stop_button = Button(label='stop', show_label=False) clear_button = Button(label='clear', show_label=False) get_set_items= ['count_rate', 'time', 'channels', 'number_of_points', 'seconds_per_point'] def __init__(self, tagger, **kwargs): super(TimeTrace, self).__init__(**kwargs) self.tagger = tagger self._reset() def _channels_default(self): return list(np.arange(8)[np.array([self.enable_0, self.enable_1, self.enable_2, self.enable_3, self.enable_4, self.enable_5, self.enable_6, self.enable_7])]) @on_trait_change('enable_0,enable_1,enable_2,enable_3,enable_4,enable_5,enable_6,enable_7') def _update_channels(self): self.channels = self._channels_default() @on_trait_change('channels,number_of_points,seconds_per_point') def _reset(self): if hasattr(self,'_timer'): self._timer.Stop() self._create_plot() self._counter = Counter(self.tagger, self.channels, int(self.seconds_per_point*1e12), self.number_of_points) self.time = self._counter.getIndex() * 1e-12 self.count_rate = self._counter.getData() / self.seconds_per_point self._timer = Timer(100, self._refresh_data) self._timer.Start() def _refresh_data(self): self.count_rate = self._counter.getData() / self.seconds_per_point def _count_rate_changed(self, new): for i, line_i in enumerate(new): self.plot_data.set_data('channel_'+str(self.channels[i]), line_i) def _time_changed(self, new): self.plot_data.set_data('time', new) def _create_plot(self): kwargs = {} for i, channel_i in enumerate(self.channels): kwargs['channel_'+str(channel_i)] = np.array(()) data = ArrayPlotData(time=np.array(()), **kwargs) plot = Plot(data, width=100, height=100, resizable='hv', padding_left=96, padding_bottom=32) plot.index_axis.title = 'time [s]' plot.value_axis.title = 'count rate [counts/s]' color_map = {0:'blue', 1:'red', 2:'green', 3:'black', 4:'brown', 5:'yellow', 6:'magenta', 7:'cyan'} for channel in self.channels: plot.plot(('time','channel_'+str(channel)), type='line', color=color_map[channel], name='channel '+str(channel)) plot.legend.align = 'll' if len(self.channels) > 1: plot.legend.visible = True else: plot.legend.visible = False self.plot_data = data self.plot = plot def _clear_button_fired(self): self._counter.clear() self.count_rate = self._counter.getData() def _start_button_fired(self): self._counter.start() self._timer.Start() def _stop_button_fired(self): self._counter.stop() self._timer.Stop() def __del__(self): self._timer.Stop() traits_view = View(VGroup( HGroup(Item('clear_button', show_label=False), Item('start_button', show_label=False), Item('stop_button', show_label=False), Item('save_button', show_label=False), ), HGroup(Item('plot', editor=ComponentEditor(size=(100,100)), show_label=False), VGroup(Item('enable_0'), Item('enable_1'), Item('enable_2'), Item('enable_3'), Item('enable_4'), Item('enable_5'), Item('enable_6'), Item('enable_7'), ), ), HGroup(Item('number_of_points'), Item ('seconds_per_point'), ), ), title='Counter', width=780, height=520, buttons=[], 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_signals,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. Signals', 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_signals\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 PandasPlot(HasTraits): '''Plot to interface a pandas df''' ### For testing rnd_cols = Bool(False) samecols = Bool(False) transpose = Bool(False) ### Traits of the actual plot and plotdatasource handler ### _dffull = Instance(DataFrame) #Any? plot = Instance(Plot) plotdata = Instance( PandasPlotData) #Data stored at any given time in the plot df = Instance(DataFrame) ### Axis traits idxname = Str('Index') colname = Str('Column') idxorient = DefaultEnum('top', 'bottom', 'left', 'right', default='bottom') colorient = DefaultEnum('top', 'bottom', 'left', 'right', default='top') selection_axis = DefaultEnum( 'index', 'value', default='index') #Which axis does selection tool sample ### Aesthetic traits title = Str('Title') #Defaults from df name linecolor = Str('yellow') pointcolor = Str('red') linestyle = Enum('line', 'scatter', 'both') markersize = Range(low=1, high=5) sampling = Range(low=0.0, high=100., value=100.0) _spacing = Property(depends_on='sampling') ### _Event Handlers def _rnd_cols_changed(self): x = np.linspace(0, 100, 100) #Index generator y = np.linspace(0, 100, 100) #Column generator scale = randint(1, 1000) self.df = DataFrame((np.random.rand(len(x), len(y))), columns=(scale / 2.0) * y, index=scale * x) def _samecols_changed(self): self.df = DataFrame((np.random.rand(100, 100))) def _transpose_changed(self): self.df = self.df.transpose() ### Axis Aesthetics @on_trait_change('idxname', 'idxcolumn', 'idxorient', 'colorient') def _axis_changed(self, trait, new): '''Change plot axis name or orientation''' setattr(self, trait, new) self._update_axis() self.plot.request_redraw( ) #Necessary but how do I only call axis redraw? def _title_changed(self, old, new): if old != new: self.plot.title = new self.plot.request_redraw( ) #HOW TO PREVENT COLLISION WITH TOP OVERLAY def _selection_axis_changed(self, old, new): if old != new: self._update_lines() def _df_changed(self, old, new): ''' Handles how updates occur when df changes. Evaluates if columns or columnlabels have been changed. Provides entry condition as well. Note: New automatically sets self.df, so when I refer to new, I am actually referring to self.df. Using "new" instead of self.df is just for readability''' ### Initialize plot first time df is passed into the class. Boolean listeners ### for df behave oddly, so uses self.plotdata for entry condition. if not self.plotdata: self.plotdata = PandasPlotData(df=new) self._dffull = new ### Try to infer plot title from df name ### try: self.title = new.name #Turn into a "transfer" method where I pass list of attributes i want look for except AttributeError: pass ### Draw barebones of plot self._plot_default() self._update_lines() ### Decide to update columns or completely redraw df. else: changed = self.plotdata.set_df(new) ### If 'event changed', don't bother updaing lines if not changed: self._update_lines() ### Plot spacing def _get__spacing(self): '''Integer spacing given % sampling''' samp = self.sampling / 100.0 colsize = df.shape[0] return colsize - int(round(colsize * samp, 0)) def _sampling_changed(self, old, new): if old != new: self._update_samples() def _update_samples(self): '''Updates the list of line plots shown or hidden based on plot sampling.''' if self._spacing == 0: return ### Hide all plots to_hide = self.plot.plots.keys() self.plot.hideplot(*to_hide) ### Show only plots in samples to_show = self.plot.plots.keys()[::self._spacing] self.plot.showplot(*to_show) self.plot.request_redraw() def _update_rangeselect(self): ''' Overwrites range selection tool in current plot.''' #### Remove current overlay self.plot.overlays = [ obj for obj in self.plot.overlays if not isinstance(obj, RangeSelectionOverlay) ] mycomp = self.plot.plots.itervalues().next()[ 0] #Quick wayt to get first value in dictionary inds = range(len(self.df.index)) idx = ArrayDataSource(inds) vals = ArrayDataSource(df.index.values) index_range = DataRange1D(idx) val_range = DataRange1D(vals) imap = LinearMapper( range=index_range) #,stretch_data=self.index_mapper.stretch_data) vmap = LinearMapper(range=val_range) # mycomp.index_range.refresh() mycomp.index_mapper = imap mycomp.value_mapper = vmap self.rangeselect = RangeSelection(mycomp, axis=self.selection_axis) self.plot.active_tool = self.rangeselect self.plot.overlays.append(RangeSelectionOverlay(component=mycomp)) self.rangeselect.on_trait_change(self.on_selection_changed, "selection") def _update_lines(self): ''' Redraws lines, plots and reapplies line selection.''' oldplots = self.plot.plots.keys() newplots = [name for name in self.plotdata.list_data(as_strings=True)] to_remove = [p for p in oldplots if p not in newplots] to_add = [p for p in newplots if p not in oldplots] if to_remove: for p in to_remove: self.plot.delplot(p) if to_add: for name in to_add: self.plot.plot(('index', name), name=name, color=self.linecolor) self._update_axis() self._update_samples() self._update_rangeselect() def on_selection_changed(self, selection): if selection != None: self.rangeXMin, self.rangeXMax = selection print selection def _update_axis(self): ''' Forces a label axis onto the plot. ''' print 'updaing axis', self.idxname indexlabels = [str(round(i, 1)) for i in self.df.index] columnlabels = [str(round(i, 1)) for i in self.df.columns] index_axis = LabelAxis( self.plot, orientation=self.idxorient, positions=range(int(float(indexlabels[0])), int(float(indexlabels[-1]))), labels=indexlabels, #, resizable='hv', title=self.idxname) col_axis = LabelAxis( self.plot, orientation=self.colorient, positions=range(int(float(columnlabels[0])), int(float(columnlabels[-1]))), labels=columnlabels, #, resizable='hv', title=self.colname) ### Remove underlays self.plot.underlays = [ obj for obj in self.plot.underlays if not isinstance(obj, PlotAxis) ] self.plot.underlays = [ obj for obj in self.plot.underlays if not isinstance(obj, LabelAxis) ] self.plot.underlays.append(index_axis) self.plot.underlays.append(col_axis) def _plot_default(self, toolbar=True, **pltkwds): ''' Draw bare plot, including main plotting area, toolbar, etc... either at initialization or global redo''' if toolbar: self.plot = ToolbarPlot(self.plotdata, **pltkwds) else: self.plot = Plot(self.plotdata, **pltkwds) self.plot.title = self.title self.plot.padding = 50 self.plot.legend.visible = False self.plot.tools.append(PanTool(self.plot)) zoom = BetterSelectingZoom(component=self.plot, tool_mode="box", always_on=False) self.plot.overlays.append(zoom) def _overwrite_plotdata(self): '''When a new instance of PandasPlotData is created, this overwrites the data source and updates the axis values.''' self.plotdata = PandasPlotData(df=self.df) self._plot_default() #CAN THIS JUST DRAW LINES ### Traits View main_group = Group( HGroup( Item('rnd_cols'), Item('samecols'), Item('transpose'), ), Item('plot', editor=ComponentEditor(), show_label=False), Item('idxname'), Item('idxorient'), Item('selection_axis'), Item('title'), Item('sampling'), # Item('df_new'), Item('df_change'), #Include('sample_group'), #Include('axis_traits_group') ) traits_view = View(Include('main_group'), height=600, width=800)
class Viewer(HasTraits): iterations = Range(0, 'max_iters') triangle = Instance(Component) comp = Instance(Component) base_width = Int(500) max_iters = Property(observe="base_width, viewport.zoom") viewport = Instance(Viewport) def _get_bounds(self): return [self.base_width, self.base_width * (SQRT3 / 2)] def _get_max_iters(self): factor = 1 if self.viewport: factor = self.viewport.zoom return int(np.log(4 / (factor * self.base_width)) / np.log(.5) + 1) def _comp_default(self): canvas = Canvas(draw_axes=True, bgcolor="gray") self.triangle = SierpinskiTriangle( position=[0.0, 0.0], bounds=[self.base_width, self.base_width * (SQRT3 / 2)], iterations=self.iterations, max_iters=self.max_iters, base_width=self.base_width, bgcolor="gray") canvas.add(self.triangle) self.viewport = Viewport(component=canvas, enable_zoom=True, stay_inside=True) self.viewport.zoom_tool.min_zoom = 1.0 self.viewport.tools.append( ViewportPanTool(self.viewport, drag_button="right")) scrolled = Scrolled( canvas, inside_padding_width=0, mousewheel_scroll=False, viewport_component=self.viewport, always_show_sb=True, continuous_drag_update=True, ) return scrolled @observe("base_width") def _update_base_width(self, event): self.triangle.bounds = [event.new, event.new * (SQRT3 / 2)] self.triangle.base_width = event.new self.triangle.invalidate_and_redraw() @observe("iterations") def _redraw(self, event): self.triangle.iterations = event.new self.triangle.invalidate_and_redraw() traits_view = View( Item(name='iterations'), Item(name='base_width'), UItem("comp", editor=ComponentEditor(size=(500, 500)), resizable=True), resizable=True, buttons=["OK"], title="Sierpinski's triangle", )
class MagView(HasTraits): python_console_cmds = Dict() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) traits_view = View( VGroup( Item('plot', editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)), show_label=False), )) def mag_set_data(self): self.last_plot_update_time = monotonic() min_data = np.min(self.mag) max_data = np.max(self.mag) padding = (max_data - min_data) / 4.0 if (self.plot.value_range.low_setting == 'auto' or (min_data - padding) < self.plot.value_range.low_setting): self.plot.value_range.low_setting = min_data - padding if (self.plot.value_range.high_setting == 'auto' or (max_data + padding) > self.plot.value_range.high_setting): self.plot.value_range.high_setting = max_data + padding self.plot_data.set_data('mag_x', self.mag[:, 0]) self.plot_data.set_data('mag_y', self.mag[:, 1]) self.plot_data.set_data('mag_z', self.mag[:, 2]) def mag_raw_callback(self, sbp_msg, **metadata): self.mag[:-1, :] = self.mag[1:, :] self.mag[-1] = (sbp_msg.mag_x, sbp_msg.mag_y, sbp_msg.mag_z) if monotonic() - self.last_plot_update_time > GUI_UPDATE_PERIOD: self.mag_set_data() def __init__(self, link): super(MagView, self).__init__() self.mag = np.zeros((NUM_POINTS, 3)) self.last_plot_update_time = 0 self.plot_data = ArrayPlotData(t=np.arange(NUM_POINTS), mag_x=[0.0], mag_y=[0.0], mag_z=[0.0]) self.plot = Plot(self.plot_data, auto_colors=colours_list, emphasized=True) self.plot.title = 'Raw Magnetometer Data' self.plot.title_color = [0, 0, 0.43] self.plot.value_axis.orientation = 'right' self.plot.value_axis.axis_line_visible = False self.legend_visible = True self.plot.legend.visible = True self.plot.legend.align = 'll' self.plot.legend.line_spacing = 1 self.plot.legend.font = 'modern 8' self.plot.legend.draw_layer = 'overlay' self.plot.legend.tools.append( LegendTool(self.plot.legend, drag_button="right")) mag_x = self.plot.plot(('t', 'mag_x'), type='line', color='auto', name='Mag. X (uT)') mag_y = self.plot.plot(('t', 'mag_y'), type='line', color='auto', name='Mag. Y (uT)') mag_z = self.plot.plot(('t', 'mag_z'), type='line', color='auto', name='Mag. Z (uT)') self.link = link self.link.add_callback(self.mag_raw_callback, SBP_MSG_MAG_RAW) self.python_console_cmds = {'track': self}
class PulsedTool(GetSetItemsMixin): """ Widget to plot a pulsed measurement. We plot * the raw data as an image * the average fluorescence response as a line plot (the average fluorescence response is used to determine a trigger point). * the spin state as a line plot """ # the measurement to analyze measurement = Any(editor=InstanceEditor) # plotting matrix_data = Instance(ArrayPlotData) line_data = Instance(ArrayPlotData) pulse_data = Instance(ArrayPlotData) matrix_plot = Instance(Plot, editor=ComponentEditor()) pulse_plot = Instance(Plot, editor=ComponentEditor()) line_plot = Instance(Plot, editor=ComponentEditor()) get_set_items = ['__doc__', 'measurement'] traits_view = View(VGroup( Item(name='measurement', style='custom', show_label=False), VSplit( Item('matrix_plot', show_label=False, width=500, height=-300, resizable=True), Item('line_plot', show_label=False, width=500, height=-300, resizable=True), Item('pulse_plot', show_label=False, width=500, height=-300, resizable=True), ), ), title='Pulsed Tool', buttons=[], resizable=True, height=-640) def __init__(self, **kwargs): super(PulsedTool, self).__init__(**kwargs) self._create_matrix_plot() self._create_pulse_plot() self._create_line_plot() self.on_trait_change(self._update_matrix_index, 'measurement.time_bins,measurement.n_laser', dispatch='ui') self.on_trait_change(self._update_matrix_value, 'measurement.count_data', dispatch='ui') self.on_trait_change(self._update_pulse_index, 'measurement.time_bins', dispatch='ui') self.on_trait_change(self._update_pulse_value, 'measurement.pulse', dispatch='ui') self.on_trait_change(self._update_line_plot_value, 'measurement.spin_state', dispatch='ui') self.on_trait_change(self._on_edge_change, 'measurement.edge', dispatch='ui') # plotting def _create_matrix_plot(self): matrix_data = ArrayPlotData(image=np.zeros((2, 2))) plot = Plot(matrix_data, width=500, height=500, resizable='hv', padding=8, padding_left=48, padding_bottom=36) plot.index_axis.title = 'time [ns]' plot.value_axis.title = 'laser pulse #' plot.img_plot('image', xbounds=(0, 1), ybounds=(0, 1), colormap=Spectral)[0] plot.tools.append(SaveTool(plot)) self.matrix_data = matrix_data self.matrix_plot = plot def _create_pulse_plot(self): pulse_data = ArrayPlotData(x=np.array((0., 0.1, 0.2)), y=np.array((0, 1, 2))) plot = Plot(pulse_data, padding=8, padding_left=64, padding_bottom=36) line = plot.plot(('x', 'y'), style='line', color='blue', name='data')[0] plot.index_axis.title = 'time [ns]' plot.value_axis.title = 'intensity' edge_marker = LinePlot( index=ArrayDataSource(np.array((0, 0))), value=ArrayDataSource(np.array((0, 1e9))), color='red', index_mapper=LinearMapper(range=plot.index_range), value_mapper=LinearMapper(range=plot.value_range), name='marker') plot.add(edge_marker) plot.tools.append(SaveTool(plot)) self.pulse_data = pulse_data self.pulse_plot = plot def _create_line_plot(self): line_data = ArrayPlotData( index=np.array((0, 1)), spin_state=np.array((0, 0)), ) plot = Plot(line_data, padding=8, padding_left=64, padding_bottom=36) plot.plot(('index', 'spin_state'), color='blue', name='spin_state') plot.index_axis.title = 'pulse #' plot.value_axis.title = 'spin state' plot.tools.append(SaveTool(plot)) self.line_data = line_data self.line_plot = plot def _update_matrix_index(self): if self.measurement is not None: self.matrix_plot.components[0].index.set_data( (self.measurement.time_bins[0], self.measurement.time_bins[-1]), (0.0, float(self.measurement.n_laser))) def _update_matrix_value(self): if self.measurement is not None: s = self.measurement.count_data.shape if not s[0] * s[1] > 1000000: self.matrix_data.set_data('image', self.measurement.count_data) def _update_pulse_index(self): if self.measurement is not None: self.pulse_data.set_data('x', self.measurement.time_bins) def _update_pulse_value(self): if self.measurement is not None: self.pulse_data.set_data('y', self.measurement.pulse) def _on_edge_change(self): if self.measurement is not None: y = self.measurement.edge self.pulse_plot.components[1].index.set_data(np.array((y, y))) def _update_line_plot_value(self): if self.measurement is not None: y = self.measurement.spin_state n = len(y) old_index = self.line_data.get_data('index') if old_index is not None and len(old_index) != n: self.line_data.set_data('index', np.arange(n)) self.line_data.set_data('spin_state', y) def save_matrix_plot(self, filename): save_figure(self.matrix_plot, filename) def save_line_plot(self, filename): save_figure(self.line_plot, filename)
class PlotExample(HasTraits): plot = Instance(Component) numpoints = Int(500) low_mode = Enum("value", "track") high_mode = Enum("value", "track") traits_view = View(Group( Item('plot', editor=ComponentEditor(), show_label=False), HGroup( HGroup(Item( 'object.plot.x_mapper.range.low_setting', label='Low', editor=TextEditor(), visible_when='object.low_mode == "value" ', ), Item('low_mode', label='Low Mode'), Item('object.plot.x_mapper.range.high_setting', label='High', editor=TextEditor(), visible_when='object.high_mode == "value" '), Item('high_mode', label='High Mode'), Item('object.plot.x_mapper.range.tracking_amount', label='Tracking Amount', editor=TextEditor(read_only=True), visible_when='object.high_mode == "track" or ' 'object.low_mode == "track"'), label='X', show_border=True), HGroup(Item('object.plot.y_mapper.range.low_setting', label='Low', editor=TextEditor()), Item('object.plot.y_mapper.range.high_setting', label='High', editor=TextEditor()), label='Y', show_border=True), ), orientation="vertical"), resizable=True, title="Function Plot", width=900, height=600) def xfunc(self, low, high): dx = (high - low) / self.numpoints real_low = ceil(low / dx) * dx real_high = ceil(high / dx) * dx return linspace(real_low, real_high, self.numpoints) def yfunc(self, low, high): x = self.xfunc(low, high) return sin(1.0 / x) def _low_mode_changed(self, newvalue): if newvalue != "value": self.plot.x_mapper.range.low_setting = newvalue def _high_mode_changed(self, newvalue): if newvalue != "value": self.plot.x_mapper.range.high_setting = newvalue def _plot_default(self): container = DataView() xds = FunctionDataSource(func=self.xfunc) yds = FunctionDataSource(func=self.yfunc) xmapper = container.x_mapper ymapper = container.y_mapper xds.data_range = xmapper.range yds.data_range = xmapper.range xmapper.range.set_bounds(-5, 10) ymapper.range.set_bounds(-1, 1.2) plot = ScatterPlot(index=xds, value=yds, index_mapper=xmapper, value_mapper=ymapper, color="green", marker="circle", marker_size=3, line_width=0) plot2 = LinePlot(index=xds, value=yds, index_mapper=xmapper, value_mapper=ymapper, color="lightgray") container.add(plot2, plot) plot.tools.append( PanTool(plot, constrain_direction="x", constrain=True)) plot.tools.append(ZoomTool(plot, axis="index", tool_mode="range")) return container
class DataBlockTablePlot(HasTraits): # the ParametersTable holding the actual array dataset = Instance(DataBlockTable) # a local reference to the data array in the dataset, for convenience selected = Property(Any, depends_on='dataset.selected') # ArrayPlotData for plot plot_data = Instance(ArrayPlotData, ()) # Chaco Plot instance plot = Instance(Plot) traits_view = View( VGroup( Item('dataset', show_label=False, style='custom', editor=InstanceEditor()), Item('plot', show_label=False, editor=ComponentEditor(), width=0.25, height=0.35), ), width=0.60, height=0.60, resizable=True, title='Parameters Plot', ) def cview(self): return View( VGroup( Item('dataset', show_label=False, style='custom', editor=InstanceEditor()), Item('plot', show_label=False, editor=ComponentEditor(), width=0.25, height=0.35), ), width=0.60, height=0.60, resizable=True, title='Raw Data Plot', ) @cached_property def _get_selected(self): return self.dataset.selected @on_trait_change('selected') def _data_source_change(self): """Handler for changes of ther selected table row """ if self.selected is None: return x = np.linspace(0, \ len(self.selected['raw_data']), \ len(self.selected['raw_data'])) self.plot_data.set_data('x', x) self.plot_data.set_data('y', self.selected['raw_data']) def _plot_data_default(self): """ This creates a list of ArrayPlotData instances, one for each species. """ plot_data = ArrayPlotData() plot_data.set_data('x', []) plot_data.set_data('y', []) return plot_data def _plot_default(self): """ This creates the default value for the plot. """ # create the main plot object plot = Plot(self.plot_data) plot.plot(('x', 'y'), type='line', name='raw data', color='lightgreen') # add the additional information plot.title = 'Row Data' plot.x_axis.title = 'Samples' plot.y_axis.title = 'Amplitude' # tools for basic interactivity plot.tools.append(PanTool(plot)) plot.tools.append(ZoomTool(plot)) plot.tools.append(DragZoom(plot, drag_button="right")) return plot
class BaselineView(HasTraits): python_console_cmds = Dict() ns = List() es = List() ds = List() 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 Baseline', 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) reset_button = Button(label='Reset Filters') reset_iar_button = Button(label='Reset IAR') init_base_button = Button(label='Init. with known baseline') 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('reset_button', show_label=False), Item('reset_iar_button', show_label=False), Item('init_base_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 _reset_button_fired(self): self.link.send(SBP_MSG_RESET_FILTERS, '\x00') def _reset_iar_button_fired(self): self.link.send(SBP_MSG_RESET_FILTERS, '\x01') def _init_base_button_fired(self): self.link.send(SBP_MSG_INIT_BASE, '') def _clear_button_fired(self): self.ns = [] self.es = [] self.ds = [] self.plot_data.set_data('n', []) self.plot_data.set_data('e', []) self.plot_data.set_data('d', []) self.plot_data.set_data('t', []) self.plot_data.set_data('curr_n', []) self.plot_data.set_data('curr_e', []) self.plot_data.set_data('curr_d', []) def _baseline_callback_ecef(self, data): #Don't do anything for ECEF currently return def iar_state_callback(self, sbp_msg): self.num_hyps = struct.unpack('<I', sbp_msg.payload)[0] def _baseline_callback_ned(self, sbp_msg): # 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.baseline_callback, sbp_msg) def update_table(self): self._table_list = self.table.items() def gps_time_callback(self, sbp_msg): self.week = MsgGPSTime(sbp_msg).wn self.nsec = MsgGPSTime(sbp_msg).ns def baseline_callback(self, sbp_msg): soln = MsgBaselineNED(sbp_msg) table = [] soln.n = soln.n * 1e-3 soln.e = soln.e * 1e-3 soln.d = soln.d * 1e-3 dist = np.sqrt(soln.n**2 + soln.e**2 + soln.d**2) 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) table.append(('GPS Time', t)) table.append(('GPS Week', str(self.week))) if self.log_file is None: self.log_file = open( time.strftime("baseline_log_%Y%m%d-%H%M%S.csv"), 'w') self.log_file.write('%s,%.4f,%.4f,%.4f,%.4f,%d,0x%02x,%d\n' % (str(t), soln.n, soln.e, soln.d, dist, soln.n_sats, soln.flags, self.num_hyps)) self.log_file.flush() table.append(('GPS ToW', tow)) table.append(('N', soln.n)) table.append(('E', soln.e)) table.append(('D', soln.d)) table.append(('Dist.', dist)) table.append(('Num. Sats.', soln.n_sats)) table.append(('Flags', '0x%02x' % soln.flags)) if soln.flags & 1: table.append(('Mode', 'Fixed RTK')) else: table.append(('Mode', 'Float')) table.append(('IAR Num. Hyps.', self.num_hyps)) self.ns.append(soln.n) self.es.append(soln.e) self.ds.append(soln.d) self.ns = self.ns[-1000:] self.es = self.es[-1000:] self.ds = self.ds[-1000:] self.plot_data.set_data('n', self.ns) self.plot_data.set_data('e', self.es) self.plot_data.set_data('d', self.ds) self.plot_data.set_data('curr_n', [soln.n]) self.plot_data.set_data('curr_e', [soln.e]) self.plot_data.set_data('curr_d', [soln.d]) self.plot_data.set_data('ref_n', [0.0]) self.plot_data.set_data('ref_e', [0.0]) self.plot_data.set_data('ref_d', [0.0]) t = range(len(self.ns)) self.plot_data.set_data('t', t) if self.position_centered: d = (self.plot.index_range.high - self.plot.index_range.low) / 2. self.plot.index_range.set_bounds(soln.e - d, soln.e + d) d = (self.plot.value_range.high - self.plot.value_range.low) / 2. self.plot.value_range.set_bounds(soln.n - d, soln.n + d) self.table = table def __init__(self, link): super(BaselineView, self).__init__() self.log_file = None self.num_hyps = 0 self.plot_data = ArrayPlotData(n=[0.0], e=[0.0], d=[0.0], t=[0.0], ref_n=[0.0], ref_e=[0.0], ref_d=[0.0], curr_e=[0.0], curr_n=[0.0], curr_d=[0.0]) self.plot = Plot(self.plot_data) lin = self.plot.plot(('e', 'n'), type='line', color=(0, 0, 1, 0.1)) pts = self.plot.plot(('e', 'n'), type='scatter', color='blue', marker='dot', line_width=0.0, marker_size=1.0) ref = self.plot.plot(('ref_e', 'ref_n'), type='scatter', color='red', marker='plus', marker_size=5, line_width=1.5) cur = self.plot.plot(('curr_e', 'curr_n'), type='scatter', color='orange', marker='plus', marker_size=5, line_width=1.5) plot_labels = [ 'Base Position', 'Rover Relative Position', 'Rover Path' ] plots_legend = dict(zip(plot_labels, [ref, cur, pts])) 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 = 'E (meters)' 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 = 'N (meters)' 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.week = None self.nsec = 0 self.link = link self.link.add_callback(self._baseline_callback_ned, SBP_MSG_BASELINE_NED) self.link.add_callback(self._baseline_callback_ecef, SBP_MSG_BASELINE_ECEF) self.link.add_callback(self.iar_state_callback, SBP_MSG_IAR_STATE) self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME) self.python_console_cmds = {'baseline': self}
class SolutionView(HasTraits): python_console_cmds = Dict() # we need to doubleup on Lists to store the psuedo absolutes separately # without rewriting everything """ 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 """ plot_history_max = Int(1000) last_plot_update_time = Float() last_stale_update_time = Float() logging_v = Bool(False) display_units = Enum(["degrees", "meters"]) 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 = List() dops_table = List() pos_table = 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 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=resource_filename('console/images/iconic/x.svg'), width=16, height=16) zoomall_button = SVGButton( label='', tooltip='Zoom All', toggle=True, filename=resource_filename('console/images/iconic/fullscreen.svg'), width=16, height=16) center_button = SVGButton( label='', tooltip='Center on Solution', toggle=True, filename=resource_filename('console/images/iconic/target.svg'), width=16, height=16) paused_button = SVGButton( label='', tooltip='Pause', toggle_tooltip='Run', toggle=True, filename=resource_filename('console/images/iconic/pause.svg'), toggle_filename=resource_filename('console/images/iconic/play.svg'), width=16, height=16) traits_view = View( HSplit( VGroup( Item('table', style='readonly', editor=TabularEditor(adapter=SimpleAdapter()), show_label=False, width=0.3), Item('rtk_pos_note', show_label=False, resizable=True, editor=MultilineTextEditor(TextEditor(multi_line=True)), style='readonly', width=0.3, height=-40), ), 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('display_units', label="Display Units"), ), 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 _reset_remove_current(self): self.plot_data.update_data(self._get_update_current()) def _get_update_current(self, current_dict={}): out_dict = { 'cur_lat_spp': [], 'cur_lng_spp': [], 'cur_lat_dgnss': [], 'cur_lng_dgnss': [], 'cur_lat_float': [], 'cur_lng_float': [], 'cur_lat_fixed': [], 'cur_lng_fixed': [], 'cur_lat_sbas': [], 'cur_lng_sbas': [], 'cur_lat_dr': [], 'cur_lng_dr': [] } out_dict.update(current_dict) return out_dict def _synchronize_plot_data_by_mode(self, mode_string, update_current=False): # do all required plot_data updates for a single # new solution with mode defined by mode_string pending_update = { 'lat_' + mode_string: [x for x in self.slns['lat_' + mode_string] if not np.isnan(x)], 'lng_' + mode_string: [y for y in self.slns['lng_' + mode_string] if not np.isnan(y)] } if update_current: current = {} if len(pending_update['lat_' + mode_string]) != 0: current = { 'cur_lat_' + mode_string: [pending_update['lat_' + mode_string][-1]], 'cur_lng_' + mode_string: [pending_update['lng_' + mode_string][-1]] } else: current = { 'cur_lat_' + mode_string: [], 'cur_lng_' + mode_string: [] } pending_update.update(self._get_update_current(current)) self.plot_data.update_data(pending_update) def _append_empty_sln_data(self, exclude_mode=None): for each_mode in mode_string_dict.values(): if exclude_mode is None or each_mode != exclude_mode: self.slns['lat_' + each_mode].append(np.nan) self.slns['lng_' + each_mode].append(np.nan) def _update_sln_data_by_mode(self, soln, mode_string): # do backend deque updates for a new solution of type # mode string self.scaling_lock.acquire() lat = (soln.lat - self.offset[0]) * self.sf[0] lng = (soln.lon - self.offset[1]) * self.sf[1] self.scaling_lock.release() self.slns['lat_' + mode_string].append(lat) self.slns['lng_' + mode_string].append(lng) # Rotate old data out by appending to deque self._append_empty_sln_data(exclude_mode=mode_string) def _clr_sln_data(self): for each in self.slns: self.slns[each].clear() def _clear_history(self): for each in self.slns: self.slns[each].clear() pending_update = { 'lat_spp': [], 'lng_spp': [], 'alt_spp': [], 'lat_dgnss': [], 'lng_dgnss': [], 'alt_dgnss': [], 'lat_float': [], 'lng_float': [], 'alt_float': [], 'lat_fixed': [], 'lng_fixed': [], 'alt_fixed': [], 'lat_sbas': [], 'lng_sbas': [], 'alt_sbas': [], 'lat_dr': [], 'lng_dr': [], 'alt_dr': [] } pending_update.update(self._get_update_current()) self.plot_data.update(pending_update) def _clear_button_fired(self): self._clear_history() def age_corrections_callback(self, sbp_msg, **metadata): age_msg = MsgAgeCorrections(sbp_msg) if age_msg.age != 0xFFFF: self.age_corrections = age_msg.age / 10.0 else: self.age_corrections = None def update_table(self): self.table = self.pos_table + self.vel_table + self.dops_table def auto_survey(self): if len(self.lats) != 0: self.latitude = sum(self.lats) / len(self.lats) self.altitude = sum(self.alts) / len(self.alts) self.longitude = sum(self.lngs) / len(self.lngs) def pos_llh_callback(self, sbp_msg, **metadata): if sbp_msg.msg_type == SBP_MSG_POS_LLH_DEP_A: soln = MsgPosLLHDepA(sbp_msg) else: soln = MsgPosLLH(sbp_msg) self.last_pos_mode = get_mode(soln) if self.last_pos_mode != 0: self.last_soln = soln mode_string = mode_string_dict[self.last_pos_mode] if mode_string not in self.pending_draw_modes: # this list allows us to tell GUI thread which solutions to update # (if we decide not to update at full data rate) # we use short strings to identify each solution mode self.pending_draw_modes.append(mode_string) self.list_lock.acquire() self._update_sln_data_by_mode(soln, mode_string) self.list_lock.release() else: self.list_lock.acquire() self._append_empty_sln_data() self.list_lock.release() self.ins_used = ((soln.flags & 0x8) >> 3) == 1 pos_table = [] soln.h_accuracy *= 1e-3 soln.v_accuracy *= 1e-3 tow = soln.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 # Return the best estimate of my local and receiver time in convenient # format that allows changing precision of the seconds ((tloc, secloc), (tgps, secgps)) = log_time_strings(self.week, tow) if self.utc_time: ((tutc, secutc)) = datetime_2_str(self.utc_time) 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 not self.logging_p: self.log_file = None if self.logging_p: if self.log_file is None: self.log_file = sopen(filepath_p, 'w') self.log_file.write( "pc_time,gps_time,tow(sec),latitude(degrees),longitude(degrees),altitude(meters)," "h_accuracy(meters),v_accuracy(meters),n_sats,flags\n") log_str_gps = "" if tgps != "" and secgps != 0: log_str_gps = "{0}:{1:06.6f}".format(tgps, float(secgps)) self.log_file.write( '%s,%s,%.3f,%.10f,%.10f,%.4f,%.4f,%.4f,%d,%d\n' % ("{0}:{1:06.6f}".format(tloc, float(secloc)), log_str_gps, tow, soln.lat, soln.lon, soln.height, soln.h_accuracy, soln.v_accuracy, soln.n_sats, soln.flags)) self.log_file.flush() if self.last_pos_mode == 0: pos_table.append(('GPS Week', EMPTY_STR)) pos_table.append(('GPS TOW', EMPTY_STR)) pos_table.append(('GPS Time', EMPTY_STR)) pos_table.append(('Num. Signals', EMPTY_STR)) pos_table.append(('Lat', EMPTY_STR)) pos_table.append(('Lng', EMPTY_STR)) pos_table.append(('Height', EMPTY_STR)) pos_table.append(('Horiz Acc', EMPTY_STR)) pos_table.append(('Vert Acc', EMPTY_STR)) else: self.last_stime_update = time.time() if self.week is not None: pos_table.append(('GPS Week', str(self.week))) pos_table.append(('GPS TOW', "{:.3f}".format(tow))) if self.week is not None: pos_table.append( ('GPS Time', "{0}:{1:06.3f}".format(tgps, float(secgps)))) if self.utc_time is not None: pos_table.append( ('UTC Time', "{0}:{1:06.3f}".format(tutc, float(secutc)))) pos_table.append(('UTC Src', self.utc_source)) if self.utc_time is None: pos_table.append(('UTC Time', EMPTY_STR)) pos_table.append(('UTC Src', EMPTY_STR)) pos_table.append(('Sats Used', soln.n_sats)) pos_table.append(('Lat', soln.lat)) pos_table.append(('Lng', soln.lon)) pos_table.append(('Height', "{0:.3f}".format(soln.height))) pos_table.append(('Horiz Acc', soln.h_accuracy)) pos_table.append(('Vert Acc', soln.v_accuracy)) pos_table.append(('Pos Flags', '0x%03x' % soln.flags)) pos_table.append(('INS Used', '{}'.format(self.ins_used))) pos_table.append(('Pos Fix Mode', mode_dict[self.last_pos_mode])) if self.age_corrections is not None: pos_table.append(('Corr. Age [s]', self.age_corrections)) # only store valid solutions for auto survey and degrees to meter transformation if self.last_pos_mode != 0: self.lats.append(soln.lat) self.lngs.append(soln.lon) self.alts.append(soln.height) self.tows.append(soln.tow) self.modes.append(self.last_pos_mode) self.auto_survey() # set-up table variables self.pos_table = pos_table self.update_table() # setup_plot variables # Updating array plot data is not thread safe, so we have to fire an event # and have the GUI thread do it if time.time() - self.last_plot_update_time > GUI_UPDATE_PERIOD: GUI.invoke_later(self._solution_draw) def _display_units_changed(self): # we store current extents of plot and current scalefactlrs self.scaling_lock.acquire() self.recenter = True # recenter flag tells _solution_draw to update view extents self.prev_extents = (self.plot.index_range.low_setting, self.plot.index_range.high_setting, self.plot.value_range.low_setting, self.plot.value_range.high_setting) self.prev_offsets = (self.offset[0], self.offset[1]) self.prev_sfs = (self.sf[0], self.sf[1]) if self.display_units == "meters": self.offset = ( np.mean( np.array(self.lats)[~(np.equal(np.array(self.modes), 0))]), np.mean( np.array(self.lngs)[~(np.equal(np.array(self.modes), 0))]), np.mean( np.array(self.alts)[~(np.equal(np.array(self.modes), 0))])) (self.meters_per_lat, self.meters_per_lon) = meters_per_deg( np.mean( np.array(self.lats)[~(np.equal(np.array(self.modes), 0))])) self.sf = (self.meters_per_lat, self.meters_per_lon) self.plot.value_axis.title = 'Latitude (meters)' self.plot.index_axis.title = 'Longitude (meters)' else: self.offset = (0, 0, 0) self.sf = (1, 1) self.plot.value_axis.title = 'Latitude (degrees)' self.plot.index_axis.title = 'Longitude (degrees)' self.scaling_lock.release() self.list_lock.acquire() # now we update the existing sln deques to go from meters back to degrees or vice versa for each_array in self.slns: index = 0 if 'lat' in str(each_array) else 1 # going from degrees to meters; do scaling with new offset and sf if self.display_units == "meters": self.slns[each_array] = deque( (np.array(self.slns[each_array]) - self.offset[index]) * self.sf[index], maxlen=PLOT_HISTORY_MAX) # going from degrees to meters; do inverse scaling with former offset and sf if self.display_units == "degrees": self.slns[each_array] = deque( np.array(self.slns[each_array]) / self.prev_sfs[index] + self.prev_offsets[index], maxlen=PLOT_HISTORY_MAX) self.pending_draw_modes = mode_string_dict.values() self.list_lock.release() def rescale_for_units_change(self): # Chaco scales view automatically when 'auto' is stored if self.prev_extents[0] != 'auto': # Otherwise use has used mousewheel zoom and we need to transform if self.display_units == 'meters': new_scaling = ( (self.prev_extents[0] - self.offset[1]) * self.sf[1], (self.prev_extents[1] - self.offset[1]) * self.sf[1], (self.prev_extents[2] - self.offset[0]) * self.sf[0], (self.prev_extents[3] - self.offset[0]) * self.sf[0]) else: new_scaling = (self.prev_extents[0] / self.prev_sfs[1] + self.prev_offsets[1], self.prev_extents[1] / self.prev_sfs[1] + self.prev_offsets[1], self.prev_extents[2] / self.prev_sfs[0] + self.prev_offsets[0], self.prev_extents[3] / self.prev_sfs[0] + self.prev_offsets[0]) # set plot scaling accordingly self.plot.index_range.low_setting = new_scaling[0] self.plot.index_range.high_setting = new_scaling[1] self.plot.value_range.low_setting = new_scaling[2] self.plot.value_range.high_setting = new_scaling[3] def _solution_draw(self): self.list_lock.acquire() current_time = time.time() self.last_plot_update_time = current_time pending_draw_modes = self.pending_draw_modes current_mode = pending_draw_modes[-1] if len( pending_draw_modes) > 0 else None # Periodically, we make sure to redraw older data to expire old plot data if current_time - self.last_stale_update_time > STALE_DATA_PERIOD: # we don't update old solution modes every timestep to try and save CPU pending_draw_modes = mode_string_dict.values() self.last_stale_update_time = current_time for mode_string in pending_draw_modes: if self.running: update_current = mode_string == current_mode if current_mode else True self._synchronize_plot_data_by_mode( mode_string, update_current=update_current) if mode_string in self.pending_draw_modes: self.pending_draw_modes.remove(mode_string) self.list_lock.release() if not self.zoomall and self.position_centered and self.running: d = (self.plot.index_range.high - self.plot.index_range.low) / 2. self.plot.index_range.set_bounds( (self.last_soln.lon - self.offset[1]) * self.sf[1] - d, (self.last_soln.lon - self.offset[1]) * self.sf[1] + d) d = (self.plot.value_range.high - self.plot.value_range.low) / 2. self.plot.value_range.set_bounds( (self.last_soln.lat - self.offset[0]) * self.sf[0] - d, (self.last_soln.lat - self.offset[0]) * self.sf[0] + d) if self.zoomall: self.recenter = False plot_square_axes(self.plot, ('lng_spp', 'lng_dgnss', 'lng_float', 'lng_fixed', 'lng_sbas', 'lng_dr'), ('lat_spp', 'lat_dgnss', 'lat_float', 'lat_fixed', 'lat_sbas', 'lat_dr')) if self.recenter: try: self.rescale_for_units_change() self.recenter = False except AttributeError: pass def dops_callback(self, sbp_msg, **metadata): flags = 0 if sbp_msg.msg_type == SBP_MSG_DOPS_DEP_A: dops = MsgDopsDepA(sbp_msg) flags = 1 else: dops = MsgDops(sbp_msg) flags = dops.flags if flags != 0: 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))] else: self.dops_table = [('PDOP', EMPTY_STR), ('GDOP', EMPTY_STR), ('TDOP', EMPTY_STR), ('HDOP', EMPTY_STR), ('VDOP', EMPTY_STR)] self.dops_table.append(('DOPS Flags', '0x%03x' % flags)) def vel_ned_callback(self, sbp_msg, **metadata): flags = 0 if sbp_msg.msg_type == SBP_MSG_VEL_NED_DEP_A: vel_ned = MsgVelNEDDepA(sbp_msg) flags = 1 else: vel_ned = MsgVelNED(sbp_msg) flags = vel_ned.flags tow = vel_ned.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 ((tloc, secloc), (tgps, secgps)) = log_time_strings(self.week, 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 not self.logging_v: self.vel_log_file = None if self.logging_v: if self.vel_log_file is None: self.vel_log_file = sopen(filepath_v, 'w') self.vel_log_file.write( 'pc_time,gps_time,tow(sec),north(m/s),east(m/s),down(m/s),speed(m/s),flags,num_signals\n' ) log_str_gps = '' if tgps != "" and secgps != 0: log_str_gps = "{0}:{1:06.6f}".format(tgps, float(secgps)) self.vel_log_file.write( '%s,%s,%.3f,%.6f,%.6f,%.6f,%.6f,%d,%d\n' % ("{0}:{1:06.6f}".format(tloc, float(secloc)), log_str_gps, tow, 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, flags, vel_ned.n_sats)) self.vel_log_file.flush() if (flags & 0x7) != 0: 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)), ] else: self.vel_table = [ ('Vel. N', EMPTY_STR), ('Vel. E', EMPTY_STR), ('Vel. D', EMPTY_STR), ] self.vel_table.append(('Vel Flags', '0x%03x' % flags)) self.update_table() def gps_time_callback(self, sbp_msg, **metadata): if sbp_msg.msg_type == SBP_MSG_GPS_TIME_DEP_A: time_msg = MsgGPSTimeDepA(sbp_msg) flags = 1 elif sbp_msg.msg_type == SBP_MSG_GPS_TIME: time_msg = MsgGPSTime(sbp_msg) flags = time_msg.flags if flags != 0: self.week = time_msg.wn self.nsec = time_msg.ns_residual def utc_time_callback(self, sbp_msg, **metadata): tmsg = MsgUtcTime(sbp_msg) microseconds = int(tmsg.ns / 1000.00) if tmsg.flags & 0x7 != 0: dt = datetime.datetime(tmsg.year, tmsg.month, tmsg.day, tmsg.hours, tmsg.minutes, tmsg.seconds, microseconds) self.utc_time = dt self.utc_time_flags = tmsg.flags if (tmsg.flags >> 3) & 0x3 == 0: self.utc_source = "Factory Default" elif (tmsg.flags >> 3) & 0x3 == 1: self.utc_source = "Non Volatile Memory" elif (tmsg.flags >> 3) & 0x3 == 2: self.utc_source = "Decoded this Session" else: self.utc_source = "Unknown" else: self.utc_time = None self.utc_source = None def __init__(self, link, dirname=''): super(SolutionView, self).__init__() self.pending_draw_modes = [] self.recenter = False self.offset = (0, 0, 0) self.sf = (1, 1) self.list_lock = threading.Lock() self.scaling_lock = threading.Lock() self.slns = { 'lat_spp': deque(maxlen=PLOT_HISTORY_MAX), 'lng_spp': deque(maxlen=PLOT_HISTORY_MAX), 'alt_spp': deque(maxlen=PLOT_HISTORY_MAX), 'lat_dgnss': deque(maxlen=PLOT_HISTORY_MAX), 'lng_dgnss': deque(maxlen=PLOT_HISTORY_MAX), 'alt_dgnss': deque(maxlen=PLOT_HISTORY_MAX), 'lat_float': deque(maxlen=PLOT_HISTORY_MAX), 'lng_float': deque(maxlen=PLOT_HISTORY_MAX), 'alt_float': deque(maxlen=PLOT_HISTORY_MAX), 'lat_fixed': deque(maxlen=PLOT_HISTORY_MAX), 'lng_fixed': deque(maxlen=PLOT_HISTORY_MAX), 'alt_fixed': deque(maxlen=PLOT_HISTORY_MAX), 'lat_sbas': deque(maxlen=PLOT_HISTORY_MAX), 'lng_sbas': deque(maxlen=PLOT_HISTORY_MAX), 'alt_sbas': deque(maxlen=PLOT_HISTORY_MAX), 'lat_dr': deque(maxlen=PLOT_HISTORY_MAX), 'lng_dr': deque(maxlen=PLOT_HISTORY_MAX), 'alt_dr': deque(maxlen=PLOT_HISTORY_MAX) } self.lats = deque(maxlen=PLOT_HISTORY_MAX) self.lngs = deque(maxlen=PLOT_HISTORY_MAX) self.alts = deque(maxlen=PLOT_HISTORY_MAX) self.tows = deque(maxlen=PLOT_HISTORY_MAX) self.modes = deque(maxlen=PLOT_HISTORY_MAX) 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.altitude = 0 self.longitude = 0 self.latitude = 0 self.last_pos_mode = 0 self.ins_used = False self.last_plot_update_time = 0 self.last_stale_update_time = 0 self.plot_data = ArrayPlotData(lat_spp=[], lng_spp=[], alt_spp=[], cur_lat_spp=[], cur_lng_spp=[], lat_dgnss=[], lng_dgnss=[], alt_dgnss=[], cur_lat_dgnss=[], cur_lng_dgnss=[], lat_float=[], lng_float=[], alt_float=[], cur_lat_float=[], cur_lng_float=[], lat_fixed=[], lng_fixed=[], alt_fixed=[], cur_lat_fixed=[], cur_lng_fixed=[], lat_sbas=[], lng_sbas=[], cur_lat_sbas=[], cur_lng_sbas=[], lng_dr=[], lat_dr=[], cur_lat_dr=[], cur_lng_dr=[]) self.plot = Plot(self.plot_data) # 1000 point buffer self.plot.plot(('lng_spp', 'lat_spp'), type='line', line_width=0.1, name='', color=color_dict[SPP_MODE]) self.plot.plot(('lng_spp', 'lat_spp'), type='scatter', name='', color=color_dict[SPP_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='line', line_width=0.1, name='', color=color_dict[DGNSS_MODE]) self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='scatter', name='', color=color_dict[DGNSS_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_float', 'lat_float'), type='line', line_width=0.1, name='', color=color_dict[FLOAT_MODE]) self.plot.plot(('lng_float', 'lat_float'), type='scatter', name='', color=color_dict[FLOAT_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_fixed', 'lat_fixed'), type='line', line_width=0.1, name='', color=color_dict[FIXED_MODE]) self.plot.plot(('lng_fixed', 'lat_fixed'), type='scatter', name='', color=color_dict[FIXED_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_sbas', 'lat_sbas'), type='line', line_width=0.1, name='', color=color_dict[SBAS_MODE]) self.plot.plot(('lng_sbas', 'lat_sbas'), type='scatter', name='', color=color_dict[SBAS_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_dr', 'lat_dr'), type='line', line_width=0.1, name='', color=color_dict[DR_MODE]) self.plot.plot(('lng_dr', 'lat_dr'), type='scatter', color=color_dict[DR_MODE], marker='dot', line_width=0.0, marker_size=1.0) # current values spp = self.plot.plot(('cur_lng_spp', 'cur_lat_spp'), type='scatter', name=mode_dict[SPP_MODE], color=color_dict[SPP_MODE], marker='plus', line_width=1.5, marker_size=5.0) dgnss = self.plot.plot(('cur_lng_dgnss', 'cur_lat_dgnss'), type='scatter', name=mode_dict[DGNSS_MODE], color=color_dict[DGNSS_MODE], marker='plus', line_width=1.5, marker_size=5.0) rtkfloat = self.plot.plot(('cur_lng_float', 'cur_lat_float'), type='scatter', name=mode_dict[FLOAT_MODE], color=color_dict[FLOAT_MODE], marker='plus', line_width=1.5, marker_size=5.0) rtkfix = self.plot.plot(('cur_lng_fixed', 'cur_lat_fixed'), type='scatter', name=mode_dict[FIXED_MODE], color=color_dict[FIXED_MODE], marker='plus', line_width=1.5, marker_size=5.0) sbas = self.plot.plot(('cur_lng_sbas', 'cur_lat_sbas'), type='scatter', name=mode_dict[SBAS_MODE], color=color_dict[SBAS_MODE], marker='plus', line_width=1.5, marker_size=5.0) dr = self.plot.plot(('cur_lng_dr', 'cur_lat_dr'), type='scatter', name=mode_dict[DR_MODE], color=color_dict[DR_MODE], marker='plus', line_width=1.5, marker_size=5.0) plot_labels = ['SPP', 'SBAS', 'DGPS', 'RTK float', 'RTK fixed', 'DR'] plots_legend = dict( zip(plot_labels, [spp, sbas, dgnss, rtkfloat, rtkfix, dr])) self.plot.legend.plots = plots_legend self.plot.legend.labels = plot_labels # sets order 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_DEP_A, SBP_MSG_POS_LLH]) self.link.add_callback(self.vel_ned_callback, [SBP_MSG_VEL_NED_DEP_A, SBP_MSG_VEL_NED]) self.link.add_callback(self.dops_callback, [SBP_MSG_DOPS_DEP_A, SBP_MSG_DOPS]) self.link.add_callback(self.gps_time_callback, [SBP_MSG_GPS_TIME_DEP_A, SBP_MSG_GPS_TIME]) self.link.add_callback(self.utc_time_callback, [SBP_MSG_UTC_TIME]) self.link.add_callback(self.age_corrections_callback, SBP_MSG_AGE_CORRECTIONS) self.week = None self.utc_time = None self.age_corrections = None self.nsec = 0 self.meters_per_lat = None self.meters_per_lon = None self.python_console_cmds = { 'solution': self, }
class MatrixViewer(HasTraits): tplot = Instance(Plot) plot = Instance(Component) custtool = Instance(CustomTool) colorbar = Instance(ColorBar) edge_para = Any data_name = Enum("a", "b") fro = Int to = Int data = None val = Float traits_view = View( Group( Item('plot', editor=ComponentEditor(size=(800,600)), show_label=False), HGroup( Item('fro', label="From", style = 'readonly', springy=True), Item('to', label="To", style = 'readonly', springy=True), Item('val', label="Value", style = 'readonly', springy=True), ), orientation = "vertical"), Item('data_name', label="Image data"), handler=CustomHandler(), resizable=True, title="Matrix Viewer" ) def __init__(self, data, **traits): """ Data is a nxn numpy array """ super(HasTraits, self).__init__(**traits) self.data_name = data.keys()[0] self.data = data self.plot = self._create_plot_component() # set trait notification on customtool self.custtool.on_trait_change(self._update_fields, "xval") self.custtool.on_trait_change(self._update_fields, "yval") def _data_name_changed(self, old, new): self.pd.set_data("imagedata", self.data[self.data_name]) self.my_plot.set_value_selection((0, 2)) def _update_fields(self): from numpy import trunc # map mouse location to array index frotmp = int(trunc(self.custtool.yval)) totmp = int(trunc(self.custtool.xval)) # check if within range sh = self.data[self.data_name].shape # assume matrix whose shape is (# of rows, # of columns) if frotmp >= 0 and frotmp < sh[0] and totmp >= 0 and totmp < sh[1]: self.fro = frotmp self.to = totmp self.val = self.data[self.data_name][self.fro, self.to] def _create_plot_component(self): # Create a plot data object and give it this data self.pd = ArrayPlotData() self.pd.set_data("imagedata", self.data[self.data_name]) # Create the plot self.tplot = Plot(self.pd, default_origin="top left") self.tplot.x_axis.orientation = "top" self.tplot.img_plot("imagedata", name="my_plot", #xbounds=(0,10), #ybounds=(0,10), colormap=jet) # Tweak some of the plot properties self.tplot.title = "Matrix" self.tplot.padding = 50 # Right now, some of the tools are a little invasive, and we need the # actual CMapImage object to give to them self.my_plot = self.tplot.plots["my_plot"][0] # Attach some tools to the plot self.tplot.tools.append(PanTool(self.tplot)) zoom = ZoomTool(component=self.tplot, tool_mode="box", always_on=False) self.tplot.overlays.append(zoom) # my custom tool to get the connection information self.custtool = CustomTool(self.tplot) self.tplot.tools.append(self.custtool) # Create the colorbar, handing in the appropriate range and colormap colormap = self.my_plot.color_mapper self.colorbar = ColorBar(index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, plot=self.my_plot, orientation='v', resizable='v', width=30, padding=20) self.colorbar.padding_top = self.tplot.padding_top self.colorbar.padding_bottom = self.tplot.padding_bottom # create a range selection for the colorbar self.range_selection = RangeSelection(component=self.colorbar) self.colorbar.tools.append(self.range_selection) self.colorbar.overlays.append(RangeSelectionOverlay(component=self.colorbar, border_color="white", alpha=0.8, fill_color="lightgray")) # we also want to the range selection to inform the cmap plot of # the selection, so set that up as well self.range_selection.listeners.append(self.my_plot) # Create a container to position the plot and the colorbar side-by-side container = HPlotContainer(use_backbuffer = True) container.add(self.tplot) container.add(self.colorbar) container.bgcolor = "white" return container
def traits_view(self): additional_param_controls = self._build_additional_param_editors() param_list_with_cost = [ALL_COST_COL_NAME] + self.param_list two_d_plot_shown = "show_cost_data_nd == '2D' and y_axis_param != " \ "'{}'".format(ALL_COST_COL_NAME) weight_range_editor = RangeEditor(low=0., high=MAX_WEIGHT) weight_doc = Label("The following control the relative importance or " "the various components that go into computing the" " cost of a model,\nthat is the difference between " "a simulation with that model and the corresponding" " experiment."), view = KromView(VGroup( VGroup(weight_doc, HGroup( Item("peak_time_weight", label="Peak time"), Item("peak_height_weight", label="Peak height"), Item("peak_slope_weight", label="Peak slope"), ), show_border=True, label="Weights", enabled_when="False", visible_when="not weight_edit_mode"), VGroup(weight_doc, Item("peak_time_weight", label="Peak time", editor=weight_range_editor), Item("peak_height_weight", label="Peak height", editor=weight_range_editor), Item("peak_slope_weight", label="Peak slope", editor=weight_range_editor), show_border=True, label="Weights", visible_when="weight_edit_mode"), HGroup( Spring(), Item("edit_weights_button", show_label=False, enabled_when="can_change_weights")), VGroup(HGroup( Item("show_cost_data_nd", label="Plot type", style="custom", enabled_when="len(param_list) > 1"), Item("x_axis_param", editor=EnumEditor(values=self.param_list)), Item("y_axis_param", editor=EnumEditor(values=param_list_with_cost), enabled_when="show_cost_data_nd != '1D'"), ), Item("plot1_2d_container", editor=ComponentEditor(), show_label=False), HGroup( Spring(), Item('color_bar_max_percentile', editor=RangeEditor(low=1, high=100, mode='spinner'), label='Colorbar high percentile (%)', visible_when=two_d_plot_shown)), VGroup(*additional_param_controls), label="Cost function plot", show_border=True, visible_when="not no_cost_data"), ), buttons=[OKButton], title="View/Edit optimizer cost function") return view
class TrackingView(HasTraits): python_console_cmds = Dict() states = List(Instance(TrackingState)) cn0_history = List() plot = Instance(Plot) plots = List() plot_data = Instance(ArrayPlotData) traits_view = View( HSplit( Item( 'plot', editor = ComponentEditor(bgcolor = (0.8, 0.8, 0.8)), show_label = False, ) ) ) def tracking_state_callback(self, data): n_channels = len(data) / TRACKING_STATE_BYTES_PER_CHANNEL if n_channels != self.n_channels: # Update number of channels self.n_channels = n_channels self.states = [TrackingState(0, 0, 0) for _ in range(n_channels)] for pl in self.plot.plots.iterkeys(): self.plot.delplot(pl.name) self.plots = [] for n in range(n_channels): self.plot_data.set_data('ch'+str(n), [0.0]) pl = self.plot.plot(('t', 'ch'+str(n)), type='line', color='auto', name='ch'+str(n)) self.plots.append(pl) print 'Number of tracking channels changed to', n_channels fmt = '<' + n_channels * 'BBf' state_data = struct.unpack(fmt, data) for n, s in enumerate(self.states): s.update(*state_data[3*n:3*(n+1)]) GUI.invoke_later(self.update_plot) def update_plot(self): self.cn0_history.append([s.cn0 for s in self.states]) self.cn0_history = self.cn0_history[-1000:] chans = np.transpose(self.cn0_history[-NUM_POINTS:]) plot_labels = [] for n in range(self.n_channels): self.plot_data.set_data('ch'+str(n), chans[n]) if self.states[n].state == 0: plot_labels.append('Ch %02d (Disabled)' % n) else: plot_labels.append('Ch %02d (PRN%02d)' % (n, self.states[n].prn+1)) plots = dict(zip(plot_labels, self.plots)) self.plot.legend.plots = plots def __init__(self, link): super(TrackingView, self).__init__() self.n_channels = None self.plot_data = ArrayPlotData(t=[0.0]) self.plot = Plot(self.plot_data, auto_colors=colours_list) self.plot.title = "Tracking C/N0" self.plot.value_range.margin = 0.1 self.plot.value_range.bounds_func = lambda l, h, m, tb: (0, h*(1+m)) self.plot.value_axis.orientation = 'right' self.plot.value_axis.axis_line_visible = False t = range(NUM_POINTS) self.plot_data.set_data('t', t) self.plot.legend.visible = True self.plot.legend.align = 'ul' self.plot.legend.tools.append(LegendTool(self.plot.legend, drag_button="right")) self.link = link self.link.add_callback(ids.TRACKING_STATE, self.tracking_state_callback) self.python_console_cmds = { 'track': self }
class ConnectionMatrixViewer(HasTraits): tplot = Instance(Plot) plot = Instance(Component) custtool = Instance(CustomTool) colorbar = Instance(ColorBar) fro = Any to = Any data = None val = Float nodelabels = Any traits_view = View( Group(Item('plot', editor=ComponentEditor(size=(800, 600)), show_label=False), HGroup( Item('fro', label="From", style='readonly', springy=True), Item('to', label="To", style='readonly', springy=True), Item('val', label="Value", style='readonly', springy=True), ), orientation="vertical"), Item('data_name', label="Edge key"), # handler=CustomHandler(), resizable=True, title="Connection Matrix Viewer") def __init__(self, nodelabels, matdict, **traits): """ Starts a matrix inspector Parameters ---------- nodelables : list List of strings of labels for the rows of the matrix matdict : dictionary Keys are the edge type and values are NxN Numpy arrays """ super(HasTraits, self).__init__(**traits) self.add_trait('data_name', Enum(matdict.keys())) self.data_name = matdict.keys()[0] self.data = matdict self.nodelables = nodelabels self.plot = self._create_plot_component() # set trait notification on customtool self.custtool.on_trait_change(self._update_fields, "xval") self.custtool.on_trait_change(self._update_fields, "yval") def _data_name_changed(self, old, new): self.pd.set_data("imagedata", self.data[self.data_name]) #self.my_plot.set_value_selection((0, 2)) self.tplot.title = "Connection Matrix for %s" % self.data_name def _update_fields(self): # map mouse location to array index frotmp = int(round(self.custtool.yval) - 1) totmp = int(round(self.custtool.xval) - 1) # check if within range sh = self.data[self.data_name].shape # assume matrix whose shape is (# of rows, # of columns) if frotmp >= 0 and frotmp < sh[0] and totmp >= 0 and totmp < sh[1]: row = " (index: %i" % (frotmp + 1) + ")" col = " (index: %i" % (totmp + 1) + ")" self.fro = " " + str(self.nodelables[frotmp]) + row self.to = " " + str(self.nodelables[totmp]) + col self.val = self.data[self.data_name][frotmp, totmp] def _create_plot_component(self): # Create a plot data object and give it this data self.pd = ArrayPlotData() self.pd.set_data("imagedata", self.data[self.data_name]) # find dimensions xdim = self.data[self.data_name].shape[1] ydim = self.data[self.data_name].shape[0] # Create the plot self.tplot = Plot(self.pd, default_origin="top left") self.tplot.x_axis.orientation = "top" self.tplot.img_plot("imagedata", name="my_plot", xbounds=(0.5, xdim + 0.5), ybounds=(0.5, ydim + 0.5), colormap=jet) # Tweak some of the plot properties self.tplot.title = "Connection Matrix for %s" % self.data_name self.tplot.padding = 80 # Right now, some of the tools are a little invasive, and we need the # actual CMapImage object to give to them self.my_plot = self.tplot.plots["my_plot"][0] # Attach some tools to the plot self.tplot.tools.append(PanTool(self.tplot)) zoom = ZoomTool(component=self.tplot, tool_mode="box", always_on=False) self.tplot.overlays.append(zoom) # my custom tool to get the connection information self.custtool = CustomTool(self.tplot) self.tplot.tools.append(self.custtool) # Create the colorbar, handing in the appropriate range and colormap colormap = self.my_plot.color_mapper self.colorbar = ColorBar( index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, plot=self.my_plot, orientation='v', resizable='v', width=30, padding=20) self.colorbar.padding_top = self.tplot.padding_top self.colorbar.padding_bottom = self.tplot.padding_bottom # create a range selection for the colorbar self.range_selection = RangeSelection(component=self.colorbar) self.colorbar.tools.append(self.range_selection) self.colorbar.overlays.append( RangeSelectionOverlay(component=self.colorbar, border_color="white", alpha=0.8, fill_color="lightgray")) # we also want to the range selection to inform the cmap plot of # the selection, so set that up as well self.range_selection.listeners.append(self.my_plot) # Create a container to position the plot and the colorbar side-by-side container = HPlotContainer(use_backbuffer=True) container.add(self.tplot) container.add(self.colorbar) container.bgcolor = "white" return container
class CMatrixViewer(MatrixViewer): tplot = Instance(Plot) plot = Instance(Component) custtool = Instance(CustomTool) colorbar = Instance(ColorBar) edge_parameter = Instance(EdgeParameters) network_reference = Any matrix_data_ref = Any labels = Any fro = Any to = Any val = Float traits_view = View(Group(Item('plot', editor=ComponentEditor(size=(800, 600)), show_label=False), HGroup( Item('fro', label="From", style='readonly', springy=True), Item('to', label="To", style='readonly', springy=True), Item('val', label="Value", style='readonly', springy=True), ), orientation="vertical"), Item('edge_parameter_name', label="Choose edge"), handler=CustomHandler(), resizable=True, title="Matrix Viewer") def __init__(self, net_ref, **traits): """ net_ref is a reference to a cnetwork """ super(MatrixViewer, self).__init__(**traits) self.network_reference = net_ref self.edge_parameter = self.network_reference._edge_para self.matrix_data_ref = self.network_reference.datasourcemanager._srcobj.edgeattributes_matrix_dict self.labels = self.network_reference.datasourcemanager._srcobj.labels # get the currently selected edge self.curr_edge = self.edge_parameter.parameterset.name # create plot self.plot = self._create_plot_component() # set trait notification on customtool self.custtool.on_trait_change(self._update_fields, "xval") self.custtool.on_trait_change(self._update_fields, "yval") # add edge parameter enum self.add_trait('edge_parameter_name', Enum(self.matrix_data_ref.keys())) self.edge_parameter_name = self.curr_edge def _edge_parameter_name_changed(self, new): # update edge parameter dialog self.edge_parameter.set_to_edge_parameter(self.edge_parameter_name) # update the data self.pd.set_data("imagedata", self.matrix_data_ref[self.edge_parameter_name]) # set range #self.my_plot.set_value_selection((0.0, 1.0)) def _update_fields(self): from numpy import trunc # map mouse location to array index frotmp = int(trunc(self.custtool.yval)) totmp = int(trunc(self.custtool.xval)) # check if within range sh = self.matrix_data_ref[self.edge_parameter_name].shape # assume matrix whose shape is (# of rows, # of columns) if frotmp >= 0 and frotmp < sh[0] and totmp >= 0 and totmp < sh[1]: self.fro = self.labels[frotmp] self.to = self.labels[totmp] self.val = self.matrix_data_ref[self.edge_parameter_name][frotmp, totmp] def _create_plot_component(self): # we need the matrices! # start with the currently selected one #nr_nodes = self.matrix_data_ref[curr_edge].shape[0] # Create a plot data obect and give it this data self.pd = ArrayPlotData() self.pd.set_data("imagedata", self.matrix_data_ref[self.curr_edge]) # Create the plot self.tplot = Plot(self.pd, default_origin="top left") self.tplot.x_axis.orientation = "top" self.tplot.img_plot( "imagedata", name="my_plot", #xbounds=(0,nr_nodes), #ybounds=(0,nr_nodes), colormap=jet) # Tweak some of the plot properties self.tplot.title = self.curr_edge self.tplot.padding = 50 # Right now, some of the tools are a little invasive, and we need the # actual CMapImage object to give to them self.my_plot = self.tplot.plots["my_plot"][0] # Attach some tools to the plot self.tplot.tools.append(PanTool(self.tplot)) zoom = ZoomTool(component=self.tplot, tool_mode="box", always_on=False) self.tplot.overlays.append(zoom) # my custom tool to get the connection information self.custtool = CustomTool(self.tplot) self.tplot.tools.append(self.custtool) # Create the colorbar, handing in the appropriate range and colormap colormap = self.my_plot.color_mapper self.colorbar = ColorBar( index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, plot=self.my_plot, orientation='v', resizable='v', width=30, padding=20) self.colorbar.padding_top = self.tplot.padding_top self.colorbar.padding_bottom = self.tplot.padding_bottom # TODO: the range selection gives a Segmentation Fault, # but why, the matrix_viewer.py example works just fine! # create a range selection for the colorbar self.range_selection = RangeSelection(component=self.colorbar) self.colorbar.tools.append(self.range_selection) self.colorbar.overlays.append( RangeSelectionOverlay(component=self.colorbar, border_color="white", alpha=0.8, fill_color="lightgray")) # we also want to the range selection to inform the cmap plot of # the selection, so set that up as well #self.range_selection.listeners.append(self.my_plot) # Create a container to position the plot and the colorbar side-by-side container = HPlotContainer(use_backbuffer=True) container.add(self.tplot) container.add(self.colorbar) container.bgcolor = "white" # my_plot.set_value_selection((-1.3, 6.9)) return container
class BaselineView(HasTraits): python_console_cmds = Dict() table = List() logging_b = Bool(False) directory_name_b = File plot = Instance(Plot) plot_data = Instance(ArrayPlotData) 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 Baseline', 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) reset_button = Button(label='Reset Filters') reset_iar_button = Button(label='Reset IAR') init_base_button = Button(label='Init. with known baseline') 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('reset_button', show_label=False), Item('reset_iar_button', show_label=False), Item('init_base_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 _reset_button_fired(self): self.link(MsgResetFilters(filter=0)) def _reset_iar_button_fired(self): self.link(MsgResetFilters(filter=1)) def _init_base_button_fired(self): self.link(MsgInitBase()) def _clear_button_fired(self): self.neds[:] = np.NAN self.fixeds[:] = False self.plot_data.set_data('n_fixed', []) self.plot_data.set_data('e_fixed', []) self.plot_data.set_data('d_fixed', []) self.plot_data.set_data('n_float', []) self.plot_data.set_data('e_float', []) self.plot_data.set_data('d_float', []) self.plot_data.set_data('t', []) self.plot_data.set_data('cur_fixed_n', []) self.plot_data.set_data('cur_fixed_e', []) self.plot_data.set_data('cur_fixed_d', []) self.plot_data.set_data('cur_float_n', []) self.plot_data.set_data('cur_float_e', []) self.plot_data.set_data('cur_float_d', []) def iar_state_callback(self, sbp_msg, **metadata): self.num_hyps = sbp_msg.num_hyps self.last_hyp_update = time.time() def _baseline_callback_ned(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.baseline_callback, sbp_msg) def update_table(self): self._table_list = self.table.items() def gps_time_callback(self, sbp_msg, **metadata): self.week = MsgGPSTime(sbp_msg).wn self.nsec = MsgGPSTime(sbp_msg).ns def mode_string(self, msg): if msg: self.fixed = (msg.flags & 1) == 1 if self.fixed: return 'Fixed RTK' else: return 'Float' return 'None' def baseline_callback(self, sbp_msg): self.last_btime_update = time.time() soln = MsgBaselineNED(sbp_msg) self.last_soln = soln table = [] soln.n = soln.n * 1e-3 soln.e = soln.e * 1e-3 soln.d = soln.d * 1e-3 dist = np.sqrt(soln.n**2 + soln.e**2 + soln.d**2) 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) table.append(('GPS Time', t)) table.append(('GPS Week', str(self.week))) if self.directory_name_b == '': filepath = time.strftime("baseline_log_%Y%m%d-%H%M%S.csv") else: filepath = os.path.join( self.directory_name_b, time.strftime("baseline_log_%Y%m%d-%H%M%S.csv")) if self.logging_b == False: self.log_file = None if self.logging_b: if self.log_file is None: self.log_file = open(filepath, 'w') self.log_file.write( 'time,north(meters),east(meters),down(meters),distance(meters),num_sats,flags,num_hypothesis\n' ) self.log_file.write('%s,%.4f,%.4f,%.4f,%.4f,%d,0x%02x,%d\n' % (str(t), soln.n, soln.e, soln.d, dist, soln.n_sats, soln.flags, self.num_hyps)) self.log_file.flush() table.append(('GPS ToW', tow)) table.append(('N', soln.n)) table.append(('E', soln.e)) table.append(('D', soln.d)) table.append(('Dist.', dist)) table.append(('Num. Sats.', soln.n_sats)) table.append(('Flags', '0x%02x' % soln.flags)) table.append(('Mode', self.mode_string(soln))) if time.time() - self.last_hyp_update < 10 and self.num_hyps != 1: table.append(('IAR Num. Hyps.', self.num_hyps)) else: table.append(('IAR Num. Hyps.', "None")) # Rotate array, deleting oldest entries to maintain # no more than N in plot self.neds[1:] = self.neds[:-1] self.fixeds[1:] = self.fixeds[:-1] # Insert latest position self.neds[0][:] = [soln.n, soln.e, soln.d] self.fixeds[0] = self.fixed neds_fixed = self.neds[self.fixeds] neds_float = self.neds[np.logical_not(self.fixeds)] if not all(map(any, np.isnan(neds_fixed))): self.plot_data.set_data('n_fixed', neds_fixed.T[0]) self.plot_data.set_data('e_fixed', neds_fixed.T[1]) self.plot_data.set_data('d_fixed', neds_fixed.T[2]) if not all(map(any, np.isnan(neds_float))): self.plot_data.set_data('n_float', neds_float.T[0]) self.plot_data.set_data('e_float', neds_float.T[1]) self.plot_data.set_data('d_float', neds_float.T[2]) if self.fixed: self.plot_data.set_data('cur_fixed_n', [soln.n]) self.plot_data.set_data('cur_fixed_e', [soln.e]) self.plot_data.set_data('cur_fixed_d', [soln.d]) self.plot_data.set_data('cur_float_n', []) self.plot_data.set_data('cur_float_e', []) self.plot_data.set_data('cur_float_d', []) else: self.plot_data.set_data('cur_float_n', [soln.n]) self.plot_data.set_data('cur_float_e', [soln.e]) self.plot_data.set_data('cur_float_d', [soln.d]) self.plot_data.set_data('cur_fixed_n', []) self.plot_data.set_data('cur_fixed_e', []) self.plot_data.set_data('cur_fixed_d', []) self.plot_data.set_data('ref_n', [0.0]) self.plot_data.set_data('ref_e', [0.0]) self.plot_data.set_data('ref_d', [0.0]) if self.position_centered: d = (self.plot.index_range.high - self.plot.index_range.low) / 2. self.plot.index_range.set_bounds(soln.e - d, soln.e + d) d = (self.plot.value_range.high - self.plot.value_range.low) / 2. self.plot.value_range.set_bounds(soln.n - d, soln.n + d) if self.zoomall: plot_square_axes(self.plot, ('e_fixed', 'e_float'), ('n_fixed', 'n_float')) self.table = table def __init__(self, link, plot_history_max=1000, dirname=''): super(BaselineView, self).__init__() self.log_file = None self.directory_name_b = dirname self.num_hyps = 0 self.last_hyp_update = 0 self.last_btime_update = 0 self.last_soln = None self.plot_data = ArrayPlotData(n_fixed=[0.0], e_fixed=[0.0], d_fixed=[0.0], n_float=[0.0], e_float=[0.0], d_float=[0.0], t=[0.0], ref_n=[0.0], ref_e=[0.0], ref_d=[0.0], cur_fixed_e=[], cur_fixed_n=[], cur_fixed_d=[], cur_float_e=[], cur_float_n=[], cur_float_d=[]) self.plot_history_max = plot_history_max self.neds = np.empty((plot_history_max, 3)) self.neds[:] = np.NAN self.fixeds = np.zeros(plot_history_max, dtype=bool) self.plot = Plot(self.plot_data) color_float = (0.5, 0.5, 1.0) color_fixed = 'orange' pts_float = self.plot.plot(('e_float', 'n_float'), type='scatter', color=color_float, marker='dot', line_width=0.0, marker_size=1.0) pts_fixed = self.plot.plot(('e_fixed', 'n_fixed'), type='scatter', color=color_fixed, marker='dot', line_width=0.0, marker_size=1.0) lin = self.plot.plot(('e_fixed', 'n_fixed'), type='line', color=(1, 0.65, 0, 0.1)) ref = self.plot.plot(('ref_e', 'ref_n'), type='scatter', color='red', marker='plus', marker_size=5, line_width=1.5) cur_fixed = self.plot.plot(('cur_fixed_e', 'cur_fixed_n'), type='scatter', color=color_fixed, marker='plus', marker_size=5, line_width=1.5) cur_float = self.plot.plot(('cur_float_e', 'cur_float_n'), type='scatter', color=color_float, marker='plus', marker_size=5, line_width=1.5) plot_labels = ['Base Position', 'RTK Fixed', 'RTK Float'] plots_legend = dict(zip(plot_labels, [ref, cur_fixed, cur_float])) 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 = 'E (meters)' 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 = 'N (meters)' 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.week = None self.nsec = 0 self.link = link self.link.add_callback(self._baseline_callback_ned, SBP_MSG_BASELINE_NED) self.link.add_callback(self.iar_state_callback, SBP_MSG_IAR_STATE) self.link.add_callback(self.gps_time_callback, SBP_MSG_GPS_TIME) self.python_console_cmds = {'baseline': self}
class ODMR_2MW(ManagedJob, GetSetItemsMixin): """Provides ODMR measurements.""" # starting and stopping keep_data = Bool( False) # helper variable to decide whether to keep existing data resubmit_button = Button( label='resubmit', desc= 'Submits the measurement to the job manager. Tries to keep previously acquired data. Behaves like a normal submit if sequence or time bins have changed since previous run.' ) # measurement parameters power = Range(low=-100., high=25., value=-8, desc='Power [dBm]', label='Power [dBm]', mode='text', auto_set=False, enter_set=True) frequency_begin = Range(low=1, high=20e9, value=2.85e9, desc='Start Frequency [Hz]', label='Begin [Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) frequency_end = Range(low=1, high=20e9, value=2.90e9, desc='Stop Frequency [Hz]', label='End [Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) frequency_delta = Range(low=1e-3, high=20e9, value=1e6, desc='frequency step [Hz]', label='Delta [Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) t_pi = Range(low=1., high=100000., value=1000., desc='length of pi pulse [ns]', label='pi [ns]', mode='text', auto_set=False, enter_set=True) laser = Range(low=1., high=10000., value=300., desc='laser [ns]', label='laser [ns]', mode='text', auto_set=False, enter_set=True) wait = Range(low=1., high=10000., value=1000., desc='wait [ns]', label='wait [ns]', mode='text', auto_set=False, enter_set=True) pulsed = Bool(False, label='pulsed') power_p = Range(low=-100., high=25., value=-20, desc='Power Pmode [dBm]', label='Power[dBm]', mode='text', auto_set=False, enter_set=True) frequency_begin_p = Range(low=1, high=20e9, value=2.87e9, desc='Start Frequency Pmode[Hz]', label='Begin[Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) frequency_end_p = Range(low=1, high=20e9, value=2.88e9, desc='Stop Frequency Pmode[Hz]', label='End[Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) frequency_delta_p = Range(low=1e-3, high=20e9, value=1e5, desc='frequency step Pmode[Hz]', label='Delta[Hz]', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_str='%e')) mw_source = Enum('mw', 'mw2', desc='Select microwave source to use', label='axis', editor=EnumEditor(cols=3, values={ 'x': '1:X', 'y': '2:Y' })) seconds_per_point = Range(low=20e-3, high=1, value=20e-3, desc='Seconds per point', label='Seconds per point', mode='text', auto_set=False, enter_set=True) stop_time = Range( low=1., value=np.inf, desc='Time after which the experiment stops by itself [s]', label='Stop time [s]', mode='text', auto_set=False, enter_set=True) n_lines = Range(low=1, high=10000, value=50, desc='Number of lines in Matrix', label='Matrix lines', mode='text', auto_set=False, enter_set=True) # control data fitting perform_fit = Bool(False, label='perform fit') number_of_resonances = Trait( 'auto', String('auto', auto_set=False, enter_set=True), Int(10000., desc='Number of Lorentzians used in fit', label='N', auto_set=False, enter_set=True)) threshold = Range( low=-99, high=99., value=-50., desc= 'Threshold for detection of resonances [%]. The sign of the threshold specifies whether the resonances are negative or positive.', label='threshold [%]', mode='text', auto_set=False, enter_set=True) # fit result fit_parameters = Array(value=np.array((np.nan, np.nan, np.nan, np.nan))) fit_frequencies = Array(value=np.array((np.nan, )), label='frequency [Hz]') fit_line_width = Array(value=np.array((np.nan, )), label='line_width [Hz]') fit_contrast = Array(value=np.array((np.nan, )), label='contrast [%]') # measurement data frequency = Array() counts = Array() counts_matrix = Array() run_time = Float(value=0.0, desc='Run time [s]', label='Run time [s]') # plotting line_label = Instance(PlotLabel) line_data = Instance(ArrayPlotData) matrix_data = Instance(ArrayPlotData) line_plot = Instance(Plot, editor=ComponentEditor()) matrix_plot = Instance(Plot, editor=ComponentEditor()) def __init__(self): super(ODMR_2MW, self).__init__() self._create_line_plot() self._create_matrix_plot() self.on_trait_change(self._update_line_data_index, 'frequency', dispatch='ui') self.on_trait_change(self._update_line_data_value, 'counts', dispatch='ui') self.on_trait_change(self._update_line_data_fit, 'fit_parameters', dispatch='ui') self.on_trait_change(self._update_matrix_data_value, 'counts_matrix', dispatch='ui') self.on_trait_change(self._update_matrix_data_index, 'n_lines,frequency', dispatch='ui') self.on_trait_change( self._update_fit, 'counts,perform_fit,number_of_resonances,threshold', dispatch='ui') def _counts_matrix_default(self): return np.zeros((self.n_lines, len(self.frequency))) def _frequency_default(self): if self.pulsed: return np.arange(self.frequency_begin_p, self.frequency_end_p + self.frequency_delta_p, self.frequency_delta_p) else: return np.arange(self.frequency_begin, self.frequency_end + self.frequency_delta, self.frequency_delta) def _counts_default(self): return np.zeros(self.frequency.shape) # data acquisition def apply_parameters(self): """Apply the current parameters and decide whether to keep previous data.""" if self.pulsed: frequency = np.arange( self.frequency_begin_p, self.frequency_end_p + self.frequency_delta_p, self.frequency_delta_p) else: frequency = np.arange(self.frequency_begin, self.frequency_end + self.frequency_delta, self.frequency_delta) if not self.keep_data or np.any(frequency != self.frequency): self.frequency = frequency self.counts = np.zeros(frequency.shape) self.run_time = 0.0 self.keep_data = True # when job manager stops and starts the job, data should be kept. Only new submission should clear data. def _run(self): try: self.state = 'run' self.apply_parameters() if self.run_time >= self.stop_time: self.state = 'done' return # if pulsed, turn on sequence if self.pulsed: ha.PulseGenerator().Sequence([(['laser'], self.laser), ([], self.wait), (['mw'], self.t_pi), ([], 15)]) else: ha.PulseGenerator().Open() n = len(self.frequency) if self.pulsed: ha.Microwave().setPower(self.power_p) ha.Microwave().initSweep( self.frequency, self.power_p * np.ones(self.frequency.shape)) else: ha.Microwave().setPower(self.power) ha.Microwave().initSweep( self.frequency, self.power * np.ones(self.frequency.shape)) ha.Counter().configure(n, self.seconds_per_point, DutyCycle=0.8) time.sleep(0.5) while self.run_time < self.stop_time: start_time = time.time() if threading.currentThread().stop_request.isSet(): break ha.Microwave().resetListPos() counts = ha.Counter().run() / 1e3 self.run_time += time.time() - start_time self.counts += counts self.counts_matrix = np.vstack( (counts, self.counts_matrix[:-1, :])) self.trait_property_changed('counts', self.counts) """ ha.Microwave().doSweep() timeout = 3. start_time = time.time() while not self._count_between_markers.ready(): time.sleep(0.1) if time.time() - start_time > timeout: print "count between markers timeout in ODMR" break counts = self._count_between_markers.getData(0) self._count_between_markers.clean() """ if self.run_time < self.stop_time: self.state = 'idle' else: self.state = 'done' if self.pulsed: ha.Microwave().setOutput(None, self.frequency_begin_p) else: ha.Microwave().setOutput(None, self.frequency_begin) ha.PulseGenerator().Light() ha.Counter().clear() except: logging.getLogger().exception('Error in odmr.') self.state = 'error' finally: if self.pulsed: ha.Microwave().setOutput(None, self.frequency_begin_p) else: ha.Microwave().setOutput(None, self.frequency_begin) # fitting def _update_fit(self): if self.perform_fit: N = self.number_of_resonances if N != 'auto': N = int(N) try: p = fitting.fit_multiple_lorentzians(self.frequency, self.counts, N, threshold=self.threshold * 0.01) except Exception: logging.getLogger().debug('ODMR fit failed.', exc_info=True) p = np.nan * np.empty(4) else: p = np.nan * np.empty(4) self.fit_parameters = p self.fit_frequencies = p[1::3] self.fit_line_width = p[2::3] N = len(p) / 3 contrast = np.empty(N) c = p[0] pp = p[1:].reshape((N, 3)) for i, pn in enumerate(pp): a = pn[2] g = pn[1] A = np.abs(a / (np.pi * g)) if a > 0: contrast[i] = 100 * A / (A + c) else: contrast[i] = 100 * A / c self.fit_contrast = contrast # plotting def _create_line_plot(self): line_data = ArrayPlotData(frequency=np.array((0., 1.)), counts=np.array((0., 0.)), fit=np.array((0., 0.))) line_plot = Plot(line_data, padding=8, padding_left=64, padding_bottom=32) line_plot.plot(('frequency', 'counts'), style='line', color='blue') line_plot.index_axis.title = 'Frequency [MHz]' line_plot.value_axis.title = 'Fluorescence/k' line_label = PlotLabel(text='', hjustify='left', vjustify='bottom', position=[64, 128]) line_plot.overlays.append(line_label) self.line_label = line_label self.line_data = line_data self.line_plot = line_plot def _create_matrix_plot(self): matrix_data = ArrayPlotData(image=np.zeros((2, 2))) matrix_plot = Plot(matrix_data, padding=8, padding_left=64, padding_bottom=32) matrix_plot.index_axis.title = 'Frequency [MHz]' matrix_plot.value_axis.title = 'line #' matrix_plot.img_plot('image', xbounds=(self.frequency[0], self.frequency[-1]), ybounds=(0, self.n_lines), colormap=Spectral) self.matrix_data = matrix_data self.matrix_plot = matrix_plot def _perform_fit_changed(self, new): plot = self.line_plot if new: plot.plot(('frequency', 'fit'), style='line', color='red', name='fit') self.line_label.visible = True else: plot.delplot('fit') self.line_label.visible = False plot.request_redraw() def _update_line_data_index(self): self.line_data.set_data('frequency', self.frequency * 1e-6) self.counts_matrix = self._counts_matrix_default() def _update_line_data_value(self): self.line_data.set_data('counts', self.counts) def _update_line_data_fit(self): if not np.isnan(self.fit_parameters[0]): self.line_data.set_data( 'fit', fitting.NLorentzians(*self.fit_parameters)(self.frequency)) p = self.fit_parameters f = p[1::3] w = p[2::3] N = len(p) / 3 contrast = np.empty(N) c = p[0] pp = p[1:].reshape((N, 3)) for i, pi in enumerate(pp): a = pi[2] g = pi[1] A = np.abs(a / (np.pi * g)) if a > 0: contrast[i] = 100 * A / (A + c) else: contrast[i] = 100 * A / c s = '' for i, fi in enumerate(f): s += 'f %i: %.6e Hz, HWHM %.3e Hz, contrast %.1f%%\n' % ( i + 1, fi, w[i], contrast[i]) self.line_label.text = s def _update_matrix_data_value(self): self.matrix_data.set_data('image', self.counts_matrix) def _update_matrix_data_index(self): if self.n_lines > self.counts_matrix.shape[0]: self.counts_matrix = np.vstack( (self.counts_matrix, np.zeros((self.n_lines - self.counts_matrix.shape[0], self.counts_matrix.shape[1])))) else: self.counts_matrix = self.counts_matrix[:self.n_lines] self.matrix_plot.components[0].index.set_data( (self.frequency[0] * 1e-6, self.frequency[-1] * 1e-6), (0.0, float(self.n_lines))) # saving data def save_line_plot(self, filename): self.save_figure(self.line_plot, filename) def save_matrix_plot(self, filename): self.save_figure(self.matrix_plot, filename) def save_all(self, filename): self.save_line_plot(filename + '_ODMR_Line_Plot.png') self.save_matrix_plot(filename + '_ODMR_Matrix_Plot.png') self.save(filename + '_ODMR.pys') # react to GUI events def submit(self): """Submit the job to the JobManager.""" self.keep_data = False ManagedJob.submit(self) print threading.currentThread().getName() def resubmit(self): """Submit the job to the JobManager.""" self.keep_data = True ManagedJob.submit(self) def _resubmit_button_fired(self): """React to start button. Submit the Job.""" self.resubmit() traits_view = View(VGroup( HGroup( Item('submit_button', show_label=False), Item('remove_button', show_label=False), Item('resubmit_button', show_label=False), Item('priority', enabled_when='state != "run"'), Item('state', style='readonly'), Item('run_time', style='readonly', format_str='%.f'), Item('stop_time'), ), Group( HGroup( Item('pulsed', enabled_when='state != "run"'), Item('power_p', width=-40, enabled_when='state != "run"'), Item('frequency_begin_p', width=-80, enabled_when='state != "run"'), Item('frequency_end_p', width=-80, enabled_when='state != "run"'), Item('frequency_delta_p', width=-80, enabled_when='state != "run"'), Item('t_pi', width=-50, enabled_when='state != "run"'), label='Pulsed Mode', ), HGroup( Item('power', width=-40, enabled_when='state != "run"'), Item('frequency_begin', width=-80, enabled_when='state != "run"'), Item('frequency_end', width=-80, enabled_when='state != "run"'), Item('frequency_delta', width=-80, enabled_when='state != "run"'), label='CW Mode', ), layout='tabbed', ), HGroup( Item('seconds_per_point', width=-40, enabled_when='state != "run"'), Item('laser', width=-50, enabled_when='state != "run"'), Item('wait', width=-50, enabled_when='state != "run"'), Item('mw_source', width=-80, enabled_when='state != "run"')), HGroup( Item('perform_fit'), Item('number_of_resonances', width=-60), Item('threshold', width=-60), Item('n_lines', width=-60), ), HGroup( Item('fit_contrast', style='readonly'), Item('fit_line_width', style='readonly'), Item('fit_frequencies', style='readonly'), ), VSplit( Item('line_plot', show_label=False, resizable=True), Item('matrix_plot', show_label=False, resizable=True), ), ), menubar=MenuBar( Menu(Action(action='saveLinePlot', name='SaveLinePlot (.png)'), Action(action='saveMatrixPlot', name='SaveMatrixPlot (.png)'), Action(action='save', name='Save (.pyd or .pys)'), Action(action='saveAll', name='Save All (.png+.pys)'), Action(action='export', name='Export as Ascii (.asc)'), Action(action='export', name='Export as Ascii (.asc)'), Action(action='load', name='Load'), Action(action='_on_close', name='Quit'), name='File')), title='ODMR', width=900, height=800, buttons=[], resizable=True, handler=ODMRHandler) get_set_items = [ 'frequency', 'counts', 'counts_matrix', 'fit_parameters', 'fit_contrast', 'fit_line_width', 'fit_frequencies', 'perform_fit', 'run_time', 'power', 'frequency_begin', 'frequency_end', 'frequency_delta', 'power_p', 'frequency_begin_p', 'frequency_end_p', 'frequency_delta_p', 'laser', 'wait', 'pulsed', 't_pi', 'seconds_per_point', 'stop_time', 'n_lines', 'number_of_resonances', 'threshold', '__doc__' ]
class Visualization(HasTraits): # Data models dipole_data_model = Instance(DataModel) signals_data_model = Instance(DataModel) # Renderers # dipole_renderer = Instance(LinePlot) signals_renderer = Instance(MultiLinePlot) # Plots dipole_plot = Instance(LinePlot) signals_plot = Instance(Plot) def _signals_renderer_default(self): print('_signals_renderer_default') """Create the default MultiLinePlot instance.""" xs = ArrayDataSource(self.signals_data_model.x_index, sort_order='ascending') xrange = DataRange1D() xrange.add(xs) ys = ArrayDataSource(self.signals_data_model.y_index, sort_order='ascending') yrange = DataRange1D() yrange.add(ys) # The data source for the MultiLinePlot. ds = MultiArrayDataSource(data=self.signals_data_model.data) multi_line_plot_renderer = \ MultiLinePlot( index = xs, yindex = ys, index_mapper = LinearMapper(range=xrange), value_mapper = LinearMapper(range=yrange), value=ds, global_max = self.signals_data_model.data.max(), global_min = self.signals_data_model.data.min(), fast_clip = False) # Add pan tool multi_line_plot_renderer.tools.append( PanTool(multi_line_plot_renderer, restrict_to_data=True)) # Add zoom tool multi_line_plot_renderer.overlays.append( ZoomTool(multi_line_plot_renderer, tool_mode="range", always_on=False, x_max_zoom_factor=20.0, y_max_zoom_factor=20.0, x_min_zoom_factor=1.0, y_min_zoom_factor=1.0, zoom_to_mouse=True)) #multi_line_plot_renderer.overlays.append(LineInspector(multi_line_plot_renderer, axis="index",write_metadata=True,is_listener=True)) # multi_line_plot_renderer.overlays.append(LineInspector(multi_line_plot_renderer, axis='value', # write_metadata=True, # is_listener=True)) multi_line_plot_renderer.overlays.append( LineInspector(multi_line_plot_renderer, axis="index", write_metadata=True, is_listener=True)) return multi_line_plot_renderer # def _dipole_renderer_default(self): # print("_dipole_renderer_default") # xs = ArrayDataSource(self.dipole_data_model.x_index, sort_order='ascending') # xrange = DataRange1D() # xrange.add(xs) # xm = LinearMapper(range = xrange) # # ys = ArrayDataSource(self.dipole_data_model.data, sort_order='ascending') # yrange = DataRange1D() # yrange.add(ys) # ym = LinearMapper(range=yrange) # # #pd = ArrayPlotData(index = self.dipole_data_model.x_index) # pd = ArrayDataSource(data = self.dipole_data_model.data) # #pd.set_data("y", self.dipole_data_model.data) # # line_plot_renderer = LinePlot(index = xs, # value=pd, # index_mapper = LinearMapper(range=xrange), # value_mapper = LinearMapper(range=yrange), # global_max = self.dipole_data_model.data.max(), # global_min = self.dipole_data_model.data.min(), # fast_clip = False) # return line_plot_renderer def _signals_plot_default(self): print('_signals_plot_default') """Create the Plot instance.""" plot = Plot() plot.add(self.signals_renderer) x_axis = PlotAxis(component=plot, mapper=self.signals_renderer.index_mapper, orientation='bottom') # y_axis = PlotAxis(component=plot, # mapper=self.signals_renderer.value_mapper, # orientation='left') plot.overlays.extend([x_axis]) plot.origin_axis_visible = False plot.padding_top = 0 plot.padding_left = 0 plot.padding_right = 0 plot.padding_bottom = 50 plot.border_visible = False plot.bgcolor = "white" plot.use_downsampling = True return plot def _dipole_plot_default(self): print('_dipole_plot_default') """Create the Plot instance.""" #pd = ArrayPlotData(index = self.dipole_data_model.x_index) #pd.set_data("y", self.dipole_data_model.data) plot = create_line_plot( (self.dipole_data_model.x_index, self.dipole_data_model.data), color='black') #plot.add(self.dipole_renderer) #plot.plot(("index", "y")) x_axis = PlotAxis(component=plot, mapper=plot.index_mapper, orientation='bottom') # # y_axis = PlotAxis(component=plot, # # mapper=self.signals_renderer.value_mapper, # # orientation='left') plot.overlays.extend([x_axis]) plot.index = self.signals_renderer.index plot.overlays.append( LineInspector(plot, write_metadata=True, is_listener=True)) # plot.overlays.append(LineInspector(plot, axis="value", # is_listener=True)) plot.origin_axis_visible = False plot.padding_top = 0 plot.padding_left = 0 plot.padding_right = 0 plot.padding_bottom = 50 plot.border_visible = False plot.bgcolor = "white" plot.use_downsampling = True return plot def _signals_data_model_changed(self, old, new): print('model_changed') xs = ArrayDataSource(self.signals_data_model.x_index, sort_order='ascending') xrange = DataRange1D() xrange.add(xs) ys = ArrayDataSource(self.signals_data_model.y_index, sort_order='ascending') yrange = DataRange1D() yrange.add(ys) # The data source for the MultiLinePlot. print('ds') ds = MultiArrayDataSource(data=self.signals_data_model.data) self.signals_renderer.set( index=xs, yindex=ys, #index_mapper = LinearMapper(range=xrange), value_mapper = LinearMapper(range=yrange), value=ds, global_max=self.signals_data_model.data.max(), global_min=self.signals_data_model.data.min()) self.signals_renderer.index_mapper.range = xrange self.signals_renderer.value_mapper.range = yrange self.signals_renderer.request_redraw() def _dipole_data_model_changed(self, old, new): print('dipole_data_model_changed') #self.dipole_plot.index_range = self.signals_renderer.index_range #self.dipole_plot.index = self.signals_renderer.index print(dir(self.dipole_data_model.x_index)) xs = ArrayDataSource(self.dipole_data_model.x_index, sort_order='ascending') xrange = DataRange1D() xrange.add(xs) self.dipole_plot.index.set_data(self.dipole_data_model.x_index) self.dipole_plot.value.set_data(self.dipole_data_model.data) self.dipole_plot.index_mapper.range = xrange self.dipole_plot.request_redraw() # def _time_default(self): # numpoints = 1000.0 # low = -5 # high = 15 # time = np.arange(low, high, (high-low)/numpoints).tolist() # return time # # def _dipole_signal_default(self): # signal = jn(10, self.time) # return signal # # def _signals_default(self): # numpoints = 1000 # signals = [] #np.zeros((10, numpoints)) # for i in range(10): # signals.append(jn(i, self.time)) # return signals # # def _dipole_plot_default(self): # plot = create_line_plot((self.time, self.dipole_signal), color = 'black') # plot.origin_axis_visible = False # plot.origin = "top left" # plot.border_visible = False # plot.bgcolor = "white" # return plot # # def _plots_container_default(self): # container = VPlotContainer() # # Plot some bessel functions # value_range = None # for i in range(10): # plot = create_line_plot((self.time,self.signals[i,:]), width=2.0)#color=tuple(COLOR_PALETTE[i]), width=2.0) # plot.origin_axis_visible = False # plot.origin = "top left" # plot.border_visible = False # plot.bgcolor = "white" # if value_range is None: # value_range = plot.value_mapper.range # else: # plot.value_range = value_range # value_range.add(plot.value) # # if i%2 == 1: # # plot.line_style = "dash" # container.add(plot) # return container # # def _signals_changed(self, old, new): # #self.signals.values = new # print("_signals_changed") # print(dir(self.plots_container)) # # def _dipole_signal_changed(self, old, new): # #self.signals.values = new # print("_signals_changed") # self.dipole_plot.set(y_values = new) # self.dipole_plot.draw() # #print(dir(self.dipole_plot)) # # self.dipole_plot. # # def zoom_in(self, zoom_factor = 1.0): # print('zoom') # #for i,s in enumerate(self.plots_container): # #self.plots_container. # @on_trait_change('scene.activated') # def update_plot(self): # # This function is called when the view is opened. We don't # # populate the scene when the view is not yet open, as some # # VTK features require a GLContext. # # # We can do normal mlab calls on the embedded scene. # self.scene.mlab.test_points3d() # Drives multi_line_plot_renderer.normalized_amplitude amplitude = Range(0.0, 3.0, value=1.0) # Drives multi_line_plot_renderer.offset offset = Range(-1.0, 1.0, value=0) # Drives multi_line_plot_renderer.scaler scale = Range(0.0, 2.0, value=1.0) #----------------------------------------------------------------------- # Trait change handlers #----------------------------------------------------------------------- def _amplitude_changed(self, amp): self.signals_renderer.normalized_amplitude = amp def _offset_changed(self, off): self.signals_renderer.offset = off # FIXME: The change does not trigger a redraw. Force a redraw by # faking an amplitude change. self.signals_renderer._amplitude_changed() def _scale_changed(self, sca): self.signals_renderer.scale = sca self.signals_renderer._amplitude_changed() # the layout of the dialog screated view = View( VSplit( Item('dipole_plot', editor=ComponentEditor(), show_label=False, height=75), Item('signals_plot', editor=ComponentEditor(), show_label=False)), #HGroup( Item('amplitude'), Item('offset'), Item('scale'), # springy=True, #), width=500, height=500, resizable=True)
class CounterTimeTrace(FreeJob, GetSetItemsMixin): trace_length = Range(low=10, high=10000, value=100, desc='Length of Count Trace', label='Trace Length') seconds_per_point = Range(low=0.001, high=1, value=0.1, desc='Seconds per point [s]', label='Seconds per point [s]') refresh_interval = Range(low=0.01, high=1, value=0.1, desc='Refresh interval [s]', label='Refresh interval [s]') # trace data C = Array() T = Array() trace_plot = Instance(Plot) trace_data = Instance(ArrayPlotData) def __init__(self): super(CounterTimeTrace, self).__init__() self.on_trait_change(self.update_T, 'T', dispatch='ui') self.on_trait_change(self.update_C, 'C', dispatch='ui') def _C_default(self): return np.zeros((self.trace_length, )) def _T_default(self): return self.seconds_per_point * np.arange(self.trace_length) def update_T(self): self.trace_data.set_data('t', self.T) def update_C(self): self.trace_data.set_data('y', self.C) def _trace_length_changed(self): self.C = self._C_default() self.T = self._T_default() def _seconds_per_point_changed(self): self.T = self._T_default() def _trace_data_default(self): return ArrayPlotData(t=self.T, y=self.C) def _trace_plot_default(self): plot = Plot(self.trace_data, width=500, height=500, resizable='hv') plot.plot(('t', 'y'), type='line', color='blue') return plot def _run(self): """Acquire Count Trace""" try: self.state = 'run' counter = ha.CountTask(self.seconds_per_point, self.trace_length) except Exception as e: logging.getLogger().exception(e) raise else: while True: threading.current_thread().stop_request.wait( self.refresh_interval) if threading.current_thread().stop_request.isSet(): break try: self.C = counter.getData() / self.seconds_per_point except Exception as e: logging.getLogger().exception(e) raise finally: self.state = 'idle' traits_view = View(VGroup( HGroup( Item('start_button', show_label=False), Item('stop_button', show_label=False), Item('priority'), Item('state', style='readonly'), ), Item('trace_plot', editor=ComponentEditor(), show_label=False), HGroup( Item('trace_length'), Item('seconds_per_point'), Item('refresh_interval'), ), ), title='Counter Time Trace', width=800, height=600, buttons=[], resizable=True, handler=GetSetItemsHandler())
class SolutionView(HasTraits): python_console_cmds = Dict() # we need to doubleup on Lists to store the psuedo absolutes separately # without rewriting everything """ 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 """ plot_history_max = Int(1000) 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 = List() dops_table = List() pos_table = 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 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=resource_filename('console/images/iconic/x.svg'), width=16, height=16) zoomall_button = SVGButton( label='', tooltip='Zoom All', toggle=True, filename=resource_filename('console/images/iconic/fullscreen.svg'), width=16, height=16) center_button = SVGButton( label='', tooltip='Center on Solution', toggle=True, filename=resource_filename('console/images/iconic/target.svg'), width=16, height=16) paused_button = SVGButton( label='', tooltip='Pause', toggle_tooltip='Run', toggle=True, filename=resource_filename('console/images/iconic/pause.svg'), toggle_filename=resource_filename('console/images/iconic/play.svg'), width=16, height=16) traits_view = View( HSplit( VGroup( Item('table', style='readonly', editor=TabularEditor(adapter=SimpleAdapter()), show_label=False, width=0.3), Item('rtk_pos_note', show_label=False, resizable=True, editor=MultilineTextEditor(TextEditor(multi_line=True)), style='readonly', width=0.3, height=-40), ), 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 _reset_remove_current(self): self.plot_data.set_data('cur_lat_spp', []) self.plot_data.set_data('cur_lng_spp', []) self.plot_data.set_data('cur_alt_spp', []) self.plot_data.set_data('cur_lat_dgnss', []) self.plot_data.set_data('cur_lng_dgnss', []) self.plot_data.set_data('cur_alt_dgnss', []) self.plot_data.set_data('cur_lat_float', []) self.plot_data.set_data('cur_lng_float', []) self.plot_data.set_data('cur_alt_float', []) self.plot_data.set_data('cur_lat_fixed', []) self.plot_data.set_data('cur_lng_fixed', []) self.plot_data.set_data('cur_alt_fixed', []) def _clear_history(self): self.plot_data.set_data('lat_spp', []) self.plot_data.set_data('lng_spp', []) self.plot_data.set_data('alt_spp', []) self.plot_data.set_data('lat_dgnss', []) self.plot_data.set_data('lng_dgnss', []) self.plot_data.set_data('alt_dgnss', []) self.plot_data.set_data('lat_float', []) self.plot_data.set_data('lng_float', []) self.plot_data.set_data('alt_float', []) self.plot_data.set_data('lat_fixed', []) self.plot_data.set_data('lng_fixed', []) self.plot_data.set_data('alt_fixed', []) def _clear_button_fired(self): self.tows = np.empty(self.plot_history_max) self.lats = np.empty(self.plot_history_max) self.lngs = np.empty(self.plot_history_max) self.alts = np.empty(self.plot_history_max) self.modes = np.empty(self.plot_history_max) self._clear_history() self._reset_remove_current() 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 age_corrections_callback(self, sbp_msg, **metadata): age_msg = MsgAgeCorrections(sbp_msg) if age_msg.age != 0xFFFF: self.age_corrections = age_msg.age / 10.0 else: self.age_corrections = None def update_table(self): self.table = self.pos_table + self.vel_table + self.dops_table def auto_survey(self): if self.last_soln.flags != 0: self.latitude_list.append(self.last_soln.lat) self.longitude_list.append(self.last_soln.lon) self.altitude_list.append(self.last_soln.height) if len(self.latitude_list) > 1000: self.latitude_list = self.latitude_list[-1000:] self.longitude_list = self.longitude_list[-1000:] self.altitude_list = self.altitude_list[-1000:] if len(self.latitude_list) != 0: self.latitude = sum(self.latitude_list) / len(self.latitude_list) self.altitude = sum(self.altitude_list) / len(self.latitude_list) self.longitude = sum(self.longitude_list) / len(self.latitude_list) def pos_llh_callback(self, sbp_msg, **metadata): if sbp_msg.msg_type == SBP_MSG_POS_LLH_DEP_A: soln = MsgPosLLHDepA(sbp_msg) else: soln = MsgPosLLH(sbp_msg) self.last_soln = soln self.last_pos_mode = get_mode(soln) pos_table = [] soln.h_accuracy *= 1e-3 soln.v_accuracy *= 1e-3 tow = soln.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 # Return the best estimate of my local and receiver time in convenient # format that allows changing precision of the seconds ((tloc, secloc), (tgps, secgps)) = log_time_strings(self.week, tow) if self.utc_time: ((tutc, secutc)) = datetime_2_str(self.utc_time) 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 not self.logging_p: self.log_file = None if self.logging_p: if self.log_file is None: self.log_file = sopen(filepath_p, 'w') self.log_file.write( "pc_time,gps_time,tow(sec),latitude(degrees),longitude(degrees),altitude(meters)," "h_accuracy(meters),v_accuracy(meters),n_sats,flags\n") log_str_gps = "" if tgps != "" and secgps != 0: log_str_gps = "{0}:{1:06.6f}".format(tgps, float(secgps)) self.log_file.write( '%s,%s,%.3f,%.10f,%.10f,%.4f,%.4f,%.4f,%d,%d\n' % ("{0}:{1:06.6f}".format(tloc, float(secloc)), log_str_gps, tow, soln.lat, soln.lon, soln.height, soln.h_accuracy, soln.v_accuracy, soln.n_sats, soln.flags)) self.log_file.flush() if self.last_pos_mode == 0: pos_table.append(('GPS Week', EMPTY_STR)) pos_table.append(('GPS TOW', EMPTY_STR)) pos_table.append(('GPS Time', EMPTY_STR)) pos_table.append(('Num. Signals', EMPTY_STR)) pos_table.append(('Lat', EMPTY_STR)) pos_table.append(('Lng', EMPTY_STR)) pos_table.append(('Height', EMPTY_STR)) pos_table.append(('Horiz Acc', EMPTY_STR)) pos_table.append(('Vert Acc', EMPTY_STR)) else: self.last_stime_update = time.time() if self.week is not None: pos_table.append(('GPS Week', str(self.week))) pos_table.append(('GPS TOW', "{:.3f}".format(tow))) if self.week is not None: pos_table.append( ('GPS Time', "{0}:{1:06.3f}".format(tgps, float(secgps)))) if self.utc_time is not None: pos_table.append( ('UTC Time', "{0}:{1:06.3f}".format(tutc, float(secutc)))) pos_table.append(('UTC Src', self.utc_source)) if self.utc_time is None: pos_table.append(('UTC Time', EMPTY_STR)) pos_table.append(('UTC Src', EMPTY_STR)) pos_table.append(('Sats Used', soln.n_sats)) pos_table.append(('Lat', soln.lat)) pos_table.append(('Lng', soln.lon)) pos_table.append(('Height', "{0:.3f}".format(soln.height))) pos_table.append(('Horiz Acc', soln.h_accuracy)) pos_table.append(('Vert Acc', soln.v_accuracy)) pos_table.append(('Pos Flags', '0x%03x' % soln.flags)) pos_table.append(('Pos Fix Mode', mode_dict[self.last_pos_mode])) if self.age_corrections is not None: pos_table.append(('Corr. Age [s]', self.age_corrections)) self.auto_survey() # set-up table variables self.pos_table = pos_table self.update_table() # setup_plot variables self.lats[1:] = self.lats[:-1] self.lngs[1:] = self.lngs[:-1] self.alts[1:] = self.alts[:-1] self.tows[1:] = self.tows[:-1] self.modes[1:] = self.modes[:-1] self.lats[0] = soln.lat self.lngs[0] = soln.lon self.alts[0] = soln.height self.tows[0] = soln.tow self.modes[0] = self.last_pos_mode self.lats = self.lats[-self.plot_history_max:] self.lngs = self.lngs[-self.plot_history_max:] self.alts = self.alts[-self.plot_history_max:] self.tows = self.tows[-self.plot_history_max:] self.modes = self.modes[-self.plot_history_max:] def solution_draw(self): if self.running: GUI.invoke_later(self._solution_draw) def _solution_draw(self): spp_indexer, dgnss_indexer, float_indexer, fixed_indexer = None, None, None, None self._clear_history() soln = self.last_soln if np.any(self.modes): spp_indexer = (self.modes == SPP_MODE) dgnss_indexer = (self.modes == DGNSS_MODE) float_indexer = (self.modes == FLOAT_MODE) fixed_indexer = (self.modes == FIXED_MODE) # make sure that there is at least one true in indexer before setting if any(spp_indexer): self.plot_data.set_data('lat_spp', self.lats[spp_indexer]) self.plot_data.set_data('lng_spp', self.lngs[spp_indexer]) self.plot_data.set_data('alt_spp', self.alts[spp_indexer]) if any(dgnss_indexer): self.plot_data.set_data('lat_dgnss', self.lats[dgnss_indexer]) self.plot_data.set_data('lng_dgnss', self.lngs[dgnss_indexer]) self.plot_data.set_data('alt_dgnss', self.alts[dgnss_indexer]) if any(float_indexer): self.plot_data.set_data('lat_float', self.lats[float_indexer]) self.plot_data.set_data('lng_float', self.lngs[float_indexer]) self.plot_data.set_data('alt_float', self.alts[float_indexer]) if any(fixed_indexer): self.plot_data.set_data('lat_fixed', self.lats[fixed_indexer]) self.plot_data.set_data('lng_fixed', self.lngs[fixed_indexer]) self.plot_data.set_data('alt_fixed', self.alts[fixed_indexer]) # update our "current solution" icon if self.last_pos_mode == SPP_MODE: self._reset_remove_current() self.plot_data.set_data('cur_lat_spp', [soln.lat]) self.plot_data.set_data('cur_lng_spp', [soln.lon]) elif self.last_pos_mode == DGNSS_MODE: self._reset_remove_current() self.plot_data.set_data('cur_lat_dgnss', [soln.lat]) self.plot_data.set_data('cur_lng_dgnss', [soln.lon]) elif self.last_pos_mode == FLOAT_MODE: self._reset_remove_current() self.plot_data.set_data('cur_lat_float', [soln.lat]) self.plot_data.set_data('cur_lng_float', [soln.lon]) elif self.last_pos_mode == FIXED_MODE: self._reset_remove_current() self.plot_data.set_data('cur_lat_fixed', [soln.lat]) self.plot_data.set_data('cur_lng_fixed', [soln.lon]) else: pass # TODO: figure out how to center the graph now that we have two separate messages # when we selectively send only SPP, the centering function won't work anymore if not self.zoomall and 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_spp', 'lng_dgnss', 'lng_float', 'lng_fixed'), ('lat_spp', 'lat_dgnss', 'lat_float', 'lat_fixed')) def dops_callback(self, sbp_msg, **metadata): flags = 0 if sbp_msg.msg_type == SBP_MSG_DOPS_DEP_A: dops = MsgDopsDepA(sbp_msg) flags = 1 else: dops = MsgDops(sbp_msg) flags = dops.flags if flags != 0: 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))] else: self.dops_table = [('PDOP', EMPTY_STR), ('GDOP', EMPTY_STR), ('TDOP', EMPTY_STR), ('HDOP', EMPTY_STR), ('VDOP', EMPTY_STR)] self.dops_table.append(('DOPS Flags', '0x%03x' % flags)) def vel_ned_callback(self, sbp_msg, **metadata): flags = 0 if sbp_msg.msg_type == SBP_MSG_VEL_NED_DEP_A: vel_ned = MsgVelNEDDepA(sbp_msg) flags = 1 else: vel_ned = MsgVelNED(sbp_msg) flags = vel_ned.flags tow = vel_ned.tow * 1e-3 if self.nsec is not None: tow += self.nsec * 1e-9 ((tloc, secloc), (tgps, secgps)) = log_time_strings(self.week, 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 not self.logging_v: self.vel_log_file = None if self.logging_v: if self.vel_log_file is None: self.vel_log_file = sopen(filepath_v, 'w') self.vel_log_file.write( 'pc_time,gps_time,tow(sec),north(m/s),east(m/s),down(m/s),speed(m/s),flags,num_signals\n' ) log_str_gps = '' if tgps != "" and secgps != 0: log_str_gps = "{0}:{1:06.6f}".format(tgps, float(secgps)) self.vel_log_file.write( '%s,%s,%.3f,%.6f,%.6f,%.6f,%.6f,%d,%d\n' % ("{0}:{1:06.6f}".format(tloc, float(secloc)), log_str_gps, tow, 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, flags, vel_ned.n_sats)) self.vel_log_file.flush() if flags != 0: 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)), ] else: self.vel_table = [ ('Vel. N', EMPTY_STR), ('Vel. E', EMPTY_STR), ('Vel. D', EMPTY_STR), ] self.vel_table.append(('Vel Flags', '0x%03x' % flags)) self.update_table() def gps_time_callback(self, sbp_msg, **metadata): if sbp_msg.msg_type == SBP_MSG_GPS_TIME_DEP_A: time_msg = MsgGPSTimeDepA(sbp_msg) flags = 1 elif sbp_msg.msg_type == SBP_MSG_GPS_TIME: time_msg = MsgGPSTime(sbp_msg) flags = time_msg.flags if flags != 0: self.week = time_msg.wn self.nsec = time_msg.ns_residual def utc_time_callback(self, sbp_msg, **metadata): tmsg = MsgUtcTime(sbp_msg) seconds = math.floor(tmsg.seconds) microseconds = int(tmsg.ns / 1000.00) if tmsg.flags & 0x1 == 1: dt = datetime.datetime(tmsg.year, tmsg.month, tmsg.day, tmsg.hours, tmsg.minutes, tmsg.seconds, microseconds) self.utc_time = dt self.utc_time_flags = tmsg.flags if (tmsg.flags >> 3) & 0x3 == 0: self.utc_source = "Factory Default" elif (tmsg.flags >> 3) & 0x3 == 1: self.utc_source = "Non Volatile Memory" elif (tmsg.flags >> 3) & 0x3 == 2: self.utc_source = "Decoded this Session" else: self.utc_source = "Unknown" else: self.utc_time = None self.utc_source = None def __init__(self, link, dirname=''): super(SolutionView, self).__init__() self.lats = np.zeros(self.plot_history_max) self.lngs = np.zeros(self.plot_history_max) self.alts = np.zeros(self.plot_history_max) self.tows = np.zeros(self.plot_history_max) self.modes = np.zeros(self.plot_history_max) 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.last_pos_mode = 0 self.plot_data = ArrayPlotData(lat_spp=[], lng_spp=[], alt_spp=[], cur_lat_spp=[], cur_lng_spp=[], lat_dgnss=[], lng_dgnss=[], alt_dgnss=[], cur_lat_dgnss=[], cur_lng_dgnss=[], lat_float=[], lng_float=[], alt_float=[], cur_lat_float=[], cur_lng_float=[], lat_fixed=[], lng_fixed=[], alt_fixed=[], cur_lat_fixed=[], cur_lng_fixed=[]) self.plot = Plot(self.plot_data) # 1000 point buffer self.plot.plot(('lng_spp', 'lat_spp'), type='line', line_width=0.1, name='', color=color_dict[SPP_MODE]) self.plot.plot(('lng_spp', 'lat_spp'), type='scatter', name='', color=color_dict[SPP_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='line', line_width=0.1, name='', color=color_dict[DGNSS_MODE]) self.plot.plot(('lng_dgnss', 'lat_dgnss'), type='scatter', name='', color=color_dict[DGNSS_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_float', 'lat_float'), type='line', line_width=0.1, name='', color=color_dict[FLOAT_MODE]) self.plot.plot(('lng_float', 'lat_float'), type='scatter', name='', color=color_dict[FLOAT_MODE], marker='dot', line_width=0.0, marker_size=1.0) self.plot.plot(('lng_fixed', 'lat_fixed'), type='line', line_width=0.1, name='', color=color_dict[FIXED_MODE]) self.plot.plot(('lng_fixed', 'lat_fixed'), type='scatter', name='', color=color_dict[FIXED_MODE], marker='dot', line_width=0.0, marker_size=1.0) # current values spp = self.plot.plot(('cur_lng_spp', 'cur_lat_spp'), type='scatter', name=mode_dict[SPP_MODE], color=color_dict[SPP_MODE], marker='plus', line_width=1.5, marker_size=5.0) dgnss = self.plot.plot(('cur_lng_dgnss', 'cur_lat_dgnss'), type='scatter', name=mode_dict[DGNSS_MODE], color=color_dict[DGNSS_MODE], marker='plus', line_width=1.5, marker_size=5.0) rtkfloat = self.plot.plot(('cur_lng_float', 'cur_lat_float'), type='scatter', name=mode_dict[FLOAT_MODE], color=color_dict[FLOAT_MODE], marker='plus', line_width=1.5, marker_size=5.0) rtkfix = self.plot.plot(('cur_lng_fixed', 'cur_lat_fixed'), type='scatter', name=mode_dict[FIXED_MODE], color=color_dict[FIXED_MODE], marker='plus', line_width=1.5, marker_size=5.0) plot_labels = ['SPP', 'DGPS', "RTK float", "RTK fixed"] plots_legend = dict(zip(plot_labels, [spp, dgnss, rtkfloat, rtkfix])) self.plot.legend.plots = plots_legend self.plot.legend.labels = plot_labels # sets order 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_DEP_A, SBP_MSG_POS_LLH]) self.link.add_callback(self.vel_ned_callback, [SBP_MSG_VEL_NED_DEP_A, SBP_MSG_VEL_NED]) self.link.add_callback(self.dops_callback, [SBP_MSG_DOPS_DEP_A, SBP_MSG_DOPS]) self.link.add_callback(self.gps_time_callback, [SBP_MSG_GPS_TIME_DEP_A, SBP_MSG_GPS_TIME]) self.link.add_callback(self.utc_time_callback, [SBP_MSG_UTC_TIME]) self.link.add_callback(self.age_corrections_callback, SBP_MSG_AGE_CORRECTIONS) call_repeatedly(0.2, self.solution_draw) self.week = None self.utc_time = None self.age_corrections = None self.nsec = 0 self.python_console_cmds = { 'solution': self, }
class SpectrumAnalyzerView(HasTraits): python_console_cmds = Dict() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) which_plot = Str("Channel 1") hint = Str("Enable with setting in \"System Monitor\" group.") traits_view = View( Item('plot', editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)), show_label=False), HGroup( Spring(width=20, springy=False), Item('', label='Channel Selection:', emphasized=True), Item( name='which_plot', show_label=False, tooltip= 'Select the RF Channel for which to display Spectrum Analyzer', editor=EnumEditor(values=[ "Channel 1", "Channel 2", "Channel 3", "Channel 4" ])), Spring(width=20, springy=True), Item('hint', show_label=False, style='readonly', style_sheet='*{font-style:italic}'), Spring(width=20, springy=True))) def parse_payload(self, raw_payload): """ Params ====== payload: is an array of ints representing bytes from the SBP_MSG_USER_DATA message 'contents' Returns ======= JSON dict of a payload based on this format, except all N of the diff_amplitude are together in a list under 'diff_amplitudes' and rx_time is split into TOW and week Frequency is in Hz, Amplitude is in dB FIELD TYPE OFFSET SHORT EXPLANATION user_msg_tag u16 0 bespoke preamble for spectrum message rx_time struct 2 struct gps_time_t defined as double TOW + s16 WEEK starting_frequency float 12 starting frequency for this packet frequency_step float 16 frequency step for points in this packet min_amplitude float 20 minimum level of amplitude amplitude_step float 24 amplitude unit diff_amplitude u8 28 N values in the above units """ # Turn the array of ints representing uint8 bytes back to binary, so you can use struct # formatting to unpack it. Otherwise you would have to manually parse each byte. pack_fmt_str = 'B' * len(raw_payload) payload = struct.pack(pack_fmt_str, *raw_payload) payload_header_fmt_str = '<Hdhffff' payload_header_bytes = struct.calcsize(payload_header_fmt_str) diff_amplitude_n = (len(raw_payload) - payload_header_bytes) diff_amplitude_fmt_str = 'B' * diff_amplitude_n fmt_str = payload_header_fmt_str + diff_amplitude_fmt_str parsed_payload = struct.unpack(fmt_str, payload) fft_msg_header = [ 'user_msg_tag', 'TOW', 'week', 'starting_frequency', 'frequency_step', 'min_amplitude', 'amplitude_step' ] payload_json = dict( zip(fft_msg_header, parsed_payload[:len(fft_msg_header)])) fft_msg_payload = parsed_payload[len(fft_msg_header):] payload_json['diff_amplitudes'] = fft_msg_payload return payload_json def _which_plot_changed(self): channel = int(self.which_plot[-1:]) self.fftmonitor.enable_channel(channel) self.fftmonitor.disable_channel( [ch for ch in CHANNELS if ch != channel]) def spectrum_analyzer_state_callback(self, sbp_msg, **metadata): ''' Params ====== sbp_msg: sbp.msg.SBP object Updates the view's data for use in self.update_plot ''' self.fftmonitor.capture_fft(sbp_msg, **metadata) channel = int(self.which_plot[-1:]) if self.fftmonitor.num_ffts(channel) > 0: most_recent_fft = self.fftmonitor.get_ffts(channel).pop() self.fftmonitor.clear_ffts() self.most_recent_complete_data['frequencies'] = most_recent_fft[ 'frequencies'] self.most_recent_complete_data['amplitudes'] = most_recent_fft[ 'amplitudes'] GUI.invoke_later(self.update_plot) def update_plot(self): most_recent_fft = self.most_recent_complete_data if len(most_recent_fft['frequencies']) != 0: self.plot_data.set_data('frequency', most_recent_fft['frequencies']) self.plot_data.set_data('amplitude', most_recent_fft['amplitudes']) self.plot.value_mapper.range.low = min( most_recent_fft['amplitudes']) self.plot.value_mapper.range.high = max( most_recent_fft['amplitudes']) def __init__(self, link): super(SpectrumAnalyzerView, self).__init__() self.link = link self.link.add_callback(self.spectrum_analyzer_state_callback, [SBP_MSG_SPECAN, SBP_MSG_SPECAN_DEP]) self.python_console_cmds = {'spectrum': self} self.fftmonitor = FFTMonitor() self.fftmonitor.enable_channel(int(self.which_plot[-1:])) self.most_recent_complete_data = { 'frequencies': np.array([]), 'amplitudes': np.array([]) } self.plot_data = ArrayPlotData() self.plot = Plot(self.plot_data, emphasized=True) self.plot.title = 'Spectrum Analyzer' self.plot.title_color = [0, 0, 0.43] self.plot.value_axis.orientation = 'right' self.plot.value_axis.title_spacing = 30 self.plot.value_axis.title = 'Amplitude (dB)' self.plot.index_axis.title = 'Frequency (MHz)' self.plot_data.set_data('frequency', [0]) self.plot_data.set_data('amplitude', [0]) self.plot.plot(('frequency', 'amplitude'), type='line', name='spectrum')
class AutoFocus( ManagedJob, GetSetItemsMixin ): # overwrite default priority from ManagedJob (default 0) priority = 10 confocal = Instance( Confocal ) odmr = Instance( ODMR ) #counter_trace = Instance ( CounterTrace ) size_xy = Range(low=0.5, high=10., value=0.8, desc='Size of XY Scan', label='Size XY [micron]', mode='slider', auto_set=False, enter_set=True) size_z = Range(low=0.5, high=10., value=1.5, desc='Size of Z Scan', label='Size Z [micron]', mode='slider', auto_set=False, enter_set=True) step_xy = Range(low=0.01, high=10., value=0.04, desc='Step of XY Scan', label='Step XY [micron]', mode='slider', auto_set=False, enter_set=True) step_z = Range(low=0.01, high=10., value=0.15, desc='Step of Z Scan', label='Step Z [micron]', mode='slider', auto_set=False, enter_set=True) seconds_per_point_xy = Range(low=1e-3, high=10, value=0.03, desc='Seconds per point for XY Scan', label='seconds per point XY [s]', mode='text', auto_set=False, enter_set=True) seconds_per_point_z = Range(low=1e-3, high=10, value=0.05, desc='Seconds per point for Z Scan', label='seconds per point Z [s]', mode='text', auto_set=False, enter_set=True) fit_method_xy = Enum('Maximum', 'Gaussian', desc='Fit Method for XY Scan', label='XY Fit Method') fit_method_z = Enum('Maximum', 'Gaussian', desc='Fit Method for Z Scan', label='Z Fit Method') X = Array(value=np.array((0.,1.)) ) Y = Array(value=np.array((0.,1.)) ) Z = Array(value=np.array((-1.,1.)) ) data_xy = Array( ) data_z = Array( value=np.array((0,0)) ) targets = Instance( {}.__class__, factory={}.__class__ ) # Dict traits are no good for pickling, therefore we have to do it with an ordinary dictionary and take care about the notification manually target_list = Instance( list, factory=list, args=([None],) ) # list of targets that are selectable in current_target editor current_target = Enum(values='target_list') drift = Array( value=np.array(((0,0,0,),)) ) drift_time = Array( value=np.array((0,)) ) current_drift = Array( value=np.array((0,0,0)) ) focus_interval = Range(low=1, high=6000, value=10, desc='Time interval between automatic focus events', label='Interval [m]', auto_set=False, enter_set=True) periodic_focus = Bool(False, label='Periodic focusing') periodic_freq_feedback = Bool(False, label='Periodic freq feedback') threshold = Range(low=1, high=6000, value=1000, desc='ignore oil junks', label='threshold kcs/s', auto_set=False, enter_set=True) target_name = Str(label='name', desc='name to use when adding or removing targets') add_target_button = Button(label='Add Target', desc='add target with given name') remove_current_target_button = Button(label='Remove Current', desc='remove current target') next_target_button = Button(label='Next Target', desc='switch to next available target') undo_button = Button(label='undo', desc='undo the movement of the stage') previous_state = Instance( () ) plot_data_image = Instance( ArrayPlotData ) plot_data_line = Instance( ArrayPlotData ) plot_data_drift = Instance( ArrayPlotData ) figure_image = Instance( HPlotContainer, editor=ComponentEditor() ) figure_line = Instance( Plot, editor=ComponentEditor() ) figure_drift = Instance( Plot, editor=ComponentEditor() ) image_plot = Instance( CMapImagePlot ) def __init__(self, confocal, odmr): super(AutoFocus, self).__init__() self.confocal = confocal self.odmr = odmr #self.counter_trace = counter_trace self.on_trait_change(self.update_plot_image, 'data_xy', dispatch='ui') self.on_trait_change(self.update_plot_line_value, 'data_z', dispatch='ui') self.on_trait_change(self.update_plot_line_index, 'Z', dispatch='ui') self.on_trait_change(self.update_plot_drift_value, 'drift', dispatch='ui') self.on_trait_change(self.update_plot_drift_index, 'drift_time', dispatch='ui') @on_trait_change('next_target_button') def next_target(self): """Convenience method to switch to the next available target.""" keys = self.targets.keys() key = self.current_target if len(keys) == 0: logging.getLogger().info('No target available. Add a target and try again!') elif not key in keys: self.current_target = keys[0] else: self.current_target = keys[(keys.index(self.current_target)+1)%len(keys)] def _targets_changed(self, name, old, new): l = new.keys() + [None] # rebuild target_list for Enum trait l.sort() self.target_list = l self._draw_targets() # redraw target labels def _current_target_changed(self): self._draw_targets() # redraw target labels def _draw_targets(self): c = self.confocal c.remove_all_labels() c.show_labels=True for key, coordinates in self.targets.iteritems(): if key == self.current_target: c.set_label(key, coordinates, marker_color='red') else: c.set_label(key, coordinates) def _periodic_focus_changed(self, new): if not new and hasattr(self, 'cron_event'): CronDaemon().remove(self.cron_event) if new: self.cron_event = CronEvent(self.submit, min=range(0,60,self.focus_interval)) CronDaemon().register(self.cron_event) def fit_xy(self): if self.fit_method_xy == 'Maximum': index = self.data_xy.argmax() xp = self.X[index%len(self.X)] yp = self.Y[index/len(self.X)] self.XYFitParameters = [xp, yp] self.xfit = xp self.yfit = yp return xp, yp else: print 'Not Implemented! Fix Me!' def fit_z(self): if self.fit_method_z == 'Maximum': zp = self.Z[self.data_z.argmax()] self.zfit = zp return zp else: print 'Not Implemented! Fix Me!' def add_target(self, key, coordinates=None): if coordinates is None: c = self.confocal coordinates = np.array((c.x,c.y,c.z)) if self.targets == {}: self.forget_drift() if self.targets.has_key(key): if warning('A target with this name already exists.\nOverwriting will move all targets.\nDo you want to continue?'): self.current_drift = coordinates - self.targets[key] self.forget_drift() else: return else: coordinates = coordinates - self.current_drift self.targets[key] = coordinates self.trait_property_changed('targets', self.targets) # trigger event such that Enum is updated and Labels are redrawn self.confocal.show_labels=True def remove_target(self, key): if not key in self.targets: logging.getLogger().info('Target cannot be removed. Target does not exist.') return self.targets.pop(key) # remove target from dictionary self.trait_property_changed('targets', self.targets) # trigger event such that Enum is updated and Labels are redrawn def remove_all_targets(self): self.targets = {} def forget_drift(self): targets = self.targets # reset coordinates of all targets according to current drift for key in targets: targets[key] += self.current_drift # trigger event such that target labels are redrawn self.trait_property_changed('targets', self.targets) # set current_drift to 0 and clear plot self.current_drift = np.array((0., 0., 0.)) self.drift_time = np.array((time.time(),)) self.drift = np.array(((0,0,0),)) def _add_target_button_fired(self): self.add_target( self.target_name ) def _remove_current_target_button_fired(self): self.remove_target( self.current_target ) def _run(self): logging.getLogger().debug("trying run.") try: self.state='run' #ha.PulseGenerator().Light() if self.current_target is None: self.focus() if np.amax(self.data_xy)<10: self._undo_button_fired() pg.Light() self.focus() # if self.periodic_freq_feedback: # self.odmr.submit() else: # focus target coordinates = self.targets[self.current_target] confocal = self.confocal confocal.x, confocal.y, confocal.z = coordinates + self.current_drift current_coordinates = self.focus() self.current_drift = current_coordinates - coordinates self.drift = np.append(self.drift, (self.current_drift,), axis=0) self.drift_time = np.append(self.drift_time, time.time()) logging.getLogger().debug('Drift: %.2f, %.2f, %.2f'%tuple(self.current_drift)) # if self.periodic_freq_feedback: # self.odmr.submit() finally: self.state = 'idle' def focus(self): """ Focuses around current position in x, y, and z-direction. """ xp = self.confocal.x yp = self.confocal.y zp = self.confocal.z self.previous_state = ((xp,yp,zp), self.current_target) ##+scanner.getXRange()[1] safety = 0 #distance to keep from the ends of scan range xmin = np.clip(xp-0.5*self.size_xy, scanner.getXRange()[0]+safety, scanner.getXRange()[1]-safety) xmax = np.clip(xp+0.5*self.size_xy, scanner.getXRange()[0]+safety, scanner.getXRange()[1]-safety) ymin = np.clip(yp-0.5*self.size_xy, scanner.getYRange()[0]+safety, scanner.getYRange()[1]-safety) ymax = np.clip(yp+0.5*self.size_xy, scanner.getYRange()[0]+safety, scanner.getYRange()[1]-safety) X = np.arange(xmin, xmax, self.step_xy) Y = np.arange(ymin, ymax, self.step_xy) self.X = X self.Y = Y XP = X[::-1] self.data_xy=np.zeros((len(Y),len(X))) #self.image_plot.index.set_data(X, Y) for i,y in enumerate(Y): if threading.current_thread().stop_request.isSet(): self.confocal.x = xp self.confocal.y = yp self.confocal.z = zp return xp, yp, zp if i%2 != 0: XL = XP else: XL = X YL = y * np.ones(X.shape) ZL = zp * np.ones(X.shape) Line = np.vstack( (XL, YL, ZL) ) c = scanner.scanLine(Line, self.seconds_per_point_xy)/1e3 if i%2 == 0: self.data_xy[i,:] = c[:] else: self.data_xy[i,:] = c[-1::-1] self.trait_property_changed('data_xy', self.data_xy) for i in range(self.data_xy.shape[0]): for j in range(self.data_xy.shape[1]): if self.data_xy[i][j]>self.threshold: self.data_xy[i][j]=0 xp, yp = self.fit_xy() self.confocal.x = xp self.confocal.y = yp Z = np.hstack( ( np.arange(zp, zp-0.5*self.size_z, -self.step_z), np.arange(zp-0.5*self.size_z, zp+0.5*self.size_z, self.step_z), np.arange(zp+0.5*self.size_z, zp, -self.step_z) ) ) Z = np.clip(Z, scanner.getZRange()[0]+safety, scanner.getZRange()[1]-safety) X = xp * np.ones(Z.shape) Y = yp * np.ones(Z.shape) if not threading.current_thread().stop_request.isSet(): Line = np.vstack( (X, Y, Z) ) data_z = scanner.scanLine(Line, self.seconds_per_point_z)/1e3 self.Z = Z self.data_z = data_z for i in range(self.data_z.shape[0]): if self.data_z[i]>self.threshold: self.data_z[i]=0 zp = self.fit_z() self.confocal.z = zp logging.getLogger().info('Focus: %.2f, %.2f, %.2f' %(xp, yp, zp)) return xp, yp, zp def undo(self): if self.previous_state is not None: coordinates, target = self.previous_state self.confocal.x, self.confocal.y, self.confocal.z = coordinates if target is not None: self.drift_time = np.delete(self.drift_time, -1) self.current_drift = self.drift[-2] self.drift = np.delete(self.drift, -1, axis=0) self.previous_state = None else: logging.getLogger().info('Can undo only once.') def _undo_button_fired(self): self.remove() self.undo() def _plot_data_image_default(self): return ArrayPlotData(image=np.zeros((2,2))) def _plot_data_line_default(self): return ArrayPlotData(x=self.Z, y=self.data_z) def _plot_data_drift_default(self): return ArrayPlotData(t=self.drift_time, x=self.drift[:,0], y=self.drift[:,1], z=self.drift[:,2]) def _figure_image_default(self): plot = Plot(self.plot_data_image, width=180, height=180, padding=3, padding_left=48, padding_bottom=32) plot.img_plot('image', colormap=jet, name='image') plot.aspect_ratio=1 #plot.value_mapper.domain_limits = (scanner.getYRange()[0],scanner.getYRange()[1]) #plot.index_mapper.domain_limits = (scanner.getXRange()[0],scanner.getXRange()[1]) plot.value_mapper.domain_limits = (0,self.size_xy) plot.index_mapper.domain_limits = (0,self.size_xy) container = HPlotContainer() image = plot.plots['image'][0] colormap = image.color_mapper colorbar = ColorBar(index_mapper=LinearMapper(range=colormap.range), color_mapper=colormap, plot=plot, orientation='v', resizable='v', width=20, height=200, padding=8, padding_left=20) container = HPlotContainer() container.add(plot) container.add(colorbar) return container def _figure_line_default(self): plot = Plot(self.plot_data_line, width=70, height=40, padding=8, padding_left=64, padding_bottom=32) plot.plot(('x','y'), color='blue') plot.index_axis.title = 'z [um]' plot.value_axis.title = 'Fluorescence [ k / s ]' return plot def _figure_drift_default(self): plot = Plot(self.plot_data_drift, width=70, height=40, padding=8, padding_left=64, padding_bottom=32) plot.plot(('t','x'), type='line', color='blue', name='x') plot.plot(('t','y'), type='line', color='red', name='y') plot.plot(('t','z'), type='line', color='green', name='z') bottom_axis = PlotAxis(plot, orientation="bottom", tick_generator=ScalesTickGenerator(scale=CalendarScaleSystem())) plot.index_axis=bottom_axis plot.index_axis.title = 'time' plot.value_axis.title = 'drift [um]' plot.legend.visible=True return plot def _image_plot_default(self): return self.figure_image.components[0].plots['image'][0] def update_plot_image(self): self.plot_data_image.set_data('image', self.data_xy) def update_plot_line_value(self): self.plot_data_line.set_data('y', self.data_z) def update_plot_line_index(self): self.plot_data_line.set_data('x', self.Z) def update_plot_drift_value(self): if len(self.drift) == 1: self.plot_data_drift.set_data('x', np.array(())) self.plot_data_drift.set_data('y', np.array(())) self.plot_data_drift.set_data('z', np.array(())) else: self.plot_data_drift.set_data('x', self.drift[:,0]) self.plot_data_drift.set_data('y', self.drift[:,1]) self.plot_data_drift.set_data('z', self.drift[:,2]) def update_plot_drift_index(self): if len(self.drift_time) == 0: self.plot_data_drift.set_data('t', np.array(())) else: self.plot_data_drift.set_data('t', self.drift_time - self.drift_time[0]) traits_view = View(VGroup(HGroup(Item('submit_button', show_label=False), Item('remove_button', show_label=False), Item('priority'), Item('state', style='readonly'), Item('undo_button', show_label=False), ), Group(VGroup(HGroup(Item('target_name'), Item('add_target_button', show_label=False), ), HGroup(Item('current_target'), Item('next_target_button', show_label=False), Item('remove_current_target_button', show_label=False), ), HGroup(Item('periodic_focus'), Item('focus_interval', enabled_when='not periodic_focus'), ), HGroup(Item('periodic_freq_feedback'), Item('threshold') ), label='tracking', ), VGroup(Item('size_xy'), Item('step_xy'), Item('size_z'), Item('step_z'), HGroup(Item('seconds_per_point_xy'), Item('seconds_per_point_z'), ), label='Settings', springy=True, ), layout='tabbed' ), VSplit(Item('figure_image', show_label=False, resizable=True)), HGroup(Item('figure_line', show_label=False, resizable=True), Item('figure_drift', show_label=False, resizable=True), ), ), menubar = MenuBar(Menu(Action(action='save', name='Save (.pyd or .pys)'), Action(action='load', name='Load'), Action(action='_on_close', name='Quit'), name='File'), Menu(Action(action='remove_all_targets', name='Remove All'), Action(action='forget_drift', name='Forget Drift'), name='Target'),), title='Auto Focus', width=500, height=700, buttons=[], resizable=True, handler=AutoFocusHandler) get_set_items=['confocal','targets','current_target','current_drift','drift','drift_time','periodic_focus', 'size_xy', 'size_z', 'step_xy', 'step_z', 'seconds_per_point_xy', 'seconds_per_point_z', 'data_xy', 'data_z', 'X', 'Y', 'Z', 'focus_interval', 'threshold' ] get_set_order=['confocal','targets']
class PlotExample(HasTraits): plot = Instance(Component) traits_view = View(Item('plot', editor=ComponentEditor(), show_label=False), resizable=True, title="Tornado Plot", width=800, height=600) def _plot_default(self): container = OverlayPlotContainer(bgcolor="white") plots = self._make_curves() for plot in plots: plot.padding = 60 container.add(plot) bottom_axis = PlotAxis(plot, orientation='bottom') label_list = [ 'var a', 'var b', 'var c', 'var d', 'var e', 'var f', 'var g', 'var h', 'var i' ] vertical_axis = LabelAxis(plot, orientation='left', title='Categories', positions=range(1, 10), labels=label_list) vertical2_axis = LabelAxis(plot, orientation='right', positions=range(1, 10), labels=label_list) plot.underlays.append(vertical_axis) plot.underlays.append(vertical2_axis) plot.underlays.append(bottom_axis) return container def _get_points(self): index = linspace(pi / 4, 3 * pi / 2, 9) data = sin(index) + 2 return (range(1, 10), data) def _make_curves(self): (index_points, value_points) = self._get_points() size = len(index_points) middle_value = 2500000.0 mid_values = middle_value * ones(size) low_values = mid_values - 10000.0 * value_points high_values = mid_values + 20000.0 * value_points idx = ArrayDataSource(index_points) vals = ArrayDataSource(low_values, sort_order="none") idx2 = ArrayDataSource(index_points) vals2 = ArrayDataSource(high_values, sort_order="none") starting_vals = ArrayDataSource(mid_values, sort_order="none") # Create the index range index_range = DataRange1D(idx, low=0.5, high=9.5) index_mapper = LinearMapper(range=index_range) # Create the value range value_range = DataRange1D(vals, vals2, low_setting='auto', high_setting='auto', tight_bounds=False) value_mapper = LinearMapper(range=value_range, tight_bounds=False) # Create the plot plot1 = BarPlot(index=idx, value=vals, value_mapper=value_mapper, index_mapper=index_mapper, starting_value=starting_vals, line_color='black', orientation='v', fill_color=tuple(COLOR_PALETTE[6]), bar_width=0.8, antialias=False) plot2 = BarPlot(index=idx2, value=vals2, value_mapper=value_mapper, index_mapper=index_mapper, starting_value=starting_vals, line_color='black', orientation='v', fill_color=tuple(COLOR_PALETTE[1]), bar_width=0.8, antialias=False) return [plot1, plot2]
class SpectrumAnalyzerView(HasTraits): python_console_cmds = Dict() plot = Instance(Plot) plot_data = Instance(ArrayPlotData) which_plot = Str("Channel 1") hint = Str("Enable with setting in \"System Monitor\" group.") traits_view = View( Item('plot', editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)), show_label=False), HGroup( Spring(width=20, springy=False), Item('', label='Channel Selection:', emphasized=True), Item( name='which_plot', show_label=False, tooltip= 'Select the RF Channel for which to display Spectrum Analyzer', editor=EnumEditor(values=[ "Channel 1", "Channel 2", "Channel 3", "Channel 4" ])), Spring(width=20, springy=True), Item('hint', show_label=False, style='readonly', style_sheet='*{font-style:italic}'), Spring(width=20, springy=True))) def parse_payload(self, raw_payload): """ Params ====== payload: is an array of ints representing bytes from the SBP_MSG_USER_DATA message 'contents' Returns ======= JSON dict of a payload based on this format, except all N of the diff_amplitude are together in a list under 'diff_amplitudes' and rx_time is split into TOW and week Frequency is in Hz, Amplitude is in dB FIELD TYPE OFFSET SHORT EXPLANATION user_msg_tag u16 0 bespoke preamble for spectrum message rx_time struct 2 struct gps_time_t defined as double TOW + s16 WEEK starting_frequency float 12 starting frequency for this packet frequency_step float 16 frequency step for points in this packet min_amplitude float 20 minimum level of amplitude amplitude_step float 24 amplitude unit diff_amplitude u8 28 N values in the above units """ # Turn the array of ints representing uint8 bytes back to binary, so you can use struct # formatting to unpack it. Otherwise you would have to manually parse each byte. pack_fmt_str = 'B' * len(raw_payload) payload = struct.pack(pack_fmt_str, *raw_payload) payload_header_fmt_str = '<Hdhffff' payload_header_bytes = struct.calcsize(payload_header_fmt_str) diff_amplitude_n = (len(raw_payload) - payload_header_bytes) diff_amplitude_fmt_str = 'B' * diff_amplitude_n fmt_str = payload_header_fmt_str + diff_amplitude_fmt_str parsed_payload = struct.unpack(fmt_str, payload) fft_msg_header = [ 'user_msg_tag', 'TOW', 'week', 'starting_frequency', 'frequency_step', 'min_amplitude', 'amplitude_step' ] payload_json = dict( zip(fft_msg_header, parsed_payload[:len(fft_msg_header)])) fft_msg_payload = parsed_payload[len(fft_msg_header):] payload_json['diff_amplitudes'] = fft_msg_payload return payload_json def get_frequencies(self, start_freq, freq_step, n): ''' start_freq: float (Hz) freq_step: float (Hz) n: int ''' return np.array([start_freq + freq_step * i for i in range(n)]) def get_amplitudes(self, min_amplitude, diffs, unit): ''' min_amplitude: float (dB) diffs: tuple of floats (dB) unit: float (dB) ''' return np.array([min_amplitude + diff * unit for diff in diffs]) def spectrum_analyzer_state_callback(self, sbp_msg, **metadata): ''' Params ====== sbp_msg: sbp.msg.SBP object Updates the view's data for use in self.update_plot ''' # Need to figure out which user_msg_tag means it's an FFT message # for now assume that all SBP_MSG_USER_DATA is relevant fft = MsgSpecan(sbp_msg) frequencies = self.get_frequencies(fft.freq_ref, fft.freq_step, len(fft.amplitude_value)) amplitudes = self.get_amplitudes(fft.amplitude_ref, fft.amplitude_value, fft.amplitude_unit) tag = fft.channel_tag if (tag == 1 and self.which_plot != "Channel 1"): return if (tag == 2 and self.which_plot != "Channel 2"): return if (tag == 3 and self.which_plot != "Channel 3"): return if (tag == 4 and self.which_plot != "Channel 4"): return timestamp = GpsTime(fft.t.wn, fft.t.tow) if len(self.incomplete_data[timestamp]['frequencies']) + len( frequencies) == NUM_POINTS: self.most_recent_complete_data['frequencies'] = np.append( self.incomplete_data[timestamp]['frequencies'], frequencies, axis=0) self.most_recent_complete_data['amplitudes'] = np.append( self.incomplete_data[timestamp]['amplitudes'], amplitudes, axis=0) self.incomplete_data.pop(timestamp) if timestamp is None or timestamp > self.most_recent: self.most_recent = timestamp GUI.invoke_later(self.update_plot) else: self.incomplete_data[timestamp]['frequencies'] = np.append( self.incomplete_data[timestamp]['frequencies'], frequencies, axis=0) self.incomplete_data[timestamp]['amplitudes'] = np.append( self.incomplete_data[timestamp]['amplitudes'], amplitudes, axis=0) def update_plot(self): most_recent_fft = self.most_recent_complete_data if len(most_recent_fft['frequencies']) != 0: self.plot_data.set_data('frequency', most_recent_fft['frequencies']) self.plot_data.set_data('amplitude', most_recent_fft['amplitudes']) self.plot.value_mapper.range.low = min( most_recent_fft['amplitudes']) self.plot.value_mapper.range.high = max( most_recent_fft['amplitudes']) def __init__(self, link): super(SpectrumAnalyzerView, self).__init__() self.link = link self.link.add_callback(self.spectrum_analyzer_state_callback, SBP_MSG_SPECAN) self.python_console_cmds = {'spectrum': self} # keys are GpsTime self.incomplete_data = defaultdict(lambda: { 'frequencies': np.array([]), 'amplitudes': np.array([]) }) self.most_recent_complete_data = { 'frequencies': np.array([]), 'amplitudes': np.array([]) } self.most_recent = None self.plot_data = ArrayPlotData() self.plot = Plot(self.plot_data, emphasized=True) self.plot.title = 'Spectrum Analyzer' self.plot.title_color = [0, 0, 0.43] self.plot.value_axis.orientation = 'right' self.plot.value_axis.title_spacing = 30 self.plot.value_axis.title = 'Amplitude (dB)' self.plot.index_axis.title = 'Frequency (MHz)' self.plot_data.set_data('frequency', [0]) self.plot_data.set_data('amplitude', [0]) self.plot.plot(('frequency', 'amplitude'), type='line', name='spectrum')
class TrackingView(CodeFiltered): python_console_cmds = Dict() legend_visible = Bool() plot = Instance(Plot) plots = List() plot_data = Instance(ArrayPlotData) traits_view = View( VGroup( Item( 'plot', editor=ComponentEditor(bgcolor=(0.8, 0.8, 0.8)), show_label=False, ), HGroup( Spring(width=8, springy=False), Item('legend_visible', label="Show Legend:"), CodeFiltered.get_filter_group(), ))) def clean_cn0(self, t): assert self.CN0_lock.locked() for k in list(self.CN0_dict.keys()): if self.CN0_age[k] < self.time[0]: del self.CN0_dict[k] del self.CN0_age[k] def measurement_state_callback(self, sbp_msg, **metadata): with self.CN0_lock: codes_that_came = [] t = monotonic() - self.t_init self.time.append(t) # first we loop over all the SIDs / channel keys we have stored and set 0 in for CN0 for i, s in enumerate(sbp_msg.states): if code_is_glo(s.mesid.code): # for Glonass satellites, store in two dictionaries FCN and SLOT # so that they can both be retrieved when displaying the channel if (s.mesid.sat > 90): self.glo_fcn_dict[i] = s.mesid.sat - 100 sat = self.glo_fcn_dict.get(i, 0) if (s.mesid.sat <= 90): self.glo_slot_dict[sat] = s.mesid.sat else: sat = s.mesid.sat key = (s.mesid.code, sat) codes_that_came.append(key) if s.cn0 != 0: self.CN0_dict[key].append(s.cn0 / 4.0) self.CN0_age[key] = t received_code_list = getattr(self, "received_codes", []) if s.mesid.code not in received_code_list: received_code_list.append(s.mesid.code) self.received_codes = received_code_list for key, cno_array in list(self.CN0_dict.items()): if key not in codes_that_came: cno_array.append(0) self.clean_cn0(t) self.update_scheduler.schedule_update('update_plot', self.update_plot) def tracking_state_callback(self, sbp_msg, **metadata): with self.CN0_lock: codes_that_came = [] t = monotonic() - self.t_init self.time.append(t) # first we loop over all the SIDs / channel keys we have stored and set 0 in for CN0 # for each SID, an array of size MAX PLOT with the history of CN0's stored # If there is no CN0 or not tracking for an epoch, 0 will be used # each array can be plotted against host_time, t for i, s in enumerate(sbp_msg.states): if code_is_glo(s.sid.code): if (s.sid.sat > 90): sat = s.sid.sat - 100 else: sat = s.fcn - GLO_FCN_OFFSET self.glo_slot_dict[sat] = s.sid.sat else: sat = s.sid.sat key = (s.sid.code, sat) codes_that_came.append(key) if s.cn0 != 0: self.CN0_dict[key].append(s.cn0 / 4.0) self.CN0_age[key] = t received_code_list = getattr(self, "received_codes", []) if s.sid.code not in received_code_list: received_code_list.append(s.sid.code) self.received_codes = received_code_list for key, cno_array in list(self.CN0_dict.items()): if key not in codes_that_came: cno_array.append(0) self.clean_cn0(t) self.update_scheduler.schedule_update('update_plot', self.update_plot) def update_plot(self): with self.CN0_lock: plot_labels = [] plots = [] # Update the underlying plot data from the CN0_dict for selected items new_plot_data = {'t': self.time} for k, cno_array in self.CN0_dict.items(): key = str(k) # set plot data if (getattr(self, 'show_{}'.format(int(k[0])), True)): new_plot_data[key] = cno_array self.plot_data.update_data(new_plot_data) # Remove any stale plots that got removed from the dictionary for each in list(self.plot.plots.keys()): if each not in [str(a) for a in self.CN0_dict.keys()] and each != 't': try: self.plot.delplot(each) except KeyError: pass try: self.plot_data.del_data(each) except KeyError: pass # add/remove plot as neccesary and build legend for k, cno_array in self.CN0_dict.items(): key = str(k) if (getattr(self, 'show_{}'.format(int(k[0])), True) and not cno_array.count(0) == NUM_POINTS): if key not in self.plot.plots.keys(): pl = self.plot.plot(('t', key), type='line', color=get_color(k), name=key) else: pl = self.plot.plots[key] plots.append(pl) plot_labels.append(get_label(k, self.glo_slot_dict)) # if not selected or all 0, remove else: if key in list(self.plot.plots.keys()): self.plot.delplot(key) plots = dict(list(zip(plot_labels, plots))) self.plot.legend.plots = plots def _legend_visible_changed(self): if self.plot: if not self.legend_visible: self.plot.legend.visible = False else: self.plot.legend.visible = True self.plot.legend.tools.append( LegendTool(self.plot.legend, drag_button="right")) def __init__(self, link): super(TrackingView, self).__init__() self.t_init = monotonic() self.time = deque([x * 1 / TRK_RATE for x in range(-NUM_POINTS, 0, 1)], maxlen=NUM_POINTS) self.CN0_lock = threading.Lock() self.CN0_dict = defaultdict(lambda: deque([0] * NUM_POINTS, maxlen=NUM_POINTS)) self.CN0_age = defaultdict(lambda: -1) self.glo_fcn_dict = {} self.glo_slot_dict = {} self.n_channels = None self.plot_data = ArrayPlotData(t=[0.0]) self.plot = Plot(self.plot_data, emphasized=True) self.plot.title = 'Tracking C/N0' self.plot.title_color = [0, 0, 0.43] self.ylim = self.plot.value_mapper.range self.ylim.low = SNR_THRESHOLD self.ylim.high = 60 self.plot.value_range.bounds_func = lambda l, h, m, tb: (0, h * (1 + m)) self.plot.value_axis.orientation = 'right' self.plot.value_axis.axis_line_visible = False self.plot.value_axis.title = 'dB-Hz' self.plot_data.set_data('t', self.time) self.plot.index_axis.title = 'seconds' self.plot.index_range.bounds_func = lambda l, h, m, tb: (h - 100, h) self.legend_visible = True self.plot.legend.visible = True self.plot.legend.align = 'll' self.plot.legend.line_spacing = 1 self.plot.legend.font = 'monospace 8' self.plot.legend.draw_layer = 'overlay' self.plot.legend.tools.append( LegendTool(self.plot.legend, drag_button="right")) self.link = link self.link.add_callback(self.measurement_state_callback, SBP_MSG_MEASUREMENT_STATE) self.link.add_callback(self.tracking_state_callback, SBP_MSG_TRACKING_STATE) self.python_console_cmds = {'track': self} self.update_scheduler = UpdateScheduler()