senoquant 1.0.0b3__py3-none-any.whl → 1.0.0b4__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.
- senoquant/__init__.py +1 -1
- senoquant/_widget.py +9 -1
- senoquant/tabs/__init__.py +2 -0
- senoquant/tabs/batch/backend.py +58 -24
- senoquant/tabs/batch/frontend.py +119 -21
- senoquant/tabs/spots/frontend.py +54 -0
- senoquant/tabs/spots/models/rmp/details.json +55 -0
- senoquant/tabs/spots/models/rmp/model.py +574 -0
- senoquant/tabs/spots/models/ufish/details.json +16 -1
- senoquant/tabs/spots/models/ufish/model.py +211 -13
- senoquant/tabs/spots/ufish_utils/core.py +31 -1
- senoquant/tabs/visualization/__init__.py +1 -0
- senoquant/tabs/visualization/backend.py +306 -0
- senoquant/tabs/visualization/frontend.py +1113 -0
- senoquant/tabs/visualization/plots/__init__.py +80 -0
- senoquant/tabs/visualization/plots/base.py +152 -0
- senoquant/tabs/visualization/plots/double_expression.py +187 -0
- senoquant/tabs/visualization/plots/spatialplot.py +156 -0
- senoquant/tabs/visualization/plots/umap.py +140 -0
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/METADATA +7 -6
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/RECORD +25 -15
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/WHEEL +0 -0
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/entry_points.txt +0 -0
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/licenses/LICENSE +0 -0
- {senoquant-1.0.0b3.dist-info → senoquant-1.0.0b4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"""UMAP plot handler for visualization."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Iterable
|
|
7
|
+
|
|
8
|
+
from .base import PlotData, SenoQuantPlot
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UMAPData(PlotData):
|
|
12
|
+
"""Configuration data for UMAP plot."""
|
|
13
|
+
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class UMAPPlot(SenoQuantPlot):
|
|
18
|
+
"""UMAP dimensionality reduction plot handler."""
|
|
19
|
+
|
|
20
|
+
feature_type = "UMAP"
|
|
21
|
+
order = 1
|
|
22
|
+
|
|
23
|
+
def build(self) -> None:
|
|
24
|
+
"""Build the UI for UMAP plot configuration."""
|
|
25
|
+
# Minimal UI for now; can add controls for n_components, metric, etc. later
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
def plot(
|
|
29
|
+
self,
|
|
30
|
+
temp_dir: Path,
|
|
31
|
+
input_path: Path,
|
|
32
|
+
export_format: str,
|
|
33
|
+
markers: list[str] | None = None,
|
|
34
|
+
thresholds: dict[str, float] | None = None,
|
|
35
|
+
) -> Iterable[Path]:
|
|
36
|
+
"""Generate UMAP plot from input CSV.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
temp_dir : Path
|
|
41
|
+
Temporary directory to write plot output.
|
|
42
|
+
input_path : Path
|
|
43
|
+
Path to input CSV file or folder containing CSV files.
|
|
44
|
+
export_format : str
|
|
45
|
+
Output format ("png", "svg", or "pdf").
|
|
46
|
+
markers : list of str, optional
|
|
47
|
+
List of selected markers to include.
|
|
48
|
+
thresholds : dict, optional
|
|
49
|
+
Dictionary of {marker_name: threshold_value} for filtering.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
iterable of Path
|
|
54
|
+
Paths to generated plot files.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
try:
|
|
58
|
+
import pandas as pd
|
|
59
|
+
except ImportError:
|
|
60
|
+
print("[UMAPPlot] pandas is not installed; skipping plot generation.")
|
|
61
|
+
return []
|
|
62
|
+
try:
|
|
63
|
+
import matplotlib.pyplot as plt
|
|
64
|
+
except ImportError:
|
|
65
|
+
print("[UMAPPlot] matplotlib is not installed; skipping plot generation.")
|
|
66
|
+
return []
|
|
67
|
+
try:
|
|
68
|
+
from umap import UMAP as UMAPReducer
|
|
69
|
+
except ImportError:
|
|
70
|
+
print("[UMAPPlot] umap-learn is not installed; skipping plot generation.")
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
print(f"[UMAPPlot] Starting with input_path={input_path}")
|
|
74
|
+
# Find the first data file (CSV or Excel) in the input folder
|
|
75
|
+
data_files = list(input_path.glob("*.csv")) + list(input_path.glob("*.xlsx")) + list(input_path.glob("*.xls"))
|
|
76
|
+
print(f"[UMAPPlot] Found {len(data_files)} data files")
|
|
77
|
+
if not data_files:
|
|
78
|
+
print(f"[UMAPPlot] No CSV/Excel files found in {input_path}")
|
|
79
|
+
return []
|
|
80
|
+
|
|
81
|
+
data_file = data_files[0]
|
|
82
|
+
print(f"[UMAPPlot] Reading {data_file}")
|
|
83
|
+
if data_file.suffix.lower() in ('.xlsx', '.xls'):
|
|
84
|
+
df = pd.read_excel(data_file)
|
|
85
|
+
else:
|
|
86
|
+
df = pd.read_csv(data_file)
|
|
87
|
+
print(f"[UMAPPlot] Loaded dataframe with shape {df.shape}")
|
|
88
|
+
if df.empty:
|
|
89
|
+
print(f"[UMAPPlot] DataFrame is empty")
|
|
90
|
+
return []
|
|
91
|
+
|
|
92
|
+
# Apply thresholds if provided
|
|
93
|
+
if thresholds:
|
|
94
|
+
for marker, thresh in thresholds.items():
|
|
95
|
+
col_name = f"{marker}_mean_intensity"
|
|
96
|
+
if col_name in df.columns:
|
|
97
|
+
# Clip values below threshold to 0
|
|
98
|
+
df.loc[df[col_name] < thresh, col_name] = 0
|
|
99
|
+
|
|
100
|
+
# Select numeric columns for UMAP
|
|
101
|
+
if markers:
|
|
102
|
+
numeric_cols = [f"{m}_mean_intensity" for m in markers if f"{m}_mean_intensity" in df.columns]
|
|
103
|
+
print(f"[UMAPPlot] Using {len(numeric_cols)} selected markers for UMAP")
|
|
104
|
+
else:
|
|
105
|
+
numeric_cols = df.select_dtypes(include=["number"]).columns
|
|
106
|
+
print(f"[UMAPPlot] Found {len(numeric_cols)} numeric columns (default)")
|
|
107
|
+
|
|
108
|
+
if len(numeric_cols) < 2:
|
|
109
|
+
print(f"[UMAPPlot] Need at least 2 numeric columns for UMAP, found {len(numeric_cols)}")
|
|
110
|
+
return []
|
|
111
|
+
|
|
112
|
+
X = df[numeric_cols].values
|
|
113
|
+
|
|
114
|
+
# Fit UMAP
|
|
115
|
+
print(f"[UMAPPlot] Fitting UMAP with {len(X)} samples")
|
|
116
|
+
reducer = UMAPReducer(n_components=2, random_state=42)
|
|
117
|
+
embedding = reducer.fit_transform(X)
|
|
118
|
+
print(f"[UMAPPlot] UMAP embedding created with shape {embedding.shape}")
|
|
119
|
+
|
|
120
|
+
# Create plot
|
|
121
|
+
fig, ax = plt.subplots(figsize=(8, 6))
|
|
122
|
+
ax.scatter(embedding[:, 0], embedding[:, 1], alpha=0.6, s=20)
|
|
123
|
+
ax.set_xlabel("UMAP 1")
|
|
124
|
+
ax.set_ylabel("UMAP 2")
|
|
125
|
+
ax.set_title("UMAP Plot")
|
|
126
|
+
|
|
127
|
+
# Save plot
|
|
128
|
+
output_file = temp_dir / f"umap_plot.{export_format}"
|
|
129
|
+
print(f"[UMAPPlot] Saving to {output_file}")
|
|
130
|
+
fig.savefig(str(output_file), dpi=150, bbox_inches="tight")
|
|
131
|
+
plt.close(fig)
|
|
132
|
+
print(f"[UMAPPlot] Plot saved successfully")
|
|
133
|
+
|
|
134
|
+
return [output_file]
|
|
135
|
+
|
|
136
|
+
except Exception as e:
|
|
137
|
+
import traceback
|
|
138
|
+
print(f"[UMAPPlot] ERROR generating UMAP plot: {e}")
|
|
139
|
+
print(traceback.format_exc())
|
|
140
|
+
return []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: senoquant
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.0b4
|
|
4
4
|
Summary: napari plugin for spatial quantification of senescence markers in tissue imaging
|
|
5
5
|
Author: SenoQuant Contributors
|
|
6
6
|
Maintainer: SenoQuant Contributors
|
|
@@ -43,13 +43,13 @@ Requires-Dist: onnxruntime-gpu>=1.21.0; platform_system != "Darwin"
|
|
|
43
43
|
Requires-Dist: openpyxl>=3.1
|
|
44
44
|
Requires-Dist: huggingface_hub>=0.23.0
|
|
45
45
|
Requires-Dist: scikit-image<0.25,>=0.22
|
|
46
|
+
Requires-Dist: PyWavelets>=1.5
|
|
46
47
|
Requires-Dist: scipy>=1.8
|
|
47
48
|
Requires-Dist: senoquant-stardist-ext>=0.1.1
|
|
48
49
|
Requires-Dist: dask[array]>=2024.4
|
|
49
50
|
Requires-Dist: dask[distributed]>=2024.4
|
|
50
|
-
|
|
51
|
-
Requires-Dist:
|
|
52
|
-
Requires-Dist: cucim>=23.4; extra == "gpu"
|
|
51
|
+
Requires-Dist: matplotlib>=3.8
|
|
52
|
+
Requires-Dist: umap-learn>=0.5
|
|
53
53
|
Provides-Extra: all
|
|
54
54
|
Requires-Dist: napari[all]; extra == "all"
|
|
55
55
|
Requires-Dist: bioio>=3.2.0; extra == "all"
|
|
@@ -72,12 +72,13 @@ Requires-Dist: onnxruntime-gpu>=1.21.0; platform_system != "Darwin" and extra ==
|
|
|
72
72
|
Requires-Dist: openpyxl>=3.1; extra == "all"
|
|
73
73
|
Requires-Dist: huggingface_hub>=0.23.0; extra == "all"
|
|
74
74
|
Requires-Dist: scikit-image<0.25,>=0.22; extra == "all"
|
|
75
|
+
Requires-Dist: PyWavelets>=1.5; extra == "all"
|
|
75
76
|
Requires-Dist: scipy>=1.8; extra == "all"
|
|
76
77
|
Requires-Dist: senoquant-stardist-ext>=0.1.1; extra == "all"
|
|
77
78
|
Requires-Dist: dask[array]>=2024.4; extra == "all"
|
|
78
79
|
Requires-Dist: dask[distributed]>=2024.4; extra == "all"
|
|
79
|
-
Requires-Dist:
|
|
80
|
-
Requires-Dist:
|
|
80
|
+
Requires-Dist: matplotlib>=3.8; extra == "all"
|
|
81
|
+
Requires-Dist: umap-learn>=0.5; extra == "all"
|
|
81
82
|
Dynamic: license-file
|
|
82
83
|
|
|
83
84
|
# SenoQuant
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
senoquant/__init__.py,sha256=
|
|
1
|
+
senoquant/__init__.py,sha256=UbZDFUGVkGaxQFqjwIfVZt0x2mckTYJpbFUXQBGg5FA,269
|
|
2
2
|
senoquant/_reader.py,sha256=HVGhwQTuuDbvNM9tEkUpE6js_Lzh7vTHXdYfDCqvvXk,154
|
|
3
|
-
senoquant/_widget.py,sha256=
|
|
3
|
+
senoquant/_widget.py,sha256=83J186GFmImr_lY3wo3bZKouW_AHR_xannIlJZwtv1M,1233
|
|
4
4
|
senoquant/napari.yaml,sha256=2r1EpZcV1B3mLv0z3FwjS8e1T-yIMzoWvNj2SBqmftI,1664
|
|
5
5
|
senoquant/utils.py,sha256=XpvJjaoN_9DMD-cxURCStFccBYNccttdJtGnFO6PD2E,641
|
|
6
6
|
senoquant/reader/__init__.py,sha256=3lDuOpQC8TGUdfXdpLrr7MaszOVCqKMYM9YaTdq3DVQ,92
|
|
7
7
|
senoquant/reader/core.py,sha256=GGEU_FVFohhWR0KkbuTl50wdS04WzroBBC67gbwfLtA,15809
|
|
8
|
-
senoquant/tabs/__init__.py,sha256=
|
|
8
|
+
senoquant/tabs/__init__.py,sha256=YvagQQzYgZNMsquHD8gvNwJJv6TfdKoycWORSLOjrLk,448
|
|
9
9
|
senoquant/tabs/batch/__init__.py,sha256=0-xDYyAEEch9Yq7OhGeTkgoXus52Y_SQjqvtIbI-I20,291
|
|
10
|
-
senoquant/tabs/batch/backend.py,sha256=
|
|
10
|
+
senoquant/tabs/batch/backend.py,sha256=0npTLVEHP_ZWrAhCy3vyQiH59j7lwD1KoYLqBZABhwo,26683
|
|
11
11
|
senoquant/tabs/batch/config.py,sha256=w6DR0Nw6BL0hrFacQPIAHb-wCirYnogYJgmAPy2j9zo,8639
|
|
12
|
-
senoquant/tabs/batch/frontend.py,sha256=
|
|
12
|
+
senoquant/tabs/batch/frontend.py,sha256=4nT8_4YrTKIHPL0IfV-RQVMVG8U5FBGZWHFkQ71Dgec,56289
|
|
13
13
|
senoquant/tabs/batch/io.py,sha256=mggktbDDsGr4hQvpu4oj1eJcxG-xiPwfquO7QBesdDk,8382
|
|
14
14
|
senoquant/tabs/batch/layers.py,sha256=JjWS6WVZ3YOd-KZ4AjqstRF0qTPwOxOgGHd5FXrer08,2078
|
|
15
15
|
senoquant/tabs/quantification/__init__.py,sha256=iCqW7cg9QFfUdnYF7JSwOEus_tm66IZXdxSShy7RxwA,34
|
|
@@ -134,14 +134,24 @@ senoquant/tabs/settings/backend.py,sha256=ZVtmrUYNsox7DiVMlcS666XRyLG7GksgC818oo
|
|
|
134
134
|
senoquant/tabs/settings/frontend.py,sha256=_hTWJHZeEtU6n6qke31R6Es63knKeHhWZYUZj0ep79s,721
|
|
135
135
|
senoquant/tabs/spots/__init__.py,sha256=dYrAIzX3A5w4TOLRRadxL2agOte_Z0ennuEIOCbJD5w,25
|
|
136
136
|
senoquant/tabs/spots/backend.py,sha256=LZdkNzw-bpK0NClbeLttpg4C_8AqnIFg1W4NaxepTSs,4547
|
|
137
|
-
senoquant/tabs/spots/frontend.py,sha256=
|
|
137
|
+
senoquant/tabs/spots/frontend.py,sha256=2uRrhWXT8q_8MySYVDoGQyETq8RDHLua5haCwnXehi4,30262
|
|
138
138
|
senoquant/tabs/spots/models/__init__.py,sha256=OKnBIi-aaBsuXmwQNeg4EKeV66gSscedXyZ1-O3cJhY,123
|
|
139
139
|
senoquant/tabs/spots/models/base.py,sha256=VABmb2E7xvWOW8J60ZZkog0ZEG4XyW96qeXJMZVuKT8,2786
|
|
140
|
-
senoquant/tabs/spots/models/
|
|
141
|
-
senoquant/tabs/spots/models/
|
|
140
|
+
senoquant/tabs/spots/models/rmp/details.json,sha256=FIuLJmA0HPvhUkLd04IPY47Hg2duV7dlwpl9BcN4G9w,1128
|
|
141
|
+
senoquant/tabs/spots/models/rmp/model.py,sha256=pdeYaXbQ1lQK1D_ZUhn0Chf9XSDV4dG2Nn4Jht3v3mI,19181
|
|
142
|
+
senoquant/tabs/spots/models/ufish/details.json,sha256=TW1pagjfQI2CYFAIRJ6pB14_bI1nU7EsoW5PLZtMcJg,602
|
|
143
|
+
senoquant/tabs/spots/models/ufish/model.py,sha256=YxCH5k2R3E9gk7H8CAbxrIQ2qa5yPOEYv7uj-hM8N-g,11074
|
|
142
144
|
senoquant/tabs/spots/ufish_utils/__init__.py,sha256=QH8ReVcWtg2_Mgx2Oxg6OZbcQ8ntp42lOMlaJoT3ZSE,394
|
|
143
|
-
senoquant/tabs/spots/ufish_utils/core.py,sha256=
|
|
144
|
-
senoquant
|
|
145
|
+
senoquant/tabs/spots/ufish_utils/core.py,sha256=agSR6KD7potqvKrUQlcGTcOuhQTykPkTcgwYI6JwHBw,11764
|
|
146
|
+
senoquant/tabs/visualization/__init__.py,sha256=RV8qmD1xqR5i2PlAk_1Dx-6XRig9q7D7H2kwcFPGruc,33
|
|
147
|
+
senoquant/tabs/visualization/backend.py,sha256=z0_mHft-fnzqSE_qv0JTX5UgWhCJ7vf11Cpa210NQDo,10877
|
|
148
|
+
senoquant/tabs/visualization/frontend.py,sha256=E4h7jBmyF7ZBnKUH1Hhvfj9YDzrbnJljp6h1k6PYLRg,42580
|
|
149
|
+
senoquant/tabs/visualization/plots/__init__.py,sha256=fyic7xGD_h4CNoDI9Ui1UrZZwgPwqJPwJ16YFRW6aXE,1965
|
|
150
|
+
senoquant/tabs/visualization/plots/base.py,sha256=hUsX7Oz2TlQb-g3eAKZL82URyoB2pbyQPCPNvGQdCzg,4297
|
|
151
|
+
senoquant/tabs/visualization/plots/double_expression.py,sha256=jcYEDt_taHtm4uSUx7viv3J2BW4MP7cGax33guwo1bc,6637
|
|
152
|
+
senoquant/tabs/visualization/plots/spatialplot.py,sha256=4GR4w8ChBFZ_hsh03_kRo3yKCfkCEbfqIeJvC3IxQ_M,5673
|
|
153
|
+
senoquant/tabs/visualization/plots/umap.py,sha256=fQuwtmsuMyWmUMcmmcuMOVqKrON0aBi-xMQ0W_vxyeA,5134
|
|
154
|
+
senoquant-1.0.0b4.dist-info/licenses/LICENSE,sha256=wJjNEZJA6A7m6ozqNeq3tXi4X5gzbEGraFm2jw5ahG0,1509
|
|
145
155
|
ufish/__init__.py,sha256=ls1camlIoMxEZz9gSkZ1OJo-MXqHWwKPtdPbZJmwp7E,22
|
|
146
156
|
ufish/api.py,sha256=Nezcny6yTGMwdmB8qZv5dyCAeDq1RCSvMcAiZmGcn1s,29658
|
|
147
157
|
ufish/model/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -154,8 +164,8 @@ ufish/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
154
164
|
ufish/utils/img.py,sha256=8CkEZyWCKriCFuSq_qPphwmj-WPUrFMDyMGnRPQCA3k,12904
|
|
155
165
|
ufish/utils/log.py,sha256=_nF9sJJAMFqQJvvIUYI5o2ffAMTHmQhDVkp2EI3rsvc,280
|
|
156
166
|
ufish/utils/spot_calling.py,sha256=y7lSWOuxG7ca1nFz2uKC7x7aSzocqQu2p3tCijvvLSI,3970
|
|
157
|
-
senoquant-1.0.
|
|
158
|
-
senoquant-1.0.
|
|
159
|
-
senoquant-1.0.
|
|
160
|
-
senoquant-1.0.
|
|
161
|
-
senoquant-1.0.
|
|
167
|
+
senoquant-1.0.0b4.dist-info/METADATA,sha256=23gWiyLwY3INGiBy-N5-heQUVt0xirsQPguswkV8XQE,7297
|
|
168
|
+
senoquant-1.0.0b4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
169
|
+
senoquant-1.0.0b4.dist-info/entry_points.txt,sha256=_HUyyJcDeBQVdUKjY3ZW9fqvHLWFn2mPXS_9KBPIzuU,52
|
|
170
|
+
senoquant-1.0.0b4.dist-info/top_level.txt,sha256=n-FXEO-BsEDOq-ur29UIHcQLD-PgvSbN2eV1onngiSU,16
|
|
171
|
+
senoquant-1.0.0b4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|