class FooDemo(HasTraits): """ Defines a class to run the demo. """ foo = Instance(DerivedFoo, ()) configure = Button('Configure') view = View( Label("Try configuring several times, each time changing the items " "on the 'Parents?' tab."), '_', HGroup(spring, Item('configure', show_label=False))) def _configure_changed(self): self.foo.configure_traits()
class EnableDemo(HasTraits): box = Instance(DrawLineComponent) view = View(HGroup(Item("object.box.line_width"), Item("object.box.line_color", style="custom")), Item("box", editor=ComponentEditor(), show_label=False), resizable=True, width=500, height=500, title="Draw Lines") def __init__(self, **traits): super(EnableDemo, self).__init__(**traits) self.box = DrawLineComponent()
def _createView(self): """Set up a view for the traits.""" # Figure out the ticks and ticklabels for the TAM. We want to put a tick on every # coincidence. The dimensions of the TAM image we're showing are N*numCoincidences # wide and tall. dim = self.subTAM.shape[0] tickWidth = dim / self._numCoincidences ticks = numpy.arange(tickWidth / 2, dim, tickWidth, dtype='float') tickLabels = [str(x) for x in range(self._numCoincidences)] self._plotEditor = PlotEditor(colorbar=True, xTicks=ticks, xTickLabels=tickLabels, yTicks=ticks, yTickLabels=tickLabels) self.traits_view = View(HGroup( Group( Group(Item( 'topology', show_label=False, label="Topology", ), Item('normalized', show_label=True), Item('magnifyActivity', show_label=True), Item('threshold', show_label=True), orientation='horizontal', show_left=False), Group( Item( 'subTAM', style='custom', show_label=False, editor=PlotEditor(colorbar=True, xTicks=ticks, xTickLabels=tickLabels, yTicks=ticks, yTickLabels=tickLabels), width=-self.plotSize[0], height=-self.plotSize[0] + self.toolbarSize, ), Item( 'output', style='readonly', show_label=False, editor=CodeEditor(), ), ), ), ), title='LocalTAM')
class DoublePendulumGUI(HasTraits): pendulum = Instance(DoublePendulum) m1 = Range(1.0, 10.0, 2.0) m2 = Range(1.0, 10.0, 2.0) l1 = Range(1.0, 10.0, 2.0) l2 = Range(1.0, 10.0, 2.0) positions = Tuple index = Int(0) timer = Instance(Timer) graph = Instance(DoublePendulumComponent) animation = Bool(True) view = View(HGroup( VGroup( Item("m1"), Item("m2"), Item("l1"), Item("l2"), ), Item("graph", editor=ComponentEditor(), show_label=False), ), width=600, height=400, title="双摆演示", resizable=True) def __init__(self): self.pendulum = DoublePendulum(self.m1, self.m2, self.l1, self.l2) self.pendulum.init_status[:] = 1.0, 2.0, 0, 0 self.graph = DoublePendulumComponent() self.graph.gui = self self.timer = Timer(10, self.on_timer) def on_timer(self, *args): if len(self.positions) == 0 or self.index == len(self.positions[0]): self.pendulum.m1 = self.m1 self.pendulum.m2 = self.m2 self.pendulum.l1 = self.l1 self.pendulum.l2 = self.l2 if self.animation: self.positions = double_pendulum_odeint( self.pendulum, 0, 0.5, 0.02) else: self.positions = double_pendulum_odeint( self.pendulum, 0, 0.00001, 0.00001) self.index = 0 self.graph.p = tuple(array[self.index] for array in self.positions) self.index += 1 self.graph.request_redraw()
def default_traits_view(self): view = View(VSplit( HGroup( Group( spring, Item('delimiter', label='Column delimiter character'), Item('comments', label='Comment character'), Item('skiprows', label='Number of lines to skip at the ' 'beginning of the file'), spring, Item('handler.update_preview', show_label=False), ), Group( Item( 'columns', show_label=False, style='readonly', editor=ListEditor(style='custom'), springy=True, ), label="Column names", show_border=True, ), ), Group(Group( Item( 'data', show_label=False, editor=self.tabular_editor, ), label="Preview table", ), Group( Item('handler.file_content', style='readonly', show_label=False, springy=True), label="%s" % self.model.filename, ), layout='tab'), ), buttons=['OK', 'Cancel', 'Help'], id='csv_load_editor', resizable=True, width=640, height=580, title='CSV import - [%s]' % self.model.filename) return view
def default_traits_view(self): view = View( VGroup( HGroup( Item("current_map", label=u"颜色映射", editor=EnumEditor(name="object.color_maps")), Item("reverse_map", label=u"反转颜色"), Item("position", label=u"位置", style="readonly"), ), Item("plot", show_label=False, editor=ComponentEditor()), ), resizable = True, width = 550, height = 300, title = u"Mandelbrot观察器" ) return view
class ListDemo2(HasTraits): filter_types = List(Str, value=["低通", "高通", "带通", "带阻"]) items = List(Str) view = View( HGroup( Item("filter_types", label="候选"), Item("items", style="custom", editor=CheckListEditor(name="filter_types")), show_labels=False ), resizable=True, width = 300, height = 180, title="动态修改候选值" )
class CSVGrapher(HasTraits): """ 主界面包括绘图列表,数据源,文件选择器和添加绘图按钮 """ graph_list = List(Instance(Graph)) # 绘图列表 data_source = Instance(DataSource) # 数据源 csv_file_name = File(filter=[u"*.csv"]) # 文件选择 add_graph_button = Button(u"添加绘图") # 添加绘图按钮 view = View( # 整个窗口分为上下两个部分 VGroup( # 上部分横向放置控件,因此用HGroup HGroup( # 文件选择控件 Item("csv_file_name", label=u"选择CSV文件", width=400), # 添加绘图按钮 Item("add_graph_button", show_label=False) ), # 下部分是绘图列表,采用ListEditor编辑器显示 Item("graph_list", style="custom", show_label=False, editor=ListEditor( use_notebook=True, # 是用多标签页格式显示 deletable=True, # 可以删除标签页 dock_style="tab", # 标签dock样式 page_name=".name") # 标题页的文本使用Graph对象的name属性 ) ), resizable = True, height = 0.8, width = 0.8, title = u"CSV数据绘图器" ) def _csv_file_name_changed(self): """ 打开新文件时的处理,根据文件创建一个DataSource """ self.data_source = DataSource() self.data_source.load_csv(self.csv_file_name) del self.graph_list[:] def _add_graph_button_changed(self): """ 添加绘图按钮的事件处理 """ if self.data_source != None: self.graph_list.append( Graph(data_source = self.data_source) )
class ListItem(HasTraits): """ Class used to represent an item in a list with traits UI. """ column_number = Int name = Str my_name = Str parent = Instance(HasTraits) view = View( HGroup( Item('name', style='readonly', show_label=False, resizable=False), Item('my_name', style='simple', show_label=False, editor=TextEditor(auto_set=False, enter_set=True), springy=True), ))
class StarDesign(HasTraits): box = Instance(StarComponent) view = View( HGroup(Item("object.box.edges", label=u"顶角数"), Item("object.box.star_color", label=u"颜色")), Item("box", editor=ComponentEditor(),show_label=False), resizable=True, width = 600, height = 400, title = u"星空设计" ) def __init__(self, **traits): super(StarDesign, self).__init__(**traits) self.box = StarComponent()
def default_traits_view(self): view = View(HGroup( VGroup('renormalized', Item('data_fig', style='custom', show_label=False), 'cr_fig', 'corr_fig'), Item('usable_data', style='custom', show_label=False, editor=CheckListEditor(values=list( map(str, self.possible_usable_data)), cols=1)), ), height=800, width=800, handler=DLS_DataHandler) return view
class FlashDemo(HasTraits): # The Flash file to display: flash = Enum( 'http://www.ianag.com/arcade/swf/sudoku.swf', 'http://www.ianag.com/arcade/swf/f-336.swf', 'http://www.ianag.com/arcade/swf/f-3D-Reversi-1612.swf', 'http://www.ianag.com/arcade/swf/game_234.swf', 'http://www.ianag.com/arcade/swf/flashmanwm.swf', 'http://www.ianag.com/arcade/swf/2379_gyroball.swf', 'http://www.ianag.com/arcade/swf/f-1416.swf', 'http://www.ianag.com/arcade/swf/mah_jongg.swf', 'http://www.ianag.com/arcade/swf/game_e4fe4e55fedc2f502be627ee6df716c5.swf', 'http://www.ianag.com/arcade/swf/rhumb.swf') # The view to display: view = View(HGroup(Item('flash', label='Pick a game to play')), '_', Item('flash', show_label=False, editor=FlashEditor()))
class MyViewController(Controller): """ Define a combined controller/view class that validates that MyModel.name is consistent with the 'allow_empty_string' flag. """ # When False, the model.name trait is not allowed to be empty: allow_empty_string = Bool # Last attempted value of model.name to be set by user: last_name = Str # Define the view associated with this controller: view = View( VGroup( HGroup(Item('name', springy=True), '10', Item('controller.allow_empty_string', label='Allow Empty')), # Add an empty vertical group so the above items don't end up # centered vertically: VGroup()), resizable=True) #-- Handler Interface ------------------------------------------------------ def name_setattr(self, info, object, name, value): """ Validate the request to change the named trait on object to the specified value. Vaildation errors raise TraitError. """ self.last_name = value if (not self.allow_empty_string) and (value.strip() == ''): raise TraitError('Empty string not allowed.') return super(MyViewController, self).setattr(info, object, name, value) #-- Event handlers --------------------------------------------------------- def controller_allow_empty_string_changed(self, info): """ 'allow_empty_string' has changed, check the name trait to ensure that it is consistent with the current setting. """ if (not self.allow_empty_string) and (self.model.name == ''): self.model.name = '?' else: self.model.name = self.last_name
def default_traits_view(self): ''' Generates the view from the param items. ''' #rf_param_items = [ Item( 'model.' + name, format_str = '%g' ) for name in self.model.param_keys ] plot_param_items = [ Item('max_x', label='max x value'), Item('n_points', label='No of plot points') ] control_items = [ Item('show', show_label=False), Item('clear', show_label=False), ] view = View( HSplit( VGroup( Item('@resp_func', show_label=False), #*rf_param_items, label='Function Parameters', id='stats.spirrid_bak.rf_model_view.rf_params', scrollable=True), VGroup(*plot_param_items, label='Plot Parameters', id='stats.spirrid_bak.rf_model_view.plot_params'), VGroup( Item('model.comment', show_label=False, style='readonly'), label='Comment', id='stats.spirrid_bak.rf_model_view.comment', scrollable=True, ), VGroup(HGroup(*control_items), Item('figure', editor=MPLFigureEditor(), resizable=True, show_label=False), label='Plot', id='stats.spirrid_bak.rf_model_view.plot'), dock='tab', id='stats.spirrid_bak.rf_model_view.split'), kind='modal', resizable=True, dock='tab', buttons=[OKButton], id='stats.spirrid_bak.rf_model_view') return view
class AnimatedGIFDemo(HasTraits): # The animated GIF file to display: gif_file = File(files[0]) # Is the animation playing or not? playing = Bool(True) # The traits view: view = View(VGroup( HGroup( Item('gif_file', editor=AnimatedGIFEditor(playing='playing'), show_label=False), Item('playing'), ), '_', Item('gif_file', label='GIF File', editor=EnumEditor(values=files))), title='Animated GIF Demo', buttons=['OK'])
class Model(HasTraits): a = Code("print 'hello'") b = Button("click me") traits_view = View(HSplit( VGroup( Tabbed( Item('a'), Item('a'), Item('a')), Item('b')), VSplit( VGroup('b','b','b'), HGroup('a', show_border=True, label="traits is great")), dock="horizontal" ), resizable=True, id="my.test.program.id")
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 WebPage(HasTraits): # The URL to display: url = Str('http://code.enthought.com') # The page title: title = Str # The page status: status = Str # The browser navigation buttons: back = Button('<--') forward = Button('-->') home = Button('Home') stop = Button('Stop') refresh = Button('Refresh') search = Button('Search') # The view to display: view = View( HGroup('back', 'forward', 'home', 'stop', 'refresh', 'search', '_', Item('status', style='readonly'), show_labels=False), Item('url', show_label=False, editor=IEHTMLEditor(home='home', back='back', forward='forward', stop='stop', refresh='refresh', search='search', title='title', status='status')))
class FileDialogDemo(HasTraits): # The name of the selected file: file_name = File # The button used to display the file dialog: open = Button('Open...') #-- Traits View Definitions ------------------------------------------------ view = View(HGroup(Item('open', show_label=False), '_', Item('file_name', style='readonly', springy=True)), width=0.5) #-- Traits Event Handlers -------------------------------------------------- def _open_changed(self): """ Handles the user clicking the 'Open...' button. """ file_name = open_file() if file_name != '': self.file_name = file_name
class BunchANumbersApp(HasPrivateTraits): #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- model = Instance(ANumericModel) #--------------------------------------------------------------------------- # Traits view definitions: #--------------------------------------------------------------------------- view = View( HGroup( Item('model', editor=number_editor, id='model'), # Item( 'model', editor = number_editor ), show_labels=False), title='Numeric Editor Test', id='enthought.traits.ui.tests.numeric_editor_test', width=0.28, height=0.6, resizable=True)
class DomainViewModel(ModelView): add_node = Button del_node = Button("Remove node") traits_view = View( HGroup( Item("model", editor=tree_editor, show_label=False), Item("model", editor=graph_editor, show_label=False), # Item("add_node", show_label=False), # Item("del_node", show_label=False, enabled_when="model.nodes"), layout="split", id=".splitter"), resizable=True, id="godot.editor_test.domain_view_model", close_result=True) def _add_node_fired(self): node = DomainNode(name="new") self.model.nodes.append(node) def _del_node_fired(self): if self.model.nodes: popped = self.model.nodes.pop() print "POPPED:", popped
class Visualization(HasTraits): alpha = Range(0.0, 4.0, 1.0/4) beta = Range(0.0, 4.0, 1.0/4) scene = Instance(MlabSceneModel, ()) def __init__(self): # Do not forget to call the parent's __init__ HasTraits.__init__(self) x, y, z, = tens_fld(1,1,1,self.beta, self.alpha) self.plot = self.scene.mlab.mesh(x, y, z, colormap='copper', representation='surface') @on_trait_change('beta,alpha') def update_plot(self): x, y, z, = tens_fld(1,1,1,self.beta, self.alpha) self.plot.mlab_source.set(x=x, y=y, z=z) # the layout of the dialog created view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene), height=550, width=550, show_label=False), HGroup( '_', 'beta', 'alpha', ), )
class MultiFitGui(HasTraits): """ data should be c x N where c is the number of data columns/axes and N is the number of points """ doplot3d = Bool(False) show3d = Button('Show 3D Plot') replot3d = Button('Replot 3D') scalefactor3d = Float(0) do3dscale = Bool(False) nmodel3d = Int(1024) usecolor3d = Bool(False) color3d = Color((0,0,0)) scene3d = Instance(MlabSceneModel,()) plot3daxes = Tuple(('x','y','z')) data = Array(shape=(None,None)) weights = Array(shape=(None,)) curveaxes = List(Tuple(Int,Int)) axisnames = Dict(Int,Str) invaxisnames = Property(Dict,depends_on='axisnames') fgs = List(Instance(FitGui)) traits_view = View(VGroup(Item('fgs',editor=ListEditor(use_notebook=True,page_name='.plotname'),style='custom',show_label=False), Item('show3d',show_label=False)), resizable=True,height=900,buttons=['OK','Cancel'],title='Multiple Model Data Fitters') plot3d_view = View(VGroup(Item('scene3d',editor=SceneEditor(scene_class=MayaviScene),show_label=False,resizable=True), Item('plot3daxes',editor=TupleEditor(cols=3,labels=['x','y','z']),label='Axes'), HGroup(Item('do3dscale',label='Scale by weight?'), Item('scalefactor3d',label='Point scale'), Item('nmodel3d',label='Nmodel')), HGroup(Item('usecolor3d',label='Use color?'),Item('color3d',label='Relation Color',enabled_when='usecolor3d')), Item('replot3d',show_label=False),springy=True), resizable=True,height=800,width=800,title='Multiple Model3D Plot') def __init__(self,data,names=None,models=None,weights=None,dofits=True,**traits): """ :param data: The data arrays :type data: sequence of c equal-length arrays (length N) :param names: Names :type names: sequence of strings, length c :param models: The models to fit for each pair either as strings or :class:`astroypsics.models.ParametricModel` objects. :type models: sequence of models, length c-1 :param weights: the weights for each point or None for no weights :type weights: array-like of size N or None :param dofits: If True, the data will be fit to the models when the object is created, otherwise the models will be passed in as-is (or as created). :type dofits: bool extra keyword arguments get passed in as new traits (r[finmask],m[finmask],l[finmask]),names='rh,Mh,Lh',weights=w[finmask],models=models,dofits=False) """ super(MultiFitGui,self).__init__(**traits) self._lastcurveaxes = None data = np.array(data,copy=False) if weights is None: self.weights = np.ones(data.shape[1]) else: self.weights = np.array(weights) self.data = data if data.shape[0] < 2: raise ValueError('Must have at least 2 columns') if isinstance(names,basestring): names = names.split(',') if names is None: if len(data) == 2: self.axisnames = {0:'x',1:'y'} elif len(data) == 3: self.axisnames = {0:'x',1:'y',2:'z'} else: self.axisnames = dict((i,str(i)) for i in data) elif len(names) == len(data): self.axisnames = dict([t for t in enumerate(names)]) else: raise ValueError("names don't match data") #default to using 0th axis as parametric self.curveaxes = [(0,i) for i in range(len(data))[1:]] if models is not None: if len(models) != len(data)-1: raise ValueError("models don't match data") for i,m in enumerate(models): fg = self.fgs[i] newtmodel = TraitedModel(m) if dofits: fg.tmodel = newtmodel fg.fitmodel = True #should happen automatically, but this makes sure else: oldpard = newtmodel.model.pardict fg.tmodel = newtmodel fg.tmodel .model.pardict = oldpard if dofits: fg.fitmodel = True def _data_changed(self): self.curveaxes = [(0,i) for i in range(len(self.data))[1:]] def _axisnames_changed(self): for ax,fg in zip(self.curveaxes,self.fgs): fg.plot.x_axis.title = self.axisnames[ax[0]] if ax[0] in self.axisnames else '' fg.plot.y_axis.title = self.axisnames[ax[1]] if ax[1] in self.axisnames else '' self.plot3daxes = (self.axisnames[0],self.axisnames[1],self.axisnames[2] if len(self.axisnames) > 2 else self.axisnames[1]) @on_trait_change('curveaxes[]') def _curveaxes_update(self,names,old,new): ax=[] for t in self.curveaxes: ax.append(t[0]) ax.append(t[1]) if set(ax) != set(range(len(self.data))): self.curveaxes = self._lastcurveaxes return #TOOD:check for recursion if self._lastcurveaxes is None: self.fgs = [FitGui(self.data[t[0]],self.data[t[1]],weights=self.weights) for t in self.curveaxes] for ax,fg in zip(self.curveaxes,self.fgs): fg.plot.x_axis.title = self.axisnames[ax[0]] if ax[0] in self.axisnames else '' fg.plot.y_axis.title = self.axisnames[ax[1]] if ax[1] in self.axisnames else '' else: for i,t in enumerate(self.curveaxes): if self._lastcurveaxes[i] != t: self.fgs[i] = fg = FitGui(self.data[t[0]],self.data[t[1]],weights=self.weights) ax = self.curveaxes[i] fg.plot.x_axis.title = self.axisnames[ax[0]] if ax[0] in self.axisnames else '' fg.plot.y_axis.title = self.axisnames[ax[1]] if ax[1] in self.axisnames else '' self._lastcurveaxes = self.curveaxes def _show3d_fired(self): self.edit_traits(view='plot3d_view') self.doplot3d = True self.replot3d = True def _plot3daxes_changed(self): self.replot3d = True @on_trait_change('weights',post_init=True) def weightsChanged(self): for fg in self.fgs: if fg.weighttype != 'custom': fg.weighttype = 'custom' fg.weights = self.weights @on_trait_change('data','fgs','replot3d','weights') def _do_3d(self): if self.doplot3d: M = self.scene3d.mlab try: xi = self.invaxisnames[self.plot3daxes[0]] yi = self.invaxisnames[self.plot3daxes[1]] zi = self.invaxisnames[self.plot3daxes[2]] x,y,z = self.data[xi],self.data[yi],self.data[zi] w = self.weights M.clf() if self.scalefactor3d == 0: sf = x.max()-x.min() sf *= y.max()-y.min() sf *= z.max()-z.min() sf = sf/len(x)/5 self.scalefactor3d = sf else: sf = self.scalefactor3d glyph = M.points3d(x,y,z,w,scale_factor=sf) glyph.glyph.scale_mode = 0 if self.do3dscale else 1 M.axes(xlabel=self.plot3daxes[0],ylabel=self.plot3daxes[1],zlabel=self.plot3daxes[2]) try: xs = np.linspace(np.min(x),np.max(x),self.nmodel3d) #find sequence of models to go from x to y and z ymods,zmods = [],[] for curri,mods in zip((yi,zi),(ymods,zmods)): while curri != xi: for i,(i1,i2) in enumerate(self.curveaxes): if curri==i2: curri = i1 mods.insert(0,self.fgs[i].tmodel.model) break else: raise KeyError ys = xs for m in ymods: ys = m(ys) zs = xs for m in zmods: zs = m(zs) if self.usecolor3d: c = (self.color3d[0]/255,self.color3d[1]/255,self.color3d[2]/255) M.plot3d(xs,ys,zs,color=c) else: M.plot3d(xs,ys,zs,np.arange(len(xs))) except (KeyError,TypeError): M.text(0.5,0.75,'Underivable relation') except KeyError: M.clf() M.text(0.25,0.25,'Data problem') @cached_property def _get_invaxisnames(self): d={} for k,v in self.axisnames.iteritems(): d[v] = k return d
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 T1(Hahn): def generate_sequence(self): tau = self.tau laser = self.laser wait = self.wait t_pi2 = self.t_pi2 t_pi = self.t_pi t_3pi2 = self.t_3pi2 sequence = [] for t in tau: #sequence.append( (['mw' ], t_3pi2 ) ) #sequence.append( (['mw' ], t_pi ) ) sequence.append(([], t)) sequence.append((['laser', 'trigger'], laser)) sequence.append(([], wait)) #for t in tau: sequence.append((['mw'], t_pi)) sequence.append(([], t)) sequence.append((['laser', 'trigger'], laser)) sequence.append(([], wait)) return sequence def _get_sequence_points(self): return 2 * len(self.tau) get_set_items = Pulsed.get_set_items + ['t_pi2', 't_pi', 't_3pi2'] 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'), ), HGroup( Item('freq', width=40), Item('power', width=20), Item('t_pi2', width=20), Item('t_pi', width=20), Item('t_3pi2', width=20), ), HGroup(Item('tau_begin', width=20), Item('tau_end', width=20), Item('tau_delta', width=20), Item('rabi_contrast', width=20)), HGroup( Item('laser', width=40), Item('wait', width=40), Item('bin_width', width=40), ), HGroup( Item('state', style='readonly'), Item('run_time', style='readonly', format_str='%.f', width=50), Item('sweeps', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('expected_duration', style='readonly', editor=TextEditor(evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('progress', style='readonly'), Item('elapsed_time', style='readonly'), ), ), title='T1', )
class Hahn(Pulsed): """Hahn echo measurement using standard pi/2-pi-pi/2 sequence. """ t_pi2 = Range(low=1., high=100000., value=1000., desc='length of pi/2 pulse [ns]', label='pi/2 [ns]', mode='text', auto_set=False, enter_set=True) 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) t_3pi2 = Range(low=1., high=100000., value=1000., desc='length of 3pi/2 pulse [ns]', label='3pi/2 [ns]', mode='text', auto_set=False, enter_set=True) rabi_contrast = Range(low=1., high=100, value=30.0, desc='Rabi contrast [%]', label='contrast', mode='text', auto_set=False, enter_set=True) def __init__(self): super(Hahn, self).__init__() def _get_sequence_points(self): return 2 * len(self.tau) def generate_sequence(self): tau = self.tau laser = self.laser wait = self.wait t_pi2 = self.t_pi2 t_pi = self.t_pi t_3pi2 = self.t_3pi2 sequence = [] for t in tau: sub = [(['mw'], t_pi2), ([], t), (['mw'], t_pi), ([], t), (['mw'], t_pi2), (['laser', 'trigger'], laser), ([], wait), (['mw'], t_pi2), ([], t), (['mw'], t_pi), ([], t), (['mw'], t_3pi2), (['laser', 'trigger'], laser), ([], wait)] sequence.extend(sub) return sequence get_set_items = Pulsed.get_set_items + ['t_pi2', 't_pi', 't_3pi2'] 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'), ), HGroup( Item('freq', width=40), Item('power', width=20), Item('t_pi2', width=20), Item('t_pi', width=20), Item('t_3pi2', width=20), ), HGroup(Item('tau_begin', width=20), Item('tau_end', width=20), Item('tau_delta', width=20), Item('rabi_contrast', width=20)), HGroup( Item('laser', width=40), Item('wait', width=40), Item('bin_width', width=40), ), HGroup( Item('state', style='readonly'), Item('run_time', style='readonly', format_str='%.f', width=50), Item('sweeps', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('expected_duration', style='readonly', editor=TextEditor(evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('progress', style='readonly'), Item('elapsed_time', style='readonly'), ), ), title='Hahn', )
class Rabi(Pulsed): """Rabi measurement. """ def __init__(self): super(Rabi, self).__init__() def generate_sequence(self): tau = self.tau laser = self.laser wait = self.wait sequence = [] for t in tau: sequence.append((['mw'], t)) sequence.append((['laser', 'trigger'], laser)) sequence.append(([], wait)) return sequence 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'), ), HGroup( Item('freq', width=40), Item('power', width=40), ), HGroup( Item('laser', width=40), Item('wait', width=40), Item('bin_width', width=-80, enabled_when='state != "run"'), Item('record_length', width=-80, enabled_when='state != "run"'), ), HGroup( Item('tau_begin', width=40), Item('tau_end', width=40), Item('tau_delta', width=40), ), HGroup( Item('state', style='readonly'), Item('run_time', style='readonly', format_str='%.f', width=50), Item('sweeps', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('expected_duration', style='readonly', editor=TextEditor(evaluate=float, format_func=lambda x: '%.f' % x), width=40), Item('progress', style='readonly'), Item('elapsed_time', style='readonly', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: ' %.f' % x), width=40), ), ), title='Rabi Measurement', )
class Pulsed(ManagedJob, GetSetItemsMixin): """Defines a pulsed measurement.""" 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.' ) sequence = Instance(list, factory=list) record_length = Range(low=100, high=100000., value=3000, desc='length of acquisition record [ns]', label='record length [ns]', mode='text', auto_set=False, enter_set=True) bin_width = Range(low=0.1, high=1000., value=3.2, desc='data bin width [ns]', label='bin width [ns]', mode='text', auto_set=False, enter_set=True) n_laser = Int(2) n_bins = Int(2) time_bins = Array(value=np.array((0, 1))) count_data = Array(value=np.zeros((2, 2))) run_time = Float(value=0.0, label='run time [ns]', format_str='%.f') 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) tau_begin = Range(low=0., high=1e8, value=300., desc='tau begin [ns]', label='tau begin [ns]', mode='text', auto_set=False, enter_set=True) tau_end = Range(low=1., high=1e8, value=4000., desc='tau end [ns]', label='tau end [ns]', mode='text', auto_set=False, enter_set=True) tau_delta = Range(low=1., high=1e8, value=50., desc='delta tau [ns]', label='delta tau [ns]', mode='text', auto_set=False, enter_set=True) tau = Array(value=np.array((0., 1.))) laser = Range(low=1., high=5e6, value=3000., desc='laser [ns]', label='laser [ns]', mode='text', auto_set=False, enter_set=True) wait = Range(low=1., high=5e6, value=5000., desc='wait [ns]', label='wait [ns]', mode='text', auto_set=False, enter_set=True) freq = Range(low=1, high=20e9, value=2.71e9, desc='frequency [Hz]', label='frequency [Hz]', mode='text', auto_set=False, enter_set=True) power = Range(low=-100., high=25., value=-26, desc='power [dBm]', label='power [dBm]', mode='text', auto_set=False, enter_set=True) sweeps = Range(low=1., high=1e10, value=1e6, desc='number of sweeps', label='sweeps', mode='text', auto_set=False, enter_set=True) expected_duration = Property( trait=Float, depends_on='sweeps,sequence', desc='expected duration of the measurement [s]', label='expected duration [s]') elapsed_sweeps = Float(value=0, desc='Elapsed Sweeps ', label='Elapsed Sweeps ', mode='text') elapsed_time = Float(value=0, desc='Elapsed Time [ns]', label='Elapsed Time [ns]', mode='text') progress = Int(value=0, desc='Progress [%]', label='Progress [%]', mode='text') import_code = Code() import_button = Button( desc= 'set parameters such as pulse length, frequency, power, etc. by executing import code specified in settings', label='import') def __init__(self): super(Pulsed, self).__init__() def submit(self): """Submit the job to the JobManager.""" self.keep_data = False ManagedJob.submit(self) 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() def generate_sequence(self): return [] @cached_property def _get_expected_duration(self): sequence_length = 0 for step in self.sequence: sequence_length += step[1] return self.sweeps * sequence_length * 1e-9 def _get_sequence_points(self): return len(self.tau) def apply_parameters(self): """Apply the current parameters and decide whether to keep previous data.""" n_bins = int(self.record_length / self.bin_width) time_bins = self.bin_width * np.arange(n_bins) tau = np.arange(self.tau_begin, self.tau_end, self.tau_delta) self.tau = tau sequence = self.generate_sequence() n_laser = find_laser_pulses(sequence) self.sequence = sequence self.sequence_points = self._get_sequence_points() self.time_bins = time_bins self.n_bins = n_bins self.n_laser = n_laser if self.keep_data and sequence == self.sequence and np.all( time_bins == self.time_bins ): # if the sequence and time_bins are the same as previous, keep existing data self.old_count_data = self.count_data.copy() self.previous_sweeps = self.elapsed_sweeps self.previous_elapsed_time = self.elapsed_time else: #self.old_count_data = np.zeros((n_laser, n_bins)) FC.Configure(self.laser, self.bin_width, self.sequence_points) #self.check = True self.old_count_data = np.zeros(FC.GetData().shape) self.previous_sweeps = 0 self.previous_elapsed_time = 0.0 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): """Acquire data.""" try: # try to run the acquisition from start_up to shut_down self.state = 'run' self.apply_parameters() PG.High([]) FC.SetCycles(np.inf) FC.SetTime(np.inf) FC.SetDelay(0) FC.SetLevel(0.6, 0.6) FC.Configure(self.laser, self.bin_width, self.sequence_points) #self.previous_time = 0 #self.previous_sweeps = 0 #self.previous_count_data = FC.GetData() MW.setFrequency(self.freq) MW.setPower(self.power) time.sleep(2.0) FC.Start() time.sleep(0.1) PG.Sequence(self.sequence, loop=True) start_time = time.time() while self.run_time < self.stop_time: self.thread.stop_request.wait(1.0) if self.thread.stop_request.isSet(): logging.getLogger().debug('Caught stop signal. Exiting.') break self.elapsed_time = time.time() - start_time self.run_time += self.elapsed_time runtime, cycles = FC.GetState() sweeps = cycles / FC.GetData().shape[0] self.elapsed_sweeps = self.previous_sweeps + sweeps self.progress = int(100 * self.elapsed_sweeps / self.sweeps) self.count_data = self.old_count_data + FC.GetData() if self.elapsed_sweeps > self.sweeps: break FC.Halt() MW.Off() PG.High(['laser']) if self.elapsed_sweeps < self.sweeps: self.state = 'idle' else: self.state = 'done' except: # if anything fails, log the exception and set the state logging.getLogger().exception( 'Something went wrong in pulsed loop.') self.state = 'error' get_set_items = [ '__doc__', 'record_length', 'laser', 'wait', 'bin_width', 'n_bins', 'time_bins', 'n_laser', 'sequence', 'count_data', 'run_time', 'tau_begin', 'tau_end', 'tau_delta', 'tau', 'power' ] 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'), ), HGroup( Item('freq', width=40), Item('power', width=40), ), HGroup( Item('laser', width=40), Item('wait', width=40), Item('bin_width', width=-80, enabled_when='state != "run"'), Item('record_length', width=-80, enabled_when='state != "run"'), ), HGroup( Item('tau_begin', width=40), Item('tau_end', width=40), Item('tau_delta', width=40), ), HGroup( Item('state', style='readonly'), Item('run_time', style='readonly', format_str='%.f'), Item('sweeps', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: '%.3e' % x), width=40), Item('expected_duration', style='readonly', editor=TextEditor(evaluate=float, format_func=lambda x: '%.f' % x), width=40), Item('progress', style='readonly'), Item('elapsed_time', style='readonly', editor=TextEditor(auto_set=False, enter_set=True, evaluate=float, format_func=lambda x: ' %.f' % x), width=40), ), ), title='Pulsed Measurement', )
def create_fit_function(category, name): """Creates FitFunction object, based on function category string and function name string >>> fit_funct = create_fit_function('general', 'linear') """ funct = getattr(CATEGORIES[category], name) return FitFunction(function=funct) data_fitter_group = Group(HGroup( Group( Group( Item('function', style='custom', show_label=False, springy=False), label='Fit function', ), 'show_results', Group( 'object.data.xmin', 'object.data.xmax', label='Data select', ), ), Group(Item('plotter', style='custom', show_label=False), label='Plotter')), HGroup(Item('fit_button', show_label=False), Item('show_button', show_label=False), Item('reset_button', show_label=False)), label='Fitter') class DataFitter(HasTraits): """Fitter object, for data fitting.
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__())