Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 92c562d

Browse filesBrowse files
committed
slicing working with PointsDataFeature, negative slices too, still major WIP
1 parent 45f7dc3 commit 92c562d
Copy full SHA for 92c562d

File tree

5 files changed

+401
-386
lines changed
Filter options

5 files changed

+401
-386
lines changed
+52-25Lines changed: 52 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,60 @@
1-
from ._colors import ColorFeature, CmapFeature, ImageCmapFeature, HeatmapCmapFeature
2-
from ._data import PointsDataFeature, ImageDataFeature, HeatmapDataFeature
3-
from ._sizes import PointsSizesFeature
4-
from ._present import PresentFeature
5-
from ._thickness import ThicknessFeature
1+
from ._colors import ColorFeature#, CmapFeature, ImageCmapFeature, HeatmapCmapFeature
2+
from ._data import PointsDataFeature#, ImageDataFeature, HeatmapDataFeature
3+
# from ._sizes import PointsSizesFeature
4+
# from ._present import PresentFeature
5+
# from ._thickness import ThicknessFeature
66
from ._base import (
77
GraphicFeature,
8-
GraphicFeatureIndexable,
8+
BufferManager,
9+
GraphicFeatureDescriptor,
910
FeatureEvent,
1011
to_gpu_supported_dtype,
1112
)
1213
from ._selection_features import LinearSelectionFeature, LinearRegionSelectionFeature
1314
from ._deleted import Deleted
15+
#
16+
# __all__ = [
17+
# "ColorFeature",
18+
# "CmapFeature",
19+
# "ImageCmapFeature",
20+
# "HeatmapCmapFeature",
21+
# "PointsDataFeature",
22+
# "PointsSizesFeature",
23+
# "ImageDataFeature",
24+
# "HeatmapDataFeature",
25+
# "PresentFeature",
26+
# "ThicknessFeature",
27+
# "GraphicFeature",
28+
# "FeatureEvent",
29+
# "to_gpu_supported_dtype",
30+
# "LinearSelectionFeature",
31+
# "LinearRegionSelectionFeature",
32+
# "Deleted",
33+
# ]
1434

15-
__all__ = [
16-
"ColorFeature",
17-
"CmapFeature",
18-
"ImageCmapFeature",
19-
"HeatmapCmapFeature",
20-
"PointsDataFeature",
21-
"PointsSizesFeature",
22-
"ImageDataFeature",
23-
"HeatmapDataFeature",
24-
"PresentFeature",
25-
"ThicknessFeature",
26-
"GraphicFeature",
27-
"GraphicFeatureIndexable",
28-
"FeatureEvent",
29-
"to_gpu_supported_dtype",
30-
"LinearSelectionFeature",
31-
"LinearRegionSelectionFeature",
32-
"Deleted",
33-
]
35+
class PresentFeature:
36+
pass
37+
38+
class Deleted:
39+
pass
40+
41+
class CmapFeature:
42+
pass
43+
44+
class PointsSizesFeature:
45+
pass
46+
47+
class ThicknessFeature:
48+
pass
49+
50+
class ImageCmapFeature:
51+
pass
52+
53+
class ImageDataFeature:
54+
pass
55+
56+
class HeatmapDataFeature:
57+
pass
58+
59+
class HeatmapCmapFeature:
60+
pass

‎fastplotlib/graphics/_features/_base.py

