class Counter(HasTraits): value = Int() add_one = Button() def _add_one_fired(self): self.value +=1 view = View('value', Item('add_one', show_label=False ))
class CitcomSHDFFileReader(Source): """This source manages a CitcomS Hdf file given to it. """ # The version of this class. Used for persistence. __version__ = 0 # The VTK dataset to manage. data = Instance(tvtk.DataSet) # Class to convert Hdf to Vtk Unstructured Grid Objects citcomshdftougrid = CitcomSHDFUgrid() current_timestep = Int(0) #To support changing the Scalar values in Mayavi2 temperature = Instance(tvtk.FloatArray()) viscosity = Instance(tvtk.FloatArray()) #Resolution comming from Hdf file nx = Int() ny = Int() nz = Int() #Current reduced resolution. User defined nx_redu = Int() ny_redu = Int() nz_redu = Int() #Number of timesteps in Hdf timesteps = Int() #Button to trigger the process of reading a timestep read_timestep = Button('Read timestep') filename = Str() ######################################## # Dynamic traits: These traits are dummies and are dynamically # updated depending on the contents of the file. # The active point scalar name. point_scalars_name = Trait('', TraitPrefixList([''])) # The active point vector name. point_vectors_name = Trait('', TraitPrefixList([''])) # The active point tensor name. point_tensors_name = Trait('', TraitPrefixList([''])) # The active cell scalar name. cell_scalars_name = Trait('', TraitPrefixList([''])) # The active cell vector name. cell_vectors_name = Trait('', TraitPrefixList([''])) # The active cell tensor name. cell_tensors_name = Trait('', TraitPrefixList([''])) ######################################## # Our view. view = View( Group( Item(name='current_timestep'), Item(name='nx_redu'), Item(name='ny_redu'), Item(name='nz_redu'), Item(name='read_timestep', style='simple', label='Simple'), Item(name='point_scalars_name'), Item(name='point_vectors_name'), Item(name='point_tensors_name'), Item(name='cell_scalars_name'), Item(name='cell_vectors_name'), Item(name='cell_tensors_name'), ), ) ###################################################################### # `object` interface ###################################################################### #Invoked during process of saving the visualization to a file def __get_pure_state__(self): d = super(CitcomSHDFFileReader, self).__get_pure_state__() output = "Filename: " + self.filename + "NX:%d NY:%d NZ:%d" % ( self.nx_redu, self.ny_redu, self.nz_redu) z = gzip_string(output) d['data'] = z return d #When the Visualisation is opened again this Method is called def __set_pure_state__(self, state): z = state.data if z: d = gunzip_string(z) m = re.search('(?<=Filename:)\w+', header) file_name = m.group(0) m = re.search('(?<=NX:)\w+', d) self.nx_redu = int(m.group(0)) m = re.search('(?<=NX:)\w+', d) self.ny_redu = int(m.group(0)) m = re.search('(?<=NX:)\w+', d) self.nz_redu = int(m.group(0)) if not isfile(file_name): msg = 'Could not find file at %s\n' % file_name msg += 'Please move the file there and try again.' raise IOError, msg self.filename = file_name #self.data = self.citcomshdftougrid.initialize(self.filename,0,0,0,0,False,False) f = tables.openFile(file_name, 'r') self.nx = int(f.root.input._v_attrs.nodex) self.ny = int(f.root.input._v_attrs.nodey) self.nz = int(f.root.input._v_attrs.nodez) self.timesteps = int(f.root.time.nrows) f.close() self.data = self.citcomshdftougrid.initialize( self.filename, self.current_timestep, self.nx_redu, self.ny_redu, self.nz_redu) self.data_changed = True self._update_data() # Now set the remaining state without touching the children. set_state(self, state, ignore=['children', '_file_path']) # Setup the children. handle_children_state(self.children, state.children) # Setup the children's state. set_state(self, state, first=['children'], ignore=['*']) ###################################################################### # `Base` interface ###################################################################### def start(self): """This is invoked when this object is added to the mayavi pipeline. """ # Do nothing if we are already running. if self.running: return # Update the data just in case. self._update_data() # Call the parent method to do its thing. This will typically # start all our children. super(CitcomSHDFFileReader, self).start() def update(self): """Invoke this to flush data changes downstream.""" self.data_changed = True def initialize(self, file_name): """This Methods initializes the reader and reads the meta-information from the Hdf file """ self.filename = file_name #self.data = self.citcomshdftougrid.initialize(self.filename,0,0,0,0,False,False) f = tables.openFile(file_name, 'r') self.nx = int(f.root.input._v_attrs.nodex) self.ny = int(f.root.input._v_attrs.nodey) self.nz = int(f.root.input._v_attrs.nodez) self.nx_redu = self.nx self.ny_redu = self.ny self.nz_redu = self.nz self.timesteps = int(f.root.time.nrows) f.close() ###################################################################### # `TreeNodeObject` interface ###################################################################### def tno_get_label(self, node): """ Gets the label to display for a specified object. """ ret = "CitcomS HDF Data (uninitialized)" if self.data: typ = self.data.__class__.__name__ ret = "CitcomS HDF Data (%d)" % self.current_timestep return ret ###################################################################### # Non-public interface ###################################################################### def _data_changed(self, data): """Invoked when the upsteam data sends an data_changed event""" self._update_data() self.outputs = [data] self.data_changed = True # Fire an event so that our label on the tree is updated. self.trait_property_changed('name', '', self.tno_get_label(None)) ##Callbacks for our traits def _current_timestep_changed(self, new_value): """Callback for the current timestep input box""" if new_value < 0: self.current_timestep = 0 if new_value > self.timesteps: self.current_timestep = self.timesteps - 1 def _read_timestep_fired(self): """Callback for the Button to read one timestep""" self.data = self.citcomshdftougrid.initialize(self.filename, self.current_timestep, self.nx_redu, self.ny_redu, self.nz_redu) self.temperature = self.citcomshdftougrid.get_vtk_temperature() self.viscosity = self.citcomshdftougrid.get_vtk_viscosity() ##New Thread Code #thread1 = CitcomSHdf2UGridThread() #thread2 = CitcomSProgressBar() #thread1.set_citcomsreader(self.filename,self.current_timestep,self.nx_redu,self.ny_redu,self.nz_redu,self.thread_callback) #progress = thread1.get_ref() #thread1.start() #thread2.set_ref(progress) #thread2.start() self.data_changed = True self._update_data() def _nx_redu_changed(self, new_value): """callback for the nx_redu input box""" if new_value < 1: self.nx_redu = 1 if new_value > self.nx: self.nx_redu = self.nx def _ny_redu_changed(self, new_value): """callback for the ny_redu input box""" if new_value < 1: self.ny_redu = 1 if new_value > self.ny: self.ny_redu = self.ny def _nz_redu_changed(self, new_value): """callback for the nz_redu input box""" if new_value < 1: self.nz_redu = 1 if new_value > self.nz: self.nz_redu = self.nz def _point_scalars_name_changed(self, value): if value == "Temperature": self.data.point_data.scalars = self.temperature if value == "Viscosity": self.data.point_data.scalars = self.viscosity self.data_changed = True self._set_data_name('scalars', 'point', value) def _point_vectors_name_changed(self, value): self._set_data_name('vectors', 'point', value) def _point_tensors_name_changed(self, value): self._set_data_name('tensors', 'point', value) ########################Non Public############################## def _set_data_name(self, data_type, attr_type, value): if not value: return dataset = self.data data = None if attr_type == 'point': data = dataset.point_data elif attr_type == 'cell': data = dataset.cell_data meth = getattr(data, 'set_active_%s' % data_type) meth(value) self.update() # Fire an event, so the changes propagate. self.data_changed = True def _update_data(self): if not self.data: return else: trait = Trait('Temperature', TraitPrefixList('Temperature', 'Viscosity')) self.add_trait('point_scalars_name', trait) trait = Trait('Velocity', TraitPrefixList('Velocity')) self.add_trait('point_vectors_name', trait) def thread_callback(self, hexagrid, vtk_viscosity, vtk_temperature): hexagrid.print_traits() self.data = hexagrid self.temperature = vtk_temperature self.viscosity = vtk_temperature
class ShowSurface(Filter): # The version of this class. Used for persistence. __version__ = 0 # The threshold filter. prog_filter = Instance(tvtk.ProgrammableFilter, ()) # Upper threshold (this is a dynamic trait that is changed when # input data changes). surfacelevel = Range(1, 17, 1, desc='the surface filter') # Our view. view = View(Group(Item(name='surfacelevel'))) current_level = Int() nx = Int() ny = Int() nz = Int() def setvalues(self, nx, ny, nz, level): """This Method needs to be set before the execution of the filter it accepts nx,ny,nz,level""" self.nx = nx self.ny = ny self.nz = nz self.current_level = level ###################################################################### # `Filter` interface. ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* its 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. """ # Just setup the default output of this filter. self.prog_filter.set_execute_method(self._showsurface) self.outputs = [self.prog_filter.output] 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 the input fires a `pipeline_changed` event. """ # By default we set the input to the first output of the first # input. fil = self.prog_filter fil.input = self.inputs[0].outputs[0] # We force the ranges to be reset to the limits of the data. # This is because if the data has changed upstream, then the # limits of the data must be changed. #self._update_ranges(reset=True) #fil.threshold_between(self.lower_threshold, self.upper_threshold) #fil.update() self.outputs[0] = fil.output self.pipeline_changed = True def update_data(self): """Override this method to do what is necessary when upstream data changes. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ #self._update_ranges(reset=True) # Propagate the data_changed event. self.prog_filter.set_execute_method(self._showsurface) self.outputs = [self.prog_filter.output] self.data_changed = True def _showsurface(self): print "showsurface update" print self.current_level input = self.prog_filter.unstructured_grid_input numCells = input.number_of_cells quadgrid = tvtk.UnstructuredGrid() quadgrid.allocate(1, 1) reduced_points = [] reduced_scalars = [] reduced_vectors = [] j = 1 cell_count = 0 for i in xrange(numCells): if j == self.current_level: cell = input.get_cell(i) scalars = input.point_data.scalars vectors = input.point_data.vectors point_ids = cell.point_ids points = cell.points reduced_points.append(points[2]) reduced_points.append(points[1]) reduced_points.append(points[5]) reduced_points.append(points[6]) reduced_scalars.append(scalars[point_ids[2]]) reduced_scalars.append(scalars[point_ids[1]]) reduced_scalars.append(scalars[point_ids[5]]) reduced_scalars.append(scalars[point_ids[6]]) reduced_vectors.append(vectors[point_ids[2]]) reduced_vectors.append(vectors[point_ids[1]]) reduced_vectors.append(vectors[point_ids[5]]) reduced_vectors.append(vectors[point_ids[6]]) quadgrid.insert_next_cell(9, [ cell_count, cell_count + 1, cell_count + 2, cell_count + 3 ]) cell_count += 4 if j == self.nx: j = 1 j += 1 vtkReduced_vectors = tvtk.FloatArray() vtkReduced_scalars = tvtk.FloatArray() vtkReduced_vectors.from_array(reduced_vectors) vtkReduced_scalars.from_array(reduced_scalars) vtkReduced_scalars.name = 'Scalars' vtkReduced_vectors.name = 'Vectors' #showsurfF.unstructured_grid_output = quadgrid self.prog_filter.unstructured_grid_output.set_cells( 9, quadgrid.get_cells()) self.prog_filter.unstructured_grid_output.point_data.scalars = vtkReduced_scalars self.prog_filter.unstructured_grid_output.point_data.vectors = vtkReduced_vectors self.prog_filter.unstructured_grid_output.points = reduced_points ###################################################################### # Non-public interface ###################################################################### def _surfacelevel_changed(self, new_value): fil = self.prog_filter print self.current_level self.current_level = new_value - 1 self._showsurface() fil.update() self.data_changed = True
class CitcomSshowCaps(Filter): # The version of this class. Used for persistence. __version__ = 0 # The threshold filter. ugrid_filter = Instance(tvtk.ExtractUnstructuredGrid, ()) # Lower threshold (this is a dynamic trait that is changed when # input data changes). lower_threshold = Range(0, 12, 0, desc='the lower threshold of the filter') # Upper threshold (this is a dynamic trait that is changed when # input data changes). upper_threshold = Range(0, 12, 12, desc='the upper threshold of the filter') # Our view. view = View( Group(Item(name='lower_threshold'), Item(name='upper_threshold'))) n = Int() caps = Int() ###################################################################### # `Filter` interface. ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* its 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. """ # Just setup the default output of this filter. self.ugrid_filter.point_clipping = 1 self.ugrid_filter.merging = 0 self.outputs = [self.ugrid_filter.output] 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 the input fires a `pipeline_changed` event. """ # By default we set the input to the first output of the first # input. fil = self.ugrid_filter fil.input = self.inputs[0].outputs[0] #Than we calculate how many points belong to one cap self.caps = 12 self.n = self.inputs[0].outputs[0].number_of_points / 12 #Than we set the output of the filter self.outputs[0] = fil.output self.outputs.append(self.inputs[0].outputs[0]) self.pipeline_changed = True def update_data(self): """Override this method to do what is necessary when upstream data changes. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ fil = self.ugrid_filter fil.update() # Propagate the data_changed event. self.data_changed = True ###################################################################### # Non-public interface ###################################################################### def _lower_threshold_changed(self, old_value, new_value): """Callback interface for the lower threshold slider""" fil = self.ugrid_filter fil.point_minimum = (self.lower_threshold) * (self.n) fil.update() self.data_changed = True def _upper_threshold_changed(self, old_value, new_value): """Callback interface for the upper threshold slider""" fil = self.ugrid_filter fil.point_maximum = self.upper_threshold * (self.n) fil.update() self.data_changed = True
class VTKFileReader(Source): """CitcomS VTK file reader. """ # The version of this class. Used for persistence. __version__ = 0 # The list of file names for the timeseries. file_list = List(Str, desc='a list of files belonging to a time series') # The current timestep (starts with 0). This trait is a dummy # and is dynamically changed when the `file_list` trait changes. # This is done so the timestep bounds are linked to the number of # the files in the file list. timestep = Range(0, 0, desc='the current time step') # A timestep view group that may be included by subclasses. time_step_group = Group(Item(name='_file_path', style='readonly'), Item(name='timestep', defined_when='len(object.file_list) > 1')) # CitcomS mesh parameters nx = Int() ny = Int() nz = Int() radius_inner = Float() ##################### # Private traits. ##################### # The current file name. This is not meant to be touched by the user. _file_path = Instance(FilePath, (), desc='the current file name') ################################################## # Dynamic traits: These traits are dummies and are dynamically # update depending on the contents of the file. # The active scalar name. scalars_name = Trait('', TraitPrefixList([''])) # The active vector name. vectors_name = Trait('', TraitPrefixList([''])) # The active tensor name. tensors_name = Trait('', TraitPrefixList([''])) # The active normals name. normals_name = Traits('', TraitPrefixList([''])) # The active tcoord name. t_coords_name = Trait('', TraitPrefixList([''])) # The active field_data name. field_data_name = Trait('', TraitPrefixList([''])) ################################################## # The VTK data file reader. reader = Instance(tvtk.DataSetReader, ()) # Our view. view = View(Group(Include('time_step_group'), Item(name='scalars_name'), Item(name='vectors_name'), Item(name='tensors_name'), Item(name='normals_name'), Item(name='t_coords_name'), Item(name='field_data_name'), Item(name='reader'))) #################################################### # `object` interface #################################################### def __get_pure_state__(self): d = super(VTKFileReader, self).__get_pure_state__() # These are obtained dynamically, so don't pickle them. for x in ['file_list', 'timestep']: d.pop(x, None) return d def __set_pure_state__(self): # The reader has its own file_name which needs to be fixed. state.reader.file_name = state._file_path.abs_path # Now call the parent class to setup everything. # Use the saved path to initialize the file_list and timestep. fname = state._file_path.abs_pth if not isfile(fname): msg = 'Could not find file at %s\n' % fname msg += 'Please move the file there and try again.' raise IOError, msg self.initialize(fname) # Now set the remaining state without touching the children. set_state(self, state, ignore=['children', '_file_path']) # Setup the children handle_children_state(self.children, state.children) # Setup the children's state. set_state(self, state, first=['children'], ignore=['*']) ############################## # `Base` interface ############################## def start(self): """This is invoked when this object is added to the mayavi pipeline. """ # Do nothing if we are already running. if self.running: return # Update the data just in case self.update_data() self.update() # Call the parent method to do its thing. This will typically # start all our children. super(VTKFileReader, self).start() def stop(self): """Invoked when this object is removed from the mayavi pipeline. """ if not self.running: return # Call the parent method to do its thing. super(VTKFileReader, self).start() ############################# # `FileDataSource` interface ############################# def update(self): if not self._file_path.get(): return reader = self.reader reader.update() self.render() def update_data(self): if not self._file_path.get(): return attrs = ['scalars', 'vectors', 'tensors', 'normals', 't_coords', 'field_data'] reader = self.reader for attr in attrs: n = getattr(reader, 'number_of_%s_in_file' % attr) method = getattr(reader, 'get_%s_name_in_file' % attr) values = [method(x) for x in xrange(n)] if values: trait = Trait(values[0], TraitPrefixList(values)) else: trait = Trait('', TraitPrefixList([''])) self.add_trait('%s_name' % attr, trait) ############################# # `TreeNodeObject` interface ############################# def tno_get_label(self, node): """Gets the label to display for a specified object.""" fname = basename(self._file_path.get()) ret = "CitcomS VTK file (%s)" % fname if len(self.file_list) > 1: return ret + " (timeseries)" else: return ret ############################# # `FileDataSource` interface ############################# def initialize(self, base_file_name): """Given a single filename which may or may not be part of a time series, this initializes the list of files. This method need not be called to initialize the data. """ self.file_list = get_file_list(base_file_name) # Read meta-information meta = "" try: vtk = open(base_file_name, "r") vtk.readline() meta = vtk.readline() except IOError: print 'cannot open file' else: vtk.close() try: m = re.search('(?<=NX:)\d+', meta) self.nx = int(m.group(0)) m = re.search('(?<=NY:)\d+', meta) self.ny = int(m.group(0)) m = re.search('(?<=NZ:)\d+', meta) self.nz = int(m.group(0)) m = re.search('(?<=Radius_Inner:)(\d+|.)+', meta) self.radius_inner = float(m.group(0)) except ValueError: print "Invalid meta information in file..." if len(self.file_list) == 0: self.file_list = [base_file_name] try: self.timestep = self.file_list.index(base_file_name) except ValueError: self.timestep = 0 ########################################################################### # Non-public interface ########################################################################### def _file_list_changed(self, value): # Change the range of the timestep suitably to reflect new list. n_files = len(self.file_list) timestep = min(self.timestep, n_files) trait = Range(0, n_files-1, timestep) self.add_trait('timestep', trait) if self.timestep == timestep: self._timestep_changed(timestep) else: self.timestep = timestep def _file_list_items_changed(self, list_event): self._file_list_changed(self.file_list) def _timestep_changed(self, value): file_list = self.file_list if len(file_list): self._file_path = FilePath(file_list[value]) else: self._file_path = FilePath('') def __file_path_changed(self, fpath): value = fpath.get() if not value return else: self.reader.file_name = value self.update_data() self.update() # Setup the outputs by resetting self.outputs. Changing # the outputs automatically fires a pipeline_changed # event. try: n = self.reader.number_of_outputs except AttributeError: # for VTK >= 4.5 n = self.reader.number_of_output_ports outputs = [] for i in range(n): outputs.append(self.reader.get_output(i)) self.outputs = outputs # Fire data_changed just in case the outputs are not # really changed. This can happen if the dataset is of # the same type as before. self.data_changed = True # Fire an event so that our label on the tree is updated. self.trait_property_changed('name', '', self.tno_get_label(None)) return def _set_data_name(self, data_type, value): if not value or not data_type: return reader = self.reader setattr(reader, data_type, value) self.update() # Fire an event, so the changes propagate. self.data_changed = True def _scalars_name_changed(self, value): self._set_data_name('scalars_name', value) def _vectors_name_changed(self, value): self._set_data_name('vectors_name', value) def _tensors_name_changed(self, value): self._set_data_name('tensors_name', value) def _normals_name_changed(self, value): self._set_data_name('normals_name', value) def _t_coords_name_changed(self, value): self._set_data_name('t_coords_name', value) def _field_data_name_changed(self, value): self._set_data_name('field_data_name', value)
class CitcomSreduce(Filter): # The version of this class. Used for persistence. __version__ = 0 # The threshold filter. probe_filter = Instance(tvtk.ProbeFilter, ()) citcomsgrid = CitcomSSphere() sphere = Instance(tvtk.SphereSource, ()) # Upper threshold (this is a dynamic trait that is changed when # input data changes). Radius = Range(0.0, 1.0, 0.0, desc='adjust radius') theta = Range(3, 40, 3, desc='the theta resolution') phi = Range(3, 40, 3, desc='the upper threshold of the filter') Selected_Source = Enum( 'Sphere', 'CitcomSGrid', ) radius_max = Float(1.0) set_radius_max = Button('Set Radius Max') # Our view. view = View( Item(name="Selected_Source"), Group(Item(name='Radius'), Item(name='theta'), Item(name='phi'), Item(name='radius_max'), Item(name='set_radius_max', style='simple', label='Simple'), show_border=True), ) grid_source = True ###################################################################### # `Filter` interface. ###################################################################### def setup_pipeline(self): """Override this method so that it *creates* its 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. """ # Just setup the default output of this filter. s = self.sphere s.set(radius=0.0, theta_resolution=20, phi_resolution=20) self.probe_filter.input = s.output self.outputs = [self.probe_filter.output] 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 the input fires a `pipeline_changed` event. """ # By default we set the input to the first output of the first # input. fil = self.probe_filter fil.source = self.inputs[0].outputs[0] self._calc_grid(0, self.theta, self.phi) fil.update() self.outputs[0] = fil.output self.pipeline_changed = True def update_data(self): """Override this method to do what is necessary when upstream data changes. This method is invoked (automatically) when any of the inputs sends a `data_changed` event. """ self.probe_filter.source = self.inputs[0].outputs[0] self.probe_filter.update() # Propagate the data_changed event. self.data_changed = True def _calc_grid(self, radius, resolution_x, resolution_y): fil = self.probe_filter coords = [] if self.Selected_Source == 'CitcomSGrid': for i in xrange(12): coords += self.citcomsgrid.coords_of_cap( radius, self.theta, self.phi, i) grid = tvtk.UnstructuredGrid() #Connectivity for 2d-Data #There is no need to interpolate with the CitcomS grid surface. If this is however #wanted uncomment this code to create the CitcomS surface information #for capnr in xrange(12): # i=1 # for n in xrange((resolution_x+1)*(resolution_y+1) - (resolution_x+1)): # if i%(resolution_x+1)!=0 : # n0 = n+(capnr*((resolution_x+1)*(resolution_y+1))) # n1 = n0+1 # n2 = n0+resolution_y+1 # n3 = n2+1 # grid.insert_next_cell(8,[n0,n1,n2,n3]) # i+=1 ## grid.points = coords fil.input = grid if self.Selected_Source == 'Sphere': sphere = tvtk.SphereSource() sphere.radius = radius sphere.theta_resolution = resolution_x sphere.phi_resolution = resolution_y #Rotate the Sphere so that the poles are at the right location transL = tvtk.Transform() trans1 = tvtk.TransformPolyDataFilter() trans2 = tvtk.TransformPolyDataFilter() trans1.input = sphere.output transL.rotate_y(90) transL.update() trans1.transform = transL trans1.update() trans2.input = trans1.output transL.rotate_z(90) transL.update() trans2.transform = transL trans2.update() fil.input = trans2.output fil.update() ###################################################################### # Non-public interface ###################################################################### def _Radius_changed(self, new_value): fil = self.probe_filter #self.sphere.radius = new_value self._calc_grid(new_value, self.theta, self.phi) fil.update() self.data_changed = True def _theta_changed(self, new_value): fil = self.probe_filter self._calc_grid(self.Radius, new_value, self.phi) fil.update() self.data_changed = True def _phi_changed(self, new_value): fil = self.probe_filter self._calc_grid(self.Radius, self.theta, new_value) fil.update() self.data_changed = True def _Selected_Source_changed(self, new_value): self._calc_grid(self.Radius, self.theta, self.phi) self.outputs[0] = self.probe_filter.output self.data_changed = True self.pipeline_changed = True def _radius_max_changed(self, new_value): if self.Radius > new_value: self.Radius = new_value if new_value <= 0.0: self.radius_max = 0.0 def _set_radius_max_fired(self): trait = Range(0.0, self.radius_max, self.Radius, desc='adjust radius') self.add_trait('Radius', trait)