Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/scenex/adaptors/_pygfx/_points.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any, Literal

import numpy as np
Expand All @@ -10,6 +11,8 @@

from ._node import Node

logger = logging.getLogger("scenex.adaptors.pygfx")

if TYPE_CHECKING:
from collections.abc import Mapping

Expand All @@ -23,6 +26,24 @@
"visual": "model",
}

_UNSUPPORTED_SYMBOL = "UNSUPPORTED"
_SYMBOL_MAP: Mapping[str, str] = {
# These symbols go under a different name
"disc": "circle",
"cross": "plus",
"x": "cross",
# These symbols are not currently supported in pygfx
# could be added with custom SDF marker textures
"arrow": _UNSUPPORTED_SYMBOL,
"clobber": _UNSUPPORTED_SYMBOL,
# NOTE: vbar is kind of like pygfx's "tick", but tick just has an edge color.
"vbar": _UNSUPPORTED_SYMBOL,
"hbar": _UNSUPPORTED_SYMBOL,
"tailed_arrow": _UNSUPPORTED_SYMBOL,
"star": _UNSUPPORTED_SYMBOL,
"cross_lines": _UNSUPPORTED_SYMBOL,
}


class Points(Node, PointsAdaptor):
"""Vispy backend adaptor for an Points node."""
Expand Down Expand Up @@ -97,7 +118,13 @@ def _snx_set_edge_color(self, arg: ColorModel) -> None:
def _snx_set_edge_width(self, edge_width: float) -> None:
self._material.edge_width = edge_width

def _snx_set_symbol(self, symbol: str) -> None: ...
def _snx_set_symbol(self, symbol: str) -> None:
py_symbol = _SYMBOL_MAP.get(symbol, symbol)
if py_symbol == _UNSUPPORTED_SYMBOL:
logger.warning("Unsupported symbol: %r", symbol)
return

self._material.marker = py_symbol

def _snx_set_scaling(self, scaling: model.ScalingMode) -> None:
self._material.size_space = SPACE_MAP[scaling]
Expand Down
25 changes: 25 additions & 0 deletions tests/adaptors/_pygfx/test_points.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import annotations

from typing import get_args

import cmap
import numpy as np
import pygfx
Expand All @@ -8,6 +10,8 @@
import scenex as snx
import scenex.adaptors._pygfx as adaptors
from scenex.adaptors._auto import get_adaptor_registry
from scenex.adaptors._pygfx._points import _SYMBOL_MAP, _UNSUPPORTED_SYMBOL
from scenex.model import SymbolName


@pytest.fixture
Expand Down Expand Up @@ -48,6 +52,27 @@ def test_points_data(points: snx.Points, adaptor: adaptors.Points) -> None:
assert np.array_equal(geom.positions.data, new_vertices)


@pytest.mark.parametrize("symbol", get_args(SymbolName))
def test_points_symbol(
points: snx.Points,
adaptor: adaptors.Points,
caplog: pytest.LogCaptureFixture,
symbol: SymbolName,
) -> None:
mat = adaptor._pygfx_node.material
assert isinstance(mat, pygfx.PointsMarkerMaterial)
assert mat.marker_mode == "uniform"
py_symbol = _SYMBOL_MAP.get(symbol, symbol)
if py_symbol == _UNSUPPORTED_SYMBOL:
with caplog.at_level("WARNING", logger="scenex.adaptors.pygfx"):
points.symbol = symbol
assert any(symbol in m for m in caplog.messages)
return

points.symbol = symbol
assert mat.marker == py_symbol


def test_points_size(points: snx.Points, adaptor: adaptors.Points) -> None:
node = adaptor._pygfx_node
mat = node.material
Expand Down
Loading