napari-piscis 0.1.20__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.
Potentially problematic release.
This version of napari-piscis might be problematic. Click here for more details.
- napari_piscis/__init__.py +1 -0
- napari_piscis/_version.py +34 -0
- napari_piscis/_widget.py +261 -0
- napari_piscis/napari.yaml +10 -0
- napari_piscis-0.1.20.dist-info/METADATA +98 -0
- napari_piscis-0.1.20.dist-info/RECORD +10 -0
- napari_piscis-0.1.20.dist-info/WHEEL +5 -0
- napari_piscis-0.1.20.dist-info/entry_points.txt +2 -0
- napari_piscis-0.1.20.dist-info/licenses/LICENSE +21 -0
- napari_piscis-0.1.20.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ._version import __version__
|
|
@@ -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.1.20'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 20)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = None
|
napari_piscis/_widget.py
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from typing import TYPE_CHECKING, Tuple, List, Union, Dict, Any, Optional
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
import napari
|
|
8
|
+
from napari.qt.threading import thread_worker
|
|
9
|
+
from napari.utils.notifications import show_info, show_warning, show_error
|
|
10
|
+
from magicgui import magic_factory
|
|
11
|
+
from loguru import logger
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from skimage.color import rgb2gray
|
|
15
|
+
from piscis import Piscis
|
|
16
|
+
from piscis.utils import pad_and_stack
|
|
17
|
+
DEPENDENCIES_INSTALLED = True
|
|
18
|
+
except ImportError as e:
|
|
19
|
+
DEPENDENCIES_INSTALLED = False
|
|
20
|
+
Piscis = None
|
|
21
|
+
pad_and_stack = None
|
|
22
|
+
rgb2gray = None
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
import napari.layers
|
|
26
|
+
import napari.types
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --- 1. Pure Scientific Logic ---
|
|
30
|
+
|
|
31
|
+
def infer_img_axes(shape: tuple) -> str:
|
|
32
|
+
"""Infers axes (e.g. 'yx', 'zyx') from shape."""
|
|
33
|
+
if len(shape) == 2:
|
|
34
|
+
return 'yx'
|
|
35
|
+
elif len(shape) == 3:
|
|
36
|
+
if shape[-1] in (3, 4):
|
|
37
|
+
return 'yxc'
|
|
38
|
+
min_dim_idx = shape.index(min(shape))
|
|
39
|
+
low_dim_shape = list(shape)
|
|
40
|
+
low_dim_shape.pop(min_dim_idx)
|
|
41
|
+
low_dim_axes = infer_img_axes(tuple(low_dim_shape))
|
|
42
|
+
return low_dim_axes[:min_dim_idx] + 'z' + low_dim_axes[min_dim_idx:]
|
|
43
|
+
else:
|
|
44
|
+
raise ValueError(f"Image shape {shape} is not supported.")
|
|
45
|
+
|
|
46
|
+
def run_inference_logic(
|
|
47
|
+
raw_image: np.ndarray,
|
|
48
|
+
model_name: str,
|
|
49
|
+
threshold: float,
|
|
50
|
+
min_distance: int,
|
|
51
|
+
intermediates: bool
|
|
52
|
+
) -> Dict[str, Any]:
|
|
53
|
+
"""Pure python function to run PISCIS inference."""
|
|
54
|
+
if not DEPENDENCIES_INSTALLED:
|
|
55
|
+
raise ImportError("PISCIS or skimage not installed.")
|
|
56
|
+
|
|
57
|
+
# 1. Analyze Input
|
|
58
|
+
axes = infer_img_axes(raw_image.shape)
|
|
59
|
+
logger.info(f"Input Shape {raw_image.shape}, Inferred axes {axes}")
|
|
60
|
+
|
|
61
|
+
is_3d_stack = 'z' in axes
|
|
62
|
+
|
|
63
|
+
# 2. Initialize Model
|
|
64
|
+
model = Piscis(model_name=model_name)
|
|
65
|
+
|
|
66
|
+
# 3. Preprocess
|
|
67
|
+
images_batch = None
|
|
68
|
+
processed_image_for_display = None
|
|
69
|
+
was_color_converted = False
|
|
70
|
+
|
|
71
|
+
if is_3d_stack:
|
|
72
|
+
if axes == 'zyx':
|
|
73
|
+
images_batch = raw_image
|
|
74
|
+
elif axes == 'yxz':
|
|
75
|
+
images_batch = np.moveaxis(raw_image, -1, 0)
|
|
76
|
+
else:
|
|
77
|
+
raise ValueError(f"Unsupported 3D axis pattern: {axes}")
|
|
78
|
+
else:
|
|
79
|
+
if axes == 'yx':
|
|
80
|
+
images_batch = np.expand_dims(raw_image, axis=0)
|
|
81
|
+
elif axes == 'yxc':
|
|
82
|
+
gray_img = rgb2gray(raw_image)
|
|
83
|
+
images_batch = gray_img
|
|
84
|
+
processed_image_for_display = gray_img
|
|
85
|
+
was_color_converted = True
|
|
86
|
+
else:
|
|
87
|
+
raise ValueError(f"Unsupported 2D axis pattern: {axes}")
|
|
88
|
+
|
|
89
|
+
# 4. Pad and Stack
|
|
90
|
+
images_padded = pad_and_stack(images_batch)
|
|
91
|
+
|
|
92
|
+
# 5. Predict
|
|
93
|
+
logger.info("PISCIS: Predicting...")
|
|
94
|
+
coords_pred, features = model.predict(
|
|
95
|
+
images_padded,
|
|
96
|
+
threshold=threshold,
|
|
97
|
+
intermediates=intermediates,
|
|
98
|
+
min_distance=min_distance,
|
|
99
|
+
stack=is_3d_stack
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
'coords': coords_pred,
|
|
104
|
+
'features': features,
|
|
105
|
+
'is_3d_stack': is_3d_stack,
|
|
106
|
+
'padded_shape': images_padded.shape,
|
|
107
|
+
'processed_image': processed_image_for_display,
|
|
108
|
+
'was_color_converted': was_color_converted
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# --- 2. Worker Thread ---
|
|
113
|
+
|
|
114
|
+
@thread_worker
|
|
115
|
+
def piscis_worker(
|
|
116
|
+
raw_image: np.ndarray,
|
|
117
|
+
model_name: str,
|
|
118
|
+
threshold: float,
|
|
119
|
+
min_distance: int,
|
|
120
|
+
intermediates: bool
|
|
121
|
+
):
|
|
122
|
+
try:
|
|
123
|
+
return run_inference_logic(
|
|
124
|
+
raw_image, model_name, threshold, min_distance, intermediates
|
|
125
|
+
)
|
|
126
|
+
except Exception as e:
|
|
127
|
+
raise e
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
# --- 3. Visualization Helper ---
|
|
131
|
+
|
|
132
|
+
def _display_features(viewer: napari.Viewer, features: Any, is_3d_stack: bool, layer_name: str):
|
|
133
|
+
"""Parses PISCIS feature maps and adds them to the Napari viewer."""
|
|
134
|
+
features_np = np.array(features)
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
if is_3d_stack:
|
|
138
|
+
# Handle 3D Stacks
|
|
139
|
+
if features_np.ndim == 5:
|
|
140
|
+
feats = features_np[0]
|
|
141
|
+
elif features_np.ndim == 4:
|
|
142
|
+
feats = features_np
|
|
143
|
+
else:
|
|
144
|
+
raise ValueError(f"Unexpected 3D shape: {features_np.shape}")
|
|
145
|
+
|
|
146
|
+
if feats.shape[0] >= 2:
|
|
147
|
+
disp_y = features_np[:, 0, :, :]
|
|
148
|
+
disp_x = features_np[:, 1, :, :]
|
|
149
|
+
|
|
150
|
+
viewer.add_image(disp_y, name=f"Disp Y ({layer_name})", visible=False)
|
|
151
|
+
viewer.add_image(disp_x, name=f"Disp X ({layer_name})", visible=False)
|
|
152
|
+
|
|
153
|
+
if feats.shape[0] > 2:
|
|
154
|
+
labels = features_np[:, 2, :, :]
|
|
155
|
+
viewer.add_image(labels, name=f"Labels ({layer_name})", visible=False)
|
|
156
|
+
pooled = features_np[:, 3, :, :]
|
|
157
|
+
viewer.add_image(pooled, name=f"Pooled Labels ({layer_name})", visible=False)
|
|
158
|
+
|
|
159
|
+
else:
|
|
160
|
+
# Handle 2D Images
|
|
161
|
+
if features_np.ndim == 4:
|
|
162
|
+
feats = features_np[0]
|
|
163
|
+
else:
|
|
164
|
+
feats = features_np
|
|
165
|
+
|
|
166
|
+
if feats.shape[0] >= 2:
|
|
167
|
+
|
|
168
|
+
viewer.add_image(feats[0], name=f"Disp Y ({layer_name})", visible=False)
|
|
169
|
+
viewer.add_image(feats[1], name=f"Disp X ({layer_name})", visible=False)
|
|
170
|
+
|
|
171
|
+
if feats.shape[0] > 2:
|
|
172
|
+
viewer.add_image(feats[2], name=f"Labels ({layer_name})", visible=False)
|
|
173
|
+
viewer.add_image(feats[3], name=f"Pooled Labels ({layer_name})", visible=False)
|
|
174
|
+
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.error(f"Error parsing features: {e}")
|
|
177
|
+
show_error(f"Error displaying features: {e}")
|
|
178
|
+
viewer.add_image(features_np, name=f"Raw Features ({layer_name})")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# --- 4. Main Widget ---
|
|
182
|
+
|
|
183
|
+
@magic_factory(
|
|
184
|
+
call_button="Run PISCIS",
|
|
185
|
+
layout="vertical",
|
|
186
|
+
image_layer={"label": "Select Input"},
|
|
187
|
+
model_name={"label": "Model Name", "choices": ["20230905"]},
|
|
188
|
+
threshold={"label": "Threshold", "min": 0.0, "max": 1.0, "step": 0.1, "value": 1.0, "tooltip": "Minimum pixels for a spot."},
|
|
189
|
+
min_distance={"label": "Min Distance", "min": 0, "max": 20, "step": 1, "value": 1},
|
|
190
|
+
intermediates={"label": "Return Feature Maps", "value": False},
|
|
191
|
+
)
|
|
192
|
+
def piscis_inference(
|
|
193
|
+
viewer: napari.Viewer,
|
|
194
|
+
image_layer: "napari.layers.Image",
|
|
195
|
+
model_name: str = "20230905",
|
|
196
|
+
threshold: float = 1.0,
|
|
197
|
+
min_distance: int = 1,
|
|
198
|
+
intermediates: bool = False,
|
|
199
|
+
):
|
|
200
|
+
if not DEPENDENCIES_INSTALLED:
|
|
201
|
+
show_error("PISCIS dependencies not found. Please install: pip install piscis scikit-image")
|
|
202
|
+
return
|
|
203
|
+
if image_layer is None:
|
|
204
|
+
show_warning("Please select an image layer.")
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
raw_image = np.asarray(image_layer.data)
|
|
208
|
+
show_info(f"PISCIS: Preparing input...")
|
|
209
|
+
|
|
210
|
+
worker = piscis_worker(
|
|
211
|
+
raw_image,
|
|
212
|
+
model_name,
|
|
213
|
+
threshold,
|
|
214
|
+
int(min_distance),
|
|
215
|
+
intermediates
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
def on_success(result):
|
|
219
|
+
coords_pred = result['coords']
|
|
220
|
+
features = result['features']
|
|
221
|
+
is_3d_stack = result['is_3d_stack']
|
|
222
|
+
was_color_converted = result['was_color_converted']
|
|
223
|
+
processed_image = result['processed_image']
|
|
224
|
+
|
|
225
|
+
# 1. Handle Color Conversion
|
|
226
|
+
if was_color_converted and processed_image is not None:
|
|
227
|
+
show_warning(f"Color input detected. Converted to grayscale for processing.")
|
|
228
|
+
|
|
229
|
+
viewer.add_image(
|
|
230
|
+
processed_image,
|
|
231
|
+
name=f"Grayscale Input ({image_layer.name})",
|
|
232
|
+
colormap='gray'
|
|
233
|
+
)
|
|
234
|
+
# Hide the original RGB layer
|
|
235
|
+
image_layer.visible = False
|
|
236
|
+
|
|
237
|
+
# 2. Handle Coordinates
|
|
238
|
+
if len(coords_pred) > 0:
|
|
239
|
+
viewer.add_points(
|
|
240
|
+
np.array(coords_pred),
|
|
241
|
+
name=f"Spots ({image_layer.name})",
|
|
242
|
+
size=3,
|
|
243
|
+
face_color='lime',
|
|
244
|
+
symbol='disc',
|
|
245
|
+
)
|
|
246
|
+
show_info(f"PISCIS: Detected {len(coords_pred)} spots.")
|
|
247
|
+
else:
|
|
248
|
+
show_info("PISCIS: No spots detected.")
|
|
249
|
+
|
|
250
|
+
# 3. Handle Feature Maps
|
|
251
|
+
if intermediates and features is not None:
|
|
252
|
+
_display_features(viewer, features, is_3d_stack, image_layer.name)
|
|
253
|
+
|
|
254
|
+
def on_error(e):
|
|
255
|
+
show_error(f"PISCIS failed: {str(e)}")
|
|
256
|
+
# Loguru syntax to attach the exception object 'e' for a traceback
|
|
257
|
+
logger.opt(exception=e).error("Worker failed")
|
|
258
|
+
|
|
259
|
+
worker.returned.connect(on_success)
|
|
260
|
+
worker.errored.connect(on_error)
|
|
261
|
+
worker.start()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
name: napari-piscis
|
|
2
|
+
display_name: Piscis
|
|
3
|
+
contributions:
|
|
4
|
+
commands:
|
|
5
|
+
- id: napari-piscis.inference
|
|
6
|
+
title: "Piscis: Inference"
|
|
7
|
+
python_name: napari_piscis._widget:piscis_inference
|
|
8
|
+
widgets:
|
|
9
|
+
- command: napari-piscis.inference
|
|
10
|
+
display_name: "Piscis Inference"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: napari-piscis
|
|
3
|
+
Version: 0.1.20
|
|
4
|
+
Summary: Napari plugin for Piscis spot detection (smFISH)
|
|
5
|
+
Author-email: Michael Blodgett <michaelablodgett@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2023-2024 William Niu
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
28
|
+
Classifier: Framework :: napari
|
|
29
|
+
Classifier: Intended Audience :: Developers
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Operating System :: OS Independent
|
|
32
|
+
Classifier: Programming Language :: Python
|
|
33
|
+
Classifier: Programming Language :: Python :: 3
|
|
34
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
39
|
+
Requires-Python: <3.14,>=3.10
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Requires-Dist: napari>=0.4.19
|
|
43
|
+
Requires-Dist: magicgui>=0.8
|
|
44
|
+
Requires-Dist: numpy
|
|
45
|
+
Requires-Dist: scikit-image
|
|
46
|
+
Requires-Dist: piscis>=0.2.7
|
|
47
|
+
Requires-Dist: jax<=0.4.30
|
|
48
|
+
Requires-Dist: loguru
|
|
49
|
+
Provides-Extra: all
|
|
50
|
+
Requires-Dist: napari[all]; extra == "all"
|
|
51
|
+
Dynamic: license-file
|
|
52
|
+
|
|
53
|
+
# napari-piscis
|
|
54
|
+
|
|
55
|
+
[](https://github.com/p5ithurism/napari-piscis/raw/main/LICENSE)
|
|
56
|
+
[](https://pypi.org/project/napari-piscis)
|
|
57
|
+
[](https://python.org)
|
|
58
|
+
[](https://github.com/p5ithurism/napari-piscis/actions)
|
|
59
|
+
[](https://codecov.io/gh/p5ithurism/napari-piscis)
|
|
60
|
+
[](https://napari-hub.org/plugins/napari-piscis)
|
|
61
|
+
[](https://napari.org/stable/plugins/index.html)
|
|
62
|
+
|
|
63
|
+
Unofficial napari plugin for [Piscis](https://github.com/zjniu/Piscis), a deep learning algorithm for spot detection.
|
|
64
|
+
|
|
65
|
+
----------------------------------
|
|
66
|
+
|
|
67
|
+
This [napari] plugin was based off of the [napari-plugin-template].
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
You can install `napari-piscis` via [pip]:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
pip install napari-piscis
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## License
|
|
78
|
+
|
|
79
|
+
Distributed under the terms of the [MIT] license,
|
|
80
|
+
"napari-piscis" is free and open source software
|
|
81
|
+
|
|
82
|
+
## Issues
|
|
83
|
+
|
|
84
|
+
If you encounter any problems, please [file an issue] along with a detailed description.
|
|
85
|
+
|
|
86
|
+
[napari]: https://github.com/napari/napari
|
|
87
|
+
[@napari]: https://github.com/napari
|
|
88
|
+
[MIT]: http://opensource.org/licenses/MIT
|
|
89
|
+
[BSD-3]: http://opensource.org/licenses/BSD-3-Clause
|
|
90
|
+
[GNU GPL v3.0]: http://www.gnu.org/licenses/gpl-3.0.txt
|
|
91
|
+
[GNU LGPL v3.0]: http://www.gnu.org/licenses/lgpl-3.0.txt
|
|
92
|
+
[Apache Software License 2.0]: http://www.apache.org/licenses/LICENSE-2.0
|
|
93
|
+
[Mozilla Public License 2.0]: https://www.mozilla.org/media/MPL/2.0/index.txt
|
|
94
|
+
[napari-plugin-template]: https://github.com/napari/napari-plugin-template
|
|
95
|
+
|
|
96
|
+
[napari]: https://github.com/napari/napari
|
|
97
|
+
[pip]: https://pypi.org/project/pip/
|
|
98
|
+
[PyPI]: https://pypi.org/
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
napari_piscis/__init__.py,sha256=WjDmvecyDIyJLYp4rCV9vsSYbQDc4L1EpYqORvEXliI,33
|
|
2
|
+
napari_piscis/_version.py,sha256=P88Jfo9OvOr8LB0vHFqLUwFR7A0eE281KxEewbcCSBc,706
|
|
3
|
+
napari_piscis/_widget.py,sha256=T-V5eskIFJghOHGW526QTedMyAle0xjaOM3g_DktG9Q,8447
|
|
4
|
+
napari_piscis/napari.yaml,sha256=6X-K-Y_dbNdn9TGjA1YzGKCpBbdA9_dmB9HdEABE5lQ,281
|
|
5
|
+
napari_piscis-0.1.20.dist-info/licenses/LICENSE,sha256=83k71GgrPZSt4JsOf6KiAyi3_XL3kdmiexDLLYWvCTI,1072
|
|
6
|
+
napari_piscis-0.1.20.dist-info/METADATA,sha256=8_iuvEH3QD5PVoIJYFOe6m4mXDIYl2lPcDJxzCKRWUg,4476
|
|
7
|
+
napari_piscis-0.1.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
+
napari_piscis-0.1.20.dist-info/entry_points.txt,sha256=rXFKdNsiSm17cVGs3vJzP6SnKPllUkk3EaWrQNQlMQo,60
|
|
9
|
+
napari_piscis-0.1.20.dist-info/top_level.txt,sha256=vKkzMwrBPY9PlqL5WNKJB-V1lNXwTioDpIh_p2bSjEk,14
|
|
10
|
+
napari_piscis-0.1.20.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-2024 William Niu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
napari_piscis
|