init
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
"""These are private methods we keep out of plotting.py to simplify the module."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
|
||||
import pyvista
|
||||
from pyvista._deprecate_positional_args import _deprecate_positional_args
|
||||
from pyvista.core.utilities.arrays import get_array
|
||||
from pyvista.core.utilities.misc import assert_empty_kwargs
|
||||
|
||||
from .colors import Color
|
||||
from .opts import InterpolationType
|
||||
from .tools import opacity_transfer_function
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pyvista.core._typing_core import NumpyArray
|
||||
|
||||
|
||||
@_deprecate_positional_args
|
||||
def prepare_smooth_shading( # noqa: PLR0917
|
||||
mesh: pyvista.DataSet, scalars, texture, split_sharp_edges, feature_angle, preference
|
||||
) -> tuple[pyvista.PolyData, NumpyArray[float]]:
|
||||
"""Prepare a dataset for smooth shading.
|
||||
|
||||
VTK requires datasets with Phong shading to have active normals.
|
||||
This requires extracting the external surfaces from non-polydata
|
||||
datasets and computing the point normals.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh : pyvista.DataSet
|
||||
Dataset to prepare smooth shading for.
|
||||
|
||||
scalars : sequence
|
||||
Sequence of scalars.
|
||||
|
||||
texture : pyvista.Texture or np.ndarray, optional
|
||||
A texture to apply to the mesh.
|
||||
|
||||
split_sharp_edges : bool
|
||||
Split sharp edges exceeding 30 degrees when plotting with
|
||||
smooth shading. Control the angle with the optional
|
||||
keyword argument ``feature_angle``. By default this is
|
||||
``False``. Note that enabling this will create a copy of
|
||||
the input mesh within the plotter. See
|
||||
:ref:`shading_example`.
|
||||
|
||||
feature_angle : float
|
||||
Angle to consider an edge a sharp edge.
|
||||
|
||||
preference : str
|
||||
If the number of points is identical to the number of cells.
|
||||
Either ``'point'`` or ``'cell'``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pyvista.PolyData
|
||||
Always a surface as we need to compute point normals.
|
||||
|
||||
"""
|
||||
is_polydata = isinstance(mesh, pyvista.PolyData)
|
||||
indices_array = None
|
||||
|
||||
has_scalars = scalars is not None
|
||||
use_points = False
|
||||
if has_scalars:
|
||||
if not isinstance(scalars, np.ndarray):
|
||||
scalars = np.array(scalars)
|
||||
if scalars.shape[0] == mesh.n_points and scalars.shape[0] == mesh.n_cells:
|
||||
use_points = preference == 'point'
|
||||
else:
|
||||
use_points = scalars.shape[0] == mesh.n_points
|
||||
|
||||
# extract surface if not already a surface
|
||||
if not is_polydata:
|
||||
mesh = mesh.extract_surface(
|
||||
pass_pointid=use_points or texture is not None,
|
||||
pass_cellid=not use_points,
|
||||
)
|
||||
indices_array = 'vtkOriginalPointIds' if use_points else 'vtkOriginalCellIds'
|
||||
|
||||
try:
|
||||
if split_sharp_edges:
|
||||
mesh = mesh.compute_normals(
|
||||
cell_normals=False,
|
||||
split_vertices=True,
|
||||
feature_angle=feature_angle,
|
||||
)
|
||||
if is_polydata:
|
||||
if has_scalars and use_points:
|
||||
# we must track the original IDs with our own array from compute_normals
|
||||
indices_array = 'pyvistaOriginalPointIds'
|
||||
elif mesh.point_data.active_normals is None:
|
||||
mesh.compute_normals(cell_normals=False, inplace=True)
|
||||
except TypeError as e:
|
||||
if 'Normals cannot be computed' in repr(e):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
if has_scalars and indices_array is not None:
|
||||
ind = mesh[indices_array]
|
||||
scalars = np.asarray(scalars)[ind]
|
||||
|
||||
return mesh, scalars # type: ignore[return-value]
|
||||
|
||||
|
||||
@_deprecate_positional_args
|
||||
def process_opacity(mesh, opacity, preference, n_colors, scalars, use_transparency): # noqa: PLR0917
|
||||
"""Process opacity.
|
||||
|
||||
This function accepts an opacity string or array and always
|
||||
returns an array that can be applied to a dataset for plotting.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mesh : pyvista.DataSet
|
||||
Dataset to process the opacity for.
|
||||
|
||||
opacity : str, sequence
|
||||
String or array. If string, can be a ``str`` name of a
|
||||
predefined mapping such as ``'linear'``, ``'geom'``,
|
||||
``'sigmoid'``, ``'sigmoid3-10'``, or the key of a cell or
|
||||
point data array.
|
||||
|
||||
preference : str
|
||||
When ``mesh.n_points == mesh.n_cells``, this parameter
|
||||
sets how the scalars will be mapped to the mesh. If
|
||||
``'point'``, causes the scalars will be associated with
|
||||
the mesh points. Can be either ``'point'`` or
|
||||
``'cell'``.
|
||||
|
||||
n_colors : int
|
||||
Number of colors to use when displaying the opacity.
|
||||
|
||||
scalars : numpy.ndarray
|
||||
Dataset scalars.
|
||||
|
||||
use_transparency : bool
|
||||
Invert the opacity mappings and make the values correspond
|
||||
to transparency.
|
||||
|
||||
Returns
|
||||
-------
|
||||
custom_opac : bool
|
||||
If using custom opacity.
|
||||
|
||||
opacity : numpy.ndarray
|
||||
Array containing the opacity.
|
||||
|
||||
"""
|
||||
custom_opac = False
|
||||
if isinstance(opacity, str):
|
||||
try:
|
||||
# Get array from mesh
|
||||
opacity = get_array(mesh, opacity, preference=preference, err=True)
|
||||
if np.any(opacity > 1):
|
||||
warnings.warn('Opacity scalars contain values over 1')
|
||||
if np.any(opacity < 0):
|
||||
warnings.warn('Opacity scalars contain values less than 0')
|
||||
custom_opac = True
|
||||
except KeyError:
|
||||
# Or get opacity transfer function (e.g. "linear")
|
||||
opacity = opacity_transfer_function(opacity, n_colors)
|
||||
else:
|
||||
if scalars.shape[0] != opacity.shape[0]:
|
||||
msg = 'Opacity array and scalars array must have the same number of elements.'
|
||||
raise ValueError(msg)
|
||||
elif isinstance(opacity, (np.ndarray, list, tuple)):
|
||||
opacity = np.asanyarray(opacity)
|
||||
if opacity.shape[0] in [mesh.n_cells, mesh.n_points]:
|
||||
# User could pass an array of opacities for every point/cell
|
||||
custom_opac = True
|
||||
else:
|
||||
opacity = opacity_transfer_function(opacity, n_colors)
|
||||
|
||||
if use_transparency:
|
||||
if np.max(opacity) <= 1.0:
|
||||
opacity = 1 - opacity
|
||||
elif isinstance(opacity, np.ndarray):
|
||||
opacity = 255 - opacity
|
||||
|
||||
return custom_opac, opacity
|
||||
|
||||
|
||||
def _common_arg_parser(
|
||||
*,
|
||||
dataset,
|
||||
theme,
|
||||
n_colors,
|
||||
scalar_bar_args,
|
||||
split_sharp_edges,
|
||||
show_scalar_bar,
|
||||
render_points_as_spheres,
|
||||
smooth_shading,
|
||||
pbr,
|
||||
clim,
|
||||
cmap,
|
||||
culling,
|
||||
name,
|
||||
nan_color,
|
||||
nan_opacity,
|
||||
texture,
|
||||
rgb,
|
||||
style,
|
||||
**kwargs,
|
||||
):
|
||||
"""Parse arguments in common between add_volume, composite, and mesh."""
|
||||
# supported aliases
|
||||
clim = kwargs.pop('rng', clim)
|
||||
cmap = kwargs.pop('colormap', cmap)
|
||||
culling = kwargs.pop('backface_culling', culling)
|
||||
rgb = kwargs.pop('rgba', rgb)
|
||||
vertex_color = kwargs.pop('vertex_color', theme.edge_color)
|
||||
vertex_style = kwargs.pop('vertex_style', 'points')
|
||||
vertex_opacity = kwargs.pop('vertex_opacity', 1.0)
|
||||
|
||||
# Support aliases for 'back', 'front', or 'none'. Consider deprecating
|
||||
if culling is False:
|
||||
culling = 'none'
|
||||
elif culling in ['b', 'backface', True]:
|
||||
culling = 'back'
|
||||
elif culling in ['f', 'frontface']:
|
||||
culling = 'front'
|
||||
|
||||
if show_scalar_bar is None:
|
||||
# use theme unless plotting RGB
|
||||
_default = theme.show_scalar_bar or scalar_bar_args
|
||||
show_scalar_bar = False if rgb else _default
|
||||
# Avoid mutating input
|
||||
scalar_bar_args = {'n_colors': n_colors} if scalar_bar_args is None else scalar_bar_args.copy()
|
||||
|
||||
# theme based parameters
|
||||
if split_sharp_edges is None:
|
||||
split_sharp_edges = theme.split_sharp_edges
|
||||
feature_angle = kwargs.pop('feature_angle', theme.sharp_edges_feature_angle)
|
||||
if render_points_as_spheres is None:
|
||||
if style == 'points_gaussian':
|
||||
render_points_as_spheres = False
|
||||
else:
|
||||
render_points_as_spheres = theme.render_points_as_spheres
|
||||
|
||||
if smooth_shading is None:
|
||||
smooth_shading = True if pbr else theme.smooth_shading
|
||||
|
||||
if name is None:
|
||||
name = f'{type(dataset).__name__}({dataset.memory_address})'
|
||||
remove_existing_actor = False
|
||||
else:
|
||||
# check if this actor already exists
|
||||
remove_existing_actor = True
|
||||
|
||||
nan_color = Color(nan_color, opacity=nan_opacity, default_color=theme.nan_color)
|
||||
|
||||
if texture is False:
|
||||
texture = None
|
||||
|
||||
# allow directly specifying interpolation (potential future feature)
|
||||
if 'interpolation' in kwargs:
|
||||
interpolation = kwargs.pop('interpolation') # pragma: no cover:
|
||||
elif pbr:
|
||||
interpolation = InterpolationType.PBR
|
||||
elif smooth_shading:
|
||||
interpolation = InterpolationType.PHONG
|
||||
else:
|
||||
interpolation = theme.lighting_params.interpolation
|
||||
|
||||
if 'scalar' in kwargs:
|
||||
msg = '`scalar` is an invalid keyword argument. Perhaps you mean `scalars` with an s?'
|
||||
raise TypeError(msg)
|
||||
|
||||
assert_empty_kwargs(**kwargs)
|
||||
return (
|
||||
scalar_bar_args,
|
||||
split_sharp_edges,
|
||||
show_scalar_bar,
|
||||
feature_angle,
|
||||
render_points_as_spheres,
|
||||
smooth_shading,
|
||||
clim,
|
||||
cmap,
|
||||
culling,
|
||||
name,
|
||||
nan_color,
|
||||
texture,
|
||||
rgb,
|
||||
interpolation,
|
||||
remove_existing_actor,
|
||||
vertex_color,
|
||||
vertex_style,
|
||||
vertex_opacity,
|
||||
)
|
||||
Reference in New Issue
Block a user