chatspatial 1.1.0__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.
- chatspatial/__init__.py +11 -0
- chatspatial/__main__.py +141 -0
- chatspatial/cli/__init__.py +7 -0
- chatspatial/config.py +53 -0
- chatspatial/models/__init__.py +85 -0
- chatspatial/models/analysis.py +513 -0
- chatspatial/models/data.py +2462 -0
- chatspatial/server.py +1763 -0
- chatspatial/spatial_mcp_adapter.py +720 -0
- chatspatial/tools/__init__.py +3 -0
- chatspatial/tools/annotation.py +1903 -0
- chatspatial/tools/cell_communication.py +1603 -0
- chatspatial/tools/cnv_analysis.py +605 -0
- chatspatial/tools/condition_comparison.py +595 -0
- chatspatial/tools/deconvolution/__init__.py +402 -0
- chatspatial/tools/deconvolution/base.py +318 -0
- chatspatial/tools/deconvolution/card.py +244 -0
- chatspatial/tools/deconvolution/cell2location.py +326 -0
- chatspatial/tools/deconvolution/destvi.py +144 -0
- chatspatial/tools/deconvolution/flashdeconv.py +101 -0
- chatspatial/tools/deconvolution/rctd.py +317 -0
- chatspatial/tools/deconvolution/spotlight.py +216 -0
- chatspatial/tools/deconvolution/stereoscope.py +109 -0
- chatspatial/tools/deconvolution/tangram.py +135 -0
- chatspatial/tools/differential.py +625 -0
- chatspatial/tools/embeddings.py +298 -0
- chatspatial/tools/enrichment.py +1863 -0
- chatspatial/tools/integration.py +807 -0
- chatspatial/tools/preprocessing.py +723 -0
- chatspatial/tools/spatial_domains.py +808 -0
- chatspatial/tools/spatial_genes.py +836 -0
- chatspatial/tools/spatial_registration.py +441 -0
- chatspatial/tools/spatial_statistics.py +1476 -0
- chatspatial/tools/trajectory.py +495 -0
- chatspatial/tools/velocity.py +405 -0
- chatspatial/tools/visualization/__init__.py +155 -0
- chatspatial/tools/visualization/basic.py +393 -0
- chatspatial/tools/visualization/cell_comm.py +699 -0
- chatspatial/tools/visualization/cnv.py +320 -0
- chatspatial/tools/visualization/core.py +684 -0
- chatspatial/tools/visualization/deconvolution.py +852 -0
- chatspatial/tools/visualization/enrichment.py +660 -0
- chatspatial/tools/visualization/integration.py +205 -0
- chatspatial/tools/visualization/main.py +164 -0
- chatspatial/tools/visualization/multi_gene.py +739 -0
- chatspatial/tools/visualization/persistence.py +335 -0
- chatspatial/tools/visualization/spatial_stats.py +469 -0
- chatspatial/tools/visualization/trajectory.py +639 -0
- chatspatial/tools/visualization/velocity.py +411 -0
- chatspatial/utils/__init__.py +115 -0
- chatspatial/utils/adata_utils.py +1372 -0
- chatspatial/utils/compute.py +327 -0
- chatspatial/utils/data_loader.py +499 -0
- chatspatial/utils/dependency_manager.py +462 -0
- chatspatial/utils/device_utils.py +165 -0
- chatspatial/utils/exceptions.py +185 -0
- chatspatial/utils/image_utils.py +267 -0
- chatspatial/utils/mcp_utils.py +137 -0
- chatspatial/utils/path_utils.py +243 -0
- chatspatial/utils/persistence.py +78 -0
- chatspatial/utils/scipy_compat.py +143 -0
- chatspatial-1.1.0.dist-info/METADATA +242 -0
- chatspatial-1.1.0.dist-info/RECORD +67 -0
- chatspatial-1.1.0.dist-info/WHEEL +5 -0
- chatspatial-1.1.0.dist-info/entry_points.txt +2 -0
- chatspatial-1.1.0.dist-info/licenses/LICENSE +21 -0
- chatspatial-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Embedding computation tools for spatial transcriptomics data.
|
|
3
|
+
|
|
4
|
+
This module provides explicit control over dimensionality reduction and clustering
|
|
5
|
+
computations. While analysis tools compute these lazily using ensure_* functions,
|
|
6
|
+
users can use this tool to control computation parameters directly.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Literal, Optional
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
from ..spatial_mcp_adapter import ToolContext
|
|
14
|
+
from ..utils.compute import (
|
|
15
|
+
ensure_diffmap,
|
|
16
|
+
ensure_leiden,
|
|
17
|
+
ensure_louvain,
|
|
18
|
+
ensure_neighbors,
|
|
19
|
+
ensure_pca,
|
|
20
|
+
ensure_spatial_neighbors,
|
|
21
|
+
ensure_umap,
|
|
22
|
+
)
|
|
23
|
+
from ..utils.mcp_utils import mcp_tool_error_handler
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EmbeddingParameters(BaseModel):
|
|
27
|
+
"""Parameters for embedding computation."""
|
|
28
|
+
|
|
29
|
+
# What to compute
|
|
30
|
+
compute_pca: bool = Field(
|
|
31
|
+
default=True,
|
|
32
|
+
description="Compute PCA dimensionality reduction",
|
|
33
|
+
)
|
|
34
|
+
compute_neighbors: bool = Field(
|
|
35
|
+
default=True,
|
|
36
|
+
description="Compute k-NN neighbor graph (requires PCA)",
|
|
37
|
+
)
|
|
38
|
+
compute_umap: bool = Field(
|
|
39
|
+
default=True,
|
|
40
|
+
description="Compute UMAP embedding (requires neighbors)",
|
|
41
|
+
)
|
|
42
|
+
compute_clustering: bool = Field(
|
|
43
|
+
default=True,
|
|
44
|
+
description="Compute Leiden clustering (requires neighbors)",
|
|
45
|
+
)
|
|
46
|
+
compute_diffmap: bool = Field(
|
|
47
|
+
default=False,
|
|
48
|
+
description="Compute diffusion map for trajectory analysis (requires neighbors)",
|
|
49
|
+
)
|
|
50
|
+
compute_spatial_neighbors: bool = Field(
|
|
51
|
+
default=True,
|
|
52
|
+
description="Compute spatial neighborhood graph for spatial analysis",
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# PCA parameters
|
|
56
|
+
n_pcs: int = Field(
|
|
57
|
+
default=30,
|
|
58
|
+
ge=2,
|
|
59
|
+
le=100,
|
|
60
|
+
description="Number of principal components",
|
|
61
|
+
)
|
|
62
|
+
use_highly_variable: bool = Field(
|
|
63
|
+
default=True,
|
|
64
|
+
description="Use only highly variable genes for PCA",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Neighbor graph parameters
|
|
68
|
+
n_neighbors: int = Field(
|
|
69
|
+
default=15,
|
|
70
|
+
ge=2,
|
|
71
|
+
le=100,
|
|
72
|
+
description="Number of neighbors for k-NN graph",
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# UMAP parameters
|
|
76
|
+
umap_min_dist: float = Field(
|
|
77
|
+
default=0.5,
|
|
78
|
+
ge=0.0,
|
|
79
|
+
le=1.0,
|
|
80
|
+
description="UMAP minimum distance parameter",
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Clustering parameters
|
|
84
|
+
clustering_method: Literal["leiden", "louvain"] = Field(
|
|
85
|
+
default="leiden",
|
|
86
|
+
description="Clustering algorithm",
|
|
87
|
+
)
|
|
88
|
+
clustering_resolution: float = Field(
|
|
89
|
+
default=1.0,
|
|
90
|
+
ge=0.1,
|
|
91
|
+
le=2.0,
|
|
92
|
+
description="Clustering resolution (higher = more clusters)",
|
|
93
|
+
)
|
|
94
|
+
clustering_key: str = Field(
|
|
95
|
+
default="leiden",
|
|
96
|
+
description="Key to store clustering results in adata.obs",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Diffusion map parameters
|
|
100
|
+
diffmap_n_comps: int = Field(
|
|
101
|
+
default=15,
|
|
102
|
+
ge=2,
|
|
103
|
+
le=50,
|
|
104
|
+
description="Number of diffusion components",
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
# Spatial neighbor parameters
|
|
108
|
+
spatial_coord_type: Literal["grid", "generic"] = Field(
|
|
109
|
+
default="generic",
|
|
110
|
+
description="Coordinate type: 'grid' for Visium hexagonal, 'generic' for others",
|
|
111
|
+
)
|
|
112
|
+
spatial_n_neighs: int = Field(
|
|
113
|
+
default=6,
|
|
114
|
+
ge=1,
|
|
115
|
+
le=30,
|
|
116
|
+
description="Number of spatial neighbors (for generic coord_type)",
|
|
117
|
+
)
|
|
118
|
+
spatial_n_rings: int = Field(
|
|
119
|
+
default=1,
|
|
120
|
+
ge=1,
|
|
121
|
+
le=3,
|
|
122
|
+
description="Number of rings (for grid coord_type)",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Force recomputation
|
|
126
|
+
force: bool = Field(
|
|
127
|
+
default=False,
|
|
128
|
+
description="Force recomputation even if results already exist",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Random seed
|
|
132
|
+
random_state: int = Field(
|
|
133
|
+
default=0,
|
|
134
|
+
description="Random seed for reproducibility",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
class EmbeddingResult(BaseModel):
|
|
139
|
+
"""Result of embedding computation."""
|
|
140
|
+
|
|
141
|
+
data_id: str
|
|
142
|
+
computed: list[str]
|
|
143
|
+
skipped: list[str]
|
|
144
|
+
n_clusters: Optional[int] = None
|
|
145
|
+
pca_variance_ratio: Optional[float] = None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@mcp_tool_error_handler()
|
|
149
|
+
async def compute_embeddings(
|
|
150
|
+
data_id: str,
|
|
151
|
+
ctx: ToolContext,
|
|
152
|
+
params: EmbeddingParameters = EmbeddingParameters(),
|
|
153
|
+
) -> EmbeddingResult:
|
|
154
|
+
"""Compute dimensionality reduction, clustering, and neighbor graphs.
|
|
155
|
+
|
|
156
|
+
This tool provides explicit control over embedding computations.
|
|
157
|
+
Analysis tools compute these lazily, but you can use this tool to:
|
|
158
|
+
- Control computation parameters (n_pcs, n_neighbors, resolution)
|
|
159
|
+
- Force recomputation with different parameters
|
|
160
|
+
- Compute specific embeddings without running full preprocessing
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
data_id: Dataset ID
|
|
164
|
+
ctx: Tool context
|
|
165
|
+
params: Embedding computation parameters
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Summary of computed embeddings
|
|
169
|
+
"""
|
|
170
|
+
adata = await ctx.get_adata(data_id)
|
|
171
|
+
computed = []
|
|
172
|
+
skipped = []
|
|
173
|
+
|
|
174
|
+
# Handle force recomputation by removing existing results
|
|
175
|
+
if params.force:
|
|
176
|
+
if params.compute_pca and "X_pca" in adata.obsm:
|
|
177
|
+
del adata.obsm["X_pca"]
|
|
178
|
+
if "pca" in adata.uns:
|
|
179
|
+
del adata.uns["pca"]
|
|
180
|
+
if params.compute_neighbors:
|
|
181
|
+
if "neighbors" in adata.uns:
|
|
182
|
+
del adata.uns["neighbors"]
|
|
183
|
+
if "connectivities" in adata.obsp:
|
|
184
|
+
del adata.obsp["connectivities"]
|
|
185
|
+
if "distances" in adata.obsp:
|
|
186
|
+
del adata.obsp["distances"]
|
|
187
|
+
if params.compute_umap and "X_umap" in adata.obsm:
|
|
188
|
+
del adata.obsm["X_umap"]
|
|
189
|
+
if params.compute_clustering and params.clustering_key in adata.obs:
|
|
190
|
+
del adata.obs[params.clustering_key]
|
|
191
|
+
if params.compute_diffmap and "X_diffmap" in adata.obsm:
|
|
192
|
+
del adata.obsm["X_diffmap"]
|
|
193
|
+
if params.compute_spatial_neighbors and "spatial_connectivities" in adata.obsp:
|
|
194
|
+
del adata.obsp["spatial_connectivities"]
|
|
195
|
+
if "spatial_distances" in adata.obsp:
|
|
196
|
+
del adata.obsp["spatial_distances"]
|
|
197
|
+
|
|
198
|
+
# 1. PCA
|
|
199
|
+
if params.compute_pca:
|
|
200
|
+
if ensure_pca(
|
|
201
|
+
adata,
|
|
202
|
+
n_comps=params.n_pcs,
|
|
203
|
+
use_highly_variable=params.use_highly_variable,
|
|
204
|
+
random_state=params.random_state,
|
|
205
|
+
):
|
|
206
|
+
computed.append("PCA")
|
|
207
|
+
else:
|
|
208
|
+
skipped.append("PCA (already exists)")
|
|
209
|
+
|
|
210
|
+
# 2. Neighbors (requires PCA)
|
|
211
|
+
if params.compute_neighbors:
|
|
212
|
+
if ensure_neighbors(
|
|
213
|
+
adata,
|
|
214
|
+
n_neighbors=params.n_neighbors,
|
|
215
|
+
n_pcs=params.n_pcs,
|
|
216
|
+
random_state=params.random_state,
|
|
217
|
+
):
|
|
218
|
+
computed.append("neighbors")
|
|
219
|
+
else:
|
|
220
|
+
skipped.append("neighbors (already exists)")
|
|
221
|
+
|
|
222
|
+
# 3. UMAP (requires neighbors)
|
|
223
|
+
if params.compute_umap:
|
|
224
|
+
if ensure_umap(
|
|
225
|
+
adata,
|
|
226
|
+
min_dist=params.umap_min_dist,
|
|
227
|
+
random_state=params.random_state,
|
|
228
|
+
):
|
|
229
|
+
computed.append("UMAP")
|
|
230
|
+
else:
|
|
231
|
+
skipped.append("UMAP (already exists)")
|
|
232
|
+
|
|
233
|
+
# 4. Clustering (requires neighbors)
|
|
234
|
+
n_clusters = None
|
|
235
|
+
if params.compute_clustering:
|
|
236
|
+
if params.clustering_method == "leiden":
|
|
237
|
+
if ensure_leiden(
|
|
238
|
+
adata,
|
|
239
|
+
resolution=params.clustering_resolution,
|
|
240
|
+
key_added=params.clustering_key,
|
|
241
|
+
random_state=params.random_state,
|
|
242
|
+
):
|
|
243
|
+
n_clusters = adata.obs[params.clustering_key].nunique()
|
|
244
|
+
computed.append(f"Leiden clustering ({n_clusters} clusters)")
|
|
245
|
+
else:
|
|
246
|
+
skipped.append(f"{params.clustering_key} (already exists)")
|
|
247
|
+
n_clusters = adata.obs[params.clustering_key].nunique()
|
|
248
|
+
else:
|
|
249
|
+
if ensure_louvain(
|
|
250
|
+
adata,
|
|
251
|
+
resolution=params.clustering_resolution,
|
|
252
|
+
key_added=params.clustering_key,
|
|
253
|
+
random_state=params.random_state,
|
|
254
|
+
):
|
|
255
|
+
n_clusters = adata.obs[params.clustering_key].nunique()
|
|
256
|
+
computed.append(f"Louvain clustering ({n_clusters} clusters)")
|
|
257
|
+
else:
|
|
258
|
+
skipped.append(f"{params.clustering_key} (already exists)")
|
|
259
|
+
n_clusters = adata.obs[params.clustering_key].nunique()
|
|
260
|
+
|
|
261
|
+
# 5. Diffusion map (requires neighbors)
|
|
262
|
+
if params.compute_diffmap:
|
|
263
|
+
if ensure_diffmap(adata, n_comps=params.diffmap_n_comps):
|
|
264
|
+
computed.append("diffusion map")
|
|
265
|
+
else:
|
|
266
|
+
skipped.append("diffusion map (already exists)")
|
|
267
|
+
|
|
268
|
+
# 6. Spatial neighbors
|
|
269
|
+
if params.compute_spatial_neighbors:
|
|
270
|
+
try:
|
|
271
|
+
if ensure_spatial_neighbors(
|
|
272
|
+
adata,
|
|
273
|
+
coord_type=params.spatial_coord_type,
|
|
274
|
+
n_neighs=params.spatial_n_neighs,
|
|
275
|
+
n_rings=params.spatial_n_rings,
|
|
276
|
+
):
|
|
277
|
+
computed.append("spatial neighbors")
|
|
278
|
+
else:
|
|
279
|
+
skipped.append("spatial neighbors (already exists)")
|
|
280
|
+
except ValueError as e:
|
|
281
|
+
await ctx.warning(f"Could not compute spatial neighbors: {e}")
|
|
282
|
+
skipped.append(f"spatial neighbors (error: {e})")
|
|
283
|
+
|
|
284
|
+
# Get PCA variance ratio if available
|
|
285
|
+
pca_variance_ratio = None
|
|
286
|
+
if "pca" in adata.uns and "variance_ratio" in adata.uns["pca"]:
|
|
287
|
+
pca_variance_ratio = float(adata.uns["pca"]["variance_ratio"].sum())
|
|
288
|
+
|
|
289
|
+
# Store updated data
|
|
290
|
+
await ctx.set_adata(data_id, adata)
|
|
291
|
+
|
|
292
|
+
return EmbeddingResult(
|
|
293
|
+
data_id=data_id,
|
|
294
|
+
computed=computed,
|
|
295
|
+
skipped=skipped,
|
|
296
|
+
n_clusters=n_clusters,
|
|
297
|
+
pca_variance_ratio=pca_variance_ratio,
|
|
298
|
+
)
|