figpack-spike-sorting 0.1.6__py3-none-any.whl → 0.1.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,159 @@
1
+ """
2
+ TiledImage view for figpack - displays large images using tiled rendering with deck.gl
3
+ """
4
+
5
+ from io import BytesIO
6
+ from tempfile import TemporaryDirectory
7
+ from typing import Any, List, Union
8
+
9
+ import numpy as np
10
+
11
+ import figpack
12
+ from ..spike_sorting_extension import spike_sorting_extension
13
+
14
+ pyvips_installation_msg = "To use TiledImage you need to install pyvips (conda install -c conda-forge pyvips recommended)"
15
+
16
+
17
+ class TiledImageLayer:
18
+ def __init__(self, label: str, data: Union[np.ndarray, Any]) -> None:
19
+ """
20
+ Initialize a TiledImageLayer
21
+
22
+ Args:
23
+ label: Label for the layer
24
+ data: Image data as numpy array (uint8, shape (height, width, 3) for RGB)
25
+ or pyvips.Image object
26
+ """
27
+ try:
28
+ import pyvips
29
+ except ImportError:
30
+ raise ImportError(pyvips_installation_msg)
31
+
32
+ self.label = label
33
+ self.data = data
34
+
35
+ if isinstance(data, pyvips.Image):
36
+ image: pyvips.Image = data
37
+ else:
38
+ if not isinstance(data, np.ndarray):
39
+ raise TypeError("Data must be a numpy array or pyvips.Image")
40
+ if data.dtype != np.uint8:
41
+ raise ValueError("Data must be of type uint8")
42
+ # Convert numpy array to pyvips image
43
+ image: pyvips.Image = pyvips.Image.new_from_array(data)
44
+
45
+ self.image = image
46
+
47
+
48
+ class TiledImage(figpack.ExtensionView):
49
+ """
50
+ A view that displays large images using tiled rendering for efficient viewing
51
+ """
52
+
53
+ def __init__(
54
+ self, *, tile_size: int, layers: List[TiledImageLayer], verbose: bool = False
55
+ ):
56
+ """
57
+ Initialize a TiledImage view
58
+
59
+ Args:
60
+ tile_size: Size of each tile in pixels (e.g., 256)
61
+ layers: List of TiledImageLayer objects
62
+ verbose: Whether to print verbose output during tile generation
63
+ """
64
+ super().__init__(
65
+ extension=spike_sorting_extension, view_type="spike_sorting.TiledImage"
66
+ )
67
+ self.tile_size = tile_size
68
+ self.layers = layers
69
+ self.verbose = verbose
70
+
71
+ def write_to_zarr_group(self, group: figpack.Group) -> None:
72
+ """
73
+ Write the TiledImage data to a Zarr group
74
+
75
+ Args:
76
+ group: Zarr group to write data into
77
+ """
78
+ import os
79
+ import pyvips
80
+
81
+ super().write_to_zarr_group(group)
82
+
83
+ group.attrs["tile_size"] = self.tile_size
84
+ group.attrs["num_layers"] = len(self.layers)
85
+
86
+ for layer_idx, layer in enumerate(self.layers):
87
+ if self.verbose:
88
+ print(
89
+ f"Processing layer {layer_idx + 1}/{len(self.layers)}: {layer.label}"
90
+ )
91
+
92
+ layer_group = group.create_group(f"layer_{layer_idx}")
93
+ layer_group.attrs["label"] = layer.label
94
+
95
+ image: pyvips.Image = layer.image
96
+ layer_group.attrs["width"] = image.width
97
+ layer_group.attrs["height"] = image.height
98
+
99
+ # Generate tiled JPEG images using pyvips dzsave
100
+ with TemporaryDirectory() as tmpdir:
101
+ # Generate the tile pyramid
102
+ image.dzsave(
103
+ f"{tmpdir}/output",
104
+ overlap=0,
105
+ tile_size=self.tile_size,
106
+ layout=pyvips.enums.ForeignDzLayout.DZ,
107
+ )
108
+
109
+ output_dirname = f"{tmpdir}/output_files"
110
+
111
+ # Count zoom levels
112
+ num_zoom_levels = 0
113
+ z = 1
114
+ while True:
115
+ dirname = f"{output_dirname}/{z}"
116
+ if not os.path.exists(dirname):
117
+ break
118
+ num_zoom_levels = z
119
+ z += 1
120
+
121
+ layer_group.attrs["num_zoom_levels"] = num_zoom_levels
122
+
123
+ # Store each tile as a zarr dataset containing JPEG bytes
124
+ tiles_group = layer_group.create_group("tiles")
125
+
126
+ for z in range(1, num_zoom_levels + 1):
127
+ dirname = f"{output_dirname}/{z}"
128
+ j = 0
129
+ while True:
130
+ if not os.path.exists(f"{dirname}/{j}_0.jpeg"):
131
+ break
132
+ k = 0
133
+ while True:
134
+ tile_path = f"{dirname}/{j}_{k}.jpeg"
135
+ if not os.path.exists(tile_path):
136
+ break
137
+
138
+ # Read the JPEG file as bytes
139
+ with open(tile_path, "rb") as f:
140
+ jpeg_bytes = f.read()
141
+
142
+ # Store as uint8 array in zarr
143
+ tile_key = f"{z}_{j}_{k}"
144
+ jpeg_array = np.frombuffer(jpeg_bytes, dtype=np.uint8)
145
+ tiles_group.create_dataset(tile_key, data=jpeg_array)
146
+
147
+ if self.verbose:
148
+ print(
149
+ f" Stored tile {tile_key}: {len(jpeg_bytes)} bytes"
150
+ )
151
+
152
+ k += 1
153
+ j += 1
154
+
155
+ if self.verbose:
156
+ print(
157
+ f" Layer {layer.label}: {image.width}x{image.height}, "
158
+ f"{num_zoom_levels} zoom levels"
159
+ )
@@ -20,6 +20,7 @@ from .UnitMetricsGraph import (
20
20
  UnitMetricsGraphUnit,
21
21
  )
