def get_data_range(self, arr=None, preference='cell'): """Get the non-NaN min and max of a named scalar array Parameters ---------- arr : str, np.ndarray, optional The name of the array to get the range. If None, the active scalar is used preference : str, optional When scalars is specified, this is the perfered scalar type to search for in the dataset. Must be either ``'point'``, ``'cell'``, or ``'field'``. """ if arr is None: # use active scalar array _, arr = self.active_scalar_info if isinstance(arr, str): arr = get_array(self, arr, preference=preference) # If array has no tuples return a NaN range if arr is None or arr.size == 0 or not np.issubdtype( arr.dtype, np.number): return (np.nan, np.nan) # Use the array range return np.nanmin(arr), np.nanmax(arr)
def get_data_range(self, arr=None, preference='row'): """Get the non-NaN min and max of a named array. Parameters ---------- arr : str, np.ndarray, optional The name of the array to get the range. If None, the active scalar is used preference : str, optional When scalars is specified, this is the preferred array type to search for in the dataset. Must be either ``'row'`` or ``'field'``. """ if arr is None: # use the first array in the row data self.GetRowData().GetArrayName(0) if isinstance(arr, str): arr = get_array(self, arr, preference=preference) # If array has no tuples return a NaN range if arr is None or arr.size == 0 or not np.issubdtype( arr.dtype, np.number): return (np.nan, np.nan) # Use the array range return np.nanmin(arr), np.nanmax(arr)
def get_data_range(self, arr=None, preference='cell'): """Get the non-NaN min and max of a named array. Parameters ---------- arr : str, np.ndarray, optional The name of the array to get the range. If None, the active scalars is used. preference : str, optional When scalars is specified, this is the preferred array type to search for in the dataset. Must be either ``'point'``, ``'cell'``, or ``'field'``. """ if arr is None: # use active scalars array _, arr = self.active_scalars_info if isinstance(arr, str): name = arr # This can return None when an array is not found - expected arr = get_array(self, name, preference=preference) if arr is None: # Raise a value error if fetching the range of an unknown array raise ValueError(f'Array `{name}` not present.') # If array has no tuples return a NaN range if arr is None or arr.size == 0 or not np.issubdtype( arr.dtype, np.number): return (np.nan, np.nan) # Use the array range return np.nanmin(arr), np.nanmax(arr)
def get_array(self, name: str, preference='cell', info=False) -> Union[Tuple, np.ndarray]: """Search both point, cell and field data for an array.""" return get_array(self, name, preference=preference, info=info, err=True)
def set_active_vectors(self, name, preference='point'): """Finds the vectors by name and appropriately sets it as active""" _, field = get_array(self, name, preference=preference, info=True) if field == POINT_DATA_FIELD: self.GetPointData().SetActiveVectors(name) elif field == CELL_DATA_FIELD: self.GetCellData().SetActiveVectors(name) else: raise RuntimeError('Data field ({}) not useable'.format(field)) self._active_vectors_info = [field, name]
def set_active_scalar(self, name, preference='cell'): """Finds the scalar by name and appropriately sets it as active""" _, field = get_array(self, name, preference=preference, info=True) self._last_active_scalar_name = self.active_scalar_info[1] if field == POINT_DATA_FIELD: self.GetPointData().SetActiveScalars(name) elif field == CELL_DATA_FIELD: self.GetCellData().SetActiveScalars(name) else: raise RuntimeError('Data field ({}) not useable'.format(field)) self._active_scalar_info = [field, name]
def rename_scalar(self, old_name, new_name, preference='cell'): """Changes array name by searching for the array then renaming it""" _, field = get_array(self, old_name, preference=preference, info=True) if field == POINT_DATA_FIELD: self.point_arrays[new_name] = self.point_arrays.pop(old_name) elif field == CELL_DATA_FIELD: self.cell_arrays[new_name] = self.cell_arrays.pop(old_name) elif field == FIELD_DATA_FIELD: self.field_arrays[new_name] = self.field_arrays.pop(old_name) else: raise RuntimeError('Array not found.') if self.active_scalar_info[1] == old_name: self.set_active_scalar(new_name, preference=field)
def rename_array(self, old_name: str, new_name: str, preference='cell'): """Change array name by searching for the array then renaming it.""" _, field = get_array(self, old_name, preference=preference, info=True) was_active = False if self.active_scalars_name == old_name: was_active = True if field == FieldAssociation.POINT: self.point_arrays[new_name] = self.point_arrays.pop(old_name) elif field == FieldAssociation.CELL: self.cell_arrays[new_name] = self.cell_arrays.pop(old_name) elif field == FieldAssociation.NONE: self.field_arrays[new_name] = self.field_arrays.pop(old_name) else: raise KeyError(f'Array with name {old_name} not found.') if was_active: self.set_active_scalars(new_name, preference=field)
def set_active_vectors(self, name, preference='point'): """Finds the vectors by name and appropriately sets it as active To deactivate any active scalars, pass ``None`` as the ``name``. """ if name is None: self.GetCellData().SetActiveVectors(None) self.GetPointData().SetActiveVectors(None) return _, field = get_array(self, name, preference=preference, info=True) if field == POINT_DATA_FIELD: self.GetPointData().SetActiveVectors(name) elif field == CELL_DATA_FIELD: self.GetCellData().SetActiveVectors(name) else: raise RuntimeError('Data field ({}) not useable'.format(field)) self._active_vectors_info = [field, name]
def get_data_range(self, name): """Gets the min/max of a scalar given its name across all blocks""" mini, maxi = np.inf, -np.inf for i in range(self.n_blocks): data = self[i] if data is None: continue # get the scalar if availble arr = get_array(data, name) if arr is None or not np.issubdtype(arr.dtype, np.number): continue tmi, tma = np.nanmin(arr), np.nanmax(arr) if tmi < mini: mini = tmi if tma > maxi: maxi = tma return mini, maxi
def set_active_vectors(self, name, preference='point'): """Find the vectors by name and appropriately sets it as active. To deactivate any active scalars, pass ``None`` as the ``name``. """ if name is None: self.GetCellData().SetActiveVectors(None) self.GetPointData().SetActiveVectors(None) return _, field = get_array(self, name, preference=preference, info=True) if field == FieldAssociation.POINT: self.GetPointData().SetActiveVectors(name) elif field == FieldAssociation.CELL: self.GetCellData().SetActiveVectors(name) else: raise ValueError(f'Data field ({field}) not usable') self._active_vectors_info = ActiveArrayInfo(field, name)
def set_active_tensors(self, name: str, preference='point'): """Find the tensors by name and appropriately sets it as active. To deactivate any active tensors, pass ``None`` as the ``name``. """ if name is None: self.GetCellData().SetActiveTensors(None) self.GetPointData().SetActiveTensors(None) field = FieldAssociation.POINT else: _, field = get_array(self, name, preference=preference, info=True) if field == FieldAssociation.POINT: ret = self.GetPointData().SetActiveTensors(name) elif field == FieldAssociation.CELL: ret = self.GetCellData().SetActiveTensors(name) else: raise ValueError(f'Data field ({field}) not usable') if ret < 0: raise ValueError(f'Data field ({field}) could not be set as the active tensors') self._active_tensors_info = ActiveArrayInfo(field, name)
def test_get_array(): grid = pyvista.UnstructuredGrid(ex.hexbeamfile) # add array to both point/cell data with same name carr = np.random.rand(grid.n_cells) grid._add_cell_array(carr, 'test_data') parr = np.random.rand(grid.n_points) grid._add_point_array(parr, 'test_data') # add other data oarr = np.random.rand(grid.n_points) grid._add_point_array(oarr, 'other') farr = np.random.rand(grid.n_points * grid.n_cells) grid._add_field_array(farr, 'field_data') assert np.allclose( carr, utilities.get_array(grid, 'test_data', preference='cell')) assert np.allclose( parr, utilities.get_array(grid, 'test_data', preference='point')) assert np.allclose(oarr, utilities.get_array(grid, 'other')) assert utilities.get_array(grid, 'foo') is None assert utilities.get_array(grid, 'test_data', preference='field') is None assert np.allclose( farr, utilities.get_array(grid, 'field_data', preference='field'))
def add_mesh_isovalue(self, mesh, scalars=None, compute_normals=False, compute_gradients=False, compute_scalars=True, preference='point', title=None, pointa=(.4, .9), pointb=(.9, .9), widget_color=None, **kwargs): """Create a contour of a mesh with a slider. Add a mesh to the scene with a slider widget that is used to contour at an isovalue of the *point* data on the mesh interactively. The isovalue mesh is saved to the ``.isovalue_meshes`` attribute on the plotter. Parameters ---------- mesh : pyvista.Common The input dataset to add to the scene and contour scalars : str The string name of the scalars on the mesh to threshold and display kwargs : dict All additional keyword arguments are passed to ``add_mesh`` to control how the mesh is displayed. """ if isinstance(mesh, pyvista.MultiBlock): raise TypeError( 'MultiBlock datasets are not supported for this widget.') name = kwargs.get('name', str(hex(id(mesh)))) # set the array to contour on if mesh.n_arrays < 1: raise AssertionError( 'Input dataset for the contour filter must have data arrays.') if scalars is None: field, scalars = mesh.active_scalars_info else: _, field = get_array(mesh, scalars, preference=preference, info=True) # NOTE: only point data is allowed? well cells works but seems buggy? if field != pyvista.POINT_DATA_FIELD: raise AssertionError( 'Contour filter only works on Point data. Array ({}) is in the Cell data.' .format(scalars)) rng = mesh.get_data_range(scalars) kwargs.setdefault('clim', kwargs.pop('rng', rng)) if title is None: title = scalars alg = vtk.vtkContourFilter() alg.SetInputDataObject(mesh) alg.SetComputeNormals(compute_normals) alg.SetComputeGradients(compute_gradients) alg.SetComputeScalars(compute_scalars) alg.SetInputArrayToProcess(0, 0, 0, field, scalars) alg.SetNumberOfContours(1) # Only one contour level self.add_mesh(mesh.outline(), name=name + "outline", opacity=0.0) if not hasattr(self, "isovalue_meshes"): self.isovalue_meshes = [] isovalue_mesh = pyvista.wrap(alg.GetOutput()) self.isovalue_meshes.append(isovalue_mesh) def callback(value): alg.SetValue(0, value) alg.Update() isovalue_mesh.shallow_copy(alg.GetOutput()) self.add_slider_widget(callback=callback, rng=rng, title=title, color=widget_color, pointa=pointa, pointb=pointb) kwargs.setdefault("reset_camera", False) actor = self.add_mesh(isovalue_mesh, scalars=scalars, **kwargs) return actor
def add_mesh_threshold(self, mesh, scalars=None, invert=False, widget_color=None, preference='cell', title=None, pointa=(.4, .9), pointb=(.9, .9), continuous=False, **kwargs): """Apply a threshold on a mesh with a slider. Add a mesh to the scene with a slider widget that is used to threshold the mesh interactively. The threshold mesh is saved to the ``.threshold_meshes`` attribute on the plotter. Parameters ---------- mesh : pyvista.Common The input dataset to add to the scene and threshold scalars : str The string name of the scalars on the mesh to threshold and display invert : bool Invert/flip the threshold kwargs : dict All additional keyword arguments are passed to ``add_mesh`` to control how the mesh is displayed. """ if isinstance(mesh, pyvista.MultiBlock): raise TypeError( 'MultiBlock datasets are not supported for threshold widget.') name = kwargs.get('name', str(hex(id(mesh)))) if scalars is None: field, scalars = mesh.active_scalars_info arr, field = get_array(mesh, scalars, preference=preference, info=True) if arr is None: raise AssertionError('No arrays present to threshold.') rng = mesh.get_data_range(scalars) kwargs.setdefault('clim', kwargs.pop('rng', rng)) if title is None: title = scalars self.add_mesh(mesh.outline(), name=name + "outline", opacity=0.0) alg = vtk.vtkThreshold() alg.SetInputDataObject(mesh) alg.SetInputArrayToProcess( 0, 0, 0, field, scalars) # args: (idx, port, connection, field, name) alg.SetUseContinuousCellRange(continuous) if not hasattr(self, "threshold_meshes"): self.threshold_meshes = [] threshold_mesh = pyvista.wrap(alg.GetOutput()) self.threshold_meshes.append(threshold_mesh) def callback(value): if invert: alg.ThresholdByLower(value) else: alg.ThresholdByUpper(value) alg.Update() threshold_mesh.shallow_copy(alg.GetOutput()) self.add_slider_widget(callback=callback, rng=rng, title=title, color=widget_color, pointa=pointa, pointb=pointb) kwargs.setdefault("reset_camera", False) actor = self.add_mesh(threshold_mesh, scalars=scalars, **kwargs) return actor
def get_array(self, name, preference='cell', info=False): """Search both point, cell and field data for an array.""" return get_array(self, name, preference=preference, info=info)