def _from_arrays(self, x, y, z): """Create VTK rectilinear grid directly from numpy arrays. Each array gives the uniques coordinates of the mesh along each axial direction. To help ensure you are using this correctly, we take the unique values of each argument. Parameters ---------- x : np.ndarray Coordinates of the nodes in x direction. y : np.ndarray Coordinates of the nodes in y direction. z : np.ndarray Coordinates of the nodes in z direction. """ # Set the coordinates along each axial direction # Must at least be an x array x = np.unique(x.ravel()) self.SetXCoordinates(_vtk.numpy_to_vtk(x)) if y is not None: y = np.unique(y.ravel()) self.SetYCoordinates(_vtk.numpy_to_vtk(y)) if z is not None: z = np.unique(z.ravel()) self.SetZCoordinates(_vtk.numpy_to_vtk(z)) # Ensure dimensions are properly set self._update_dimensions()
def vector_poly_data(orig, vec): """Create a vtkPolyData object composed of vectors.""" # shape, dimension checking if not isinstance(orig, np.ndarray): orig = np.asarray(orig) if not isinstance(vec, np.ndarray): vec = np.asarray(vec) if orig.ndim != 2: orig = orig.reshape((-1, 3)) elif orig.shape[1] != 3: raise ValueError('orig array must be 3D') if vec.ndim != 2: vec = vec.reshape((-1, 3)) elif vec.shape[1] != 3: raise ValueError('vec array must be 3D') # Create vtk points and cells objects vpts = _vtk.vtkPoints() vpts.SetData(_vtk.numpy_to_vtk(np.ascontiguousarray(orig), deep=True)) npts = orig.shape[0] cells = np.empty((npts, 2), dtype=pyvista.ID_TYPE) cells[:, 0] = 1 cells[:, 1] = np.arange(npts, dtype=pyvista.ID_TYPE) vcells = pyvista.utilities.cells.CellArray(cells, npts) # Create vtkPolyData object pdata = _vtk.vtkPolyData() pdata.SetPoints(vpts) pdata.SetVerts(vcells) # Add vectors to polydata name = 'vectors' vtkfloat = _vtk.numpy_to_vtk(np.ascontiguousarray(vec), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveVectors(name) # Add magnitude of vectors to polydata name = 'mag' scalars = (vec * vec).sum(1)**0.5 vtkfloat = _vtk.numpy_to_vtk(np.ascontiguousarray(scalars), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveScalars(name) return pyvista.PolyData(pdata)
def vtk_points(points, deep=True): """Convert numpy array or array-like to a vtkPoints object.""" points = np.asanyarray(points) # verify is numeric if not np.issubdtype(points.dtype, np.number): raise TypeError('Points must be a numeric type') # check dimensionality if points.ndim == 1: points = points.reshape(-1, 3) elif points.ndim > 2: raise ValueError('Dimension of ``points`` should be 1 or 2, not ' f'{points.ndim}') # verify shape if points.shape[1] != 3: raise ValueError('Points array must contain three values per point. ' f'Shape is {points.shape} and should be (X, 3)') # points must be contiguous points = np.require(points, requirements=['C']) vtkpts = _vtk.vtkPoints() vtk_arr = _vtk.numpy_to_vtk(points, deep=deep) vtkpts.SetData(vtk_arr) return vtkpts
def vtk_points(points, deep=True): """Convert numpy points to a vtkPoints object.""" if not points.flags['C_CONTIGUOUS']: points = np.ascontiguousarray(points) vtkpts = _vtk.vtkPoints() vtkpts.SetData(_vtk.numpy_to_vtk(points, deep=deep)) return vtkpts
def vtk_points(points, deep=True): """Convert numpy array or array-like to a ``vtkPoints`` object. Parameters ---------- points : numpy.ndarray or sequence Points to convert. Should be 1 or 2 dimensional. Accepts a single point or several points. deep : bool, optional Perform a deep copy of the array. Only applicable if ``points`` is a :class:`numpy.ndarray`. Returns ------- vtk.vtkPoints The vtkPoints object. Examples -------- >>> import pyvista >>> import numpy as np >>> points = np.random.random((10, 3)) >>> vpoints = pyvista.vtk_points(points) >>> vpoints # doctest:+SKIP (vtkmodules.vtkCommonCore.vtkPoints)0x7f0c2e26af40 """ points = np.asanyarray(points) # verify is numeric if not np.issubdtype(points.dtype, np.number): raise TypeError('Points must be a numeric type') # check dimensionality if points.ndim == 1: points = points.reshape(-1, 3) elif points.ndim > 2: raise ValueError('Dimension of ``points`` should be 1 or 2, not ' f'{points.ndim}') # verify shape if points.shape[1] != 3: raise ValueError('Points array must contain three values per point. ' f'Shape is {points.shape} and should be (X, 3)') # points must be contiguous points = np.require(points, requirements=['C']) vtkpts = _vtk.vtkPoints() vtk_arr = _vtk.numpy_to_vtk(points, deep=deep) vtkpts.SetData(vtk_arr) return vtkpts
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 z(self, coords): """Set the coordinates along the Z-direction.""" self.SetZCoordinates(_vtk.numpy_to_vtk(coords)) self._update_dimensions() self.Modified()
def vector_poly_data(orig, vec): """Create a pyvista.PolyData object composed of vectors. Parameters ---------- orig : numpy.ndarray Array of vector origins. vec : numpy.ndarray Array of vectors. Returns ------- pyvista.PolyData Mesh containing the ``orig`` points along with the ``'vectors'`` and ``'mag'`` point arrays representing the vectors and magnitude of the the vectors at each point. Examples -------- Create basic vector field. This is a point cloud where each point has a vector and magnitude attached to it. >>> import pyvista >>> import numpy as np >>> x, y = np.meshgrid(np.linspace(-5,5,10),np.linspace(-5,5,10)) >>> points = np.vstack((x.ravel(), y.ravel(), np.zeros(x.size))).T >>> u = x/np.sqrt(x**2 + y**2) >>> v = y/np.sqrt(x**2 + y**2) >>> vectors = np.vstack((u.ravel()**3, v.ravel()**3, np.zeros(u.size))).T >>> pdata = pyvista.vector_poly_data(points, vectors) >>> pdata.point_data.keys() ['vectors', 'mag'] Convert these to arrows and plot it. >>> pdata.glyph(orient='vectors', scale='mag').plot() """ # shape, dimension checking if not isinstance(orig, np.ndarray): orig = np.asarray(orig) if not isinstance(vec, np.ndarray): vec = np.asarray(vec) if orig.ndim != 2: orig = orig.reshape((-1, 3)) elif orig.shape[1] != 3: raise ValueError('orig array must be 3D') if vec.ndim != 2: vec = vec.reshape((-1, 3)) elif vec.shape[1] != 3: raise ValueError('vec array must be 3D') # Create vtk points and cells objects vpts = _vtk.vtkPoints() vpts.SetData(_vtk.numpy_to_vtk(np.ascontiguousarray(orig), deep=True)) npts = orig.shape[0] cells = np.empty((npts, 2), dtype=pyvista.ID_TYPE) cells[:, 0] = 1 cells[:, 1] = np.arange(npts, dtype=pyvista.ID_TYPE) vcells = pyvista.utilities.cells.CellArray(cells, npts) # Create vtkPolyData object pdata = _vtk.vtkPolyData() pdata.SetPoints(vpts) pdata.SetVerts(vcells) # Add vectors to polydata name = 'vectors' vtkfloat = _vtk.numpy_to_vtk(np.ascontiguousarray(vec), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveVectors(name) # Add magnitude of vectors to polydata name = 'mag' scalars = (vec * vec).sum(1)**0.5 vtkfloat = _vtk.numpy_to_vtk(np.ascontiguousarray(scalars), deep=True) vtkfloat.SetName(name) pdata.GetPointData().AddArray(vtkfloat) pdata.GetPointData().SetActiveScalars(name) return pyvista.PolyData(pdata)
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 _from_arrays(self, offset, cells, cell_type, points, deep=True): """Create VTK unstructured grid from numpy arrays. Parameters ---------- offset : np.ndarray dtype=np.int64 Array indicating the start location of each cell in the cells array. Set to ``None`` when using VTK 9+. cells : np.ndarray dtype=np.int64 Array of cells. Each cell contains the number of points in the cell and the node numbers of the cell. cell_type : np.uint8 Cell types of each cell. Each cell type numbers can be found from vtk documentation. See example below. points : np.ndarray Numpy array containing point locations. Examples -------- >>> import numpy >>> import vtk >>> import pyvista >>> offset = np.array([0, 9]) >>> cells = np.array([8, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15]) >>> cell_type = np.array([vtk.VTK_HEXAHEDRON, vtk.VTK_HEXAHEDRON], np.int8) >>> cell1 = np.array([[0, 0, 0], ... [1, 0, 0], ... [1, 1, 0], ... [0, 1, 0], ... [0, 0, 1], ... [1, 0, 1], ... [1, 1, 1], ... [0, 1, 1]]) >>> cell2 = np.array([[0, 0, 2], ... [1, 0, 2], ... [1, 1, 2], ... [0, 1, 2], ... [0, 0, 3], ... [1, 0, 3], ... [1, 1, 3], ... [0, 1, 3]]) >>> points = np.vstack((cell1, cell2)) >>> grid = pyvista.UnstructuredGrid(offset, cells, cell_type, points) """ # Convert to vtk arrays vtkcells = CellArray(cells, cell_type.size, deep) if cell_type.dtype != np.uint8: cell_type = cell_type.astype(np.uint8) cell_type_np = cell_type cell_type = _vtk.numpy_to_vtk(cell_type, deep=deep) # Convert points to vtkPoints object points = pyvista.vtk_points(points, deep=deep) self.SetPoints(points) # vtk9 does not require an offset array if _vtk.VTK9: if offset is not None: warnings.warn('VTK 9 no longer accepts an offset array', stacklevel=3) self.SetCells(cell_type, vtkcells) else: if offset is None: offset = generate_cell_offsets(cells, cell_type_np) self.SetCells(cell_type, numpy_to_idarr(offset), vtkcells)