22
22
  from .SortingCuration import SortingCuration
23
+ from .TiledImage import TiledImage, TiledImageLayer
23
24
 
24
25
  __all__ = [
25
26
  "Autocorrelograms",
@@ -42,4 +43,6 @@ __all__ = [
42
43
  "UnitMetricsGraphMetric",
43
44
  "UnitMetricsGraphUnit",
44
45
  "SortingCuration",
46
+ "TiledImage",
47
+ "TiledImageLayer",
45
48
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: figpack_spike_sorting
3
- Version: 0.1.6
3
+ Version: 0.1.8
4
4
  Summary: Spike Sorting specific extension for figpack
5
5
  Home-page: https://github.com/flatironinstitute/figpack
6
6
  Author: figpack contributors
@@ -1,5 +1,5 @@
1
- figpack_spike_sorting/__init__.py,sha256=XWtb7794TixjHJDii3OeYOdM-GYVLsR0BEfiUMEP_vQ,100
2
- figpack_spike_sorting/figpack_spike_sorting.js,sha256=qxu-lFeqfIkWaRrZ9OX_MMjSrZ8zbD4Nz94kCoPmaRU,663123
1
+ figpack_spike_sorting/__init__.py,sha256=X3iWqqx6ep-Gznn4FbdnV5eUsflN-q7z-JiF4IalB3M,100
2
+ figpack_spike_sorting/figpack_spike_sorting.js,sha256=D3FB0vIMOM3WN-P5VUIZZIVI4iBMp7NjXpwSis5gMkw,1509907
3
3
  figpack_spike_sorting/spike_sorting_extension.py,sha256=ugpk8hDsO4RmyQRNjfhB4Pw5p10FmhQeu3koBynSPHU,755
4
4
  figpack_spike_sorting/style.css,sha256=R4pcnrpSMpOsBn7X1t-JBP8ODktsc5e8o95Fl_0LVps,3208
5
5
  figpack_spike_sorting/views/AutocorrelogramItem.py,sha256=qHmvIdHpbfVA_utPb5N2oP3hSP2cGnlT8VLaxOXV4UM,738
@@ -12,14 +12,15 @@ figpack_spike_sorting/views/RasterPlotItem.py,sha256=iW7fuDEjSfvf5YMIwrF_6cmKvD7
12
12
  figpack_spike_sorting/views/SortingCuration.py,sha256=J3p9vrhbnRt05qeihZk_i6EBWDcTGYs293WVW_9qLSk,1243
13
13
  figpack_spike_sorting/views/SpikeAmplitudes.py,sha256=H_VV0Z1kAVCztNaTYnOW8tqyu6FLtgFPWNrlmokVKeI,13290
14
14
  figpack_spike_sorting/views/SpikeAmplitudesItem.py,sha256=j5Na-diY-vRUAPu0t0VkyFCSKFnQ_f5HT077mB3Cy8c,1134
15
+ figpack_spike_sorting/views/TiledImage.py,sha256=_nvFhvRoGWd7MN84d9CphB0bK4j0txlx035zm-hCDic,5457
15
16
  figpack_spike_sorting/views/UnitLocations.py,sha256=K18oJFnKshn0fZ9NtgKXcWGroJGc_OaF3f_ZEEInZPA,2336
16
17
  figpack_spike_sorting/views/UnitMetricsGraph.py,sha256=8YZo2-5d-RHKSfyUKYAfDvW9hZDCTzmnUAyb3fPWo3I,3373
17
18
  figpack_spike_sorting/views/UnitSimilarityScore.py,sha256=cJA9MkETos9qHhV1tqgA7SfNEaPo-duXYCE76hSFGnA,948
18
19
  figpack_spike_sorting/views/UnitsTable.py,sha256=8aluJ2tCnwsFOLbjbJDyY2z1ml9VK7Sz5_bxdRUAeDI,2758
19
20
  figpack_spike_sorting/views/UnitsTableColumn.py,sha256=zBnuoeILTuiVLDvtcOxqa37E5WlbR12rlwNJUeWXxY4,847
20
21
  figpack_spike_sorting/views/UnitsTableRow.py,sha256=rEb2hMTA_pl2fTW1nOvnGir0ysfNx4uww3aekZzfWjk,720
21
- figpack_spike_sorting/views/__init__.py,sha256=m7XRK-rCsqXXbNtilncHsUzDK09j3gWeTqfYWUs9_jM,1316
22
- figpack_spike_sorting-0.1.6.dist-info/METADATA,sha256=AFNFDdpxitRyp26XLKnKAh5E4Cyd0nq-ZV8J_a2m6rE,1218
23
- figpack_spike_sorting-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
24
- figpack_spike_sorting-0.1.6.dist-info/top_level.txt,sha256=CAkWrQc1wGK5laYDkT2GBjGgAuNwWNXKodTQlTcpxus,22
25
- figpack_spike_sorting-0.1.6.dist-info/RECORD,,
22
+ figpack_spike_sorting/views/__init__.py,sha256=gUt261Id35gNiJyne6GY-NzIGyTfRDmL25tNjyC2dLY,1409
23
+ figpack_spike_sorting-0.1.8.dist-info/METADATA,sha256=48QIQNnjJ4_RpsX7uhn7fvtKN8kpJepvtM4Lxj1U78U,1218
24
+ figpack_spike_sorting-0.1.8.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
25
+ figpack_spike_sorting-0.1.8.dist-info/top_level.txt,sha256=CAkWrQc1wGK5laYDkT2GBjGgAuNwWNXKodTQlTcpxus,22
26
+ figpack_spike_sorting-0.1.8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5