diff --git a/fastplotlib/utils/functions.py b/fastplotlib/utils/functions.py index 97a3df742..9b6c83c6c 100644 --- a/fastplotlib/utils/functions.py +++ b/fastplotlib/utils/functions.py @@ -408,14 +408,9 @@ def parse_cmap_values( def cuda_to_numpy(arr: CudaArrayProtocol) -> np.ndarray: - try: - import cupy - except ImportError: - raise ImportError( - "`cupy` is required to work with GPU arrays\npip install cupy" - ) - - return cupy.asnumpy(arr) + + data = np.from_dlpack(arr, device='cpu') + return data def subsample_array( diff --git a/fastplotlib/widgets/nd_widget/_base.py b/fastplotlib/widgets/nd_widget/_base.py index 5ca15889d..ce17baef7 100644 --- a/fastplotlib/widgets/nd_widget/_base.py +++ b/fastplotlib/widgets/nd_widget/_base.py @@ -198,6 +198,13 @@ def spatial_dims(self, sdims: Sequence[str]): self._spatial_dims = tuple(sdims) + @property + def spatial_dims_indices(self) -> tuple[int, ...]: + """ + The ordered spatial dim indices that correspond to the named spatial dims + """ + return tuple(self.spatial_dims.index(d) for d in self.dims if d in self.spatial_dims) + @property def tooltip(self) -> bool: """ @@ -529,12 +536,7 @@ async def get_window_output(self, indices: dict[str, Any]) -> ArrayProtocol: f"windowed_slice.ndim != len(self.spatial_dims): {windowed_slice.ndim} != {len(self.spatial_dims)}" ) - # transpose to spatial dims - spatial_dims_int = tuple( - self.spatial_dims.index(d) for d in self.dims if d in self.spatial_dims - ) - - return windowed_slice.transpose(*spatial_dims_int) + return windowed_slice async def _get_raw_data_slice(self, indices: dict[str, Any]) -> ArrayProtocol: """ diff --git a/fastplotlib/widgets/nd_widget/_nd_image.py b/fastplotlib/widgets/nd_widget/_nd_image.py index 3090e14c7..40dd510f9 100644 --- a/fastplotlib/widgets/nd_widget/_nd_image.py +++ b/fastplotlib/widgets/nd_widget/_nd_image.py @@ -258,7 +258,7 @@ async def get(self, indices: dict[str, Any]) -> ArrayProtocol: if isinstance(window_output, CudaArrayProtocol): window_output = await run_in_thread_pool(self._executor, cuda_to_numpy, window_output) - return window_output + return window_output.transpose(*self.spatial_dims_indices) def _recompute_histogram(self): """ diff --git a/fastplotlib/widgets/nd_widget/_nd_positions/_nd_positions.py b/fastplotlib/widgets/nd_widget/_nd_positions/_nd_positions.py index 2cc768f52..9ca5eee93 100644 --- a/fastplotlib/widgets/nd_widget/_nd_positions/_nd_positions.py +++ b/fastplotlib/widgets/nd_widget/_nd_positions/_nd_positions.py @@ -112,6 +112,7 @@ def __init__( self.cmap_transform_each = cmap_transform_each self.sizes = sizes + def _check_shape_feature( self, prop: str, check_shape: tuple[int, int] ) -> tuple[int, int]: @@ -555,6 +556,8 @@ async def get(self, indices: dict[str, Any]) -> dict[str, ArrayProtocol]: if isinstance(data, CudaArrayProtocol): data = await run_in_thread_pool(self._executor, cuda_to_numpy, data) + data = data.transpose(*self.spatial_dims_indices) + return { "data": data, **other, diff --git a/fastplotlib/widgets/nd_widget/_nd_vectors.py b/fastplotlib/widgets/nd_widget/_nd_vectors.py index 138ddee95..1a4d1b8e5 100644 --- a/fastplotlib/widgets/nd_widget/_nd_vectors.py +++ b/fastplotlib/widgets/nd_widget/_nd_vectors.py @@ -157,7 +157,7 @@ async def get(self, indices: dict[str, Any]) -> ArrayProtocol: Example: get((100, 5)) """ - # this will be squeezed output, with dims in the order of the user set spatial dims + # this will be squeezed output, with dims in the order of self.dims window_output = await self.get_window_output(indices) # apply spatial_func; CUDA arrays run inline, numpy goes through the thread pool @@ -175,7 +175,7 @@ async def get(self, indices: dict[str, Any]) -> ArrayProtocol: if isinstance(window_output, CudaArrayProtocol): window_output = await run_in_thread_pool(self._executor, cuda_to_numpy, window_output) - return window_output + return window_output.transpose(*self.spatial_dims_indices) class NDVectors(NDGraphic): diff --git a/pyproject.toml b/pyproject.toml index 0352cf27c..9c914bd79 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ keywords = [ ] requires-python = ">= 3.10" dependencies = [ - "numpy>=1.23.0", + "numpy>=2.1.0", "pygfx==0.16.0", "wgpu", # Let pygfx constrain the wgpu version "cmap>=0.1.3",