Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 962c9ba

Browse files
add size_space to pygfx.PointsMaterial scatter kwargs (#689)
* add size_space to pygfx.PointsMaterial kwargs * add CoordSpace graphic feature * store _coord_space graphic feature * add coordspace to features init * make size_space a property of PositionsGraphic * rename CoordSpace->SizeSpace for consistency / avoid confusion with pygfx.CoordSpace * fix size_space feature, FeatureEvent type=size_space?? * add getters/setters to scatter/line graphics * add size_space to _features cls dict * move size_space properties to base PositionGraphics class, add link to CoordSpace in docstring * fix comment for SizeSpace scatter/line * return .value, set_value() * don't coerce str, check if "Line" in class name * add test for size_space * add tests for setting properties * double quotes for the linting overlords * regen api docs * double quotes on "size_space" * black formatting spaces / trailing commas
1 parent f204f55 commit 962c9ba

File tree

10 files changed

+140
-5
lines changed

10 files changed

+140
-5
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.. _api.SizeSpace:
2+
3+
SizeSpace
4+
*********
5+
6+
=========
7+
SizeSpace
8+
=========
9+
.. currentmodule:: fastplotlib.graphics._features
10+
11+
Constructor
12+
~~~~~~~~~~~
13+
.. autosummary::
14+
:toctree: SizeSpace_api
15+
16+
SizeSpace
17+
18+
Properties
19+
~~~~~~~~~~
20+
.. autosummary::
21+
:toctree: SizeSpace_api
22+
23+
SizeSpace.value
24+
25+
Methods
26+
~~~~~~~
27+
.. autosummary::
28+
:toctree: SizeSpace_api
29+
30+
SizeSpace.add_event_handler
31+
SizeSpace.block_events
32+
SizeSpace.clear_event_handlers
33+
SizeSpace.remove_event_handler
34+
SizeSpace.set_value
35+

docs/source/api/graphic_features/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Graphic Features
77
VertexColors
88
UniformColor
99
UniformSize
10+
SizeSpace
1011
Thickness
1112
VertexPositions
1213
PointsSizesFeature

docs/source/api/graphics/LineGraphic.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Properties
3131
LineGraphic.offset
3232
LineGraphic.right_click_menu
3333
LineGraphic.rotation
34+
LineGraphic.size_space
3435
LineGraphic.supported_events
3536
LineGraphic.thickness
3637
LineGraphic.visible

docs/source/api/graphics/ScatterGraphic.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Properties
3131
ScatterGraphic.offset
3232
ScatterGraphic.right_click_menu
3333
ScatterGraphic.rotation
34+
ScatterGraphic.size_space
3435
ScatterGraphic.sizes
3536
ScatterGraphic.supported_events
3637
ScatterGraphic.visible

fastplotlib/graphics/_features/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
VertexColors,
33
UniformColor,
44
UniformSize,
5+
SizeSpace,
56
Thickness,
67
VertexPositions,
78
PointsSizesFeature,
@@ -42,6 +43,7 @@
4243
"VertexColors",
4344
"UniformColor",
4445
"UniformSize",
46+
"SizeSpace",
4547
"Thickness",
4648
"VertexPositions",
4749
"PointsSizesFeature",

fastplotlib/graphics/_features/_positions_graphics.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,27 @@ def set_value(self, graphic, value: float | int):
182182
self._call_event_handlers(event)
183183

184184

185+
# manages the coordinate space for scatter/line
186+
class SizeSpace(GraphicFeature):
187+
def __init__(self, value: str):
188+
self._value = value
189+
super().__init__()
190+
191+
@property
192+
def value(self) -> str:
193+
return self._value
194+
195+
def set_value(self, graphic, value: str):
196+
if "Line" in graphic.world_object.material.__class__.__name__:
197+
graphic.world_object.material.thickness_space = value
198+
else:
199+
graphic.world_object.material.size_space = value
200+
self._value = value
201+
202+
event = FeatureEvent(type="size_space", info={"value": value})
203+
self._call_event_handlers(event)
204+
205+
185206
class VertexPositions(BufferManager):
186207
"""
187208
+----------+----------------------------------------------------------+------------------------------------------------------------------------------------------+

fastplotlib/graphics/_positions_base.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
UniformColor,
1111
VertexCmap,
1212
PointsSizesFeature,
13+
SizeSpace,
1314
)
1415

1516

@@ -54,6 +55,19 @@ def cmap(self, name: str):
5455

5556
self._cmap[:] = name
5657

58+
@property
59+
def size_space(self):
60+
"""
61+
The coordinate space in which the size is expressed (‘screen’, ‘world’, ‘model’)
62+
63+
See https://docs.pygfx.org/stable/_autosummary/utils/utils/enums/pygfx.utils.enums.CoordSpace.html#pygfx.utils.enums.CoordSpace for available options.
64+
"""
65+
return self._size_space.value
66+
67+
@size_space.setter
68+
def size_space(self, value: str):
69+
self._size_space.set_value(self, value)
70+
5771
def __init__(
5872
self,
5973
data: Any,
@@ -63,6 +77,7 @@ def __init__(
6377
cmap: str | VertexCmap = None,
6478
cmap_transform: np.ndarray = None,
6579
isolated_buffer: bool = True,
80+
size_space: str = "screen",
6681
*args,
6782
**kwargs,
6883
):
@@ -132,6 +147,7 @@ def __init__(
132147
self._colors, cmap_name=None, transform=None, alpha=alpha
133148
)
134149

150+
self._size_space = SizeSpace(size_space)
135151
super().__init__(*args, **kwargs)
136152

137153
def unshare_property(self, property: str):

fastplotlib/graphics/line.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66

77
from ._positions_base import PositionsGraphic
88
from .selectors import LinearRegionSelector, LinearSelector, RectangleSelector
9-
from ._features import Thickness
9+
from ._features import Thickness, SizeSpace
1010

1111

1212
class LineGraphic(PositionsGraphic):
13-
_features = {"data", "colors", "cmap", "thickness"}
13+
_features = {"data", "colors", "cmap", "thickness", "size_space"}
1414

1515
def __init__(
1616
self,
@@ -22,6 +22,7 @@ def __init__(
2222
cmap: str = None,
2323
cmap_transform: np.ndarray | Iterable = None,
2424
isolated_buffer: bool = True,
25+
size_space: str = "screen",
2526
**kwargs,
2627
):
2728
"""
@@ -53,6 +54,9 @@ def __init__(
5354
cmap_transform: 1D array-like of numerical values, optional
5455
if provided, these values are used to map the colors from the cmap
5556
57+
size_space: str, default "screen"
58+
coordinate space in which the size is expressed (‘screen’, ‘world’, ‘model’)
59+
5660
**kwargs
5761
passed to Graphic
5862
@@ -66,6 +70,7 @@ def __init__(
6670
cmap=cmap,
6771
cmap_transform=cmap_transform,
6872
isolated_buffer=isolated_buffer,
73+
size_space=size_space,
6974
**kwargs,
7075
)
7176

@@ -83,10 +88,14 @@ def __init__(
8388
color_mode="uniform",
8489
color=self.colors,
8590
pick_write=True,
91+
thickness_space=self.size_space,
8692
)
8793
else:
8894
material = MaterialCls(
89-
thickness=self.thickness, color_mode="vertex", pick_write=True
95+
thickness=self.thickness,
96+
color_mode="vertex",
97+
pick_write=True,
98+
thickness_space=self.size_space,
9099
)
91100
geometry = pygfx.Geometry(
92101
positions=self._data.buffer, colors=self._colors.buffer

fastplotlib/graphics/scatter.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
import pygfx
55

66
from ._positions_base import PositionsGraphic
7-
from ._features import PointsSizesFeature, UniformSize
7+
from ._features import PointsSizesFeature, UniformSize, SizeSpace
88

99

1010
class ScatterGraphic(PositionsGraphic):
11-
_features = {"data", "sizes", "colors", "cmap"}
11+
_features = {"data", "sizes", "colors", "cmap", "size_space"}
1212

1313
def __init__(
1414
self,
@@ -21,6 +21,7 @@ def __init__(
2121
isolated_buffer: bool = True,
2222
sizes: float | np.ndarray | Iterable[float] = 1,
2323
uniform_size: bool = False,
24+
size_space: str = "screen",
2425
**kwargs,
2526
):
2627
"""
@@ -60,6 +61,9 @@ def __init__(
6061
if True, uses a uniform buffer for the scatter point sizes,
6162
basically saves GPU VRAM when all scatter points are the same size
6263
64+
size_space: str, default "screen"
65+
coordinate space in which the size is expressed (‘screen’, ‘world’, ‘model’)
66+
6367
kwargs
6468
passed to Graphic
6569
@@ -73,13 +77,15 @@ def __init__(
7377
cmap=cmap,
7478
cmap_transform=cmap_transform,
7579
isolated_buffer=isolated_buffer,
80+
size_space=size_space,
7681
**kwargs,
7782
)
7883

7984
n_datapoints = self.data.value.shape[0]
8085

8186
geo_kwargs = {"positions": self._data.buffer}
8287
material_kwargs = {"pick_write": True}
88+
self._size_space = SizeSpace(size_space)
8389

8490
if uniform_color:
8591
material_kwargs["color_mode"] = "uniform"
@@ -97,6 +103,7 @@ def __init__(
97103
self._sizes = PointsSizesFeature(sizes, n_datapoints=n_datapoints)
98104
geo_kwargs["sizes"] = self.sizes.buffer
99105

106+
material_kwargs["size_space"] = self.size_space
100107
world_object = pygfx.Points(
101108
pygfx.Geometry(**geo_kwargs),
102109
material=pygfx.PointsMaterial(**material_kwargs),

tests/test_positions_graphics.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,3 +443,45 @@ def test_thickness(thickness):
443443

444444
else:
445445
assert isinstance(graphic.world_object.material, pygfx.LineMaterial)
446+
447+
448+
@pytest.mark.parametrize("graphic_type", ["line", "scatter"])
449+
@pytest.mark.parametrize("size_space", ["screen", "world", "model"])
450+
def test_size_space(graphic_type, size_space):
451+
fig = fpl.Figure()
452+
453+
kwargs = dict()
454+
for kwarg in ["size_space"]:
455+
if locals()[kwarg] is not None:
456+
# add to dict of arguments that will be passed
457+
kwargs[kwarg] = locals()[kwarg]
458+
459+
data = generate_positions_spiral_data("xy")
460+
461+
if size_space is None:
462+
size_space = "screen" # default space
463+
464+
# size_space is really an alias for pygfx.utils.enums.CoordSpace
465+
if graphic_type == "line":
466+
graphic = fig[0, 0].add_line(data=data, **kwargs)
467+
468+
# test getter
469+
assert graphic.world_object.material.thickness_space == size_space
470+
assert graphic.size_space == size_space
471+
472+
# test setter
473+
graphic.size_space = "world"
474+
assert graphic.size_space == "world"
475+
assert graphic.world_object.material.thickness_space == "world"
476+
477+
elif graphic_type == "scatter":
478+
479+
# test getter
480+
graphic = fig[0, 0].add_scatter(data=data, **kwargs)
481+
assert graphic.world_object.material.size_space == size_space
482+
assert graphic.size_space == size_space
483+
484+
# test setter
485+
graphic.size_space = "world"
486+
assert graphic.size_space == "world"
487+
assert graphic.world_object.material.size_space == "world"

0 commit comments

Comments
 (0)