@nahisaho/satori 0.9.0 → 0.11.0
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.
- package/README.md +188 -39
- package/package.json +1 -1
- package/src/.github/skills/scientific-clinical-trials-analytics/SKILL.md +340 -0
- package/src/.github/skills/scientific-computational-materials/SKILL.md +353 -0
- package/src/.github/skills/scientific-environmental-ecology/SKILL.md +295 -0
- package/src/.github/skills/scientific-epidemiology-public-health/SKILL.md +332 -0
- package/src/.github/skills/scientific-epigenomics-chromatin/SKILL.md +567 -0
- package/src/.github/skills/scientific-gene-expression-transcriptomics/SKILL.md +330 -0
- package/src/.github/skills/scientific-immunoinformatics/SKILL.md +341 -0
- package/src/.github/skills/scientific-infectious-disease/SKILL.md +342 -0
- package/src/.github/skills/scientific-lab-data-management/SKILL.md +334 -0
- package/src/.github/skills/scientific-microbiome-metagenomics/SKILL.md +349 -0
- package/src/.github/skills/scientific-neuroscience-electrophysiology/SKILL.md +400 -0
- package/src/.github/skills/scientific-pharmacogenomics/SKILL.md +342 -0
- package/src/.github/skills/scientific-population-genetics/SKILL.md +336 -0
- package/src/.github/skills/scientific-proteomics-mass-spectrometry/SKILL.md +401 -0
- package/src/.github/skills/scientific-regulatory-science/SKILL.md +256 -0
- package/src/.github/skills/scientific-scientific-schematics/SKILL.md +336 -0
- package/src/.github/skills/scientific-single-cell-genomics/SKILL.md +361 -0
- package/src/.github/skills/scientific-spatial-transcriptomics/SKILL.md +281 -0
- package/src/.github/skills/scientific-systems-biology/SKILL.md +310 -0
- package/src/.github/skills/scientific-text-mining-nlp/SKILL.md +358 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-scientific-schematics
|
|
3
|
+
description: |
|
|
4
|
+
科学図式・作図スキル。CONSORT フロー図 (臨床試験)、実験プロトコルフロー、
|
|
5
|
+
ニューラルネットワークアーキテクチャ図、分子パスウェイ図、
|
|
6
|
+
TikZ/SVG/Mermaid ベースの出版品質ベクター図の生成、
|
|
7
|
+
AI レビューによる図の反復改善。
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scientific Schematics
|
|
11
|
+
|
|
12
|
+
研究論文・プレゼンテーション向けの科学図式を
|
|
13
|
+
プログラマティックに生成するパイプライン。
|
|
14
|
+
CONSORT フロー図、NN アーキテクチャ図、パスウェイ図等を
|
|
15
|
+
TikZ / SVG / Mermaid で出版品質のベクター形式として出力する。
|
|
16
|
+
|
|
17
|
+
## When to Use
|
|
18
|
+
|
|
19
|
+
- 臨床試験の CONSORT フロー図を作成するとき
|
|
20
|
+
- ニューラルネットワークアーキテクチャの図を生成するとき
|
|
21
|
+
- 分子パスウェイ・シグナル伝達経路図を描くとき
|
|
22
|
+
- 実験プロトコルのフローチャートが必要なとき
|
|
23
|
+
- 出版品質の SVG/PDF ベクター図を作成するとき
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
## 1. CONSORT フロー図
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import json
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def generate_consort_diagram(enrollment, allocation_arms,
|
|
36
|
+
followup_lost, analyzed,
|
|
37
|
+
output_file="figures/consort_flow.svg"):
|
|
38
|
+
"""
|
|
39
|
+
CONSORT (Consolidated Standards of Reporting Trials) フロー図。
|
|
40
|
+
|
|
41
|
+
CONSORT 2010 チェックリスト準拠:
|
|
42
|
+
- Enrollment: 適格性評価 → 除外/ランダム化
|
|
43
|
+
- Allocation: 各群への割付
|
|
44
|
+
- Follow-up: 追跡 (脱落・中止)
|
|
45
|
+
- Analysis: 解析対象
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# SVG 生成
|
|
49
|
+
svg_width = 800
|
|
50
|
+
svg_height = 900
|
|
51
|
+
box_width = 200
|
|
52
|
+
box_height = 60
|
|
53
|
+
|
|
54
|
+
svg_elements = []
|
|
55
|
+
svg_elements.append(
|
|
56
|
+
f'<svg xmlns="http://www.w3.org/2000/svg" '
|
|
57
|
+
f'width="{svg_width}" height="{svg_height}" '
|
|
58
|
+
f'viewBox="0 0 {svg_width} {svg_height}">'
|
|
59
|
+
)
|
|
60
|
+
svg_elements.append(
|
|
61
|
+
'<style>'
|
|
62
|
+
'.box { fill: white; stroke: black; stroke-width: 1.5; }'
|
|
63
|
+
'.text { font-family: Arial; font-size: 12px; text-anchor: middle; }'
|
|
64
|
+
'.label { font-family: Arial; font-size: 14px; font-weight: bold; }'
|
|
65
|
+
'.arrow { stroke: black; stroke-width: 1.5; marker-end: url(#arrowhead); }'
|
|
66
|
+
'</style>'
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Arrowhead marker
|
|
70
|
+
svg_elements.append(
|
|
71
|
+
'<defs><marker id="arrowhead" markerWidth="10" markerHeight="7" '
|
|
72
|
+
'refX="10" refY="3.5" orient="auto">'
|
|
73
|
+
'<polygon points="0 0, 10 3.5, 0 7" fill="black"/>'
|
|
74
|
+
'</marker></defs>'
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Enrollment box
|
|
78
|
+
cx = svg_width // 2
|
|
79
|
+
y = 30
|
|
80
|
+
svg_elements.append(
|
|
81
|
+
f'<rect class="box" x="{cx - box_width//2}" y="{y}" '
|
|
82
|
+
f'width="{box_width}" height="{box_height}" rx="5"/>'
|
|
83
|
+
)
|
|
84
|
+
svg_elements.append(
|
|
85
|
+
f'<text class="text" x="{cx}" y="{y + 25}">Assessed for eligibility</text>'
|
|
86
|
+
)
|
|
87
|
+
svg_elements.append(
|
|
88
|
+
f'<text class="text" x="{cx}" y="{y + 42}">(n={enrollment})</text>'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
print(f" CONSORT flow diagram generated: {output_file}")
|
|
92
|
+
print(f" Enrollment: {enrollment}")
|
|
93
|
+
print(f" Arms: {len(allocation_arms)}")
|
|
94
|
+
print(f" Analyzed: {analyzed}")
|
|
95
|
+
|
|
96
|
+
svg_elements.append('</svg>')
|
|
97
|
+
svg_content = '\n'.join(svg_elements)
|
|
98
|
+
|
|
99
|
+
with open(output_file, 'w') as f:
|
|
100
|
+
f.write(svg_content)
|
|
101
|
+
|
|
102
|
+
return output_file
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## 2. ニューラルネットワークアーキテクチャ図
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
import json
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def generate_nn_architecture(layers, title="Neural Network Architecture",
|
|
112
|
+
output_file="figures/nn_architecture.svg"):
|
|
113
|
+
"""
|
|
114
|
+
ニューラルネットワークアーキテクチャ図の SVG 生成。
|
|
115
|
+
|
|
116
|
+
レイヤー定義例:
|
|
117
|
+
layers = [
|
|
118
|
+
{"name": "Input", "type": "input", "shape": "(B, 3, 224, 224)"},
|
|
119
|
+
{"name": "Conv1", "type": "conv", "params": "64 filters, 3×3"},
|
|
120
|
+
{"name": "BatchNorm", "type": "norm", "params": "64"},
|
|
121
|
+
{"name": "ReLU", "type": "activation"},
|
|
122
|
+
{"name": "MaxPool", "type": "pool", "params": "2×2"},
|
|
123
|
+
{"name": "FC", "type": "dense", "params": "512 → 10"},
|
|
124
|
+
{"name": "Softmax", "type": "output", "shape": "(B, 10)"},
|
|
125
|
+
]
|
|
126
|
+
"""
|
|
127
|
+
# 色マッピング
|
|
128
|
+
type_colors = {
|
|
129
|
+
"input": "#E8F5E9",
|
|
130
|
+
"conv": "#BBDEFB",
|
|
131
|
+
"norm": "#F3E5F5",
|
|
132
|
+
"activation": "#FFF9C4",
|
|
133
|
+
"pool": "#FFE0B2",
|
|
134
|
+
"dense": "#B2DFDB",
|
|
135
|
+
"attention": "#F8BBD0",
|
|
136
|
+
"residual": "#D1C4E9",
|
|
137
|
+
"output": "#FFCDD2",
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
svg_width = 300
|
|
141
|
+
box_height = 50
|
|
142
|
+
box_width = 240
|
|
143
|
+
gap = 15
|
|
144
|
+
svg_height = len(layers) * (box_height + gap) + 80
|
|
145
|
+
|
|
146
|
+
svg_parts = []
|
|
147
|
+
svg_parts.append(
|
|
148
|
+
f'<svg xmlns="http://www.w3.org/2000/svg" '
|
|
149
|
+
f'width="{svg_width}" height="{svg_height}">'
|
|
150
|
+
)
|
|
151
|
+
svg_parts.append(
|
|
152
|
+
'<style>.lbl{font-family:monospace;font-size:11px;text-anchor:middle;}</style>'
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
y = 40
|
|
156
|
+
cx = svg_width // 2
|
|
157
|
+
|
|
158
|
+
# Title
|
|
159
|
+
svg_parts.append(f'<text x="{cx}" y="20" '
|
|
160
|
+
f'style="font-family:Arial;font-size:14px;font-weight:bold;'
|
|
161
|
+
f'text-anchor:middle;">{title}</text>')
|
|
162
|
+
|
|
163
|
+
for i, layer in enumerate(layers):
|
|
164
|
+
color = type_colors.get(layer.get("type", ""), "#FFFFFF")
|
|
165
|
+
svg_parts.append(
|
|
166
|
+
f'<rect x="{cx - box_width//2}" y="{y}" '
|
|
167
|
+
f'width="{box_width}" height="{box_height}" '
|
|
168
|
+
f'rx="5" fill="{color}" stroke="#333" stroke-width="1"/>'
|
|
169
|
+
)
|
|
170
|
+
svg_parts.append(
|
|
171
|
+
f'<text class="lbl" x="{cx}" y="{y + 20}">{layer["name"]}</text>'
|
|
172
|
+
)
|
|
173
|
+
extra = layer.get("params", layer.get("shape", ""))
|
|
174
|
+
if extra:
|
|
175
|
+
svg_parts.append(
|
|
176
|
+
f'<text class="lbl" x="{cx}" y="{y + 36}" '
|
|
177
|
+
f'style="font-size:9px;fill:#666;">{extra}</text>'
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Arrow
|
|
181
|
+
if i < len(layers) - 1:
|
|
182
|
+
arrow_y = y + box_height
|
|
183
|
+
svg_parts.append(
|
|
184
|
+
f'<line x1="{cx}" y1="{arrow_y}" '
|
|
185
|
+
f'x2="{cx}" y2="{arrow_y + gap}" '
|
|
186
|
+
f'stroke="#333" stroke-width="1.5" marker-end="url(#arrowhead)"/>'
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
y += box_height + gap
|
|
190
|
+
|
|
191
|
+
svg_parts.append('</svg>')
|
|
192
|
+
|
|
193
|
+
with open(output_file, 'w') as f:
|
|
194
|
+
f.write('\n'.join(svg_parts))
|
|
195
|
+
|
|
196
|
+
print(f" NN architecture diagram: {output_file}")
|
|
197
|
+
print(f" Layers: {len(layers)}")
|
|
198
|
+
|
|
199
|
+
return output_file
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 3. 分子パスウェイ図 (Mermaid)
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
def generate_pathway_mermaid(pathway_name, nodes, edges,
|
|
206
|
+
output_file="figures/pathway.md"):
|
|
207
|
+
"""
|
|
208
|
+
分子パスウェイ / シグナル伝達経路の Mermaid 図生成。
|
|
209
|
+
|
|
210
|
+
ノードタイプ:
|
|
211
|
+
- receptor: 受容体 (細胞膜)
|
|
212
|
+
- kinase: キナーゼ
|
|
213
|
+
- tf: 転写因子
|
|
214
|
+
- gene: 標的遺伝子
|
|
215
|
+
- metabolite: 代謝産物
|
|
216
|
+
"""
|
|
217
|
+
mermaid_lines = ["```mermaid", "graph TD"]
|
|
218
|
+
|
|
219
|
+
# ノード定義
|
|
220
|
+
node_shapes = {
|
|
221
|
+
"receptor": ("([", "])"), # Stadium
|
|
222
|
+
"kinase": ("{{", "}}"), # Hexagon
|
|
223
|
+
"tf": ("[[", "]]"), # Subroutine
|
|
224
|
+
"gene": ("[/", "/]"), # Parallelogram
|
|
225
|
+
"metabolite": ("((", "))"), # Circle
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
for node in nodes:
|
|
229
|
+
nid = node["id"]
|
|
230
|
+
label = node["label"]
|
|
231
|
+
ntype = node.get("type", "default")
|
|
232
|
+
l_bracket, r_bracket = node_shapes.get(ntype, ("[", "]"))
|
|
233
|
+
mermaid_lines.append(f" {nid}{l_bracket}{label}{r_bracket}")
|
|
234
|
+
|
|
235
|
+
# エッジ定義
|
|
236
|
+
for edge in edges:
|
|
237
|
+
src = edge["from"]
|
|
238
|
+
tgt = edge["to"]
|
|
239
|
+
label = edge.get("label", "")
|
|
240
|
+
etype = edge.get("type", "activate")
|
|
241
|
+
|
|
242
|
+
if etype == "activate":
|
|
243
|
+
arrow = f"-->|{label}|" if label else "-->"
|
|
244
|
+
elif etype == "inhibit":
|
|
245
|
+
arrow = f"-.->|{label}|" if label else "-.->"
|
|
246
|
+
elif etype == "phosphorylate":
|
|
247
|
+
arrow = f"==>|{label}|" if label else "==>"
|
|
248
|
+
else:
|
|
249
|
+
arrow = "-->"
|
|
250
|
+
|
|
251
|
+
mermaid_lines.append(f" {src} {arrow} {tgt}")
|
|
252
|
+
|
|
253
|
+
mermaid_lines.append("```")
|
|
254
|
+
|
|
255
|
+
content = '\n'.join(mermaid_lines)
|
|
256
|
+
|
|
257
|
+
with open(output_file, 'w') as f:
|
|
258
|
+
f.write(content)
|
|
259
|
+
|
|
260
|
+
print(f" Pathway diagram: {output_file}")
|
|
261
|
+
print(f" Nodes: {len(nodes)}, Edges: {len(edges)}")
|
|
262
|
+
|
|
263
|
+
return output_file
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 4. TikZ 出版品質図
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
def generate_tikz_figure(tikz_code, output_file="figures/tikz_figure.tex",
|
|
270
|
+
compile_pdf=True):
|
|
271
|
+
"""
|
|
272
|
+
TikZ (LaTeX) ベースの出版品質ベクター図。
|
|
273
|
+
|
|
274
|
+
テンプレート:
|
|
275
|
+
- 実験プロトコルフロー
|
|
276
|
+
- 統計解析ワークフロー
|
|
277
|
+
- 比較テーブル
|
|
278
|
+
- タイムライン (研究計画)
|
|
279
|
+
"""
|
|
280
|
+
latex_template = r"""\documentclass[border=5pt]{standalone}
|
|
281
|
+
\usepackage{tikz}
|
|
282
|
+
\usetikzlibrary{arrows.meta, positioning, shapes.geometric, calc}
|
|
283
|
+
\begin{document}
|
|
284
|
+
%s
|
|
285
|
+
\end{document}""" % tikz_code
|
|
286
|
+
|
|
287
|
+
with open(output_file, 'w') as f:
|
|
288
|
+
f.write(latex_template)
|
|
289
|
+
|
|
290
|
+
if compile_pdf:
|
|
291
|
+
import subprocess
|
|
292
|
+
import os
|
|
293
|
+
out_dir = os.path.dirname(output_file)
|
|
294
|
+
subprocess.run(
|
|
295
|
+
["pdflatex", "-output-directory", out_dir, output_file],
|
|
296
|
+
capture_output=True, timeout=30
|
|
297
|
+
)
|
|
298
|
+
pdf_file = output_file.replace(".tex", ".pdf")
|
|
299
|
+
print(f" TikZ compiled: {pdf_file}")
|
|
300
|
+
else:
|
|
301
|
+
print(f" TikZ source: {output_file}")
|
|
302
|
+
|
|
303
|
+
return output_file
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## References
|
|
307
|
+
|
|
308
|
+
### Output Files
|
|
309
|
+
|
|
310
|
+
| ファイル | 形式 |
|
|
311
|
+
|---|---|
|
|
312
|
+
| `figures/consort_flow.svg` | SVG |
|
|
313
|
+
| `figures/nn_architecture.svg` | SVG |
|
|
314
|
+
| `figures/pathway.md` | Mermaid Markdown |
|
|
315
|
+
| `figures/tikz_figure.tex` | LaTeX/TikZ |
|
|
316
|
+
| `figures/tikz_figure.pdf` | PDF |
|
|
317
|
+
|
|
318
|
+
### 利用可能ツール
|
|
319
|
+
|
|
320
|
+
> [ToolUniverse](https://github.com/mims-harvard/ToolUniverse) SMCP 経由で利用可能な外部ツール。
|
|
321
|
+
|
|
322
|
+
なし — ローカル SVG/TikZ/Mermaid 生成。
|
|
323
|
+
|
|
324
|
+
### 参照スキル
|
|
325
|
+
|
|
326
|
+
| スキル | 関連 |
|
|
327
|
+
|---|---|
|
|
328
|
+
| `scientific-visualization` | データ可視化全般 |
|
|
329
|
+
| `scientific-clinical-trials-analytics` | CONSORT 図のデータソース |
|
|
330
|
+
| `scientific-grant-writing` | 研究計画図 |
|
|
331
|
+
| `scientific-network-analysis` | ネットワーク図 |
|
|
332
|
+
| `scientific-presentation` | プレゼン素材 |
|
|
333
|
+
|
|
334
|
+
### 依存パッケージ
|
|
335
|
+
|
|
336
|
+
`json`, `os`, `subprocess` (TikZ コンパイル時のみ `texlive`)
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-single-cell-genomics
|
|
3
|
+
description: |
|
|
4
|
+
シングルセルゲノミクス解析スキル。scRNA-seq データの品質管理・正規化・
|
|
5
|
+
次元削減(PCA/UMAP)・クラスタリング(Leiden)・差次発現遺伝子(DEG)同定・
|
|
6
|
+
セルタイプアノテーション・RNA velocity・細胞間コミュニケーション推定パイプライン。
|
|
7
|
+
Scanpy / AnnData フレームワークに準拠。
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scientific Single-Cell Genomics
|
|
11
|
+
|
|
12
|
+
scRNA-seq / snRNA-seq データを対象に、QC → 正規化 → 高変動遺伝子選択 →
|
|
13
|
+
次元削減 → クラスタリング → DEG → セルタイプアノテーションの標準パイプラインを提供する。
|
|
14
|
+
CELLxGENE Census・HCA データポータルとの連携も組み込む。
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
- scRNA-seq / snRNA-seq データの解析パイプラインが必要なとき
|
|
19
|
+
- セルタイプのクラスタリングとアノテーションを行うとき
|
|
20
|
+
- クラスタ間の差次発現遺伝子を同定するとき
|
|
21
|
+
- RNA velocity による細胞分化軌跡を解析するとき
|
|
22
|
+
- CellChat / CellPhoneDB による細胞間コミュニケーション推定を行うとき
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
## 1. QC・前処理パイプライン
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import scanpy as sc
|
|
32
|
+
import numpy as np
|
|
33
|
+
import pandas as pd
|
|
34
|
+
|
|
35
|
+
def sc_qc_preprocessing(adata, min_genes=200, max_genes=5000,
|
|
36
|
+
max_pct_mito=20, min_cells=3):
|
|
37
|
+
"""
|
|
38
|
+
scRNA-seq 標準 QC パイプライン。
|
|
39
|
+
|
|
40
|
+
QC メトリクス:
|
|
41
|
+
- n_genes_by_counts: 細胞あたり検出遺伝子数
|
|
42
|
+
- total_counts: 細胞あたり総 UMI カウント
|
|
43
|
+
- pct_counts_mt: ミトコンドリア遺伝子比率(%)
|
|
44
|
+
|
|
45
|
+
フィルタリング基準:
|
|
46
|
+
- min_genes ≤ n_genes ≤ max_genes
|
|
47
|
+
- pct_mito ≤ max_pct_mito
|
|
48
|
+
- 遺伝子は min_cells 以上の細胞で発現
|
|
49
|
+
"""
|
|
50
|
+
# ミトコンドリア遺伝子のアノテーション
|
|
51
|
+
adata.var["mt"] = adata.var_names.str.startswith(("MT-", "mt-"))
|
|
52
|
+
sc.pp.calculate_qc_metrics(adata, qc_vars=["mt"], inplace=True)
|
|
53
|
+
|
|
54
|
+
n_before = adata.n_obs
|
|
55
|
+
# 細胞フィルタ
|
|
56
|
+
sc.pp.filter_cells(adata, min_genes=min_genes)
|
|
57
|
+
adata = adata[adata.obs["n_genes_by_counts"] <= max_genes].copy()
|
|
58
|
+
adata = adata[adata.obs["pct_counts_mt"] <= max_pct_mito].copy()
|
|
59
|
+
# 遺伝子フィルタ
|
|
60
|
+
sc.pp.filter_genes(adata, min_cells=min_cells)
|
|
61
|
+
|
|
62
|
+
n_after = adata.n_obs
|
|
63
|
+
print(f" QC: {n_before} → {n_after} cells ({n_before - n_after} removed)")
|
|
64
|
+
|
|
65
|
+
return adata
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def sc_normalize(adata, target_sum=1e4, n_top_genes=2000):
|
|
69
|
+
"""
|
|
70
|
+
正規化・HVG 選択パイプライン。
|
|
71
|
+
|
|
72
|
+
手順:
|
|
73
|
+
1. Library size normalization (target_sum)
|
|
74
|
+
2. Log1p 変換
|
|
75
|
+
3. Highly Variable Gene (HVG) 選択 (Seurat v3 法)
|
|
76
|
+
"""
|
|
77
|
+
adata.layers["counts"] = adata.X.copy()
|
|
78
|
+
sc.pp.normalize_total(adata, target_sum=target_sum)
|
|
79
|
+
sc.pp.log1p(adata)
|
|
80
|
+
adata.layers["log_normalized"] = adata.X.copy()
|
|
81
|
+
sc.pp.highly_variable_genes(adata, n_top_genes=n_top_genes, flavor="seurat_v3",
|
|
82
|
+
layer="counts")
|
|
83
|
+
print(f" HVG: {adata.var['highly_variable'].sum()} genes selected")
|
|
84
|
+
return adata
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 2. 次元削減・クラスタリング
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
def sc_clustering(adata, n_pcs=50, n_neighbors=15, resolution=1.0,
|
|
91
|
+
random_state=42):
|
|
92
|
+
"""
|
|
93
|
+
PCA → 近傍グラフ → UMAP → Leiden クラスタリング。
|
|
94
|
+
|
|
95
|
+
Parameters:
|
|
96
|
+
n_pcs: PCA 主成分数
|
|
97
|
+
n_neighbors: k-NN グラフの近傍数
|
|
98
|
+
resolution: Leiden クラスタリングの解像度
|
|
99
|
+
"""
|
|
100
|
+
sc.pp.scale(adata, max_value=10)
|
|
101
|
+
sc.tl.pca(adata, n_comps=n_pcs, random_state=random_state)
|
|
102
|
+
|
|
103
|
+
# Elbow plot 用の分散説明率
|
|
104
|
+
variance_ratio = adata.uns["pca"]["variance_ratio"]
|
|
105
|
+
cumvar = np.cumsum(variance_ratio)
|
|
106
|
+
n_pcs_use = int(np.argmax(cumvar >= 0.9)) + 1
|
|
107
|
+
n_pcs_use = max(n_pcs_use, 15)
|
|
108
|
+
print(f" PCA: using {n_pcs_use} PCs (cumulative variance ≥ 90%)")
|
|
109
|
+
|
|
110
|
+
sc.pp.neighbors(adata, n_pcs=n_pcs_use, n_neighbors=n_neighbors,
|
|
111
|
+
random_state=random_state)
|
|
112
|
+
sc.tl.umap(adata, random_state=random_state)
|
|
113
|
+
sc.tl.leiden(adata, resolution=resolution, random_state=random_state)
|
|
114
|
+
|
|
115
|
+
n_clusters = adata.obs["leiden"].nunique()
|
|
116
|
+
print(f" Leiden: {n_clusters} clusters (resolution={resolution})")
|
|
117
|
+
return adata
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 3. 差次発現遺伝子(DEG)同定
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
def sc_deg_analysis(adata, groupby="leiden", method="wilcoxon",
|
|
124
|
+
n_genes=200, min_logfc=0.25, max_pval=0.05):
|
|
125
|
+
"""
|
|
126
|
+
クラスタ間の差次発現遺伝子を同定する。
|
|
127
|
+
|
|
128
|
+
method:
|
|
129
|
+
- "wilcoxon": Wilcoxon rank-sum test(推奨)
|
|
130
|
+
- "t-test_overestim_var": Welch's t-test(高速)
|
|
131
|
+
- "logreg": Logistic regression
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
DataFrame with top DEGs per cluster
|
|
135
|
+
"""
|
|
136
|
+
sc.tl.rank_genes_groups(adata, groupby=groupby, method=method, n_genes=n_genes)
|
|
137
|
+
|
|
138
|
+
deg_results = []
|
|
139
|
+
for cluster in adata.obs[groupby].unique():
|
|
140
|
+
df = sc.get.rank_genes_groups_df(adata, group=cluster)
|
|
141
|
+
df["cluster"] = cluster
|
|
142
|
+
df_sig = df[(df["logfoldchanges"].abs() >= min_logfc) &
|
|
143
|
+
(df["pvals_adj"] < max_pval)]
|
|
144
|
+
deg_results.append(df_sig)
|
|
145
|
+
|
|
146
|
+
deg_df = pd.concat(deg_results, ignore_index=True)
|
|
147
|
+
print(f" DEG: {len(deg_df)} significant genes across {adata.obs[groupby].nunique()} clusters")
|
|
148
|
+
return deg_df
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## 4. セルタイプアノテーション
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
def annotate_celltypes_marker(adata, marker_dict, groupby="leiden",
|
|
155
|
+
threshold=0.5):
|
|
156
|
+
"""
|
|
157
|
+
マーカー遺伝子ベースのセルタイプアノテーション。
|
|
158
|
+
|
|
159
|
+
marker_dict 例:
|
|
160
|
+
{
|
|
161
|
+
"T cells": ["CD3D", "CD3E", "CD8A", "CD4"],
|
|
162
|
+
"B cells": ["CD19", "MS4A1", "CD79A"],
|
|
163
|
+
"Monocytes": ["CD14", "LYZ", "FCGR3A"],
|
|
164
|
+
"NK cells": ["NKG7", "GNLY", "KLRD1"],
|
|
165
|
+
"Dendritic": ["FCER1A", "CST3", "CLEC10A"],
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
各クラスタのマーカー遺伝子発現スコアを計算し、最も高いスコアに対応する
|
|
169
|
+
セルタイプをアサインする。
|
|
170
|
+
"""
|
|
171
|
+
sc.tl.score_genes(adata, gene_list=[], score_name="_dummy")
|
|
172
|
+
|
|
173
|
+
scores = {}
|
|
174
|
+
for cell_type, markers in marker_dict.items():
|
|
175
|
+
valid_markers = [m for m in markers if m in adata.var_names]
|
|
176
|
+
if valid_markers:
|
|
177
|
+
score_name = f"score_{cell_type.replace(' ', '_')}"
|
|
178
|
+
sc.tl.score_genes(adata, gene_list=valid_markers, score_name=score_name)
|
|
179
|
+
scores[cell_type] = score_name
|
|
180
|
+
|
|
181
|
+
# クラスタごとに最高スコアのセルタイプを割り当て
|
|
182
|
+
cluster_annotations = {}
|
|
183
|
+
for cluster in adata.obs[groupby].unique():
|
|
184
|
+
mask = adata.obs[groupby] == cluster
|
|
185
|
+
best_type = "Unknown"
|
|
186
|
+
best_score = -np.inf
|
|
187
|
+
for cell_type, score_col in scores.items():
|
|
188
|
+
mean_score = adata.obs.loc[mask, score_col].mean()
|
|
189
|
+
if mean_score > best_score and mean_score > threshold:
|
|
190
|
+
best_score = mean_score
|
|
191
|
+
best_type = cell_type
|
|
192
|
+
cluster_annotations[cluster] = best_type
|
|
193
|
+
|
|
194
|
+
adata.obs["cell_type"] = adata.obs[groupby].map(cluster_annotations)
|
|
195
|
+
print(f" Annotation: {len(set(cluster_annotations.values()))} cell types assigned")
|
|
196
|
+
return adata, cluster_annotations
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## 5. RNA Velocity
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
def rna_velocity_analysis(adata_loom_path, adata, basis="umap"):
|
|
203
|
+
"""
|
|
204
|
+
scVelo による RNA velocity 解析。
|
|
205
|
+
|
|
206
|
+
RNA velocity は、スプライシング状態(unspliced/spliced)の比率から
|
|
207
|
+
遺伝子発現の時間的変化方向を推定する。
|
|
208
|
+
|
|
209
|
+
Modes:
|
|
210
|
+
- stochastic: 確率的モデル(推奨、高速)
|
|
211
|
+
- dynamical: 動的モデル(精度高、低速)
|
|
212
|
+
"""
|
|
213
|
+
import scvelo as scv
|
|
214
|
+
|
|
215
|
+
# 前処理
|
|
216
|
+
scv.pp.filter_and_normalize(adata, min_shared_counts=20, n_top_genes=2000)
|
|
217
|
+
scv.pp.moments(adata, n_pcs=30, n_neighbors=30)
|
|
218
|
+
|
|
219
|
+
# Velocity 推定
|
|
220
|
+
scv.tl.velocity(adata, mode="stochastic")
|
|
221
|
+
scv.tl.velocity_graph(adata)
|
|
222
|
+
|
|
223
|
+
# 可視化
|
|
224
|
+
scv.pl.velocity_embedding_stream(adata, basis=basis,
|
|
225
|
+
save="figures/velocity_stream.png")
|
|
226
|
+
|
|
227
|
+
# Latent time(擬似時間)
|
|
228
|
+
scv.tl.latent_time(adata)
|
|
229
|
+
print(f" Velocity: latent time range [{adata.obs['latent_time'].min():.3f}, "
|
|
230
|
+
f"{adata.obs['latent_time'].max():.3f}]")
|
|
231
|
+
|
|
232
|
+
return adata
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 6. 細胞間コミュニケーション推定
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
def cell_communication_analysis(adata, groupby="cell_type",
|
|
239
|
+
database="CellChatDB.human"):
|
|
240
|
+
"""
|
|
241
|
+
CellChat によるリガンド-レセプター相互作用解析。
|
|
242
|
+
|
|
243
|
+
パイプライン:
|
|
244
|
+
1. L-R ペアデータベースのロード
|
|
245
|
+
2. 発現ベースのコミュニケーション確率計算
|
|
246
|
+
3. シグナリングネットワーク推定
|
|
247
|
+
4. 経路レベル集約
|
|
248
|
+
"""
|
|
249
|
+
import cellchat
|
|
250
|
+
|
|
251
|
+
cc = cellchat.CellChat(adata, groupby=groupby)
|
|
252
|
+
cc.preprocess()
|
|
253
|
+
cc.identify_overexpressed_genes()
|
|
254
|
+
cc.identify_overexpressed_interactions()
|
|
255
|
+
|
|
256
|
+
cc.compute_communication_prob(database=database)
|
|
257
|
+
cc.filter_communication(min_cells=10)
|
|
258
|
+
cc.compute_communication_prob_pathway()
|
|
259
|
+
|
|
260
|
+
# ネットワーク可視化
|
|
261
|
+
cc.aggregate_net()
|
|
262
|
+
cc.net_analysis()
|
|
263
|
+
|
|
264
|
+
# 結果取得
|
|
265
|
+
lr_pairs = cc.get_significant_interactions()
|
|
266
|
+
print(f" CellChat: {len(lr_pairs)} significant L-R interactions")
|
|
267
|
+
|
|
268
|
+
return cc, lr_pairs
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## 7. 可視化
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
def sc_visualization_panel(adata, deg_df=None, save_dir="figures"):
|
|
275
|
+
"""
|
|
276
|
+
シングルセル解析結果の可視化パネル。
|
|
277
|
+
|
|
278
|
+
生成図:
|
|
279
|
+
1. QC violin plot (n_genes, total_counts, pct_mito)
|
|
280
|
+
2. UMAP — leiden clusters
|
|
281
|
+
3. UMAP — cell types
|
|
282
|
+
4. DEG dot plot (top markers per cluster)
|
|
283
|
+
5. Marker heatmap
|
|
284
|
+
"""
|
|
285
|
+
import matplotlib.pyplot as plt
|
|
286
|
+
import os
|
|
287
|
+
os.makedirs(save_dir, exist_ok=True)
|
|
288
|
+
|
|
289
|
+
# 1. QC violin
|
|
290
|
+
sc.pl.violin(adata, ["n_genes_by_counts", "total_counts", "pct_counts_mt"],
|
|
291
|
+
jitter=0.4, multi_panel=True, save="_qc.png")
|
|
292
|
+
|
|
293
|
+
# 2. UMAP — clusters
|
|
294
|
+
sc.pl.umap(adata, color="leiden", legend_loc="on data",
|
|
295
|
+
title="Leiden Clusters", save="_leiden.png")
|
|
296
|
+
|
|
297
|
+
# 3. UMAP — cell types
|
|
298
|
+
if "cell_type" in adata.obs.columns:
|
|
299
|
+
sc.pl.umap(adata, color="cell_type",
|
|
300
|
+
title="Cell Type Annotation", save="_celltypes.png")
|
|
301
|
+
|
|
302
|
+
# 4. DEG dot plot
|
|
303
|
+
if deg_df is not None:
|
|
304
|
+
top_markers = deg_df.groupby("cluster").head(5)["names"].unique().tolist()
|
|
305
|
+
sc.pl.dotplot(adata, var_names=top_markers[:30],
|
|
306
|
+
groupby="leiden", save="_markers.png")
|
|
307
|
+
|
|
308
|
+
# 5. Stacked violin
|
|
309
|
+
if deg_df is not None:
|
|
310
|
+
top5 = deg_df.groupby("cluster").head(3)["names"].unique().tolist()[:20]
|
|
311
|
+
sc.pl.stacked_violin(adata, var_names=top5,
|
|
312
|
+
groupby="leiden", save="_stacked.png")
|
|
313
|
+
|
|
314
|
+
print(f" Figures saved to {save_dir}/")
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## References
|
|
318
|
+
|
|
319
|
+
### Output Files
|
|
320
|
+
|
|
321
|
+
| ファイル | 形式 |
|
|
322
|
+
|---|---|
|
|
323
|
+
| `results/sc_qc_summary.json` | JSON |
|
|
324
|
+
| `results/sc_deg_results.csv` | CSV |
|
|
325
|
+
| `results/sc_celltype_annotations.json` | JSON |
|
|
326
|
+
| `results/sc_velocity_summary.json` | JSON |
|
|
327
|
+
| `results/sc_cellchat_interactions.csv` | CSV |
|
|
328
|
+
| `figures/umap_leiden.png` | PNG |
|
|
329
|
+
| `figures/umap_celltypes.png` | PNG |
|
|
330
|
+
| `figures/velocity_stream.png` | PNG |
|
|
331
|
+
| `figures/deg_dotplot.png` | PNG |
|
|
332
|
+
|
|
333
|
+
### 利用可能ツール
|
|
334
|
+
|
|
335
|
+
> [ToolUniverse](https://github.com/mims-harvard/ToolUniverse) SMCP 経由で利用可能な外部ツール。
|
|
336
|
+
|
|
337
|
+
| カテゴリ | 主要ツール | 用途 |
|
|
338
|
+
|---|---|---|
|
|
339
|
+
| CELLxGENE | `CELLxGENE_get_expression_data` | シングルセル発現データ取得 |
|
|
340
|
+
| CELLxGENE | `CELLxGENE_get_cell_metadata` | 細胞メタデータ取得 |
|
|
341
|
+
| CELLxGENE | `CELLxGENE_get_gene_metadata` | 遺伝子メタデータ取得 |
|
|
342
|
+
| CELLxGENE | `CELLxGENE_get_presence_matrix` | 遺伝子存在マトリクス |
|
|
343
|
+
| CELLxGENE | `CELLxGENE_get_embeddings` | 埋め込みベクトル取得 |
|
|
344
|
+
| CELLxGENE | `CELLxGENE_download_h5ad` | H5AD ファイルダウンロード |
|
|
345
|
+
| HCA | `hca_search_projects` | Human Cell Atlas プロジェクト検索 |
|
|
346
|
+
| HCA | `hca_get_file_manifest` | HCA ファイルマニフェスト取得 |
|
|
347
|
+
| HPA | `HPA_get_rna_expression_by_source` | 組織別 RNA 発現データ |
|
|
348
|
+
|
|
349
|
+
### 参照スキル
|
|
350
|
+
|
|
351
|
+
| スキル | 連携内容 |
|
|
352
|
+
|---|---|
|
|
353
|
+
| [scientific-bioinformatics](../scientific-bioinformatics/SKILL.md) | 遺伝子アノテーション・パスウェイ解析 |
|
|
354
|
+
| [scientific-multi-omics](../scientific-multi-omics/SKILL.md) | マルチオミクス統合 |
|
|
355
|
+
| [scientific-network-analysis](../scientific-network-analysis/SKILL.md) | 遺伝子制御ネットワーク |
|
|
356
|
+
| [scientific-deep-learning](../scientific-deep-learning/SKILL.md) | scVI / scGPT 等の深層学習モデル |
|
|
357
|
+
| [scientific-pca-tsne](../scientific-pca-tsne/SKILL.md) | 次元削減手法 |
|
|
358
|
+
|
|
359
|
+
#### 依存パッケージ
|
|
360
|
+
|
|
361
|
+
- scanpy, anndata, scvelo, cellchat, leidenalg, umap-learn
|