"""Factory functions for volumetric and voxel-based objects."""
import warnings
from typing import Any, Callable, Optional, Tuple, Union
from typing import Dict as TypingDict
from typing import List as TypingList
import numpy as np
from ..helpers import check_attribute_color_range, check_unsigned_range, rgb_volume_channels
from ..objects import MIP, MarchingCubes, SparseVoxels, Volume, VolumeSlice, VoxelChunk, Voxels, VoxelsGroup
from ..transform import process_transform_arguments
from .common import _default_color, default_colormap, nice_colors
# Type aliases for better readability
ArrayLike = Union[TypingList, np.ndarray, Tuple]
ColorMap = Union[TypingList[TypingList[float]], TypingDict[str, Any], np.ndarray]
ColorRange = TypingList[float]
OpacityFunction = TypingList[float]
def _warn_rgb_ignores(color_map, color_range):
"""An RGB volume maps nothing, so a colormap or a range would only look like it works."""
if color_map is not None and len(color_map) > 0:
warnings.warn(
"color_map is ignored for an RGB volume: the colour is in the data",
stacklevel=3,
)
if color_range is not None and len(color_range) > 0:
warnings.warn(
"color_range is ignored for an RGB volume: there is no scalar to window",
stacklevel=3,
)
[docs]
def volume(
volume: ArrayLike,
color_map: Optional[ColorMap] = None,
opacity_function: Optional[OpacityFunction] = None,
color_range: ColorRange = None,
samples: float = 512.0,
alpha_coef: float = 50.0,
gradient_step: float = 0.005,
roughness: float = 0.25,
metalness: float = 0.0,
light_scale: float = 1.0,
shadow: str = "off",
interpolation: bool = True,
shadow_delay: int = 500,
shadow_res: int = 128,
mask: ArrayLike = None,
mask_opacities: ArrayLike = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
**kwargs: Any,
) -> Volume:
"""
Create a Volume drawable for direct volume rendering of a scalar field.
Parameters
----------
volume : array_like
3D array of `float`, indexed as [z, y, x]. A 4D array of `uint8` shaped [z, y, x, 3] or
[z, y, x, 4] is colour per voxel instead - the measurement itself, the way a photographic
or RGB-encoded scan carries it - and is drawn without a colormap: color_map and
color_range are ignored, and the alpha comes from opacity_function over Rec. 709
luminance.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
opacity_function : list, optional
A list of float tuples (attribute value, opacity), sorted by attribute value. The first
tuple should have value 0.0, the last 1.0; opacity is in the range 0.0 to 1.0. Default is
None.
color_range : list, optional
A pair [min_value, max_value], which determines the levels of color attribute mapped to 0
and 1 in the color map respectively. Default is None.
samples : float, optional
Number of iteration per 1 unit of space. Default is 512.0.
alpha_coef : float, optional
Alpha multiplier. Default is 50.0.
gradient_step : float, optional
Distance the finite differences of the shading gradient are taken over, as a fraction of
the mean edge of the volume's box. Default is 0.005.
roughness : float, optional
Roughness of the specular highlight of the isodensity surface (GGX), 0.0-1.0. Default is
0.25.
metalness : float, optional
Metalness of the specular highlight: 0.0 dielectric, 1.0 metal tinted by the transfer-
function colour. Default is 0.0.
light_scale : float, optional
Multiplies the light the medium collects, so the volume can be exposed without touching
the rest of the scene. Only the cinematic renderer reads it. Every ratio in the image
survives, self-shadowing included - unlike a brighter environment, which lifts the
geometry around the volume as well. Default is 1.0.
shadow : str, optional
Type of shadow on volume. Legal values are: 'off' shadow disabled, 'on_demand' update
shadow map on demand ( self.shadow_map_update() ), 'dynamic' update shadow map
automaticaly every shadow_delay. Default is 'off'.
interpolation : bool, optional
Whether volume raycasting should interpolate data or not. Default is True.
shadow_delay : float, optional
Minimum number of miliseconds between shadow map updates. Default is 500.
shadow_res : int, optional
Resolution of shadow map. Default is 128.
mask : array_like, optional
3D array of `int` in range (0, 255), indexed as [z, y, x]. Default is None.
mask_opacities : array_like, optional
List of opacity values for mask. Default is None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
Volume
The created Volume object.
"""
if color_range is None:
color_range = []
if mask is None:
mask = []
if mask_opacities is None:
mask_opacities = []
if rgb_volume_channels(volume):
_warn_rgb_ignores(color_map, color_range)
color_map = []
color_range = []
# the colour needs no ramp, the alpha does: without one the box is opaque and all you
# see is its front face. Luminance from 0 to 1 is the axis this ramp runs along.
if opacity_function is None:
opacity_function = [0.0, 0.0, 1.0, 1.0]
else:
if color_map is None:
color_map = default_colormap
color_range = (
check_attribute_color_range(volume, color_range)
if type(color_range) is not dict
else color_range
)
if opacity_function is None:
# ravel first: a colormap given as (N, 4) slices by row here, and the ramp then
# spans whatever the sampled rows happen to hold instead of the first column
if type(color_map) is dict:
values = np.concatenate(
[np.asarray(frame, np.float32).ravel()[::4] for frame in color_map.values()]
)
else:
values = np.asarray(color_map, np.float32).ravel()[::4]
opacity_function = [np.min(values), 0.0, np.max(values), 1.0]
return process_transform_arguments(
Volume(
volume=volume,
color_map=color_map,
opacity_function=opacity_function,
color_range=color_range,
compression_level=compression_level,
visible=visible,
samples=samples,
alpha_coef=alpha_coef,
gradient_step=gradient_step,
roughness=roughness,
metalness=metalness,
light_scale=light_scale,
interpolation=interpolation,
shadow=shadow,
shadow_delay=shadow_delay,
shadow_res=shadow_res,
mask=mask,
mask_opacities=mask_opacities,
name=name,
group=group,
custom_data=custom_data,
),
**kwargs,
)
[docs]
def mip(
volume: ArrayLike,
color_map: Optional[ColorMap] = None,
opacity_function: Optional[OpacityFunction] = None,
color_range: ColorRange = None,
samples: float = 512.0,
gradient_step: float = 0.005,
roughness: float = 0.25,
metalness: float = 0.0,
interpolation: bool = True,
mask: ArrayLike = None,
mask_opacities: ArrayLike = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
**kwargs: Any,
) -> MIP:
"""
Create a MIP drawable, a maximum intensity projection of a scalar field.
Parameters
----------
volume : array_like
3D array of `float`, indexed as [z, y, x]. A 4D array of `uint8` shaped [z, y, x, 3] or
[z, y, x, 4] is colour per voxel; the maximum along the ray is then taken over Rec. 709
luminance and the pixel keeps the colour of the voxel that reached it, so color_map and
color_range are ignored and opacity_function runs along that luminance.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
opacity_function : list, optional
A list of float tuples (attribute value, opacity), sorted by attribute value. The first
tuple should have value 0.0, the last 1.0; opacity is in the range 0.0 to 1.0. Default is
None.
color_range : list, optional
A pair [min_value, max_value], which determines the levels of color attribute mapped to 0
and 1 in the color map respectively. Default is None.
samples : float, optional
Number of iteration per 1 unit of space. Default is 512.0.
gradient_step : float, optional
Distance the finite differences of the shading gradient are taken over, as a fraction of
the mean edge of the volume's box. Default is 0.005.
roughness : float, optional
Roughness of the specular highlight of the isodensity surface (GGX), 0.0-1.0. Default is
0.25.
metalness : float, optional
Metalness of the specular highlight: 0.0 dielectric, 1.0 metal tinted by the transfer-
function colour. Default is 0.0.
interpolation : bool, optional
Whether the ray march should interpolate the data or read the nearest voxel. Default is
True.
mask : array_like, optional
3D array of `int` in range (0, 255), indexed as [z, y, x]. Default is None.
mask_opacities : array_like, optional
List of opacity values for mask. Default is None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
MIP
The created MIP object.
"""
if color_range is None:
color_range = []
if mask is None:
mask = []
if mask_opacities is None:
mask_opacities = []
if rgb_volume_channels(volume):
_warn_rgb_ignores(color_map, color_range)
color_map = []
color_range = []
# the brightest voxel along the ray still needs an alpha, and it comes from the same
# luminance that decided which voxel that was
if opacity_function is None:
opacity_function = [0.0, 0.0, 1.0, 1.0]
else:
if color_map is None:
color_map = default_colormap
color_range = (
check_attribute_color_range(volume, color_range)
if type(color_range) is not dict
else color_range
)
if opacity_function is None:
# color_map may be a TimeSeries dict, which cannot be sliced; derive the default
# ramp from the union of its frames in that case.
# ravel first: a colormap given as (N, 4) slices by row here, and the ramp then
# spans whatever the sampled rows happen to hold instead of the first column
if type(color_map) is dict:
values = np.concatenate(
[np.asarray(frame, np.float32).ravel()[::4] for frame in color_map.values()]
)
else:
values = np.asarray(color_map, np.float32).ravel()[::4]
opacity_function = [np.min(values), 0.0, np.max(values), 1.0]
return process_transform_arguments(
MIP(
volume=volume,
color_map=color_map,
opacity_function=opacity_function,
color_range=color_range,
samples=samples,
gradient_step=gradient_step,
roughness=roughness,
metalness=metalness,
interpolation=interpolation,
mask=mask,
mask_opacities=mask_opacities,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
),
**kwargs,
)
[docs]
def volume_slice(
volume: ArrayLike = None,
color_map: Optional[ColorMap] = None,
color_range: ColorRange = None,
opacity_function: OpacityFunction = None,
opacity: float = 1.0,
mask: ArrayLike = None,
active_masks: ArrayLike = None,
color_map_masks: Optional[ColorMap] = None,
mask_opacity: float = 0.5,
slice_x: int = -1,
slice_y: int = -1,
slice_z: int = 0,
interpolation: int = 1,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
click_callback: Optional[Callable] = None,
hover_callback: Optional[Callable] = None,
**kwargs: Any,
) -> VolumeSlice:
"""
Create a VolumeSlice drawable showing axis-aligned slices of a scalar field.
Parameters
----------
volume : array_like, optional
3D array of `float`, indexed as [z, y, x]. A list of two such arrays is a two-channel
slice, read through a 2D colormap. A 4D array of `uint8` shaped [z, y, x, 3] or
[z, y, x, 4] is colour per voxel and is drawn as it stands, without a colormap.
Default is None.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
color_range : list, optional
A pair [min_value, max_value], which determines the levels of color attribute mapped to 0
and 1 in the color map respectively. Default is None.
opacity_function : list, optional
A list of float tuples (attribute value, opacity), sorted by attribute value. The first
tuple should have value 0.0, the last 1.0; opacity is in the range 0.0 to 1.0. Default is
None.
opacity : float, optional
Opacity of slice. Default is 1.0.
mask : array_like, optional
3D array of `int` in range (0, 255), indexed as [z, y, x]. Default is None.
active_masks : array_like, optional
List of values from mask. Default is None.
color_map_masks : list, optional
Flat array of `int` packed RGB colors (0xff0000 is red, 0xff is blue). The color defined
at index i is for voxel value (i+1), e.g.: Default is None.
mask_opacity : float, optional
Mask enhanced coefficient. Default is 0.5.
slice_x : int, optional
Index of the slice along x, or -1 for none. Default is -1.
slice_y : int, optional
Index of the slice along y, or -1 for none. Default is -1.
slice_z : int, optional
Index of the slice along z, or -1 for none. Default is 0.
interpolation : int, optional
0 - no interpolation, 1 - linear, 2 - cubic. Default is 1.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
click_callback : callable, optional
Called with the picking parameters when the object is clicked, while the plot is
in mode='callback'. Default is None.
hover_callback : callable, optional
Called with the picking parameters when the cursor is over the object, while the
plot is in mode='callback'. Default is None.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
VolumeSlice
The created VolumeSlice object.
"""
if volume is None:
volume = []
if color_range is None:
color_range = []
if opacity_function is None:
opacity_function = []
if mask is None:
mask = []
if active_masks is None:
active_masks = []
if color_map is None and not rgb_volume_channels(volume):
color_map = default_colormap
if color_map_masks is None:
color_map_masks = nice_colors
if rgb_volume_channels(volume):
_warn_rgb_ignores(color_map, color_range)
if len(opacity_function) > 0:
warnings.warn(
"opacity_function is ignored for an RGB volume_slice: a slice is opaque and "
"its alpha is the object's opacity",
stacklevel=2,
)
color_map = []
color_range = []
opacity_function = []
else:
color_map = (
np.array(color_map, np.float32) if type(color_map) is not dict else color_map
)
if len(volume) > 0:
color_range = check_attribute_color_range(volume, color_range, channels=True)
# createCanvasGradient2d writes a fixed alpha, so a transfer function has no channel to
# apply to once there are two. Saying so beats dropping it without a word.
if isinstance(volume, (list, tuple)) and len(volume) > 1 and len(opacity_function) > 0:
warnings.warn(
"opacity_function is ignored for a multi-channel volume_slice: the 2D colormap "
"carries colour only",
stacklevel=2,
)
return process_transform_arguments(
VolumeSlice(
volume=volume,
color_map=color_map,
color_range=color_range,
opacity_function=opacity_function,
opacity=opacity,
slice_x=slice_x,
slice_y=slice_y,
slice_z=slice_z,
interpolation=interpolation,
mask=mask,
mask_opacity=mask_opacity,
active_masks=active_masks,
color_map_masks=color_map_masks,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
click_callback=click_callback,
hover_callback=hover_callback,
),
**kwargs,
)
[docs]
def voxels(
voxels: ArrayLike,
color_map: Optional[ColorMap] = None,
wireframe: bool = False,
outlines: bool = True,
outlines_color: int = 0,
opacity: float = 1.0,
roughness: float = 0.4,
metalness: float = 0.0,
bounds: Optional[ArrayLike] = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
**kwargs: Any,
) -> Voxels:
"""
Create a Voxels drawable from a dense array of voxel ids.
Parameters
----------
voxels : array_like
3D array of `int` in range (0, 255), indexed as [z, y, x]. 0 means empty voxel, 1 and
above refer to consecutive color_map entries.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
wireframe : bool, optional
Whether mesh should display as wireframe. Default is False.
outlines : bool, optional
Whether mesh should display with outlines. Default is True.
outlines_color : int, optional
Packed RGB color of the resulting outlines (0xff0000 is red, 0xff is blue) Default is 0.
opacity : float, optional
Opacity of voxels. Default is 1.0.
roughness : float, optional
Roughness of the material. Default is 0.4.
metalness : float, optional
Metalness of the material. Default is 0.0.
bounds : array_like, optional
Bounding box [xmin, xmax, ymin, ymax, zmin, zmax] the object is scaled into; derived from
the data when omitted. Default is None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
Voxels
The created Voxels object.
"""
if color_map is None:
color_map = nice_colors
# process_transform_arguments only reads separate xmin/xmax/... out of **kwargs when
# "bounds" is absent from it, so always setting kwargs["bounds"] here (as a prior revision
# did) shadowed those arguments even when the caller passed them and not bounds.
if bounds is not None:
kwargs["bounds"] = bounds
elif not any(k in kwargs for k in ("xmin", "xmax", "ymin", "ymax", "zmin", "zmax")):
max_z, max_y, max_x = np.shape(voxels)
kwargs["bounds"] = np.array([0, max_x, 0, max_y, 0, max_z])
return process_transform_arguments(
Voxels(
voxels=voxels,
color_map=color_map,
wireframe=wireframe,
outlines=outlines,
outlines_color=outlines_color,
opacity=opacity,
roughness=roughness,
metalness=metalness,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
),
**kwargs,
)
[docs]
def sparse_voxels(
sparse_voxels: ArrayLike,
space_size: ArrayLike,
color_map: Optional[ColorMap] = None,
wireframe: bool = False,
outlines: bool = True,
outlines_color: int = 0,
opacity: float = 1.0,
roughness: float = 0.4,
metalness: float = 0.0,
bounds: Optional[ArrayLike] = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
**kwargs: Any,
) -> SparseVoxels:
"""
Create a SparseVoxels drawable from a list of voxel coordinates and ids.
Parameters
----------
sparse_voxels : array_like
2D array of `coords` in format [[x,y,z,v],[x,y,z,v]]. v = 0 means empty voxel, 1 and above
refer to consecutive color_map entries.
space_size : array_like
Width, height and length of the voxel space, in voxels.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
wireframe : bool, optional
Whether mesh should display as wireframe. Default is False.
outlines : bool, optional
Whether mesh should display with outlines. Default is True.
outlines_color : int, optional
Packed RGB color of the resulting outlines (0xff0000 is red, 0xff is blue) Default is 0.
opacity : float, optional
Opacity of voxels. Default is 1.0.
roughness : float, optional
Roughness of the material. Default is 0.4.
metalness : float, optional
Metalness of the material. Default is 0.0.
bounds : array_like, optional
Bounding box [xmin, xmax, ymin, ymax, zmin, zmax] the object is scaled into; derived from
the data when omitted. Default is None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
SparseVoxels
The created SparseVoxels object.
"""
if color_map is None:
color_map = nice_colors
assert (
isinstance(space_size, (tuple, list, np.ndarray))
and np.shape(space_size) == (3,)
and all(d > 0 for d in space_size)
)
# a named parameter never reaches **kwargs, which is the only thing
# process_transform_arguments reads - so bounds was accepted and dropped
if bounds is not None:
kwargs["bounds"] = bounds
return process_transform_arguments(
SparseVoxels(
sparse_voxels=sparse_voxels,
space_size=space_size,
color_map=color_map,
wireframe=wireframe,
outlines=outlines,
outlines_color=outlines_color,
opacity=opacity,
roughness=roughness,
metalness=metalness,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
),
**kwargs,
)
[docs]
def voxels_group(
space_size: ArrayLike,
voxels_group: TypingList[TypingDict[str, Any]] = None,
chunks_ids: TypingList[int] = None,
color_map: Optional[ColorMap] = None,
wireframe: bool = False,
outlines: bool = True,
outlines_color: int = 0,
opacity: float = 1.0,
roughness: float = 0.4,
metalness: float = 0.0,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
**kwargs: Any,
) -> VoxelsGroup:
"""
Create a VoxelsGroup drawable, a voxel space assembled from chunks.
Parameters
----------
space_size : array_like
Width, height and length of the voxel space, in voxels.
voxels_group : array_like, optional
List of `chunks` in format {voxels 'np.array, coord' [x,y,z], multiple: number}. Default
is None.
chunks_ids : list, optional
Ids of the VoxelChunk objects the group is assembled from. Default is None.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
wireframe : bool, optional
Whether mesh should display as wireframe. Default is False.
outlines : bool, optional
Whether mesh should display with outlines. Default is True.
outlines_color : int, optional
Packed RGB color of the resulting outlines (0xff0000 is red, 0xff is blue) Default is 0.
opacity : float, optional
Opacity of voxels. Default is 1.0.
roughness : float, optional
Roughness of the material. Default is 0.4.
metalness : float, optional
Metalness of the material. Default is 0.0.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
VoxelsGroup
The created VoxelsGroup object.
"""
if voxels_group is None:
voxels_group = []
if chunks_ids is None:
chunks_ids = []
if color_map is None:
color_map = nice_colors
for g in voxels_group:
g["coord"] = np.array(g["coord"])
g["voxels"] = np.array(g["voxels"])
if "multiple" not in g:
g["multiple"] = 1
return process_transform_arguments(
VoxelsGroup(
voxels_group=voxels_group,
chunks_ids=chunks_ids,
space_size=space_size,
color_map=color_map,
wireframe=wireframe,
outlines=outlines,
outlines_color=outlines_color,
opacity=opacity,
roughness=roughness,
metalness=metalness,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
),
**kwargs,
)
[docs]
def marching_cubes(
scalar_field: ArrayLike,
level: float,
color: int = _default_color,
attribute: ArrayLike = None,
color_map: Optional[ColorMap] = None,
color_range: ColorRange = None,
opacity_function: OpacityFunction = None,
wireframe: bool = False,
flat_shading: bool = True,
roughness: float = 0.4,
metalness: float = 0.0,
shininess: float = None,
opacity: float = 1.0,
spacings_x: ArrayLike = None,
spacings_y: ArrayLike = None,
spacings_z: ArrayLike = None,
name: Optional[str] = None,
group: Optional[str] = None,
custom_data: Optional[TypingDict[str, Any]] = None,
compression_level: int = 0,
visible: bool = True,
click_callback: Optional[Callable] = None,
hover_callback: Optional[Callable] = None,
**kwargs: Any,
) -> MarchingCubes:
"""
Create a MarchingCubes drawable, an isosurface of a scalar field.
Parameters
----------
scalar_field : array_like
3D array of the scalar field, indexed as [z, y, x]. The surface faces outwards where the
field is negative inside it.
level : float
Value at the computed isosurface.
color : int, optional
Packed RGB color of the isosurface (0xff0000 is red, 0xff is blue). Default is 255.
attribute : array_like, optional
3D array of float sampled on the same grid as scalar_field, from which the surface colour
is read at each vertex. A flat, per-vertex array is not accepted: it cannot be sampled at
a position and is ignored, with a warning in the browser console. Default is None.
color_map : list, optional
A list of float quadruplets (attribute value, R, G, B), sorted by attribute value. The
first quadruplet should have value 0.0, the last 1.0; R, G, B are RGB color components in
the range 0.0 to 1.0. Default is None.
color_range : list, optional
A pair [min_value, max_value], which determines the levels of color attribute mapped to 0
and 1 in the color map respectively. Default is None.
opacity_function : list, optional
A list of float tuples (attribute value, opacity), sorted by attribute value. The first
tuple should have value 0.0, the last 1.0; opacity is in the range 0.0 to 1.0. Default is
None.
wireframe : bool, optional
Whether mesh should display as wireframe. Default is False.
flat_shading : bool, optional
Whether mesh should display with flat shading. Default is True.
roughness : float, optional
Roughness of object material. Default is 0.4.
metalness : float, optional
Metalness of object material. Default is 0.0.
shininess : float, optional
Removed in 3.0.0; passing it raises. Use roughness and metalness. Default is None.
opacity : float, optional
Opacity of mesh. Default is 1.0.
spacings_x : array_like, optional
Distances between consecutive samples along x: one shorter than that axis of scalar_field.
Any other length is ignored and the axis falls back to even spacing. Default is None.
spacings_y : array_like, optional
Distances between consecutive samples along y, one shorter than that axis. Default is
None.
spacings_z : array_like, optional
Distances between consecutive samples along z, one shorter than that axis. Default is
None.
name : str, optional
A name of the object. Default is None.
group : str, optional
A name of a group. Default is None.
custom_data : dict, optional
An object with custom data attached to object. Default is None.
compression_level : int, optional
Level of compression [-1, 9]. Default is 0.
visible : bool, optional
Whether the object is drawn. Default is True.
click_callback : callable, optional
Called with the picking parameters when the object is clicked, while the plot is
in mode='callback'. Default is None.
hover_callback : callable, optional
Called with the picking parameters when the cursor is over the object, while the
plot is in mode='callback'. Default is None.
**kwargs
Additional keyword arguments passed to process_transform_arguments.
Returns
-------
MarchingCubes
The created MarchingCubes object.
"""
if attribute is None:
attribute = []
if color_range is None:
color_range = []
if opacity_function is None:
opacity_function = []
if spacings_x is None:
spacings_x = []
if spacings_y is None:
spacings_y = []
if spacings_z is None:
spacings_z = []
if color_map is None:
color_map = default_colormap
attribute = (
np.array(attribute, np.float32) if type(attribute) is not dict else attribute
)
color_range = check_attribute_color_range(attribute, color_range)
return process_transform_arguments(
MarchingCubes(
scalar_field=scalar_field,
spacings_x=spacings_x,
spacings_y=spacings_y,
spacings_z=spacings_z,
color=color,
attribute=attribute,
color_map=color_map,
color_range=color_range,
opacity_function=opacity_function,
level=level,
wireframe=wireframe,
flat_shading=flat_shading,
roughness=roughness,
metalness=metalness,
shininess=shininess,
opacity=opacity,
name=name,
group=group,
custom_data=custom_data,
compression_level=compression_level,
visible=visible,
click_callback=click_callback,
hover_callback=hover_callback,
),
**kwargs,
)
[docs]
def voxel_chunk(
voxels: ArrayLike, coord: ArrayLike, multiple: int = 1, compression_level: int = 0
) -> VoxelChunk:
"""Create a VoxelChunk object for selective updating voxels.
Parameters
----------
voxels : array_like
Array of voxel data.
coord : array_like
Coordinates for the chunk.
multiple : int, optional
Multiple factor, by default 1.
compression_level : int, optional
Compression level for the chunk, by default 0.
Returns
-------
VoxelChunk
VoxelChunk object.
"""
voxels = np.asarray(voxels)
check_unsigned_range(voxels, np.uint8)
return VoxelChunk(
voxels=voxels.astype(np.uint8),
coord=np.array(coord, np.uint32),
multiple=multiple,
compression_level=compression_level,
)