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