@@ -186,7 +186,7 @@ def __init__(
186
186
super ().__init__ ()
187
187
if isolated_buffer :
188
188
# useful if data is read-only, example: memmaps
189
- bdata = np .zeros (data .shape )
189
+ bdata = np .zeros (data .shape , dtype = data . dtype )
190
190
bdata [:] = data [:]
191
191
else :
192
192
# user's input array is used as the buffer
@@ -209,7 +209,7 @@ def value(self) -> NDArray:
209
209
def buffer (self ) -> pygfx .Buffer | pygfx .Texture :
210
210
return self ._buffer
211
211
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 , ...] :
213
213
"""
214
214
Cleanup slice indices for setitem, returns positive indices. Converts negative indices to positive if necessary.
215
215
@@ -220,7 +220,7 @@ def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ..
220
220
if isinstance (key , int ):
221
221
if abs (key ) > upper_bound : # absolute value in case negative index
222
222
raise IndexError (f"key value: { key } out of range for dimension with size: { upper_bound } " )
223
- return [ key ]
223
+ return key
224
224
225
225
elif isinstance (key , np .ndarray ):
226
226
if key .ndim > 1 :
@@ -246,16 +246,22 @@ def cleanup_key(self, key: int | np.ndarray[int, bool] | slice | tuple[slice, ..
246
246
raise TypeError (f"Can only use 1D boolean or integer arrays for fancy indexing graphic features" )
247
247
248
248
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
253
259
254
260
if not isinstance (key , (slice , range )):
255
261
raise TypeError ("Must pass slice or int object" )
256
262
257
263
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
259
265
# absolute value of the step in case it's negative
260
266
# since we convert start and stop to be positive below it is fine for step to be converted to positive
261
267
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, ..
265
271
stop %= upper_bound
266
272
267
273
if start > stop :
268
- raise ValueError ("start index greater than stop index" )
274
+ raise ValueError (f "start index: { start } greater than stop index: { stop } " )
269
275
270
276
return range (start , stop , step )
271
277
@@ -288,8 +294,21 @@ def _update_range(self, key):
288
294
elif isinstance (key , int ):
289
295
offset = key
290
296
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
+
291
310
else :
292
- raise TypeError
311
+ raise TypeError ( key )
293
312
294
313
self .buffer .update_range (offset = offset , size = size )
295
314
@@ -298,7 +317,7 @@ def __repr__(self):
298
317
f"{ self .value .__repr__ ()} "
299
318
300
319
301
- class GraphicProperty :
320
+ class GraphicFeatureDescriptor :
302
321
def __init__ (self , name ):
303
322
self .name = name
304
323
@@ -312,30 +331,3 @@ def __get__(self, instance, owner):
312
331
def __set__ (self , obj , value ):
313
332
feature = self ._get_feature (obj )
314
333
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