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.
@@ -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.0b3
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
- Provides-Extra: gpu
51
- Requires-Dist: cupy-cuda12x>=12.0; extra == "gpu"
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: cupy-cuda12x>=12.0; extra == "all"
80
- Requires-Dist: cucim>=23.4; extra == "all"
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=mNRYmhG-SXPlokw7tiuHYRGLzqtfECSRH-QIpZiEJbk,269
1
+ senoquant/__init__.py,sha256=UbZDFUGVkGaxQFqjwIfVZt0x2mckTYJpbFUXQBGg5FA,269
2
2
  senoquant/_reader.py,sha256=HVGhwQTuuDbvNM9tEkUpE6js_Lzh7vTHXdYfDCqvvXk,154
3
- senoquant/_widget.py,sha256=nuNaKvWAx7aKXORAipOUf7sUI5I3DvZazXnwrJcBqcw,1102
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=DnIT3E7XRSw2CmlZ-Ma4aYpoUFSFjF-66kMDNPaZEmU,371
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=R8cSMkPL8sf49-vNc7PnvWrLA3FQ_1KJ9KQHSUnd0Os,24727
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=_zhv2H7UneeMtB8jZ6YZhFGaqu6DhuAB6Q7BtHS3fxA,51987
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=IGyT-rWbX_vVgaIiDkxkijt6EoAPdnkW2dKOvL2Ziwg,28151
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/ufish/details.json,sha256=126sbAoU1SMCLCCphUKcTqh4HtKbPYDdgm41cNifMmA,312
141
- senoquant/tabs/spots/models/ufish/model.py,sha256=iOxdQizYmQ8Fj-CvFjMkAEjFBKpwqC5gjxmHc9jfGBI,4236
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=ZuJU8tkY3KJ9N-jMqMeYjsCcfhaZon44e1CcjxLR51Q,10649
144
- senoquant-1.0.0b3.dist-info/licenses/LICENSE,sha256=wJjNEZJA6A7m6ozqNeq3tXi4X5gzbEGraFm2jw5ahG0,1509
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.0b3.dist-info/METADATA,sha256=pY9mFrZO9gi6IBl4MGxM7y9XWrSN9pueFvzfh0nc6us,7269
158
- senoquant-1.0.0b3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
159
- senoquant-1.0.0b3.dist-info/entry_points.txt,sha256=_HUyyJcDeBQVdUKjY3ZW9fqvHLWFn2mPXS_9KBPIzuU,52
160
- senoquant-1.0.0b3.dist-info/top_level.txt,sha256=n-FXEO-BsEDOq-ur29UIHcQLD-PgvSbN2eV1onngiSU,16
161
- senoquant-1.0.0b3.dist-info/RECORD,,
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,,