Copy file name to clipboardExpand all lines: fastplotlib/graphics/_features/_base.py
+30-38Lines changed: 30 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def __init__(
186186
super().__init__()
187187
if isolated_buffer:
188188
# useful if data is read-only, example: memmaps
189-
bdata = np.zeros(data.shape)
189+
bdata = np.zeros(data.shape, dtype=data.dtype)
190190
bdata[:] = data[:]
191191
else:
192192
# user's input array is used as the buffer
@@ -209,7 +209,7 @@ def value(self) -> NDArray:
209209
def buffer(self) -> pygfx.Buffer | pygfx.Texture:
210210
return self._buffer
211211

212-
def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ...]) -> int | np.ndarray | range:
212+
def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ...]) -> int | np.ndarray | range | tuple[range, ...]:
213213
"""
214214
Cleanup slice indices for setitem, returns positive indices. Converts negative indices to positive if necessary.
215215
@@ -220,7 +220,7 @@ def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ..
220220
if isinstance(key, int):
221221
if abs(key) > upper_bound: # absolute value in case negative index
222222
raise IndexError(f"key value: {key} out of range for dimension with size: {upper_bound}")
223-
return [key]
223+
return key
224224

225225
elif isinstance(key, np.ndarray):
226226
if key.ndim > 1:
@@ -246,16 +246,22 @@ def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ..
246246
raise TypeError(f"Can only use 1D boolean or integer arrays for fancy indexing graphic features")
247247

248248
elif isinstance(key, tuple):
249-
if isinstance(key[0], slice):
250-
key = key[0]
251-
else:
252-
raise TypeError
249+
# multiple dimension slicing
250+
if not all([isinstance(k, (int, slice, range, np.ndarray)) for k in key]):
251+
raise TypeError(key)
252+
253+
cleaned_tuple = list()
254+
# cleanup the key for each dim
255+
for k in key:
256+
cleaned_tuple.append(self.cleanup_key(k))
257+
258+
return key
253259

254260
if not isinstance(key, (slice, range)):
255261
raise TypeError("Must pass slice or int object")
256262

257263
start = key.start if key.start is not None else 0
258-
stop = key.stop if key.stop is not None else self.value.shape[0]
264+
stop = key.stop if key.stop is not None else self.value.shape[0] - 1
259265
# absolute value of the step in case it's negative
260266
# since we convert start and stop to be positive below it is fine for step to be converted to positive
261267
step = abs(key.step) if key.step is not None else 1
@@ -265,7 +271,7 @@ def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ..
265271
stop %= upper_bound
266272

267273
if start > stop:
268-
raise ValueError("start index greater than stop index")
274+
raise ValueError(f"start index: {start} greater than stop index: {stop}")
269275

270276
return range(start, stop, step)
271277

@@ -288,8 +294,21 @@ def _update_range(self, key):
288294
elif isinstance(key, int):
289295
offset = key
290296
size = 1
297+
elif isinstance(key, tuple):
298+
key: range | slice = key[0]
299+
upper_bound = self.value.shape[0]
300+
301+
offset = key.start if key.start is not None else 0
302+
# size is number of points so do not subtract 1 from upper bound like in cleanup_key for indexing
303+
stop = key.stop if key.stop is not None else upper_bound
304+
305+
offset %= upper_bound
306+
stop %= upper_bound + 1
307+
308+
size = stop - offset
309+
291310
else:
292-
raise TypeError
311+
raise TypeError(key)
293312

294313
self.buffer.update_range(offset=offset, size=size)
295314

@@ -298,7 +317,7 @@ def __repr__(self):
298317
f"{self.value.__repr__()}"
299318

300319

301-
class GraphicProperty:
320+
class GraphicFeatureDescriptor:
302321
def __init__(self, name):
303322
self.name = name
304323

@@ -312,30 +331,3 @@ def __get__(self, instance, owner):
312331
def __set__(self, obj, value):
313332
feature = self._get_feature(obj)
314333
feature[:] = value
315-
316-
317-
318-
class ColorFeature(BufferManager):
319-
"""Manage color buffer for positions type objects"""
320-
321-
def __init__(self, data: str | np.ndarray, n_colors: int, isolated_buffer: bool):
322-
if not isinstance(data, np.ndarray):
323-
# isolated buffer is only useful when data is a numpy array
324-
isolated_buffer = False
325-
326-
colors = parse_colors(data, n_colors)
327-
328-
super().__init__(colors, isolated_buffer)
329-
330-
def __setitem__(self, key, value):
331-
if isinstance(value, BufferManager):
332-
# trying to set feature from another feature instance
333-
value = value.value
334-
335-
key = self.cleanup_slice(key)
336-
337-
colors = parse_colors(value, len(key))
338-
339-
self.buffer.data[key] = colors
340-
341-
self._update_range(key.start, key.stop - key.start)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.