class Sp4ArrayFileSource(ArraySource): file_name = Str component = Enum('Amp', 'Phase', 'Real', 'Imag') set_component = Str f = Instance(sp4.Sp4File) view = View(Group(Item(name='transpose_input_array'), Item(name='file_name', editor=TextEditor(auto_set=False,\ enter_set=True)), Item(name='component', editor=EnumEditor(values=component)), Item(name='scalar_name'), Item(name='vector_name'), Item(name='spacing'), Item(name='origin'), Item(name='update_image_data', show_label=False), show_labels=True) ) def __init__(self, **kw_args): super(Sp4ArrayFileSource, self).__init__(**kw_args) fn = kw_args.pop('file_name', None) if fn is not None: self.file_name = fn self._open(self.file_name) self.component = "Amp" self._component_changed('Amp') def _open(self, fn): self.f = sp4.Sp4File(self.file_name) def _component_changed(self, info): if info == "Amp": self.scalar_data = numpy.abs(self.f.GetArray()) if info == "Phase": self.scalar_data = numpy.angle(self.f.GetArray()) self.update() def _file_name_changed(self, info): print self.file_name
class Shape(HasTraits): shape_type = Enum("rectangle", "circle") editable = Bool x, y, w, h, r = [Int] * 5 view = View(VGroup( HGroup(Item("shape_type"), Item("editable")), VGroup(Item("x"), Item("y"), Item("w"), Item("h"), visible_when="shape_type=='rectangle'", enabled_when="editable"), VGroup(Item("x"), Item("y"), Item("r"), visible_when="shape_type=='circle'", enabled_when="editable"), ), resizable=True)
class ShapeSelector(HasTraits): select = Enum(*[cls.__name__ for cls in Shape.__subclasses__()]) shape = Instance(Shape) view = View( VGroup( Item("select"), Item("shape", style="custom"), Item("object.shape.info", style="custom"), show_labels = False ), width = 350, height = 300, resizable = True ) def __init__(self, **traits): super(ShapeSelector, self).__init__(**traits) self._select_changed() def _select_changed(self): klass = [c for c in Shape.__subclasses__() if c.__name__ == self.select][0] self.shape = klass()
class Line(AbstractOverlay): orientation = Enum("h", "v") color = ColorTrait("green") width = Int(1) def overlay(self, component, gc, *args, **kw): if component is None: return gc.save_state() gc.set_stroke_color(self.color_) gc.set_line_width(self.width) if self.orientation == "h": mid = component.y + component.height / 2 gc.move_to(component.x, mid) gc.line_to(component.x2, mid) else: mid = component.x + component.width / 2 gc.move_to(mid, component.y) gc.line_to(mid, component.y2) gc.stroke_path() gc.restore_state()
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")
class Label(HasTraits): """ The Label class implements the data model for a label. """ #### 'Label' interface #################################################### # The name. name = Unicode # The size in points. size = Int(18) # The style. style = Scriptable(Enum('normal', 'bold', 'italic')) ########################################################################### # 'Label' interface. ########################################################################### @scriptable def __init__(self, **traits): """ Initialise the object. We only implement this so that it can be decorated and so the script manager knows how to recreate it. """ super(Label, self).__init__(**traits) @scriptable def increment_size(self, by): """ Increment the current font size. This demonstrates a scriptable method. """ self.size += by @scriptable def decrement_size(self, by): """ decrement the current font size. This demonstrates a scriptable method. """ self.size -= by
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
class MlabPreferencesHelper(PreferencesHelper): # The preferences path for which we use. preferences_path = 'enthought.mayavi.mlab' ###################################################################### # Our preferences. # The mlab backend to use. backend = Enum('auto', 'envisage', 'simple', 'test', desc='the mlab backend to use') # The background color of the renderer. background_color = Tuple(Range(0., 1.), Range(0., 1.), Range(0., 1.), editor=RGBColorEditor, desc='the background color of the scene') # The foreground color of the renderer. foreground_color = Tuple(Range(0., 1.), Range(0., 1.), Range(0., 1.), editor=RGBColorEditor, desc='the foreground color of the scene') # Offscreen rendering. offscreen = Bool(desc='if mlab should use offscreen rendering' ' (no window will show up in this case)') ###################################################################### # Traits UI view. traits_view = View(Group(Item('backend'), Item('background_color'), Item('foreground_color'), Item('offscreen')), resizable=True)
class BooleanOpFilter(ProcessObject): name = "Boolean Operation" input = Input tool = Input operation = Enum("cut", "fuse", "common") map = {'cut': BRepAlgoAPI.BRepAlgoAPI_Cut, 'fuse': BRepAlgoAPI.BRepAlgoAPI_Fuse, 'common': BRepAlgoAPI.BRepAlgoAPI_Common} traits_view = View('operation') def _operation_changed(self, vnew): self.name = "Boolean Op: %s"%vnew self.modified = True def execute(self): builder = self.map[self.operation] s1 = self.input.shape s2 = self.tool.shape return builder(s1, s2).Shape()
class CfgFile(HasTraits): name = Str parent = Any directory = DelegatesTo('parent') descendents = List(This) config_type = Enum('appman', 'XM', 'PVA', 'task_state', 'target_positions', 'start_positions', 'auto_control_config', 'grasp_event', 'auto_pilot', 'module_config', 'tool_change') def _descendents_default(self): if self.config_type == 'XM': fd = parse_XM_config(self.directory + '/' + self.name) task_state_config_files = fd['task_state_config_files'] l = [] for kid in task_state_config_files: l.append(CfgFile(name=kid, config_type='task_state', parent=self)) if fd.has_key('tool_change_config_files'): tool_change_config_files = fd['tool_change_config_files'] for kid in tool_change_config_files: l.append(CfgFile(name=kid, config_type='tool_change', parent=self)) elif self.config_type == 'task_state': fd = parse_XM_config(self.directory + '/' + self.name) l = [CfgFile(name=fd['target_configurations_file'], config_type='target_positions', parent=self)] elif self.config_type == 'appman': fd = parse_appman(self.directory + '/' + self.name, self.parent.name) kids = fd['module_config_files'] l = [] for kid in kids: l.append(CfgFile(name=os.path.relpath(kid, self.directory), config_type='module_config', parent=self)) else: l = [] return l
class SimplePlotDecoder(DataDecoder): """ Decodes lines of text formatted using a simple format. """ name = Str('SimplePlot Decoder') view = View( Item(name="pass_through", label="Pass-through"), title='SimplePlot decoder' ) pass_through = Enum('User messages', 'Plot-o-matic messages', 'Both', 'None') _sub_re = re.compile('\W+') def decode(self, data): """ Decode an input string of the form ~variable_name#value. """ if data[0] != '~': if self.pass_through == 'User messages' or self.pass_through == 'Both': print data[:-1] return None if self.pass_through == 'Plot-o-matic messages' or self.pass_through == 'Both': print data[:-1] var_name, val = data[1:].split('#') var_name = self._sub_re.sub('_', var_name) new_dict = {} try: new_dict[var_name] = float(val) except: new_dict[var_name] = val return new_dict
class MandelbrotController(AbstractController): application = Instance("MandelbrotDemo") event_state = Enum("normal", "moving") start_x = Float start_y = Float def normal_left_down(self, evt): self.event_state = "moving" self.start_x = evt.x self.start_y = evt.y def moving_mouse_move(self, evt): app = self.application dx = evt.x - self.start_x dy = evt.y - self.start_y app.cx -= dx/float(self.component.x2)*2*app.d app.cy -= dy/float(self.component.y2)*2*app.d self.start_x = evt.x self.start_y = evt.y app.update_plot() def moving_left_up(self, evt): self.event_state = "normal" def normal_mouse_wheel(self, evt): app = self.application x0, x1, y0, y1 = app.cx-app.d, app.cx+app.d, app.cy-app.d, app.cy+app.d x = x0 + evt.x/float(self.component.x2)*2*app.d y = y0 + evt.y/float(self.component.y2)*2*app.d if evt.mouse_wheel < 0: d2 = app.d * 1.2 else: d2 = app.d / 1.2 scale = d2/app.d app.cx = (2*x+(x0+x1-2*x)*scale)/2 app.cy = (2*y+(y0+y1-2*y)*scale)/2 app.d = d2 app.update_plot()
class ISplitWidget(Interface): """ Mix-in class for split widgets. A split widget is one that is split in two either horizontally or vertically. """ #### 'ISplitWidget' interface ############################################# # The direction in which the widget is split. # # Splitting vertically means there will be a left hand panel and a right # hand panel, splitting horizontally means there will be a top panel and # a bottom panel. direction = Enum('vertical', 'vertical', 'horizontal') # The ratio of the size of the left/top pane to the right/bottom pane. ratio = Float(0.5) # An optional callable that provides the left hand/top panel. lhs = Callable # An optional callable that provides the right hand/bottom panel. rhs = Callable ########################################################################### # Protected 'ISplitWidget' interface. ########################################################################### def _create_splitter(self, parent): """ Create the toolkit-specific control that represents the widget. """ def _create_lhs(self, parent): """ Creates the left hand/top panel depending on the direction. """ def _create_rhs(self, parent): """ Creates the right hand/bottom panel depending on the direction. """
class Guest(HasPrivateTraits): # The name of the guest: name = Str # The hotel the guest is staying at: hotel = Instance(Hotel) # The room plan the guest has chosen: plan = Enum('Flop house', 'Cheap', 'Cozy', 'Deluxe') # The maximum temperature allowed by the guest's plan: max_temperature = Property(depends_on='plan') # The current room temperature as set by the guest: temperature = Range('hotel.min_temperature', 'max_temperature') # The view of the guest: view = View(Item('plan'), Item('temperature')) # Property implementations: @cached_property def _get_max_temperature(self): return { 'Flop house': 62, 'Cheap': 66, 'Cozy': 75, 'Deluxe': 85 }[self.plan] # Default values: def _name_default(self): return choice([ 'Leah', 'Vibha', 'Janet', 'Jody', 'Dave', 'Evan', 'Ilan', 'Gael', 'Peter', 'Robert', 'Judah', 'Eric', 'Travis', 'Mike', 'Bryce', 'Chris' ])
class ImagePlot(HasTraits): plot = Instance(Plot) colormap = Enum(sorted(color_map_name_dict.keys())) data = Array traits_view = View(Item('colormap'), Item('plot', editor=ComponentEditor(), show_label=False), width=600, height=400, title="Color Map") def __init__(self): # Create plot data. row = linspace(0, 1, 100) self.data = ones([10, 100]) * row plotdata = ArrayPlotData(imagedata=self.data) # Create a Plot and associate it with the PlotData plot = Plot(plotdata) # Create a line plot in the Plot plot.img_plot("imagedata", xbounds=(0, 1), colormap=color_map_name_dict[self.colormap])[0] plot.y_axis.visible = False self.plot = plot self.plot.aspect_ratio = 5 def _colormap_changed(self, new): colormap = color_map_name_dict[self.colormap] colormap = colormap(self.plot.color_mapper.range) self.plot.color_mapper = colormap self.plot.request_redraw()
#------------------------------------------------------------------------------- # Imports: #------------------------------------------------------------------------------- from enthought.traits.api \ import HasTraits, Trait, Enum, Range from enthought.traits.ui.api \ import EnumEditor #------------------------------------------------------------------------------- # Trait definitions: #------------------------------------------------------------------------------- values = ['one', 'two', 'three', 'four'] enum = Enum(*values) range = Range(1, 4) #------------------------------------------------------------------------------- # 'TestEnumEditor' class: #------------------------------------------------------------------------------- class TestEnumEditor(HasTraits): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- value = Trait(1, enum,
class IDialog(IWindow): """ The abstract interface for all pyface dialogs. Usage: Sub-class this class and either override '_create_contents' or more simply, just override the two methods that do the real work:- 1) '_create_dialog_area' creates the main content of the dialog. 2) '_create_buttons' creates the dialog buttons. """ #### 'IDialog' interface ################################################## # The label for the 'cancel' button. The default is toolkit specific. cancel_label = Unicode # The context sensitive help Id (the 'Help' button is only shown iff this # is set). help_id = Str # The label for the 'help' button. The default is toolkit specific. help_label = Unicode # The label for the 'ok' button. The default is toolkit specific. ok_label = Unicode # Is the dialog resizeable? resizeable = Bool(True) # The return code after the window is closed to indicate whether the dialog # was closed via 'Ok' or 'Cancel'). return_code = Int(OK) # The dialog style (is it modal or not). # FIXME v3: It doesn't seem possible to use non-modal dialogs. (How do you # get access to the buttons?) style = Enum('modal', 'nonmodal') ########################################################################### # 'IDialog' interface. ########################################################################### def open(self): """ Opens the dialog. If the dialog is modal then the dialog's event loop is entered and the dialog closed afterwards. The 'return_code' trait is updated according to the button the user pressed and this value is also returned. If the dialog is non-modal 'OK' is returned. """ ########################################################################### # Protected 'IDialog' interface. ########################################################################### def _create_buttons(self, parent): """ Create and return the buttons. parent is the parent control. """ def _create_contents(self, parent): """ Create the dialog contents. parent is the parent control. """ def _create_dialog_area(self, parent): """ Create and return the main content of the dialog. parent is the parent control. """ def _show_modal(self): """ Opens the dialog as a modal dialog and returns the return code. """
class PointSelectionDemo(HasTraits): color = Enum(Colors.keys()) green_selection = List() red_selection = List() plot = Instance(Plot) data = Instance(ArrayPlotData) traits_view = View(HSplit( Item('plot', editor=ComponentEditor(), show_label=False), VGroup( Item("color", show_label=False, style="custom"), Heading(u"绿色选择点"), Item("green_selection", show_label=False, style="readonly"), Heading(u"红色选择点"), Item("red_selection", show_label=False, style="readonly"), )), width=800, height=400, resizable=True, title=u"数据点选择演示") def __init__(self, **traits): super(PointSelectionDemo, self).__init__(**traits) x = np.random.rand(100) y = np.random.rand(100) data = ArrayPlotData(x=x, y=y) plot = Plot(data, padding=25) self.scatter = scatter = plot.plot(("x", "y"), type="scatter", marker_size=4)[0] self.select_tools = {} for i, c in enumerate(Colors.keys()): hover_name = "hover_%s" % c selection_name = "selections_%s" % c self.select_tools[c] = ScatterInspector( scatter, hover_metadata_name=hover_name, selection_metadata_name=selection_name) scatter.overlays.append( ScatterInspectorOverlay( scatter, hover_metadata_name=hover_name, selection_metadata_name=selection_name, hover_color="transparent", hover_outline_color=c, hover_marker_size=6, hover_line_width=1, selection_color=Colors[c], )) scatter.active_tool = self.select_tools[self.color] scatter.index.on_trait_change(self.selection_changed, 'metadata_changed') self.plot = plot self.data = data def _color_changed(self): self.scatter.active_tool = self.select_tools[self.color] def selection_changed(self): x = self.scatter.index.get_data() y = self.scatter.value.get_data() metadata = self.scatter.index.metadata selection = metadata.get("selections_green", []) self.green_selection = [ "%d, (%f, %f)" % (s, x[s], y[s]) for s in selection ] selection = metadata.get("selections_red", []) self.red_selection = [ "%d, (%f, %f)" % (s, x[s], y[s]) for s in selection ]
class Subgraph(BaseGraph): """ Defines a representation of a subgraph in Graphviz's dot language. """ #-------------------------------------------------------------------------- # Trait definitions: #-------------------------------------------------------------------------- # An ID is one of the following: # * Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores # ('_') or digits ([0-9]), not beginning with a digit; # * a number [-]?(.[0-9]+ | [0-9]+(.[0-9]*)? ); # * any double-quoted string ("...") possibly containing escaped # quotes (\")1; # * an HTML string (<...>). # ID = Str # # name = Alias("ID", desc="synonym for ID") # Used by InstanceEditor # # # Subgraph nodes. # nodes = List(Instance(Node)) # # # Subgraph edges. # edges = List(Instance(Edge)) # # # Subgraphs of the subgraph. # subgraphs = List(Instance("godot.subgraph.Subgraph")) # # # Separate rectangular layout regions. # clusters = List(Instance("godot.cluster.Cluster")) # Parent graph in the graph heirarchy. # parent = Instance("godot.graph.Graph") # Root graph instance. # root = Instance("godot.graph.Graph") #-------------------------------------------------------------------------- # Xdot trait definitions: #-------------------------------------------------------------------------- # For a given graph object, one will typically a draw directive before the # label directive. For example, for a node, one would first use the # commands in _draw_ followed by the commands in _ldraw_. # _draw_ = Str(desc="xdot drawing directive") # # # Label draw directive. # _ldraw_ = Str(desc="xdot label drawing directive") #-------------------------------------------------------------------------- # Dot trait definitions. #-------------------------------------------------------------------------- # Rank constraints on the nodes in a subgraph. If rank="same", all nodes # are placed on the same rank. If rank="min", all nodes are placed on the # minimum rank. If rank="source", all nodes are placed on the minimum rank, # and the only nodes on the minimum rank belong to some subgraph whose rank # attribute is "source" or "min". Analogous criteria hold for rank="max" # and rank="sink". (Note: the minimum rank is topmost or leftmost, and the # maximum rank is bottommost or rightmost.) rank = Enum("same", "min", "source", "max", "sink", desc="rank constraints on the nodes in a subgraph", graphviz=True) #-------------------------------------------------------------------------- # Views: #-------------------------------------------------------------------------- traits_view = View( VGroup( Group( Item("vp", editor=ComponentEditor(height=100), show_label=False), Item("arrange", show_label=False)), VGroup( HGroup(Item("ID"), Item("rank")), Tabbed(nodes_item, edges_item, dock="tab"), # subgraphs_notebook_group ), layout="split"), title="Subgraph", id="godot.subgraph", buttons=["OK", "Cancel", "Help"], resizable=True) #-------------------------------------------------------------------------- # "object" interface: #-------------------------------------------------------------------------- def __str__(self): """ Returns a string representation of the cluster in dot language. """ s = "subgraph" return "%s %s" % (s, super(Subgraph, self).__str__())
class ExampleModel(HasTraits): valid_models = Property(List) root = Enum(values='valid_models') def _get_valid_models(self): return ['model1', 'model2', 'model3']
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
class Outline(Module): # The version of this class. Used for persistence. __version__ = 0 # The `Outline` filter which can either be an instance of # `OutlineFilter` or `OutlineCornerFilter`. The `ObjectBase` class # is the superclass of both the `OutlineFilter` and the # `OutlineCornerFilter`. outline_filter = Property(Instance(tvtk.ObjectBase, allow_none=False), record=True) # Enum to set the outline type. outline_mode = Enum('full', 'cornered', desc='if outline mode is "full" or "cornered"') actor = Instance(Actor, allow_none=False, record=True) input_info = PipelineInfo(datasets=['any'], attribute_types=['any'], attributes=['any']) # An outline source, optionally used to choose the bounds of the # outline. outline_source = Instance(tvtk.OutlineSource, ()) bounds = DelegatesTo('outline_source', desc="the bounds of the outline: xmin, xmax, ymin, ymax") manual_bounds = Bool( desc="whether the bounds are automatically inferred from " "the data source") # Create the UI for the traits. # The controls for the outline_filter should be enabled only when the # Cornered Outline Filter is selected. view = View(Group( Group( Item(name='outline_mode'), Item(name='outline_filter', style='custom', enabled_when='outline_mode == "cornered"', visible_when='outline_mode == "cornered"', resizable=True, show_label=False), label='Outline', show_labels=False), Group('manual_bounds', Item('bounds', enabled_when='manual_bounds'), label='Bounds', ), Item(name='actor', style='custom'), layout='tabbed', show_labels=False), resizable=True) ######################################## # Private traits. # We make these private traits and cache them because if we create # these anew each time the `outline_mode` changes, then we loose # any settings the user changed on the previous mode. _full_outline = Instance(tvtk.OutlineFilter, args=(), allow_none=False) _cornered_outline = Instance(tvtk.OutlineCornerFilter, args=(), allow_none=False) ###################################################################### # `Module` interface ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* the tvtk pipeline. This method is invoked when the object is initialized via `__init__`. Note that at the time this method is called, the tvtk data pipeline will *not* yet be setup. So upstream data will not be available. The idea is that you simply create the basic objects and setup those parts of the pipeline not dependent on upstream sources and filters. You should also set the `actors` attribute up at this point. """ # When any trait on the outline filters change call the render # method. self._full_outline.on_trait_change(self.render) self._cornered_outline.on_trait_change(self.render) self.actor = Actor() def update_pipeline(self): """Override this method so that it *updates* the tvtk pipeline when data upstream is known to have changed. This method is invoked (automatically) when any of the inputs sends a `pipeline_changed` event. """ mm = self.module_manager if mm is None: return self._outline_mode_changed(self.outline_mode) self.pipeline_changed = True def update_data(self): """Override this method so that it flushes the vtk pipeline if that is necessary. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ # Just set data_changed, the component should do the rest. self.data_changed = True ###################################################################### # Non-public methods. ###################################################################### def _outline_mode_changed(self, value): """This method is invoked (automatically) when the 'outline_mode' attribute is changed. """ # Properties don't fire events, so we fire an event here so UI # elements and any listners can update due to the changed mode. new = self.outline_filter old = self._cornered_outline if new is self._full_outline: old = self._cornered_outline self.trait_property_changed('outline_filter', old, new) mm = self.module_manager if mm is None: return # Set the input of the filter. self._manual_bounds_changed() # The module has a list of outputs, but at this stage, # the output of the newly instantiated filter will be its only output. self.outputs = [self.outline_filter.output] def _get_outline_filter(self): if self.outline_mode == 'full': return self._full_outline else: return self._cornered_outline def _actor_changed(self, old, new): new.scene = self.scene new.inputs = [self] self._change_components(old, new) def _manual_bounds_changed(self): if self.manual_bounds: self.outline_filter.input = self.outline_source.output else: # Set the input of the filter. mm = self.module_manager self.outline_filter.input = mm.source.outputs[0] def _bounds_changed(self): self.pipeline_changed = True
""" Defines the class that describes the information on the inputs and outputs of an object in the pipeline. """ # Author: Prabhu Ramachandran <*****@*****.**> # Copyright (c) 2008, Prabhu Ramachandran Enthought, Inc. # License: BSD Style. # Enthought library imports. from enthought.traits.api import HasTraits, Enum, List # The list of datasets supported. DataSet = Enum('none', 'any', 'image_data', 'rectilinear_grid', 'poly_data', 'structured_grid', 'unstructured_grid') # Attribute type. AttributeType = Enum('any', 'cell', 'point', 'none') # Attribute. Attribute = Enum('any', 'none', 'scalars', 'vectors', 'tensors') ################################################################################ # Utility functions. ################################################################################ def get_tvtk_dataset_name(dataset): """Given a TVTK dataset `dataset` return the string dataset type of the dataset. """ result = 'none' if hasattr(dataset, 'is_a'):
class tcProject(HasTraits): c_states = List(tcGeneric) p_states = List(tcGeneric) processes = List(tcProcess) selected = List(tcProcess) filtered_processes = List(tcProcess) remove_filter = Button(image=ImageResource("clear.png"), width_padding=0, height_padding=0, style='toolbar') minimum_time_filter = Enum((0, 1000, 10000, 50000, 100000, 500000, 1000000, 5000000, 1000000, 5000000, 10000000, 50000000)) minimum_events_filter = Enum( (0, 2, 4, 8, 10, 20, 40, 100, 1000, 10000, 100000, 1000000)) plot_redraw = Long() filter = Str("") filter_invalid = Property(depends_on="filter") filename = Str("") power_event = CArray num_cpu = Property(Int, depends_on='c_states') num_process = Property(Int, depends_on='process') traits_view = View( VGroup( HGroup( Item( 'filter', invalid="filter_invalid", width=1, tooltip= 'filter the process list using a regular expression,\nallowing you to quickly find a process' ), Item('remove_filter', show_label=False, style='custom', tooltip='clear the filter')), HGroup( Item( 'minimum_time_filter', width=1, label='dur', tooltip= 'filter the process list with minimum duration process is scheduled' ), Item( 'minimum_events_filter', width=1, label='num', tooltip= 'filter the process list with minimum number of events process is generating' ), )), Item('filtered_processes', show_label=False, height=40, editor=process_table_editor)) first_ts = 0 def _get_filter_invalid(self): try: r = re.compile(self.filter) except: return True return False def _remove_filter_changed(self): self.filter = "" def _filter_changed(self): try: r = re.compile(self.filter) except: r = None filtered_processes = self.processes if self.minimum_events_filter: filtered_processes = filter( lambda p: self.minimum_events_filter < len(p.start_ts), filtered_processes) if self.minimum_time_filter: filtered_processes = filter( lambda p: self.minimum_time_filter < p.total_time, filtered_processes) if r: filtered_processes = filter(lambda p: r.search(p.comm), filtered_processes) self.filtered_processes = filtered_processes _minimum_time_filter_changed = _filter_changed _minimum_events_filter_changed = _filter_changed def _processes_changed(self): self._filter_changed() def _on_show(self): for i in self.selected: i.show = True self.plot_redraw += 1 def _on_hide(self): for i in self.selected: i.show = False self.plot_redraw += 1 def _on_select_all(self): if self.selected == self.filtered_processes: self.selected = [] else: self.selected = self.filtered_processes self.plot_redraw += 1 def _on_invert(self): for i in self.filtered_processes: i.show = not i.show self.plot_redraw += 1 @cached_property def _get_num_cpu(self): return len(self.c_states) def _get_num_process(self): return len(self.processes) def process_list_selected(self, selection): print selection ######### stats part ########## def process_stats(self, start, end): fact = 100. / (end - start) for tc in self.processes: starts, ends, types = tc.get_partial_tables(start, end) inds = np.where(types == colors.get_color_id("running")) tot = sum(ends[inds] - starts[inds]) tc.selection_time = int(tot) tc.selection_pc = tot * fact def get_selection_text(self, start, end): low_line = -1 high_line = -1 low_i = searchsorted(self.timestamps, start) high_i = searchsorted(self.timestamps, end) low_line = self.linenumbers[low_i] high_line = self.linenumbers[high_i] return self.get_partial_text(self.filename, low_line, high_line) ######### generic parsing part ########## def generic_find_process(self, pid, comm, ptype, same_pid_match_timestamp=0): if self.tmp_process.has_key((pid, comm)): return self.tmp_process[(pid, comm)] # else try to find if there has been a process with same pid recently, and different name. Only for user_process because other traces set pid to 0 if same_pid_match_timestamp != 0 and ptype == "user_process": for k, p in self.tmp_process.items(): if k[0] == pid and p['type'] == "user_process": if len( p['start_ts'] ) > 0 and p['start_ts'][-1] > same_pid_match_timestamp: p['comm'] = comm self.tmp_process[(pid, comm)] = p del self.tmp_process[k] return p tmp = { 'type': ptype, 'comm': comm, 'pid': pid, 'start_ts': [], 'end_ts': [], 'types': [], 'cpus': [], 'comments': [] } if not (pid == 0 and ptype == "user_process"): self.tmp_process[(pid, comm)] = tmp return tmp def generic_process_start(self, process, event, build_p_stack=True): if process['type'] == "user_process" and process['pid'] == 0: return # ignore swapper event if len(process['start_ts']) > len(process['end_ts']): process['end_ts'].append(event.timestamp) if self.first_ts == 0: self.first_ts = event.timestamp self.cur_process_by_pid[process['pid']] = process if build_p_stack: p_stack = self.cur_process[event.common_cpu] if p_stack: p = p_stack[-1] if len(p['start_ts']) > len(p['end_ts']): p['end_ts'].append(event.timestamp) # mark old process to wait for cpu p['start_ts'].append(int(event.timestamp)) p['types'].append(colors.get_color_id("waiting_for_cpu")) p['cpus'].append(event.common_cpu) p_stack.append(process) else: self.cur_process[event.common_cpu] = [process] # mark process to use cpu process['start_ts'].append(event.timestamp) process['types'].append(colors.get_color_id("running")) process['cpus'].append(event.common_cpu) def generic_process_end(self, process, event, build_p_stack=True): if process['type'] == "user_process" and process['pid'] == 0: return # ignore swapper event if len(process['start_ts']) > len(process['end_ts']): process['end_ts'].append(event.timestamp) if build_p_stack: p_stack = self.cur_process[event.common_cpu] if p_stack: p = p_stack.pop() if p['pid'] != process['pid']: print "warning: process premption stack following failure on CPU", event.common_cpu, p[ 'comm'], p['pid'], process['comm'], process[ 'pid'], map( lambda a: "%s:%d" % (a['comm'], a['pid']), p_stack), event.linenumber p_stack = [] if p_stack: p = p_stack[-1] if len(p['start_ts']) > len(p['end_ts']): p['end_ts'].append(event.timestamp) # mark old process to run on cpu p['start_ts'].append(event.timestamp) p['types'].append(colors.get_color_id("running")) p['cpus'].append(event.common_cpu) def generic_process_single_event(self, process, event): if len(process['start_ts']) > len(process['end_ts']): process['end_ts'].append(event.timestamp) # mark process to use cpu process['start_ts'].append(event.timestamp) process['types'].append(colors.get_color_id("running")) process['cpus'].append(event.common_cpu) process['end_ts'].append(event.timestamp) def generic_add_wake(self, caller, callee, event): self.wake_events.append( ((caller['comm'], caller['pid']), (callee['comm'], callee['pid']), event.timestamp)) def do_function_default(self, event): process = self.generic_find_process( 0, "kernel function:%s" % (event.callee), "function") self.generic_process_single_event(process, event) def do_event_default(self, event): event.name = event.event.split(":")[0] process = self.generic_find_process(0, "event:%s" % (event.name), "event") self.generic_process_single_event(process, event) process['comments'].append(event.event) def start_parsing(self, get_partial_text): # we build our data into python data formats, who are resizeable # once everything is parsed, we will transform it into numpy array, for fast access self.tmp_c_states = [] self.tmp_p_states = [] self.tmp_process = {} self.timestamps = [] self.linenumbers = [] self.cur_process_by_pid = {} self.wake_events = [] self.cur_process = [None] * 20 self.last_irq = {} self.last_spi = [] self.missed_power_end = 0 self.get_partial_text = get_partial_text self.methods = {} import plugin colors.parse_colors(plugin.get_plugins_additional_colors()) plugin.get_plugins_methods(self.methods) self.process_types = { "function": (tcProcess, plugin.MISC_TRACES_CLASS), "event": (tcProcess, plugin.MISC_TRACES_CLASS) } self.process_types.update( plugin.get_plugins_additional_process_types()) def finish_parsing(self): #put generated data in unresizable numpy format c_states = [] i = 0 for tc in self.tmp_c_states: t = tcIdleState(name='cpu%d' % (i)) while len(tc['start_ts']) > len(tc['end_ts']): tc['end_ts'].append(tc['start_ts'][-1]) t.start_ts = numpy.array(tc['start_ts']) t.end_ts = numpy.array(tc['end_ts']) t.types = numpy.array(tc['types']) c_states.append(t) i += 1 self.c_states = c_states i = 0 p_states = [] for tc in self.tmp_p_states: t = tcFrequencyState(name='cpu%d' % (i)) t.start_ts = numpy.array(tc['start_ts']) t.end_ts = numpy.array(tc['end_ts']) t.types = numpy.array(tc['types']) i += 1 p_states.append(t) self.wake_events = numpy.array(self.wake_events, dtype=[('waker', tuple), ('wakee', tuple), ('time', 'uint64')]) self.p_states = p_states processes = [] last_ts = 0 for pid, comm in self.tmp_process: tc = self.tmp_process[pid, comm] if len(tc['end_ts']) > 0 and last_ts < tc['end_ts'][-1]: last_ts = tc['end_ts'][-1] if len(self.tmp_process) > 0: progress = ProgressDialog(title="precomputing data", message="precomputing overview data...", max=len(self.tmp_process), show_time=False, can_cancel=False) progress.open() i = 0 for pid, comm in self.tmp_process: tc = self.tmp_process[pid, comm] if self.process_types.has_key(tc['type']): klass, order = self.process_types[tc['type']] t = klass(pid=pid, comm=tc['comm'], project=self) else: t = tcProcess(pid=pid, comm=comm, project=self) while len(tc['start_ts']) > len(tc['end_ts']): tc['end_ts'].append(last_ts) t.start_ts = numpy.array(tc['start_ts']) t.end_ts = numpy.array(tc['end_ts']) t.types = numpy.array(tc['types']) t.cpus = numpy.array(tc['cpus']) t.comments = tc['comments'] #numpy.array(tc['comments']) t.process_type = tc["type"] # precompute 16 levels of overview cache t.get_overview_ts(1 << 16) processes.append(t) progress.update(i) i += 1 if len(self.tmp_process) > 0: progress.close() self.tmp_process = [] def cmp_process(x, y): # sort process by type, pid, comm def type_index(t): try: return self.process_types[t][1] except ValueError: return len(order) + 1 c = cmp(type_index(x.process_type), type_index(y.process_type)) if c != 0: return c c = cmp(x.pid, y.pid) if c != 0: return c c = cmp(x.comm, y.comm) return c processes.sort(cmp_process) self.processes = processes self.p_states = p_states self.tmp_c_states = [] self.tmp_p_states = [] self.tmp_process = {} def ensure_cpu_allocated(self, cpu): # ensure we have enough per_cpu p/c_states timecharts while len(self.tmp_c_states) <= cpu: self.tmp_c_states.append({ 'start_ts': [], 'end_ts': [], 'types': [] }) while len(self.tmp_p_states) <= cpu: self.tmp_p_states.append({ 'start_ts': [], 'end_ts': [], 'types': [] }) def run_callbacks(self, callback, event): if callback in self.methods: for m in self.methods[callback]: try: m(self, event) except AttributeError: if not hasattr(m, "num_exc"): m.num_exc = 0 m.num_exc += 1 if m.num_exc < 10: print "bug in ", m, "still continue.." traceback.print_exc() print event if m.num_exc == 10: print m, "is too buggy, disabling, please report bug!" self.methods[callback].remove(m) if len(self.methods[callback]) == 0: del self.methods[callback] return True return False def handle_trace_event(self, event): self.linenumbers.append(event.linenumber) self.timestamps.append(event.timestamp) if event.event == 'function': callback = "do_function_" + event.callee self.run_callbacks("do_all_functions", event) else: callback = "do_event_" + event.event self.run_callbacks("do_all_events", event) if not self.run_callbacks(callback, event): if event.event == 'function': self.do_function_default(event) else: self.do_event_default(event)
class ParametricSurface(Source): # The version of this class. Used for persistence. __version__ = 0 # Flag to set the parametric function type. function = Enum('boy', 'conic_spiral', 'cap', 'dini', 'ellipsoid', 'enneper', 'figure8klein', 'klein', 'mobius', 'random_hills', 'roman', 'spline', 'super_ellipsoid', 'super_toroid', 'torus', desc='which parametric function to be used') # Define the trait 'parametric_function' whose value must be an instance of # type ParametricFunction parametric_function = Instance(tvtk.ParametricFunction, allow_none=False, record=True) # The Parametric function source which generates the data. source = Instance(tvtk.ParametricFunctionSource, args=(), kw={'scalar_mode': 'distance'}, allow_none=False, record=True) # Information about what this object can produce. output_info = PipelineInfo(datasets=['poly_data'], attribute_types=['any'], attributes=['any']) ######################################## # Private traits. # A dictionary that maps the function names to instances of the # parametric surfaces _function_dict = Dict(Str, Instance(tvtk.ParametricFunction, allow_none=False)) ###################################################################### # `object` interface ###################################################################### def __init__(self, **traits): # Setup the function dict. fd = { 'boy': tvtk.ParametricBoy(), 'conic_spiral': tvtk.ParametricConicSpiral(), 'cap': tvtk.ParametricCrossCap(), 'dini': tvtk.ParametricDini(), 'ellipsoid': tvtk.ParametricEllipsoid(), 'enneper': tvtk.ParametricEnneper(), 'figure8klein': tvtk.ParametricFigure8Klein(), 'klein': tvtk.ParametricKlein(), 'mobius': tvtk.ParametricMobius(), 'random_hills': tvtk.ParametricRandomHills(), 'roman': tvtk.ParametricRoman(), 'spline': tvtk.ParametricSpline(), 'super_ellipsoid': tvtk.ParametricSuperEllipsoid(), 'super_toroid': tvtk.ParametricSuperToroid(), 'torus': tvtk.ParametricTorus() } self._function_dict = fd # Call parent class' init. super(ParametricSurface, self).__init__(**traits) # Initialize the function to the default mode's instance from # the dictionary self.parametric_function = self._function_dict[self.function] # Call render everytime source traits change. self.source.on_trait_change(self.render) # Setup the outputs. self.outputs = [self.source.output] ###################################################################### # Non-public methods. ###################################################################### def _function_changed(self, value): """This method is invoked (automatically) when the `function` trait is changed. """ self.parametric_function = self._function_dict[self.function] def _parametric_function_changed(self, old, new): """This method is invoked (automatically) when the `parametric_function` attribute is changed. """ self.source.parametric_function = self.parametric_function # Setup the handlers so that if old is not None: old.on_trait_change(self.render, remove=True) new.on_trait_change(self.render) self.data_changed = True
class CircleSelection(AbstractController): metadata = Property(depends_on='component') event_state = Enum('normal', 'selecting', 'selected', 'moving') selection_update = Event x = Float # 圆心X坐标 y = Float # 圆心Y坐标 r = Float # 半径 mx = Float # 移动开始时的鼠标的X坐标 my = Float # 移动开始时的鼠标的Y坐标 x0 = Float # 移动开始时的圆心X坐标 y0 = Float # 移动开始时的圆心Y坐标 def _get_metadata(self): return self.component.index.metadata def normal_left_down(self, event): self.x, self.y = event.x, event.y self.metadata['circle_center'] = self.x, self.y self.metadata['circle_radius'] = 0 self.event_state = 'selecting' def selecting_mouse_move(self, event): self.r = np.sqrt((self.x - event.x)**2 + (self.y - event.y)**2) self.metadata['circle_radius'] = self.r self._update_selection() def selecting_left_up(self, event): self.event_state = 'selected' def selected_left_down(self, event): r = np.sqrt((self.x - event.x)**2 + (self.y - event.y)**2) if r > self.r: del self.metadata['circle_center'] del self.metadata['circle_radius'] del self.metadata['selections'] self.selection_update = True self.event_state = 'normal' else: self.mx, self.my = event.x, event.y self.x0, self.y0 = self.x, self.y self.event_state = 'moving' def moving_mouse_move(self, event): self.x = self.x0 + event.x - self.mx self.y = self.y0 + event.y - self.my self.metadata['circle_center'] = self.x, self.y self._update_selection() def moving_left_up(self, event): self.event_state = 'selected' def _update_selection(self): points = np.transpose( np.array((self.component.index.get_data(), self.component.value.get_data()))) screen_points = self.component.map_screen(points) tmp = screen_points - np.array([self.x, self.y]) tmp **= 2 dist = np.sum(tmp, axis=1) self.metadata['selections'] = dist < self.r * self.r self.selection_update = True
class SmithCircleRenderer(BaseXYPlot): """ Plots a circle in dataspace. If you don't want the edge of the polygon to be drawn, set **edge_color** to transparent; don't try to do this by setting **edge_width** to 0. In some drawing systems, such as PostScript, a line width of 0 means to make the line as small as possible while still putting ink on the page. """ # The color of the line on the edge of the polygon. color = black_color_trait # The thickness of the edge of the polygon. line_width = Float(1.0) # The line dash style for the edge of the polygon. line_style = LineStyle # The color of the face of the polygon. face_color = transparent_color_trait # Override the hittest_type trait inherited from BaseXYPlot hittest_type = Enum("poly", "point", "line") #### Private 'BaseXYPlot' interface ######################################## # def __init__(self, *args, **kw): # super(self.__class__, self).__init__(*args, **kw) def _downsample(self): #return self.map_screen(self._cached_data_pts) return self._cached_data_pts def _draw_plot(self, *args, **kw): """ Draws the 'plot' layer. """ # Simple compatibility with new-style rendering loop return self._draw_component(*args, **kw) def _draw_component(self, gc, view_bounds=None, mode='normal'): """ Renders the component. """ self._gather_points() self._render(gc, self._cached_data_pts) def _gather_points(self): """ Collects the data points that are within the bounds of the plot and caches them. """ if self._cache_valid: return data = transpose(self.value.get_data()) x_center = data[0].real.astype(float) y_center = data[0].imag.astype(float) radius = data[1].astype(float) if not self.index or not self.value: return if len(x_center) == 0 or len( radius) == 0 or len(x_center) != len(radius): self._cached_data_pts = [] self._cache_valid = True return circles = np.transpose(np.array((x_center, y_center, radius))) self._cached_data_pts = circles self._cache_valid = True def _render(self, gc, circles): """ Renders a circle.""" map_x = self.index_mapper.map_screen map_y = self.value_mapper.map_screen for circle in circles: x_center = map_x(circle[0]) y_center = map_y(circle[1]) radius = map_x(circle[2]) - map_x(0) with gc: gc.clip_to_rect( map_x(self.x_mapper.range.low), map_y(self.y_mapper.range.low), map_x(self.x_mapper.range.high) - map_x(self.x_mapper.range.low), map_y(self.y_mapper.range.high) - map_y(self.y_mapper.range.low)) gc.set_stroke_color(self.color_) gc.set_line_width(self.line_width) gc.set_line_dash(self.line_style_) gc.set_fill_color(self.face_color_) gc.arc(x_center, y_center, radius, 0, 2 * pi) gc.draw_path() def _render_icon(self, gc, x, y, width, height): """ Renders a representation of this plot as an icon into the box defined by the parameters. Used by the legend. """ with gc: gc.set_stroke_color(self.edge_color_) gc.set_line_width(self.line_width) gc.set_fill_color(self.face_color_) if hasattr(self, 'line_style_'): gc.set_line_dash(self.line_style_) gc.draw_rect((x, y, width, height)) return #------------------------------------------------------------------------ # AbstractPlotRenderer interface #------------------------------------------------------------------------ # def map_screen(self, data_array): # """ Maps an array of data points into screen space and returns it as # an array. # Implements the AbstractPlotRenderer interface. # """ # print "map_screen" # # data_array is Nx2 array # if len(data_array) == 0: # return [] # x_ary, y_ary, r_ary = transpose(data_array) # sx = self.index_mapper.map_screen(x_ary) # sy = self.value_mapper.map_screen(y_ary) # sr = (self.index_mapper.map_screen(r_ary) - # self.index_mapper.map_screen(0)) # for i in range(len(sx)): # print "center = ({0}, {1}), radius = {2}".format(x_ary[i], y_ary[i], # r_ary[i]) # if self.orientation == "h": # return transpose(array((sx, sy, sr))) # else: # return transpose(array((sy, sx, sr))) def hittest(self, screen_pt, threshold=7.0, return_distance=False): """ Performs point-in-polygon testing or point/line proximity testing. If self.hittest_type is "line" or "point", then behaves like the parent class BaseXYPlot.hittest(). If self.hittest_type is "poly", then returns True if the given point is inside the polygon, and False otherwise. """ if self.hittest_type in ("line", "point"): return BaseXYPlot.hittest(self, screen_pt, threshold, return_distance) data_pt = self.map_data(screen_pt, all_values=True) index = self.index.get_data() value = self.value.get_data() poly = np.vstack((index, value)).T if points_in_polygon([data_pt], poly)[0] == 1: return True else: return False #------------------------------------------------------------------------ # Event handlers #------------------------------------------------------------------------ def _alpha_changed(self): self.color_ = self.color_[0:3] + (self.alpha, ) self.face_color_ = self.face_color_[0:3] + (self.alpha, ) self.invalidate_draw() self.request_redraw()
class TriangleWave(HasTraits): # 指定三角波的最窄和最宽范围,由于Range类型不能将常数和Traits属性名混用 # 所以定义这两个值不变的Trait属性 low = Float(0.02) hi = Float(1.0) # 三角波形的宽度 wave_width = Range("low", "hi", 0.5) # 三角波的顶点C的x轴坐标 length_c = Range("low", "wave_width", 0.5) # 三角波的定点的y轴坐标 height_c = Float(1.0) # FFT计算所使用的取样点数,这里用一个Enum类型的属性以供用户从列表中选择 fftsize = Enum([(2**x) for x in range(6, 12)]) # FFT频谱图的x轴上限值 fft_graph_up_limit = Range(0, 400, 20) # 用于显示FFT的结果 peak_list = Str # 采用多少个频率合成三角波 N = Range(1, 40, 4) # 保存绘图数据的对象 plot_data = Instance(AbstractPlotData) # 绘制波形图的容器 plot_wave = Instance(Component) # 绘制FFT频谱图的容器 plot_fft = Instance(Component) # 包括两个绘图的容器 container = Instance(Component) # 设置用户界面的视图, 注意一定要指定窗口的大小,这样绘图容器才能正常初始化 view = View(HSplit( VSplit( VGroup(Item("wave_width", editor=scrubber, label="波形宽度"), Item("length_c", editor=scrubber, label="最高点x坐标"), Item("height_c", editor=scrubber, label="最高点y坐标"), Item("fft_graph_up_limit", editor=scrubber, label="频谱图范围"), Item("fftsize", label="FFT点数"), Item("N", label="合成波频率数")), Item("peak_list", style="custom", show_label=False, width=100, height=250)), VGroup(Item("container", editor=ComponentEditor(size=(600, 300)), show_label=False), orientation="vertical")), resizable=True, width=800, height=600, title="三角波FFT演示") # 创建绘图的辅助函数,创建波形图和频谱图有很多类似的地方,因此单独用一个函数以 # 减少重复代码 def _create_plot(self, data, name, type="line"): p = Plot(self.plot_data) p.plot(data, name=name, title=name, type=type) p.tools.append(PanTool(p)) zoom = ZoomTool(component=p, tool_mode="box", always_on=False) p.overlays.append(zoom) p.title = name return p def __init__(self): # 首先需要调用父类的初始化函数 super(TriangleWave, self).__init__() # 创建绘图数据集,暂时没有数据因此都赋值为空,只是创建几个名字,以供Plot引用 self.plot_data = ArrayPlotData(x=[], y=[], f=[], p=[], x2=[], y2=[]) # 创建一个垂直排列的绘图容器,它将频谱图和波形图上下排列 self.container = VPlotContainer() # 创建波形图,波形图绘制两条曲线: 原始波形(x,y)和合成波形(x2,y2) self.plot_wave = self._create_plot(("x", "y"), "Triangle Wave") self.plot_wave.plot(("x2", "y2"), color="red") # 创建频谱图,使用数据集中的f和p self.plot_fft = self._create_plot(("f", "p"), "FFT", type="scatter") # 将两个绘图容器添加到垂直容器中 self.container.add(self.plot_wave) self.container.add(self.plot_fft) # 设置 self.plot_wave.x_axis.title = "Samples" self.plot_fft.x_axis.title = "Frequency pins" self.plot_fft.y_axis.title = "(dB)" # 改变fftsize为1024,因为Enum的默认缺省值为枚举列表中的第一个值 self.fftsize = 1024 # FFT频谱图的x轴上限值的改变事件处理函数,将最新的值赋值给频谱图的响应属性 def _fft_graph_up_limit_changed(self): self.plot_fft.x_axis.mapper.range.high = self.fft_graph_up_limit def _N_changed(self): self.plot_sin_combine() # 多个trait属性的改变事件处理函数相同时,可以用@on_trait_change指定 @on_trait_change("wave_width, length_c, height_c, fftsize") def update_plot(self): # 计算三角波 global y_data x_data = np.arange(0, 1.0, 1.0 / self.fftsize) func = self.triangle_func() # 将func函数的返回值强制转换成float64 y_data = np.cast["float64"](func(x_data)) # 计算频谱 fft_parameters = np.fft.fft(y_data) / len(y_data) # 计算各个频率的振幅 fft_data = np.clip( 20 * np.log10(np.abs(fft_parameters))[:self.fftsize / 2 + 1], -120, 120) # 将计算的结果写进数据集 self.plot_data.set_data("x", np.arange(0, self.fftsize)) # x坐标为取样点 self.plot_data.set_data("y", y_data) self.plot_data.set_data("f", np.arange(0, len(fft_data))) # x坐标为频率编号 self.plot_data.set_data("p", fft_data) # 合成波的x坐标为取样点,显示2个周期 self.plot_data.set_data("x2", np.arange(0, 2 * self.fftsize)) # 更新频谱图x轴上限 self._fft_graph_up_limit_changed() # 将振幅大于-80dB的频率输出 peak_index = (fft_data > -80) peak_value = fft_data[peak_index][:20] result = [] for f, v in zip(np.flatnonzero(peak_index), peak_value): result.append("%s : %s" % (f, v)) self.peak_list = "\n".join(result) # 保存现在的fft计算结果,并计算正弦合成波 self.fft_parameters = fft_parameters self.plot_sin_combine() # 计算正弦合成波,计算2个周期 def plot_sin_combine(self): index, data = fft_combine(self.fft_parameters, self.N, 2) self.plot_data.set_data("y2", data) # 返回一个ufunc计算指定参数的三角波 def triangle_func(self): c = self.wave_width c0 = self.length_c hc = self.height_c def trifunc(x): x = x - int(x) # 三角波的周期为1,因此只取x坐标的小数部分进行计算 if x >= c: r = 0.0 elif x < c0: r = x / c0 * hc else: r = (c - x) / (c - c0) * hc return r # 用trifunc函数创建一个ufunc函数,可以直接对数组进行计算, 不过通过此函数 # 计算得到的是一个Object数组,需要进行类型转换 return np.frompyfunc(trifunc, 1, 1)
class StarComponent(Component): stars = List(Star) star_color = Color((255,255,255)) edges = Range(3, 10, 5) sx = Float # 移动开始时的星星中心X坐标 sy = Float # 移动开始时的星星中心Y坐标 mx = Float # 移动开始时的鼠标X坐标 my = Float # 移动开始时的鼠标Y坐标 moving_star = Instance(Star) event_state = Enum("normal", "drawing", "moving") def normal_left_down(self, event): "添加一个Star对象进stars列表,并切换到drawing状态" self.stars.append( Star(x=event.x, y=event.y, r=0, theta=0, n=self.edges, s = 0.5, c=convert_color(self.star_color))) self.event_state = "drawing" self.request_redraw() def drawing_mouse_move(self, event): "修改stars中最后一个Star对象的半径和起始角度" star = self.stars[-1] star.r = np.sqrt((event.x-star.x)**2+(event.y-star.y)**2) star.theta = np.arctan2(event.y-star.y, event.x-star.x) self.request_redraw() def drawing_left_up(self, event): "完成一个星形的绘制,回到normal状态" self.event_state = "normal" def normal_mouse_wheel(self, event): "找到包含鼠标坐标的星形,并修改其半径比例" star = self.find_star(event.x, event.y) if star is not None: star.s += event.mouse_wheel * 0.02 if star.s < 0.05: star.s = 0.05 self.request_redraw() def normal_right_down(self, event): "找到包含鼠标坐标的星形,用moving_star属性保存它,并进入moving状态" star = self.find_star(event.x, event.y) if star is not None: self.mx, self.my = event.x, event.y # 记录鼠标位置 self.sx, self.sy = star.x, star.y # 记录星形的中心位置 self.moving_star = star self.event_state = "moving" def moving_mouse_move(self, event): "修改moving_star的x,y坐标,实现星形的移动" self.moving_star.x = self.sx + event.x - self.mx self.moving_star.y = self.sy + event.y - self.my self.request_redraw() def moving_right_up(self, event): "移动操作结束,回到normal状态" self.event_state = "normal" def _draw_overlay(self, gc, view_bounds=None, mode="normal"): gc.clear((0,0,0,1)) #填充为全黑 gc.save_state() for star in self.stars: draw_star(gc, star.x, star.y, star.r, star.c, star.theta, star.n, star.s) gc.draw_path() gc.restore_state() def find_star(self, x, y): from enthought.kiva.agg import points_in_polygon for star in self.stars[::-1]: if points_in_polygon((x, y), star.polygon()): return star return None
class CfgFile(HasTraits): name = Str config_name = Str parent = Any directory = Str descendents = List config_type = Enum('MT', 'appman', 'XM', 'PVA', 'task_state', 'target_positions', 'start_positions', 'auto_control_config', 'grasp_event', 'auto_pilot', 'module_config', 'tool_change') def _descendents_default(self): if self.config_type == 'MT': multi_task_file = self.directory + '/' + self.name parser = SafeConfigParser() parser.read(multi_task_file) mt_config = dict(parser.items('config')) mt_app_list = re.sub(r"[\n\r]+", '', mt_config['config_names']).split(',') l = [] files = {'XM': 'XM.config', 'appman': 'appman.conf'} for app in mt_app_list: app_dir = CONFIG_DIR + '/' + app l.append( SubSession(name=app, files=files, directory=app_dir, parent=self)) elif self.config_type == 'XM': fd = parse_XM_config(self.directory + '/' + self.name) task_state_config_files = fd['task_state_config_files'] l = [] for kid in task_state_config_files: l.append( CfgFile(name=kid, config_type='task_state', directory=self.directory, parent=self)) if fd.has_key('tool_change_config_files'): tool_change_config_files = fd['tool_change_config_files'] for kid in tool_change_config_files: l.append( CfgFile(name=kid, config_type='tool_change', directory=self.directory, parent=self)) elif self.config_type == 'task_state': fd = parse_XM_config(self.directory + '/' + self.name) l = [ CfgFile(name=fd['target_configurations_file'], config_type='target_positions', parent=self, directory=self.directory) ] elif self.config_type == 'appman': parent_name = self.parent.name if parent_name == 'multi_task.config': parent_name = self.config_name l = [] try: fd = parse_appman(self.directory + '/' + self.name, parent_name) kids = fd['module_config_files'] for kid in kids: l.append( CfgFile(name=os.path.relpath(kid, self.directory), config_type='module_config', parent=self, directory=self.directory)) except (ValueError) as e: print "Error while reading 'appman.conf' file: ", e else: l = [] return l