scmcp-shared 0.2.5__py3-none-any.whl → 0.3.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.
- scmcp_shared/__init__.py +1 -1
- scmcp_shared/cli.py +96 -0
- scmcp_shared/schema/__init__.py +9 -0
- scmcp_shared/schema/io.py +0 -4
- scmcp_shared/schema/tl.py +0 -5
- scmcp_shared/server/__init__.py +11 -49
- scmcp_shared/server/base.py +153 -0
- scmcp_shared/server/io.py +70 -70
- scmcp_shared/server/pl.py +287 -338
- scmcp_shared/server/pp.py +319 -373
- scmcp_shared/server/tl.py +392 -441
- scmcp_shared/server/util.py +240 -250
- scmcp_shared/util.py +82 -17
- {scmcp_shared-0.2.5.dist-info → scmcp_shared-0.3.0.dist-info}/METADATA +1 -1
- scmcp_shared-0.3.0.dist-info/RECORD +21 -0
- scmcp_shared-0.2.5.dist-info/RECORD +0 -19
- {scmcp_shared-0.2.5.dist-info → scmcp_shared-0.3.0.dist-info}/WHEEL +0 -0
- {scmcp_shared-0.2.5.dist-info → scmcp_shared-0.3.0.dist-info}/licenses/LICENSE +0 -0
scmcp_shared/server/pl.py
CHANGED
@@ -5,362 +5,311 @@ import scanpy as sc
|
|
5
5
|
from fastmcp import FastMCP, Context
|
6
6
|
from fastmcp.exceptions import ToolError
|
7
7
|
from ..schema.pl import *
|
8
|
-
from ..schema import
|
8
|
+
from ..schema import AdataInfo
|
9
9
|
from pathlib import Path
|
10
|
-
from ..logging_config import setup_logger
|
11
10
|
from ..util import forward_request, sc_like_plot, get_ads
|
11
|
+
from .base import BaseMCP
|
12
12
|
|
13
13
|
|
14
|
-
|
14
|
+
class ScanpyPlottingMCP(BaseMCP):
|
15
|
+
def __init__(self, include_tools: list = None, exclude_tools: list = None, AdataInfo: AdataInfo = AdataInfo):
|
16
|
+
"""
|
17
|
+
Initialize ScanpyPreprocessingMCP with optional tool filtering.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
include_tools (list, optional): List of tool names to include. If None, all tools are included.
|
21
|
+
exclude_tools (list, optional): List of tool names to exclude. If None, no tools are excluded.
|
22
|
+
AdataInfo: The AdataInfo class to use for type annotations.
|
23
|
+
"""
|
24
|
+
super().__init__("ScanpyMCP-PL-Server", include_tools, exclude_tools, AdataInfo)
|
15
25
|
|
16
|
-
|
26
|
+
def _tool_pca(self):
|
27
|
+
def _pca(request: PCAModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
28
|
+
"""Scatter plot in PCA coordinates. default figure for PCA plot"""
|
29
|
+
try:
|
30
|
+
if (res := forward_request("pl_pca", request, adinfo)) is not None:
|
31
|
+
return res
|
32
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
33
|
+
fig_path = sc_like_plot(sc.pl.pca, adata, request, adinfo)
|
34
|
+
return {"figpath": fig_path}
|
35
|
+
except ToolError as e:
|
36
|
+
raise ToolError(e)
|
37
|
+
except Exception as e:
|
38
|
+
if hasattr(e, '__context__') and e.__context__:
|
39
|
+
raise ToolError(e.__context__)
|
40
|
+
else:
|
41
|
+
raise ToolError(e)
|
42
|
+
return _pca
|
17
43
|
|
44
|
+
def _tool_diffmap(self):
|
45
|
+
def _diffmap(request: DiffusionMapModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
46
|
+
"""Plot diffusion map embedding of cells."""
|
47
|
+
try:
|
48
|
+
if (res := forward_request("pl_diffmap", request, adinfo)) is not None:
|
49
|
+
return res
|
50
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
51
|
+
fig_path = sc_like_plot(sc.pl.diffmap, adata, request, adinfo)
|
52
|
+
return {"figpath": fig_path}
|
53
|
+
except ToolError as e:
|
54
|
+
raise ToolError(e)
|
55
|
+
except Exception as e:
|
56
|
+
if hasattr(e, '__context__') and e.__context__:
|
57
|
+
raise ToolError(e.__context__)
|
58
|
+
else:
|
59
|
+
raise ToolError(e)
|
60
|
+
return _diffmap
|
18
61
|
|
62
|
+
def _tool_violin(self):
|
63
|
+
def _violin(request: ViolinModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
64
|
+
"""Plot violin plot of one or more variables."""
|
65
|
+
try:
|
66
|
+
if (res := forward_request("pl_violin", request, adinfo)) is not None:
|
67
|
+
return res
|
68
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
69
|
+
fig_path = sc_like_plot(sc.pl.violin, adata, request, adinfo)
|
70
|
+
return {"figpath": fig_path}
|
71
|
+
except KeyError as e:
|
72
|
+
raise ToolError(f"doest found {e} in current sampleid with adtype {adinfo.adtype}")
|
73
|
+
except ToolError as e:
|
74
|
+
raise ToolError(e)
|
75
|
+
except Exception as e:
|
76
|
+
if hasattr(e, '__context__') and e.__context__:
|
77
|
+
raise ToolError(e.__context__)
|
78
|
+
else:
|
79
|
+
raise ToolError(e)
|
80
|
+
return _violin
|
19
81
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
):
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
raise ToolError(e.__context__)
|
38
|
-
else:
|
39
|
-
raise ToolError(e)
|
82
|
+
def _tool_stacked_violin(self):
|
83
|
+
def _stacked_violin(request: StackedViolinModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
84
|
+
"""Plot stacked violin plots. Makes a compact image composed of individual violin plots stacked on top of each other."""
|
85
|
+
try:
|
86
|
+
if (res := forward_request("pl_stacked_violin", request, adinfo)) is not None:
|
87
|
+
return res
|
88
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
89
|
+
fig_path = sc_like_plot(sc.pl.stacked_violin, adata, request, adinfo)
|
90
|
+
return {"figpath": fig_path}
|
91
|
+
except ToolError as e:
|
92
|
+
raise ToolError(e)
|
93
|
+
except Exception as e:
|
94
|
+
if hasattr(e, '__context__') and e.__context__:
|
95
|
+
raise ToolError(e.__context__)
|
96
|
+
else:
|
97
|
+
raise ToolError(e)
|
98
|
+
return _stacked_violin
|
40
99
|
|
41
|
-
|
42
|
-
async def
|
43
|
-
|
44
|
-
|
45
|
-
):
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
raise ToolError(e.__context__)
|
59
|
-
else:
|
60
|
-
raise ToolError(e)
|
100
|
+
def _tool_heatmap(self):
|
101
|
+
async def _heatmap(request: HeatmapModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
102
|
+
"""Heatmap of the expression values of genes."""
|
103
|
+
try:
|
104
|
+
if (res := forward_request("pl_heatmap", request, adinfo)) is not None:
|
105
|
+
return res
|
106
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
107
|
+
fig_path = sc_like_plot(sc.pl.heatmap, adata, request, adinfo)
|
108
|
+
return {"figpath": fig_path}
|
109
|
+
except ToolError as e:
|
110
|
+
raise ToolError(e)
|
111
|
+
except Exception as e:
|
112
|
+
if hasattr(e, '__context__') and e.__context__:
|
113
|
+
raise ToolError(e.__context__)
|
114
|
+
else:
|
115
|
+
raise ToolError(e)
|
116
|
+
return _heatmap
|
61
117
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
):
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
except Exception as e:
|
80
|
-
if hasattr(e, '__context__') and e.__context__:
|
81
|
-
raise ToolError(e.__context__)
|
82
|
-
else:
|
83
|
-
raise ToolError(e)
|
118
|
+
def _tool_dotplot(self):
|
119
|
+
def _dotplot(request: DotplotModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
120
|
+
"""Plot dot plot of expression values per gene for each group."""
|
121
|
+
try:
|
122
|
+
if (res := forward_request("pl_dotplot", request, adinfo)) is not None:
|
123
|
+
return res
|
124
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
125
|
+
fig_path = sc_like_plot(sc.pl.dotplot, adata, request, adinfo)
|
126
|
+
return {"figpath": fig_path}
|
127
|
+
except ToolError as e:
|
128
|
+
raise ToolError(e)
|
129
|
+
except Exception as e:
|
130
|
+
if hasattr(e, '__context__') and e.__context__:
|
131
|
+
raise ToolError(e.__context__)
|
132
|
+
else:
|
133
|
+
raise ToolError(e)
|
134
|
+
return _dotplot
|
84
135
|
|
136
|
+
def _tool_matrixplot(self):
|
137
|
+
def _matrixplot(request: MatrixplotModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
138
|
+
"""matrixplot, Create a heatmap of the mean expression values per group of each var_names."""
|
139
|
+
try:
|
140
|
+
if (res := forward_request("pl_matrixplot", request, adinfo)) is not None:
|
141
|
+
return res
|
142
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
143
|
+
fig_path = sc_like_plot(sc.pl.matrixplot, adata, request, adinfo)
|
144
|
+
return {"figpath": fig_path}
|
145
|
+
except ToolError as e:
|
146
|
+
raise ToolError(e)
|
147
|
+
except Exception as e:
|
148
|
+
if hasattr(e, '__context__') and e.__context__:
|
149
|
+
raise ToolError(e.__context__)
|
150
|
+
else:
|
151
|
+
raise ToolError(e)
|
152
|
+
return _matrixplot
|
85
153
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
):
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
raise ToolError(e.__context__)
|
104
|
-
else:
|
105
|
-
raise ToolError(e)
|
154
|
+
def _tool_tracksplot(self):
|
155
|
+
def _tracksplot(request: TracksplotModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
156
|
+
"""tracksplot, compact plot of expression of a list of genes."""
|
157
|
+
try:
|
158
|
+
if (res := forward_request("pl_tracksplot", request, adinfo)) is not None:
|
159
|
+
return res
|
160
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
161
|
+
fig_path = sc_like_plot(sc.pl.tracksplot, adata, request, adinfo)
|
162
|
+
return {"figpath": fig_path}
|
163
|
+
except ToolError as e:
|
164
|
+
raise ToolError(e)
|
165
|
+
except Exception as e:
|
166
|
+
if hasattr(e, '__context__') and e.__context__:
|
167
|
+
raise ToolError(e.__context__)
|
168
|
+
else:
|
169
|
+
raise ToolError(e)
|
170
|
+
return _tracksplot
|
106
171
|
|
172
|
+
def _tool_scatter(self):
|
173
|
+
def _scatter(request: EnhancedScatterModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
174
|
+
"""Plot a scatter plot of two variables, Scatter plot along observations or variables axes."""
|
175
|
+
try:
|
176
|
+
if (res := forward_request("pl_scatter", request, adinfo)) is not None:
|
177
|
+
return res
|
178
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
179
|
+
fig_path = sc_like_plot(sc.pl.scatter, adata, request, adinfo)
|
180
|
+
return {"figpath": fig_path}
|
181
|
+
except ToolError as e:
|
182
|
+
raise ToolError(e)
|
183
|
+
except Exception as e:
|
184
|
+
if hasattr(e, '__context__') and e.__context__:
|
185
|
+
raise ToolError(e.__context__)
|
186
|
+
else:
|
187
|
+
raise ToolError(e)
|
188
|
+
return _scatter
|
107
189
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
):
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
raise ToolError(e.__context__)
|
126
|
-
else:
|
127
|
-
raise ToolError(e)
|
190
|
+
def _tool_embedding(self):
|
191
|
+
def _embedding(request: EmbeddingModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
192
|
+
"""Scatter plot for user specified embedding basis (e.g. umap, tsne, etc)."""
|
193
|
+
try:
|
194
|
+
if (res := forward_request("pl_embedding", request, adinfo)) is not None:
|
195
|
+
return res
|
196
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
197
|
+
fig_path = sc_like_plot(sc.pl.embedding, adata, request, adinfo)
|
198
|
+
return {"figpath": fig_path}
|
199
|
+
except KeyError as e:
|
200
|
+
raise ToolError(f"doest found {e} in current sampleid with adtype {adinfo.adtype}")
|
201
|
+
except Exception as e:
|
202
|
+
if hasattr(e, '__context__') and e.__context__:
|
203
|
+
raise ToolError(e.__context__)
|
204
|
+
else:
|
205
|
+
raise ToolError(e)
|
206
|
+
return _embedding
|
128
207
|
|
208
|
+
def _tool_embedding_density(self):
|
209
|
+
def _embedding_density(request: EmbeddingDensityModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
210
|
+
"""Plot the density of cells in an embedding."""
|
211
|
+
try:
|
212
|
+
if (res := forward_request("pl_embedding_density", request, adinfo)) is not None:
|
213
|
+
return res
|
214
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
215
|
+
fig_path = sc_like_plot(sc.pl.embedding_density, adata, request, adinfo)
|
216
|
+
return {"figpath": fig_path}
|
217
|
+
except ToolError as e:
|
218
|
+
raise ToolError(e)
|
219
|
+
except Exception as e:
|
220
|
+
if hasattr(e, '__context__') and e.__context__:
|
221
|
+
raise ToolError(e.__context__)
|
222
|
+
else:
|
223
|
+
raise ToolError(e)
|
224
|
+
return _embedding_density
|
129
225
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
):
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
raise ToolError(e.__context__)
|
148
|
-
else:
|
149
|
-
raise ToolError(e)
|
226
|
+
def _tool_rank_genes_groups(self):
|
227
|
+
def _rank_genes_groups(request: RankGenesGroupsModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
228
|
+
"""Plot ranking of genes based on differential expression."""
|
229
|
+
try:
|
230
|
+
if (res := forward_request("pl_rank_genes_groups", request, adinfo)) is not None:
|
231
|
+
return res
|
232
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
233
|
+
fig_path = sc_like_plot(sc.pl.rank_genes_groups, adata, request, adinfo)
|
234
|
+
return {"figpath": fig_path}
|
235
|
+
except ToolError as e:
|
236
|
+
raise ToolError(e)
|
237
|
+
except Exception as e:
|
238
|
+
if hasattr(e, '__context__') and e.__context__:
|
239
|
+
raise ToolError(e.__context__)
|
240
|
+
else:
|
241
|
+
raise ToolError(e)
|
242
|
+
return _rank_genes_groups
|
150
243
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
):
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
raise ToolError(e.__context__)
|
169
|
-
else:
|
170
|
-
raise ToolError(e)
|
244
|
+
def _tool_rank_genes_groups_dotplot(self):
|
245
|
+
def _rank_genes_groups_dotplot(request: RankGenesGroupsDotplotModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
246
|
+
"""Plot ranking of genes(DEGs) using dotplot visualization. Defualt plot DEGs for rank_genes_groups tool"""
|
247
|
+
try:
|
248
|
+
if (res := forward_request("pl_rank_genes_groups_dotplot", request, adinfo)) is not None:
|
249
|
+
return res
|
250
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
251
|
+
fig_path = sc_like_plot(sc.pl.rank_genes_groups_dotplot, adata, request, adinfo)
|
252
|
+
return {"figpath": fig_path}
|
253
|
+
except ToolError as e:
|
254
|
+
raise ToolError(e)
|
255
|
+
except Exception as e:
|
256
|
+
if hasattr(e, '__context__') and e.__context__:
|
257
|
+
raise ToolError(e.__context__)
|
258
|
+
else:
|
259
|
+
raise ToolError(e)
|
260
|
+
return _rank_genes_groups_dotplot
|
171
261
|
|
262
|
+
def _tool_clustermap(self):
|
263
|
+
def _clustermap(request: ClusterMapModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
264
|
+
"""Plot hierarchical clustering of cells and genes."""
|
265
|
+
try:
|
266
|
+
if (res := forward_request("pl_clustermap", request, adinfo)) is not None:
|
267
|
+
return res
|
268
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
269
|
+
fig_path = sc_like_plot(sc.pl.clustermap, adata, request, adinfo)
|
270
|
+
return {"figpath": fig_path}
|
271
|
+
except ToolError as e:
|
272
|
+
raise ToolError(e)
|
273
|
+
except Exception as e:
|
274
|
+
if hasattr(e, '__context__') and e.__context__:
|
275
|
+
raise ToolError(e.__context__)
|
276
|
+
else:
|
277
|
+
raise ToolError(e)
|
278
|
+
return _clustermap
|
172
279
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
):
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
raise ToolError(e.__context__)
|
191
|
-
else:
|
192
|
-
raise ToolError(e)
|
280
|
+
def _tool_highly_variable_genes(self):
|
281
|
+
def _highly_variable_genes(request: HighlyVariableGenesModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
282
|
+
"""plot highly variable genes; Plot dispersions or normalized variance versus means for genes."""
|
283
|
+
try:
|
284
|
+
if (res := forward_request("pl_highly_variable_genes", request, adinfo)) is not None:
|
285
|
+
return res
|
286
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
287
|
+
fig_path = sc_like_plot(sc.pl.highly_variable_genes, adata, request, adinfo)
|
288
|
+
return {"figpath": fig_path}
|
289
|
+
except ToolError as e:
|
290
|
+
raise ToolError(e)
|
291
|
+
except Exception as e:
|
292
|
+
if hasattr(e, '__context__') and e.__context__:
|
293
|
+
raise ToolError(e.__context__)
|
294
|
+
else:
|
295
|
+
raise ToolError(e)
|
296
|
+
return _highly_variable_genes
|
193
297
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
):
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
raise ToolError(e.__context__)
|
212
|
-
else:
|
213
|
-
raise ToolError(e)
|
298
|
+
def _tool_pca_variance_ratio(self):
|
299
|
+
def _pca_variance_ratio(request: PCAVarianceRatioModel, adinfo: self.AdataInfo=self.AdataInfo()):
|
300
|
+
"""Plot the PCA variance ratio to visualize explained variance."""
|
301
|
+
try:
|
302
|
+
if (res := forward_request("pl_pca_variance_ratio", request, adinfo)) is not None:
|
303
|
+
return res
|
304
|
+
adata = get_ads().get_adata(adinfo=adinfo)
|
305
|
+
fig_path = sc_like_plot(sc.pl.pca_variance_ratio, adata, request, adinfo)
|
306
|
+
return {"figpath": fig_path}
|
307
|
+
except ToolError as e:
|
308
|
+
raise ToolError(e)
|
309
|
+
except Exception as e:
|
310
|
+
if hasattr(e, '__context__') and e.__context__:
|
311
|
+
raise ToolError(e.__context__)
|
312
|
+
else:
|
313
|
+
raise ToolError(e)
|
314
|
+
return _pca_variance_ratio
|
214
315
|
|
215
|
-
@pl_mcp.tool()
|
216
|
-
async def embedding(
|
217
|
-
request: EmbeddingModel,
|
218
|
-
adinfo: AdataModel = AdataModel()
|
219
|
-
):
|
220
|
-
"""Scatter plot for user specified embedding basis (e.g. umap, tsne, etc)."""
|
221
|
-
try:
|
222
|
-
result = await forward_request("pl_embedding", request, adinfo)
|
223
|
-
if result is not None:
|
224
|
-
return result
|
225
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
226
|
-
fig_path = sc_like_plot(sc.pl.embedding, adata, request,adinfo)
|
227
|
-
return {"figpath": fig_path}
|
228
|
-
except KeyError as e:
|
229
|
-
raise ToolError(f"doest found {e} in current sampleid with adtype {adinfo.adtype}")
|
230
|
-
except Exception as e:
|
231
|
-
if hasattr(e, '__context__') and e.__context__:
|
232
|
-
raise ToolError(e.__context__)
|
233
|
-
else:
|
234
|
-
raise ToolError(e)
|
235
|
-
|
236
|
-
|
237
|
-
@pl_mcp.tool()
|
238
|
-
async def embedding_density(
|
239
|
-
request: EmbeddingDensityModel,
|
240
|
-
adinfo: AdataModel = AdataModel()
|
241
|
-
):
|
242
|
-
"""Plot the density of cells in an embedding."""
|
243
|
-
try:
|
244
|
-
result = await forward_request("pl_embedding_density", request, adinfo)
|
245
|
-
if result is not None:
|
246
|
-
return result
|
247
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
248
|
-
fig_path = sc_like_plot(sc.pl.embedding_density, adata, request,adinfo)
|
249
|
-
return {"figpath": fig_path}
|
250
|
-
except ToolError as e:
|
251
|
-
raise ToolError(e)
|
252
|
-
except Exception as e:
|
253
|
-
if hasattr(e, '__context__') and e.__context__:
|
254
|
-
raise ToolError(e.__context__)
|
255
|
-
else:
|
256
|
-
raise ToolError(e)
|
257
|
-
|
258
|
-
@pl_mcp.tool()
|
259
|
-
async def rank_genes_groups(
|
260
|
-
request: RankGenesGroupsModel,
|
261
|
-
adinfo: AdataModel = AdataModel()
|
262
|
-
):
|
263
|
-
"""Plot ranking of genes based on differential expression."""
|
264
|
-
try:
|
265
|
-
result = await forward_request("pl_rank_genes_groups", request, adinfo)
|
266
|
-
if result is not None:
|
267
|
-
return result
|
268
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
269
|
-
fig_path = sc_like_plot(sc.pl.rank_genes_groups, adata, request,adinfo)
|
270
|
-
return {"figpath": fig_path}
|
271
|
-
except ToolError as e:
|
272
|
-
raise ToolError(e)
|
273
|
-
except Exception as e:
|
274
|
-
if hasattr(e, '__context__') and e.__context__:
|
275
|
-
raise ToolError(e.__context__)
|
276
|
-
else:
|
277
|
-
raise ToolError(e)
|
278
|
-
|
279
|
-
|
280
|
-
@pl_mcp.tool()
|
281
|
-
async def rank_genes_groups_dotplot(
|
282
|
-
request: RankGenesGroupsDotplotModel,
|
283
|
-
adinfo: AdataModel = AdataModel()
|
284
|
-
):
|
285
|
-
"""Plot ranking of genes(DEGs) using dotplot visualization. Defualt plot DEGs for rank_genes_groups tool"""
|
286
|
-
from fastmcp.exceptions import ClientError
|
287
|
-
try:
|
288
|
-
result = await forward_request("pl_rank_genes_groups_dotplot", request, adinfo)
|
289
|
-
if result is not None:
|
290
|
-
return result
|
291
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
292
|
-
fig_path = sc_like_plot(sc.pl.rank_genes_groups_dotplot, adata, request,adinfo)
|
293
|
-
return {"figpath": fig_path}
|
294
|
-
except ToolError as e:
|
295
|
-
raise ToolError(e)
|
296
|
-
except Exception as e:
|
297
|
-
if hasattr(e, '__context__') and e.__context__:
|
298
|
-
raise ToolError(e.__context__)
|
299
|
-
else:
|
300
|
-
raise ToolError(e)
|
301
|
-
|
302
|
-
|
303
|
-
@pl_mcp.tool()
|
304
|
-
async def clustermap(
|
305
|
-
request: ClusterMapModel = ClusterMapModel(),
|
306
|
-
adinfo: AdataModel = AdataModel()
|
307
|
-
):
|
308
|
-
"""Plot hierarchical clustering of cells and genes."""
|
309
|
-
try:
|
310
|
-
result = await forward_request("pl_clustermap", request, adinfo)
|
311
|
-
if result is not None:
|
312
|
-
return result
|
313
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
314
|
-
fig_path = sc_like_plot(sc.pl.clustermap, adata, request,adinfo)
|
315
|
-
return {"figpath": fig_path}
|
316
|
-
except ToolError as e:
|
317
|
-
raise ToolError(e)
|
318
|
-
except Exception as e:
|
319
|
-
if hasattr(e, '__context__') and e.__context__:
|
320
|
-
raise ToolError(e.__context__)
|
321
|
-
else:
|
322
|
-
raise ToolError(e)
|
323
|
-
|
324
|
-
@pl_mcp.tool()
|
325
|
-
async def highly_variable_genes(
|
326
|
-
request: HighlyVariableGenesModel = HighlyVariableGenesModel(),
|
327
|
-
adinfo: AdataModel = AdataModel()
|
328
|
-
):
|
329
|
-
"""plot highly variable genes; Plot dispersions or normalized variance versus means for genes."""
|
330
|
-
try:
|
331
|
-
result = await forward_request("pl_highly_variable_genes", request, adinfo)
|
332
|
-
if result is not None:
|
333
|
-
return result
|
334
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
335
|
-
fig_path = sc_like_plot(sc.pl.highly_variable_genes, adata, request,adinfo)
|
336
|
-
return {"figpath": fig_path}
|
337
|
-
except ToolError as e:
|
338
|
-
raise ToolError(e)
|
339
|
-
except Exception as e:
|
340
|
-
if hasattr(e, '__context__') and e.__context__:
|
341
|
-
raise ToolError(e.__context__)
|
342
|
-
else:
|
343
|
-
raise ToolError(e)
|
344
|
-
|
345
|
-
|
346
|
-
@pl_mcp.tool()
|
347
|
-
async def pca_variance_ratio(
|
348
|
-
request: PCAVarianceRatioModel = PCAVarianceRatioModel(),
|
349
|
-
adinfo: AdataModel = AdataModel()
|
350
|
-
):
|
351
|
-
"""Plot the PCA variance ratio to visualize explained variance."""
|
352
|
-
### there is some bug, as scanpy.pl.pca_variance_ratio didn't return axis
|
353
|
-
try:
|
354
|
-
result = await forward_request("pl_pca_variance_ratio", request, adinfo)
|
355
|
-
if result is not None:
|
356
|
-
return result
|
357
|
-
adata = get_ads().get_adata(adinfo=adinfo)
|
358
|
-
fig_path = sc_like_plot(sc.pl.pca_variance_ratio, adata, request,adinfo)
|
359
|
-
return {"figpath": fig_path}
|
360
|
-
except ToolError as e:
|
361
|
-
raise ToolError(e)
|
362
|
-
except Exception as e:
|
363
|
-
if hasattr(e, '__context__') and e.__context__:
|
364
|
-
raise ToolError(e.__context__)
|
365
|
-
else:
|
366
|
-
raise ToolError(e)
|