napari-ome-arrow 0.0.2__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,15 @@
1
+ """
2
+ Init for napari_ome_arrow
3
+ """
4
+
5
+ try:
6
+ from ._version import version as __version__
7
+ except ImportError:
8
+ __version__ = "unknown"
9
+
10
+ from ._reader import napari_get_reader
11
+
12
+ __all__ = [
13
+ "__version__",
14
+ "napari_get_reader",
15
+ ]
@@ -0,0 +1,331 @@
1
+ """
2
+ Minimal napari reader for OME-Arrow sources (stack patterns, OME-Zarr, OME-Parquet,
3
+ OME-TIFF) plus a fallback .npy example.
4
+
5
+ Behavior:
6
+ * If NAPARI_OME_ARROW_LAYER_TYPE is set to "image" or "labels",
7
+ that choice is used.
8
+ * Otherwise, in a GUI/Qt context, the user is prompted with a modal
9
+ dialog asking whether to load as image or labels.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import os
15
+ import warnings
16
+ from collections.abc import Sequence
17
+ from pathlib import Path
18
+ from typing import Any, Union
19
+
20
+ import numpy as np
21
+ from ome_arrow.core import OMEArrow
22
+
23
+ PathLike = Union[str, Path]
24
+ LayerData = tuple[np.ndarray, dict[str, Any], str]
25
+
26
+
27
+ def _maybe_set_viewer_3d(arr: np.ndarray) -> None:
28
+ """
29
+ If the array has a Z axis with size > 1, switch the current napari viewer
30
+ to 3D (ndisplay = 3).
31
+
32
+ Assumes OME-Arrow's TCZYX convention or a subset, i.e., Z is always
33
+ the third-from-last axis. No-op if there's no active viewer.
34
+ """
35
+ # Need at least (Z, Y, X)
36
+ if arr.ndim < 3:
37
+ return
38
+
39
+ z_size = arr.shape[-3]
40
+ if z_size <= 1:
41
+ return
42
+
43
+ try:
44
+ import napari
45
+
46
+ viewer = napari.current_viewer()
47
+ except Exception:
48
+ # no viewer / not in GUI context → silently skip
49
+ return
50
+
51
+ if viewer is not None:
52
+ viewer.dims.ndisplay = 3
53
+
54
+
55
+ # --------------------------------------------------------------------- #
56
+ # Mode selection (env var + GUI prompt)
57
+ # --------------------------------------------------------------------- #
58
+
59
+
60
+ def _get_layer_mode(sample_path: str) -> str:
61
+ """
62
+ Decide whether to load as 'image' or 'labels'.
63
+
64
+ Priority:
65
+ 1. NAPARI_OME_ARROW_LAYER_TYPE env var (image/labels)
66
+ 2. If in a Qt GUI context, show a modal dialog asking the user
67
+ 3. Otherwise, default to 'image'
68
+ """
69
+ mode = os.environ.get("NAPARI_OME_ARROW_LAYER_TYPE")
70
+ if mode is not None:
71
+ mode = mode.lower()
72
+ if mode in {"image", "labels"}:
73
+ return mode
74
+ raise RuntimeError(
75
+ f"Invalid NAPARI_OME_ARROW_LAYER_TYPE={mode!r}; expected 'image' or 'labels'."
76
+ )
77
+
78
+ # No env var → try to prompt in GUI context
79
+ try:
80
+ from qtpy import QtWidgets
81
+ except Exception:
82
+ # no Qt, probably headless: default to image
83
+ warnings.warn(
84
+ "NAPARI_OME_ARROW_LAYER_TYPE not set and Qt not available; "
85
+ "defaulting to 'image'.",
86
+ stacklevel=2,
87
+ )
88
+ return "image"
89
+
90
+ app = QtWidgets.QApplication.instance()
91
+ if app is None:
92
+ # Again, likely headless or non-Qt usage
93
+ warnings.warn(
94
+ "NAPARI_OME_ARROW_LAYER_TYPE not set and no QApplication instance; "
95
+ "defaulting to 'image'.",
96
+ stacklevel=2,
97
+ )
98
+ return "image"
99
+
100
+ # Build a simple modal choice dialog
101
+ msg = QtWidgets.QMessageBox()
102
+ msg.setWindowTitle("napari-ome-arrow: choose layer type")
103
+ msg.setText(
104
+ f"<p align='left'>How should '{Path(sample_path).name}' be loaded?<br><br>"
105
+ "You can also set NAPARI_OME_ARROW_LAYER_TYPE=image or labels to skip this prompt.</p>"
106
+ )
107
+
108
+ # Use ActionRole for ALL buttons so Qt does NOT reorder them
109
+ image_button = msg.addButton("Image", QtWidgets.QMessageBox.ActionRole)
110
+ labels_button = msg.addButton("Labels", QtWidgets.QMessageBox.ActionRole)
111
+ cancel_button = msg.addButton("Cancel", QtWidgets.QMessageBox.ActionRole)
112
+
113
+ # If you want Esc to behave as Cancel:
114
+ msg.setEscapeButton(cancel_button)
115
+
116
+ msg.exec_()
117
+ clicked = msg.clickedButton()
118
+
119
+ if clicked is labels_button:
120
+ return "labels"
121
+ if clicked is image_button:
122
+ return "image"
123
+
124
+ raise RuntimeError("User cancelled napari-ome-arrow load dialog.")
125
+
126
+
127
+ # --------------------------------------------------------------------- #
128
+ # Helper utilities
129
+ # --------------------------------------------------------------------- #
130
+
131
+
132
+ def _as_labels(arr: np.ndarray) -> np.ndarray:
133
+ """Convert any array into an integer label array."""
134
+ if arr.dtype.kind == "f":
135
+ arr = np.nan_to_num(arr, nan=0.0, posinf=0.0, neginf=0.0)
136
+ arr = np.round(arr).astype(np.int32, copy=False)
137
+ elif arr.dtype.kind not in ("i", "u"):
138
+ arr = arr.astype(np.int32, copy=False)
139
+ return arr
140
+
141
+
142
+ def _looks_like_ome_source(path_str: str) -> bool:
143
+ """Basic extension / pattern sniffing for OME-Arrow supported formats."""
144
+ s = path_str.strip().lower()
145
+ p = Path(path_str)
146
+
147
+ looks_stack = any(c in path_str for c in "<>*")
148
+ looks_zarr = (
149
+ s.endswith((".ome.zarr", ".zarr"))
150
+ or ".zarr/" in s
151
+ or p.exists()
152
+ and p.is_dir()
153
+ and p.suffix.lower() == ".zarr"
154
+ )
155
+ looks_parquet = s.endswith(
156
+ (".ome.parquet", ".parquet", ".pq")
157
+ ) or p.suffix.lower() in {
158
+ ".parquet",
159
+ ".pq",
160
+ }
161
+ looks_tiff = s.endswith(
162
+ (".ome.tif", ".ome.tiff", ".tif", ".tiff")
163
+ ) or p.suffix.lower() in {
164
+ ".tif",
165
+ ".tiff",
166
+ }
167
+ looks_npy = s.endswith(".npy")
168
+ return (
169
+ looks_stack or looks_zarr or looks_parquet or looks_tiff or looks_npy
170
+ )
171
+
172
+
173
+ # --------------------------------------------------------------------- #
174
+ # napari entry point: napari_get_reader
175
+ # --------------------------------------------------------------------- #
176
+
177
+
178
+ def napari_get_reader(path: Union[PathLike, Sequence[PathLike]]):
179
+ """
180
+ Napari plugin hook: return a reader callable if this plugin can read `path`.
181
+
182
+ This MUST return a function object (e.g. `reader_function`) or None.
183
+ """
184
+ # napari may pass a list/tuple or a single path
185
+ first = str(path[0] if isinstance(path, (list, tuple)) else path).strip()
186
+
187
+ if _looks_like_ome_source(first):
188
+ return reader_function
189
+ return None
190
+
191
+
192
+ # --------------------------------------------------------------------- #
193
+ # Reader implementation: reader_function
194
+ # --------------------------------------------------------------------- #
195
+
196
+
197
+ def _read_one(src: str, mode: str) -> LayerData:
198
+ """
199
+ Read a single source into (data, add_kwargs, layer_type),
200
+ obeying `mode` = 'image' or 'labels'.
201
+ """
202
+ s = src.lower()
203
+ p = Path(src)
204
+
205
+ looks_stack = any(c in src for c in "<>*")
206
+ looks_zarr = (
207
+ s.endswith((".ome.zarr", ".zarr"))
208
+ or ".zarr/" in s
209
+ or p.exists()
210
+ and p.is_dir()
211
+ and p.suffix.lower() == ".zarr"
212
+ )
213
+ looks_parquet = s.endswith(
214
+ (".ome.parquet", ".parquet", ".pq")
215
+ ) or p.suffix.lower() in {
216
+ ".parquet",
217
+ ".pq",
218
+ }
219
+ looks_tiff = s.endswith(
220
+ (".ome.tif", ".ome.tiff", ".tif", ".tiff")
221
+ ) or p.suffix.lower() in {
222
+ ".tif",
223
+ ".tiff",
224
+ }
225
+ looks_npy = s.endswith(".npy")
226
+
227
+ add_kwargs: dict[str, Any] = {"name": p.name}
228
+
229
+ # ---- OME-Arrow-backed sources -----------------------------------
230
+ if looks_stack or looks_zarr or looks_parquet or looks_tiff:
231
+ obj = OMEArrow(src)
232
+ arr = obj.export(how="numpy", dtype=np.uint16) # TCZYX
233
+ info = obj.info() # may contain 'shape': (T, C, Z, Y, X)
234
+
235
+ # Recover from accidental 1D flatten
236
+ if getattr(arr, "ndim", 0) == 1:
237
+ T, C, Z, Y, X = info.get("shape", (1, 1, 1, 0, 0))
238
+ if Y and X and arr.size == Y * X:
239
+ arr = arr.reshape((1, 1, 1, Y, X))
240
+ else:
241
+ raise ValueError(
242
+ f"Flat array with unknown shape for {src}: size={arr.size}"
243
+ )
244
+
245
+ if mode == "image":
246
+ # Image: preserve channels
247
+ if arr.ndim >= 5:
248
+ add_kwargs["channel_axis"] = 1 # TCZYX
249
+ elif arr.ndim == 4:
250
+ add_kwargs["channel_axis"] = 0 # CZYX
251
+ layer_type = "image"
252
+ else:
253
+ # Labels: squash channels, ensure integer dtype
254
+ if arr.ndim == 5: # (T, C, Z, Y, X)
255
+ arr = arr[:, 0, ...]
256
+ elif arr.ndim == 4: # (C, Z, Y, X)
257
+ arr = arr[0, ...]
258
+ arr = _as_labels(arr)
259
+ add_kwargs.setdefault("opacity", 0.7)
260
+ layer_type = "labels"
261
+
262
+ # 🔹 Ask viewer to switch to 3D if there is a real Z-stack
263
+ _maybe_set_viewer_3d(arr)
264
+
265
+ return arr, add_kwargs, layer_type
266
+
267
+ # ---- bare .npy fallback -----------------------------------------
268
+ if looks_npy:
269
+ arr = np.load(src)
270
+ if arr.ndim == 1:
271
+ n = int(np.sqrt(arr.size))
272
+ if n * n == arr.size:
273
+ arr = arr.reshape(n, n)
274
+ else:
275
+ raise ValueError(
276
+ f".npy is 1D and not a square image: {arr.shape}"
277
+ )
278
+
279
+ if mode == "image":
280
+ if arr.ndim == 3 and arr.shape[0] <= 6:
281
+ add_kwargs["channel_axis"] = 0
282
+ layer_type = "image"
283
+ else:
284
+ # labels
285
+ if arr.ndim == 3: # treat as (C, Y, X) → first channel
286
+ arr = arr[0, ...]
287
+ arr = _as_labels(arr)
288
+ add_kwargs.setdefault("opacity", 0.7)
289
+ layer_type = "labels"
290
+
291
+ # 🔹 Same 3D toggle for npy-based data
292
+ _maybe_set_viewer_3d(arr)
293
+
294
+ return arr, add_kwargs, layer_type
295
+
296
+ raise ValueError(f"Unrecognized path for napari-ome-arrow reader: {src}")
297
+
298
+
299
+ def reader_function(
300
+ path: Union[PathLike, Sequence[PathLike]],
301
+ ) -> list[LayerData]:
302
+ """
303
+ The actual reader callable napari will use.
304
+
305
+ It reads one or more paths, prompting the user (or using the env var)
306
+ to decide 'image' vs 'labels', and returns a list of LayerData tuples.
307
+ """
308
+ paths: list[str] = [
309
+ str(p) for p in (path if isinstance(path, (list, tuple)) else [path])
310
+ ]
311
+ layers: list[LayerData] = []
312
+
313
+ # Use the first path as context for the dialog label
314
+ try:
315
+ mode = _get_layer_mode(sample_path=paths[0]) # 'image' or 'labels'
316
+ except RuntimeError as e:
317
+ # If user canceled the dialog, propagate a clean error for napari
318
+ raise ValueError(str(e)) from e
319
+
320
+ for src in paths:
321
+ try:
322
+ layers.append(_read_one(src, mode=mode))
323
+ except Exception as e:
324
+ warnings.warn(
325
+ f"Failed to read '{src}' with napari-ome-arrow: {e}",
326
+ stacklevel=2,
327
+ )
328
+
329
+ if not layers:
330
+ raise ValueError("No readable inputs found for given path(s).")
331
+ return layers
@@ -0,0 +1,34 @@
1
+ # file generated by setuptools-scm
2
+ # don't change, don't track in version control
3
+
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
12
+
13
+ TYPE_CHECKING = False
14
+ if TYPE_CHECKING:
15
+ from typing import Tuple
16
+ from typing import Union
17
+
18
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
20
+ else:
21
+ VERSION_TUPLE = object
22
+ COMMIT_ID = object
23
+
24
+ version: str
25
+ __version__: str
26
+ __version_tuple__: VERSION_TUPLE
27
+ version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
30
+
31
+ __version__ = version = '0.0.2'
32
+ __version_tuple__ = version_tuple = (0, 0, 2)
33
+
34
+ __commit_id__ = commit_id = None
@@ -0,0 +1,23 @@
1
+ name: napari-ome-arrow
2
+ display_name: OME-Arrow
3
+ contributions:
4
+ commands:
5
+ - id: napari-ome-arrow.get_reader
6
+ python_name: napari_ome_arrow._reader:napari_get_reader
7
+ title: Open OME-Arrow data
8
+ readers:
9
+ - command: napari-ome-arrow.get_reader
10
+ filename_patterns:
11
+ # OME-Parquet
12
+ - "*.ome.parquet"
13
+ - "*.parquet"
14
+ - "*.pq"
15
+ # OME-TIFF
16
+ - "*.ome.tif"
17
+ - "*.ome.tiff"
18
+ - "*.tif"
19
+ - "*.tiff"
20
+ # OME-Zarr
21
+ - "*.ome.zarr"
22
+ - "*.zarr"
23
+ accepts_directories: true
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: napari-ome-arrow
3
+ Version: 0.0.2
4
+ Summary: A Napari plugin for OME-Arrow and OME-Parquet bioimage data
5
+ License:
6
+ Copyright (c) 2025, Dave Bunten
7
+ All rights reserved.
8
+
9
+ Redistribution and use in source and binary forms, with or without
10
+ modification, are permitted provided that the following conditions are met:
11
+
12
+ * Redistributions of source code must retain the above copyright notice, this
13
+ list of conditions and the following disclaimer.
14
+
15
+ * Redistributions in binary form must reproduce the above copyright notice,
16
+ this list of conditions and the following disclaimer in the documentation
17
+ and/or other materials provided with the distribution.
18
+
19
+ * Neither the name of copyright holder nor the names of its
20
+ contributors may be used to endorse or promote products derived from
21
+ this software without specific prior written permission.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
+
34
+ Project-URL: Bug Tracker, https://github.com/wayscience/napari-ome-arrow/issues
35
+ Project-URL: Documentation, https://github.com/wayscience/napari-ome-arrow#README.md
36
+ Project-URL: Source Code, https://github.com/wayscience/napari-ome-arrow
37
+ Project-URL: User Support, https://github.com/wayscience/napari-ome-arrow/issues
38
+ Classifier: Framework :: napari
39
+ Classifier: Intended Audience :: Developers
40
+ Classifier: License :: OSI Approved :: BSD License
41
+ Classifier: Operating System :: OS Independent
42
+ Classifier: Programming Language :: Python
43
+ Classifier: Programming Language :: Python :: 3 :: Only
44
+ Classifier: Programming Language :: Python :: 3.11
45
+ Classifier: Programming Language :: Python :: 3.12
46
+ Classifier: Programming Language :: Python :: 3.13
47
+ Classifier: Programming Language :: Python :: 3.14
48
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
49
+ Requires-Python: >=3.11
50
+ Description-Content-Type: text/markdown
51
+ License-File: LICENSE
52
+ Requires-Dist: magicgui
53
+ Requires-Dist: numpy
54
+ Requires-Dist: ome-arrow>=0.0.2
55
+ Requires-Dist: qtpy>=2.4
56
+ Requires-Dist: scikit-image
57
+ Provides-Extra: all
58
+ Requires-Dist: napari; extra == "all"
59
+ Requires-Dist: qtpy>=2.4; extra == "all"
60
+ Provides-Extra: pyqt6
61
+ Requires-Dist: napari[pyqt6]; extra == "pyqt6"
62
+ Requires-Dist: pyqt6>=6.6; extra == "pyqt6"
63
+ Requires-Dist: qtpy>=2.4; extra == "pyqt6"
64
+ Provides-Extra: pyside6
65
+ Requires-Dist: napari[pyside6]; extra == "pyside6"
66
+ Requires-Dist: pyside6>=6.6; extra == "pyside6"
67
+ Requires-Dist: qtpy>=2.4; extra == "pyside6"
68
+ Dynamic: license-file
69
+
70
+ # napari-ome-arrow
71
+
72
+ [![License BSD-3](https://img.shields.io/pypi/l/napari-ome-arrow.svg?color=green)](https://github.com/wayscience/napari-ome-arrow/raw/main/LICENSE)
73
+ [![PyPI](https://img.shields.io/pypi/v/napari-ome-arrow.svg?color=green)](https://pypi.org/project/napari-ome-arrow)
74
+ [![Python Version](https://img.shields.io/pypi/pyversions/napari-ome-arrow.svg?color=green)](https://python.org)
75
+ [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-ome-arrow)](https://napari-hub.org/plugins/napari-ome-arrow)
76
+ [![npe2](https://img.shields.io/badge/plugin-npe2-blue?link=https://napari.org/stable/plugins/index.html)](https://napari.org/stable/plugins/index.html)
77
+
78
+ `napari-ome-arrow` is a minimal plugin for [napari](https://napari.org) that opens image data through the [OME-Arrow](https://github.com/wayscience/ome-arrow) toolkit.
79
+
80
+ It provides a single, explicit pathway for loading OME-style bioimage data:
81
+
82
+ - **OME-TIFF** (`.ome.tif`, `.ome.tiff`, `.tif`, `.tiff`)
83
+ - **OME-Zarr** (`.ome.zarr`, `.zarr` stores and URLs)
84
+ - **OME-Parquet** (`.ome.parquet`, `.parquet`, `.pq`)
85
+ - **Bio-Formats–style stack patterns** (paths containing `<`, `>`, or `*`)
86
+ - A simple **`.npy` fallback** for quick testing / ad-hoc arrays
87
+
88
+ ## Key features
89
+
90
+ - ✅ **Unified reader via OMEArrow**
91
+ All supported formats are loaded through `OME-Arrow`, which normalizes data into a common **TCZYX**-like representation.
92
+
93
+ - ✅ **Explicit image vs labels mode**
94
+ This plugin never guesses whether your data are intensities or segmentation masks. You must tell it:
95
+
96
+ - via the GUI prompt when you drop/open a file in napari, or
97
+ - via an environment variable for scripted/CLI usage.
98
+
99
+ - ✅ **Interactive choice in the GUI**
100
+ When `NAPARI_OME_ARROW_LAYER_TYPE` is not set and you open a supported file, napari shows a small dialog:
101
+
102
+ > *How should `my_data.ome.tif` be loaded?*
103
+ > `[Image] [Labels] [Cancel]`
104
+
105
+ This makes the “image vs labels” choice explicit at load time without relying on file naming conventions.
106
+
107
+ - ✅ **Image mode**
108
+
109
+ - Returns a napari **image layer**
110
+ - Preserves channels and sets `channel_axis` when appropriate
111
+ (e.g. multi-channel OME-TIFF or stack patterns)
112
+ - Works for 2D, 3D (Z-stacks), and higher-dimensional data (T, C, Z, Y, X)
113
+
114
+ - ✅ **Labels mode**
115
+
116
+ - Returns a napari **labels layer**
117
+ - Converts data to an integer dtype (suitable for labels)
118
+ - Applies a reasonable default opacity for overlaying on images
119
+
120
+ - ✅ **Automatic 3D for Z-stacks**
121
+ If the loaded data include a true Z dimension (`Z > 1`, assuming a TCZYX subset), the plugin asks the current viewer to switch to **3D** (`viewer.dims.ndisplay = 3`) so z-stacks open directly in volume mode.
122
+
123
+ - ✅ **Headless / scripted friendly**
124
+ When Qt is not available (e.g., in headless or purely programmatic contexts), the reader:
125
+
126
+ - respects `NAPARI_OME_ARROW_LAYER_TYPE`, and
127
+ - defaults to `"image"` if the variable is not set.
128
+
129
+ ______________________________________________________________________
130
+
131
+ This [napari] plugin was generated with [copier] using the [napari-plugin-template] (None).
132
+
133
+ ## Installation
134
+
135
+ You can install `napari-ome-arrow` via [pip]:
136
+
137
+ ```
138
+ pip install napari-ome-arrow
139
+ ```
140
+
141
+ If napari is not already installed, you can install `napari-ome-arrow` with napari and Qt via:
142
+
143
+ ```
144
+ pip install "napari-ome-arrow[all]"
145
+ ```
146
+
147
+ To install latest development version :
148
+
149
+ ```
150
+ pip install git+https://github.com/wayscience/napari-ome-arrow.git
151
+ ```
152
+
153
+ ## Usage
154
+
155
+ ### From the napari GUI
156
+
157
+ 1. Install the plugin (see above).
158
+ 1. Start napari.
159
+ 1. Drag and drop an OME-TIFF, OME-Zarr, OME-Parquet file, or stack pattern into the viewer.
160
+ 1. When prompted, choose **Image** or **Labels**.
161
+
162
+ The plugin will:
163
+
164
+ - load the data through `OMEArrow`,
165
+ - map channels and axes appropriately, and
166
+ - automatically switch to 3D if there is a Z-stack.
167
+
168
+ ### From the command line
169
+
170
+ You can control the mode via an environment variable:
171
+
172
+ ```bash
173
+ # Load as regular images
174
+ NAPARI_OME_ARROW_LAYER_TYPE=image napari my_data.ome.tif
175
+
176
+ # Load as labels (segmentation)
177
+ NAPARI_OME_ARROW_LAYER_TYPE=labels napari my_labels.ome.parquet
178
+ ```
179
+
180
+ ## Contributing
181
+
182
+ Contributions are very welcome.
183
+ Please reference our [CONTRIBUTING.md](CONTRIBUTING.md) guide.
184
+
185
+ ## License
186
+
187
+ Please see the [LICENSE](LICENSE) file for more information.
188
+
189
+ ## Issues
190
+
191
+ If you encounter any problems, please [file an issue] along with a detailed description.
192
+
193
+ [copier]: https://copier.readthedocs.io/en/stable/
194
+ [file an issue]: https://github.com/wayscience/napari-ome-arrow/issues
195
+ [napari]: https://github.com/napari/napari
196
+ [napari-plugin-template]: https://github.com/napari/napari-plugin-template
197
+ [pip]: https://pypi.org/project/pip/
@@ -0,0 +1,10 @@
1
+ napari_ome_arrow/__init__.py,sha256=hfpJMmD3HYHJH-0lh-esO04Pe57u8YbK4OO_qcx1b8o,236
2
+ napari_ome_arrow/_reader.py,sha256=98vYiA5zK19sLCywWRKXJESmd3DbULIvpDJeiIg7raA,10398
3
+ napari_ome_arrow/_version.py,sha256=huLsL1iGeXWQKZ8bjwDdIWC7JOkj3wnzBh-HFMZl1PY,704
4
+ napari_ome_arrow/napari.yaml,sha256=L64Y_YyvIlkOBgP2b8HciimyE3xmzfo9ASj5o-wu9gI,567
5
+ napari_ome_arrow-0.0.2.dist-info/licenses/LICENSE,sha256=RuLVTR9eFL6OX1phw5Ue8tdGrhgoG9ZErP6QrxrUlaE,1486
6
+ napari_ome_arrow-0.0.2.dist-info/METADATA,sha256=3WRgK92QSCD5CT0k4FcY9bcRtCqm09QZdwZ1A_zWE-E,8087
7
+ napari_ome_arrow-0.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ napari_ome_arrow-0.0.2.dist-info/entry_points.txt,sha256=ZNpIZF-jrixFQlUNA1kR_jCBsBDxvoIrmc_lrQqu8VE,66
9
+ napari_ome_arrow-0.0.2.dist-info/top_level.txt,sha256=IRsRRK6uFbyipfWh77Br3G4_6uvSYp8CL01RjMN6Mzk,17
10
+ napari_ome_arrow-0.0.2.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [napari.manifest]
2
+ napari-ome-arrow = napari_ome_arrow:napari.yaml
@@ -0,0 +1,28 @@
1
+
2
+ Copyright (c) 2025, Dave Bunten
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ * Neither the name of copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ napari_ome_arrow