def offset(self): """Get cell locations Array.""" carr = self.GetCells() if _vtk.VTK9: # This will be the number of cells + 1. return _vtk.vtk_to_numpy(carr.GetOffsetsArray()) else: # this is no longer used in >= VTK9 return _vtk.vtk_to_numpy(self.GetCellLocationsArray())
def cell_points(self, ind: int) -> np.ndarray: """Return the points in a cell. Parameters ---------- ind : int Cell ID. Returns ------- numpy.ndarray An array of floats with shape (number of points, 3) containing the coordinates of the cell corners. Examples -------- >>> from pyvista import examples >>> mesh = examples.load_airplane() >>> mesh.cell_points(0) # doctest:+SKIP [[896.99401855 48.76010132 82.26560211] [906.59301758 48.76010132 80.74520111] [907.53900146 55.49020004 83.65809631]] """ # A copy of the points must be returned to avoid overlapping them since the # `vtk.vtkExplicitStructuredGrid.GetCell` is an override method. points = self.GetCell(ind).GetPoints().GetData() points = _vtk.vtk_to_numpy(points) return points.copy()
def cell_points(self, ind: int) -> np.ndarray: """Return the points in a cell. Parameters ---------- ind : int Cell ID. Returns ------- numpy.ndarray An array of floats with shape (number of points, 3) containing the coordinates of the cell corners. Examples -------- >>> from pyvista import examples >>> mesh = examples.load_airplane() >>> mesh.cell_points(0) # doctest:+SKIP [[896.99401855 48.76010132 82.26560211] [906.59301758 48.76010132 80.74520111] [907.53900146 55.49020004 83.65809631]] """ points = self.GetCell(ind).GetPoints().GetData() return _vtk.vtk_to_numpy(points)
def cell_connectivity(self): """Return a the vtk cell connectivity as a numpy array.""" carr = self.GetCells() if _vtk.VTK9: return _vtk.vtk_to_numpy(carr.GetConnectivityArray()) raise AttributeError('Install vtk>=9.0.0 for `cell_connectivity`\n' 'Otherwise, use the legacy `cells` method')
def image_from_window(ren_win, as_vtk=False, ignore_alpha=False): """Extract the image from the render window as an array.""" width, height = ren_win.GetSize() arr = _vtk.vtkUnsignedCharArray() ren_win.GetRGBACharPixelData(0, 0, width - 1, height - 1, 0, arr) data = _vtk.vtk_to_numpy(arr).reshape(height, width, -1)[::-1] if ignore_alpha: data = data[:, :, :-1] if as_vtk: return wrap_image_array(data) return data
def convert_array(arr, name=None, deep=False, array_type=None): """Convert a NumPy array to a vtkDataArray or vice versa. Parameters ---------- arr : np.ndarray or vtkDataArray A numpy array or vtkDataArry to convert. name : str, optional The name of the data array for VTK. deep : bool, optional If input is numpy array then deep copy values. array_type : int, optional VTK array type ID as specified in specified in ``vtkType.h``. Returns ------- vtkDataArray, numpy.ndarray, or DataFrame The converted array. If input is a :class:`numpy.ndarray` then returns ``vtkDataArray`` or is input is ``vtkDataArray`` then returns NumPy ``ndarray``. """ if arr is None: return if isinstance(arr, np.ndarray): if arr.dtype is np.dtype('O'): arr = arr.astype('|S') arr = np.ascontiguousarray(arr) if arr.dtype.type in (np.str_, np.bytes_): # This handles strings vtk_data = convert_string_array(arr) else: # This will handle numerical data arr = np.ascontiguousarray(arr) vtk_data = _vtk.numpy_to_vtk(num_array=arr, deep=deep, array_type=array_type) if isinstance(name, str): vtk_data.SetName(name) return vtk_data # Otherwise input must be a vtkDataArray if not isinstance( arr, (_vtk.vtkDataArray, _vtk.vtkBitArray, _vtk.vtkStringArray)): raise TypeError(f'Invalid input array type ({type(arr)}).') # Handle booleans if isinstance(arr, _vtk.vtkBitArray): arr = vtk_bit_array_to_char(arr) # Handle string arrays if isinstance(arr, _vtk.vtkStringArray): return convert_string_array(arr) # Convert from vtkDataArry to NumPy return _vtk.vtk_to_numpy(arr)
def convert_array(arr, name=None, deep=0, array_type=None): """Convert a NumPy array to a vtkDataArray or vice versa. Parameters ----------- arr : ndarray or vtkDataArry A numpy array or vtkDataArry to convert name : str The name of the data array for VTK deep : bool if input is numpy array then deep copy values Returns ------- vtkDataArray, ndarray, or DataFrame: the converted array (if input is a NumPy ndaray then returns ``vtkDataArray`` or is input is ``vtkDataArray`` then returns NumPy ``ndarray``). If pdf==True and the input is ``vtkDataArry``, return a pandas DataFrame. """ if arr is None: return if isinstance(arr, np.ndarray): if arr.dtype is np.dtype('O'): arr = arr.astype('|S') arr = np.ascontiguousarray(arr) if arr.dtype.type in (np.str_, np.bytes_): # This handles strings vtk_data = convert_string_array(arr) else: # This will handle numerical data arr = np.ascontiguousarray(arr) vtk_data = _vtk.numpy_to_vtk(num_array=arr, deep=deep, array_type=array_type) if isinstance(name, str): vtk_data.SetName(name) return vtk_data # Otherwise input must be a vtkDataArray if not isinstance( arr, (_vtk.vtkDataArray, _vtk.vtkBitArray, _vtk.vtkStringArray)): raise TypeError(f'Invalid input array type ({type(arr)}).') # Handle booleans if isinstance(arr, _vtk.vtkBitArray): arr = vtk_bit_array_to_char(arr) # Handle string arrays if isinstance(arr, _vtk.vtkStringArray): return convert_string_array(arr) # Convert from vtkDataArry to NumPy return _vtk.vtk_to_numpy(arr)
def add_scalar_bar(self, title='', mapper=None, n_labels=5, italic=False, bold=False, title_font_size=None, label_font_size=None, color=None, font_family=None, shadow=False, width=None, height=None, position_x=None, position_y=None, vertical=None, interactive=None, fmt=None, use_opacity=True, outline=False, nan_annotation=False, below_label=None, above_label=None, background_color=None, n_colors=None, fill=False, render=False): """Create scalar bar using the ranges as set by the last input mesh. Parameters ---------- mapper : vtkMapper, optional Mapper used for the scalar bar. Defaults to the last mapper created by the plotter. title : string, optional Title of the scalar bar. Default ``''`` which is rendered as an empty title. n_labels : int, optional Number of labels to use for the scalar bar. italic : bool, optional Italicises title and bar labels. Default False. bold : bool, optional Bolds title and bar labels. Default True title_font_size : float, optional Sets the size of the title font. Defaults to None and is sized automatically. label_font_size : float, optional Sets the size of the title font. Defaults to None and is sized automatically. color : string or 3 item list, optional, defaults to white Either a string, rgb list, or hex color string. For example: * ``color='white'`` * ``color='w'`` * ``color=[1, 1, 1]`` * ``color='#FFFFFF'`` font_family : string, optional Font family. Must be either courier, times, or arial. shadow : bool, optional Adds a black shadow to the text. Defaults to False width : float, optional The percentage (0 to 1) width of the window for the colorbar height : float, optional The percentage (0 to 1) height of the window for the colorbar position_x : float, optional The percentage (0 to 1) along the windows's horizontal direction to place the bottom left corner of the colorbar position_y : float, optional The percentage (0 to 1) along the windows's vertical direction to place the bottom left corner of the colorbar interactive : bool, optional Use a widget to control the size and location of the scalar bar. use_opacity : bool, optional Optionally display the opacity mapping on the scalar bar outline : bool, optional Optionally outline the scalar bar to make opacity mappings more obvious. nan_annotation : bool, optional Annotate the NaN color below_label : str, optional String annotation for values below the scalars range above_label : str, optional String annotation for values above the scalars range background_color : array, optional The color used for the background in RGB format. n_colors : int, optional The maximum number of color displayed in the scalar bar. fill : bool Draw a filled box behind the scalar bar with the ``background_color`` render : bool, optional Force a render when True. Default ``True``. Examples -------- Add a custom interactive scalar bar that is horizontal, has an outline, and has a custom formatting. >>> import pyvista as pv >>> sphere = pv.Sphere() >>> sphere['Data'] = sphere.points[:, 2] >>> plotter = pv.Plotter() >>> _ = plotter.add_mesh(sphere, show_scalar_bar=False) >>> _ = plotter.add_scalar_bar('Data', interactive=True, vertical=False, ... outline=True, fmt='%10.5f') Notes ----- Setting title_font_size, or label_font_size disables automatic font sizing for both the title and label. """ if mapper is None: raise ValueError('Mapper cannot be ``None`` when creating a scalar bar') if interactive is None: interactive = pyvista.global_theme.interactive if font_family is None: font_family = pyvista.global_theme.font.family if label_font_size is None: label_font_size = pyvista.global_theme.font.label_size if title_font_size is None: title_font_size = pyvista.global_theme.font.title_size if color is None: color = pyvista.global_theme.font.color if fmt is None: fmt = pyvista.global_theme.font.fmt if vertical is None: if pyvista.global_theme.colorbar_orientation.lower() == 'vertical': vertical = True # Automatically choose size if not specified if width is None: if vertical: width = pyvista.global_theme.colorbar_vertical.width else: width = pyvista.global_theme.colorbar_horizontal.width if height is None: if vertical: height = pyvista.global_theme.colorbar_vertical.height else: height = pyvista.global_theme.colorbar_horizontal.height # Check that this data hasn't already been plotted if title in list(self._scalar_bar_ranges.keys()): clim = list(self._scalar_bar_ranges[title]) newrng = mapper.scalar_range oldmappers = self._scalar_bar_mappers[title] # get max for range and reset everything if newrng[0] < clim[0]: clim[0] = newrng[0] if newrng[1] > clim[1]: clim[1] = newrng[1] for mh in oldmappers: mh.scalar_range = clim[0], clim[1] mapper.scalar_range = clim[0], clim[1] self._scalar_bar_mappers[title].append(mapper) self._scalar_bar_ranges[title] = clim self._scalar_bar_actors[title].SetLookupTable(mapper.lookup_table) # Color bar already present and ready to be used so returning return # Automatically choose location if not specified if position_x is None or position_y is None: try: slot = min(self._plotter._scalar_bar_slots) self._plotter._scalar_bar_slots.remove(slot) self._plotter._scalar_bar_slot_lookup[title] = slot except: raise RuntimeError('Maximum number of color bars reached.') if position_x is None: if vertical: position_x = pyvista.global_theme.colorbar_vertical.position_x position_x -= slot * (width + 0.2 * width) else: position_x = pyvista.global_theme.colorbar_horizontal.position_x if position_y is None: if vertical: position_y = pyvista.global_theme.colorbar_vertical.position_y else: position_y = pyvista.global_theme.colorbar_horizontal.position_y position_y += slot * height # parse color color = parse_color(color) # Create scalar bar scalar_bar = _vtk.vtkScalarBarActor() # self._scalar_bars.append(scalar_bar) if background_color is not None: background_color = parse_color(background_color, opacity=1.0) background_color = np.array(background_color) * 255 scalar_bar.GetBackgroundProperty().SetColor(background_color[0:3]) if fill: scalar_bar.DrawBackgroundOn() lut = _vtk.vtkLookupTable() lut.DeepCopy(mapper.lookup_table) ctable = _vtk.vtk_to_numpy(lut.GetTable()) alphas = ctable[:, -1][:, np.newaxis] / 255. use_table = ctable.copy() use_table[:, -1] = 255. ctable = (use_table * alphas) + background_color * (1 - alphas) lut.SetTable(_vtk.numpy_to_vtk(ctable, array_type=_vtk.VTK_UNSIGNED_CHAR)) else: lut = mapper.lookup_table scalar_bar.SetLookupTable(lut) if n_colors is not None: scalar_bar.SetMaximumNumberOfColors(n_colors) if n_labels < 1: scalar_bar.DrawTickLabelsOff() else: scalar_bar.DrawTickLabelsOn() scalar_bar.SetNumberOfLabels(n_labels) if nan_annotation: scalar_bar.DrawNanAnnotationOn() if above_label: scalar_bar.DrawAboveRangeSwatchOn() scalar_bar.SetAboveRangeAnnotation(above_label) if below_label: scalar_bar.DrawBelowRangeSwatchOn() scalar_bar.SetBelowRangeAnnotation(below_label) # edit the size of the colorbar scalar_bar.SetHeight(height) scalar_bar.SetWidth(width) scalar_bar.SetPosition(position_x, position_y) if fmt is not None: scalar_bar.SetLabelFormat(fmt) if vertical: scalar_bar.SetOrientationToVertical() else: scalar_bar.SetOrientationToHorizontal() if label_font_size is not None or title_font_size is not None: scalar_bar.UnconstrainedFontSizeOn() scalar_bar.AnnotationTextScalingOn() label_text = scalar_bar.GetLabelTextProperty() anno_text = scalar_bar.GetAnnotationTextProperty() label_text.SetColor(color) anno_text.SetColor(color) label_text.SetShadow(shadow) anno_text.SetShadow(shadow) # Set font label_text.SetFontFamily(parse_font_family(font_family)) anno_text.SetFontFamily(parse_font_family(font_family)) label_text.SetItalic(italic) anno_text.SetItalic(italic) label_text.SetBold(bold) anno_text.SetBold(bold) if label_font_size: label_text.SetFontSize(label_font_size) anno_text.SetFontSize(label_font_size) # Set properties self._scalar_bar_ranges[title] = mapper.scalar_range self._scalar_bar_mappers[title] = [mapper] scalar_bar.SetTitle(title) title_text = scalar_bar.GetTitleTextProperty() title_text.SetJustificationToCentered() title_text.SetItalic(italic) title_text.SetBold(bold) title_text.SetShadow(shadow) if title_font_size: title_text.SetFontSize(title_font_size) # Set font title_text.SetFontFamily(parse_font_family(font_family)) # set color title_text.SetColor(color) self._scalar_bar_actors[title] = scalar_bar if interactive: scalar_widget = _vtk.vtkScalarBarWidget() scalar_widget.SetScalarBarActor(scalar_bar) scalar_widget.SetInteractor(self._plotter.iren.interactor) scalar_widget.SetEnabled(1) rep = scalar_widget.GetRepresentation() scalar_widget.On() if vertical is True or vertical is None: rep.SetOrientation(1) # 0 = Horizontal, 1 = Vertical else: # y position determined emperically y = -position_y/2 - height - scalar_bar.GetPosition()[1] rep.GetPositionCoordinate().SetValue(width, y) rep.GetPosition2Coordinate().SetValue(height, width) rep.SetOrientation(0) # 0 = Horizontal, 1 = Vertical self._scalar_bar_widgets[title] = scalar_widget if use_opacity: scalar_bar.SetUseOpacity(True) if outline: scalar_bar.SetDrawFrame(True) frame_prop = scalar_bar.GetFrameProperty() frame_prop.SetColor(color) else: scalar_bar.SetDrawFrame(False) # finally, add to the actor and return the scalar bar self._plotter.add_actor(scalar_bar, reset_camera=False, pickable=False, render=render) return scalar_bar
def cells(self): """Return a numpy array of the cells.""" return _vtk.vtk_to_numpy(self.GetData()).ravel()
def z(self): """Get the coordinates along the Z-direction.""" return _vtk.vtk_to_numpy(self.GetZCoordinates())
def celltypes(self): """Get the cell types array.""" return _vtk.vtk_to_numpy(self.GetCellTypesArray())
def linear_copy(self, deep=False): """Return a copy of the unstructured grid containing only linear cells. Converts the following cell types to their linear equivalents. - VTK_QUADRATIC_TETRA --> VTK_TETRA - VTK_QUADRATIC_PYRAMID --> VTK_PYRAMID - VTK_QUADRATIC_WEDGE --> VTK_WEDGE - VTK_QUADRATIC_HEXAHEDRON --> VTK_HEXAHEDRON Parameters ---------- deep : bool When True, makes a copy of the points array. Default False. Cells and cell types are always copied. Returns ------- grid : pyvista.UnstructuredGrid UnstructuredGrid containing only linear cells. """ lgrid = self.copy(deep) # grab the vtk object vtk_cell_type = _vtk.numpy_to_vtk(self.GetCellTypesArray(), deep=True) celltype = _vtk.vtk_to_numpy(vtk_cell_type) celltype[celltype == _vtk.VTK_QUADRATIC_TETRA] = _vtk.VTK_TETRA celltype[celltype == _vtk.VTK_QUADRATIC_PYRAMID] = _vtk.VTK_PYRAMID celltype[celltype == _vtk.VTK_QUADRATIC_WEDGE] = _vtk.VTK_WEDGE celltype[celltype == _vtk.VTK_QUADRATIC_HEXAHEDRON] = _vtk.VTK_HEXAHEDRON # track quad mask for later quad_quad_mask = celltype == _vtk.VTK_QUADRATIC_QUAD celltype[quad_quad_mask] = _vtk.VTK_QUAD quad_tri_mask = celltype == _vtk.VTK_QUADRATIC_TRIANGLE celltype[quad_tri_mask] = _vtk.VTK_TRIANGLE vtk_offset = self.GetCellLocationsArray() cells = _vtk.vtkCellArray() cells.DeepCopy(self.GetCells()) lgrid.SetCells(vtk_cell_type, vtk_offset, cells) # fixing bug with display of quad cells if np.any(quad_quad_mask): if _vtk.VTK9: quad_offset = lgrid.offset[:-1][quad_quad_mask] base_point = lgrid.cell_connectivity[quad_offset] lgrid.cell_connectivity[quad_offset + 4] = base_point lgrid.cell_connectivity[quad_offset + 5] = base_point lgrid.cell_connectivity[quad_offset + 6] = base_point lgrid.cell_connectivity[quad_offset + 7] = base_point else: quad_offset = lgrid.offset[quad_quad_mask] base_point = lgrid.cells[quad_offset + 1] lgrid.cells[quad_offset + 5] = base_point lgrid.cells[quad_offset + 6] = base_point lgrid.cells[quad_offset + 7] = base_point lgrid.cells[quad_offset + 8] = base_point if np.any(quad_tri_mask): if _vtk.VTK9: tri_offset = lgrid.offset[:-1][quad_tri_mask] base_point = lgrid.cell_connectivity[tri_offset] lgrid.cell_connectivity[tri_offset + 3] = base_point lgrid.cell_connectivity[tri_offset + 4] = base_point lgrid.cell_connectivity[tri_offset + 5] = base_point else: tri_offset = lgrid.offset[quad_tri_mask] base_point = lgrid.cells[tri_offset + 1] lgrid.cells[tri_offset + 4] = base_point lgrid.cells[tri_offset + 5] = base_point lgrid.cells[tri_offset + 6] = base_point return lgrid
def cells(self): """Legacy method: Return a pointer to the cells as a numpy object.""" return _vtk.vtk_to_numpy(self.GetCells().GetData())
def faces(self): """Return a pointer to the points as a numpy object.""" return _vtk.vtk_to_numpy(self.GetPolys().GetData())
def lines(self): """Return a pointer to the lines as a numpy object.""" return _vtk.vtk_to_numpy(self.GetLines().GetData()).ravel()
def verts(self): """Get the vertex cells.""" return _vtk.vtk_to_numpy(self.GetVerts().GetData())