from typing import *
import numpy as np
import pygfx
from .line import LineGraphic
from .features import (
InfLineAxisData,
InfLineColors,
UniformColor,
)
from ..utils.types import ColorLike, MultiColorLike, ColormapLike
from ..utils import global_config
[docs]
@global_config.register
class InfLineGraphic(LineGraphic):
_features = {
"data": InfLineAxisData,
"colors": (InfLineColors, UniformColor),
}
# one color per line, each broadcast to the two vertices of the line's segment
_VertexColorsCls = InfLineColors
@global_config.declare(
"thickness",
"colors",
"cmap",
"start_is_infinite",
"end_is_infinite",
"dash_pattern",
"size_space",
)
def __init__(
self,
data: Any,
axis: Literal["x", "y", "z"] | None = None,
thickness: float = 2.0,
colors: ColorLike | MultiColorLike = "w",
cmap: ColormapLike = None,
cmap_transform: np.ndarray | None = None,
cmap_range: tuple[float, float] | None = None,
start_is_infinite: bool = True,
end_is_infinite: bool = True,
dash_pattern: str | tuple | list = (),
size_space: Literal["screen", "world", "model"] = "screen",
**kwargs,
):
"""
Create a collection of infinite lines.
Parameters
----------
data: array-like
The line positions. If ``axis`` is "x", "y", or "z", a 1D array of positions along
that axis; one infinite line is drawn at each position. If ``axis`` is None, ``data``
is used directly as the segment endpoints, of shape [n_points, 2 | 3], where every two
consecutive points define one line.
axis: "x", "y", "z", or None, default None
The axis along which the line positions are given. If None, ``data`` is interpreted
directly as the segment endpoints.
thickness: float, optional, default 2.0
thickness of the lines
colors: ColorLike or MultiColorLike, default "w"
specify colors as a single human-readable string, a single RGBA array, or a Sequence
(array, tuple, or list) of strings or RGBA arrays. A sequence of colors provides one
color per line.
cmap: str, optional
Apply a colormap to the lines instead of assigning colors manually, one color per line.
This overrides any argument passed to "colors". For supported colormaps see the
``cmap`` library catalogue: https://cmap-docs.readthedocs.io/en/stable/catalog/
cmap_transform: np.ndarray, optional
1D array-like of numerical values, if provided, these values are used to map the colors from the cmap
cmap_range: (float, float), optional
the (min, max) of the cmap_transform mapped onto the colormap, defaults to the transform's own range
start_is_infinite: bool, default True
whether the start of each line is extended to infinity
end_is_infinite: bool, default True
whether the end of each line is extended to infinity
dash_pattern: str, tuple, or list, default ()
The dash pattern. May be a matplotlib-style string, one of ``"-", "--", "-.", ":"``
or ``"solid", "dashed", "dashdot", "dotted"``, or a sequence of floats describing the
length of strokes and gaps.
size_space: str, default "screen"
coordinate space in which the thickness is expressed ("screen", "world", "model")
**kwargs
passed to :class:`.Graphic`
"""
self._start_is_infinite = bool(start_is_infinite)
self._end_is_infinite = bool(end_is_infinite)
data = InfLineAxisData(data, axis=axis)
super().__init__(
data=data,
thickness=thickness,
colors=colors,
cmap=cmap,
cmap_transform=cmap_transform,
cmap_range=cmap_range,
size_space=size_space,
dash_pattern=dash_pattern,
thin=False,
**kwargs,
)
def _make_material(self) -> pygfx.LineInfiniteSegmentMaterial:
return pygfx.LineInfiniteSegmentMaterial(
start_is_infinite=self._start_is_infinite,
end_is_infinite=self._end_is_infinite,
**self._get_material_kwargs(),
)
@property
def axis(self) -> str | None:
"""the axis the lines are defined along ("x", "y", "z"), or None if set from endpoints"""
return self._data.axis
@property
def start_is_infinite(self) -> bool:
"""Get or set whether the start of each line is extended to infinity"""
return self._start_is_infinite
@start_is_infinite.setter
def start_is_infinite(self, value: bool):
self._start_is_infinite = bool(value)
self.world_object.material.start_is_infinite = self._start_is_infinite
@property
def end_is_infinite(self) -> bool:
"""Get or set whether the end of each line is extended to infinity"""
return self._end_is_infinite
@end_is_infinite.setter
def end_is_infinite(self, value: bool):
self._end_is_infinite = bool(value)
self.world_object.material.end_is_infinite = self._end_is_infinite
@property
def thin(self) -> bool:
"""infinite lines do not support the thin line material"""
return False
@thin.setter
def thin(self, value: bool):
if value:
raise NotImplementedError(
"`InfLineGraphic` does not support the thin line material"
)
def _selectors_not_supported(self, *args, **kwargs):
raise NotImplementedError("selectors are not supported on `InfLineGraphic`")
add_linear_selector = _selectors_not_supported
add_linear_region_selector = _selectors_not_supported
add_rectangle_selector = _selectors_not_supported
add_polygon_selector = _selectors_not_supported