@nahisaho/satori 0.16.0 → 0.17.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.
@@ -0,0 +1,294 @@
1
+ ---
2
+ name: scientific-human-cell-atlas
3
+ description: |
4
+ Human Cell Atlas (HCA) データポータルスキル。HCA Data Portal API
5
+ プロジェクト検索・ファイルダウンロード・CELLxGENE Census 統合・
6
+ 細胞型アノテーション・アトラス構築。ToolUniverse 連携: hca_tools。
7
+ tu_tools:
8
+ - key: hca_tools
9
+ name: Human Cell Atlas Tools
10
+ description: HCA データポータル プロジェクト・バンドル・ファイル検索
11
+ ---
12
+
13
+ # Scientific Human Cell Atlas
14
+
15
+ HCA Data Portal / CELLxGENE Census を活用した大規模シングルセル
16
+ アトラスデータアクセス・解析パイプラインを提供する。
17
+
18
+ ## When to Use
19
+
20
+ - HCA Data Portal からプロジェクト・実験データを検索するとき
21
+ - CELLxGENE Census で大規模シングルセルアトラスを照会するとき
22
+ - 特定組織/疾患の細胞型構成を調べるとき
23
+ - 複数 HCA プロジェクト間で細胞型を比較するとき
24
+ - シングルセルアトラスのリファレンスマッピングを行うとき
25
+ - 希少細胞型の発見・アノテーションを実施するとき
26
+
27
+ ---
28
+
29
+ ## Quick Start
30
+
31
+ ## 1. HCA Data Portal プロジェクト検索
32
+
33
+ ```python
34
+ import requests
35
+ import pandas as pd
36
+ import json
37
+
38
+ HCA_BASE = "https://service.azul.data.humancellatlas.org"
39
+ HCA_CATALOG = "dcp44"
40
+
41
+
42
+ def hca_search_projects(keyword=None, organ=None, disease=None,
43
+ species="Homo sapiens", limit=25):
44
+ """
45
+ HCA Data Portal — プロジェクト検索。
46
+
47
+ Parameters:
48
+ keyword: str — キーワード検索
49
+ organ: str — 臓器 (例: "lung", "heart")
50
+ disease: str — 疾患 (例: "COVID-19")
51
+ species: str — 生物種
52
+ limit: int — 最大結果数
53
+ """
54
+ url = f"{HCA_BASE}/index/projects"
55
+ params = {"catalog": HCA_CATALOG, "size": limit}
56
+
57
+ filters = {}
58
+ if organ:
59
+ filters["organ"] = {"is": [organ]}
60
+ if disease:
61
+ filters["disease"] = {"is": [disease]}
62
+ if species:
63
+ filters["genusSpecies"] = {"is": [species]}
64
+ if keyword:
65
+ params["q"] = keyword
66
+ if filters:
67
+ params["filters"] = json.dumps(filters)
68
+
69
+ resp = requests.get(url, params=params, timeout=30)
70
+ resp.raise_for_status()
71
+ data = resp.json()
72
+
73
+ projects = []
74
+ for hit in data.get("hits", []):
75
+ proj = hit.get("projects", [{}])[0]
76
+ samples = hit.get("samples", [{}])[0]
77
+ protocols = hit.get("protocols", [{}])[0]
78
+ projects.append({
79
+ "project_id": proj.get("projectId", ""),
80
+ "title": proj.get("projectTitle", ""),
81
+ "organ": ", ".join(samples.get("organ", [])),
82
+ "disease": ", ".join(samples.get("disease", [])),
83
+ "species": ", ".join(samples.get("genusSpecies", [])),
84
+ "cell_count": hit.get("cellSuspensions", [{}])[0].get(
85
+ "totalCells", 0),
86
+ "library_method": ", ".join(protocols.get(
87
+ "libraryConstructionApproach", [])),
88
+ "donor_count": samples.get("donorCount", 0),
89
+ })
90
+
91
+ df = pd.DataFrame(projects)
92
+ print(f"HCA: {len(df)} projects found")
93
+ return df
94
+ ```
95
+
96
+ ## 2. HCA ファイル取得
97
+
98
+ ```python
99
+ def hca_get_project_files(project_id, file_format=None):
100
+ """
101
+ HCA — プロジェクトのファイル一覧取得。
102
+
103
+ Parameters:
104
+ project_id: str — プロジェクト UUID
105
+ file_format: str — ファイル形式 (例: "h5ad", "loom", "csv")
106
+ """
107
+ url = f"{HCA_BASE}/index/files"
108
+ filters = {"projectId": {"is": [project_id]}}
109
+ if file_format:
110
+ filters["fileFormat"] = {"is": [file_format]}
111
+
112
+ params = {
113
+ "catalog": HCA_CATALOG,
114
+ "filters": json.dumps(filters),
115
+ "size": 100,
116
+ }
117
+ resp = requests.get(url, params=params, timeout=30)
118
+ resp.raise_for_status()
119
+ data = resp.json()
120
+
121
+ files = []
122
+ for hit in data.get("hits", []):
123
+ for f in hit.get("files", []):
124
+ files.append({
125
+ "file_id": f.get("uuid", ""),
126
+ "name": f.get("name", ""),
127
+ "format": f.get("format", ""),
128
+ "size_bytes": f.get("size", 0),
129
+ "url": f.get("url", ""),
130
+ })
131
+
132
+ df = pd.DataFrame(files)
133
+ print(f"HCA files ({project_id[:8]}): {len(df)} files")
134
+ return df
135
+ ```
136
+
137
+ ## 3. CELLxGENE Census アトラスクエリ
138
+
139
+ ```python
140
+ def cellxgene_census_query(organism="homo_sapiens", tissue=None,
141
+ disease=None, cell_type=None,
142
+ gene_list=None, max_cells=50000):
143
+ """
144
+ CELLxGENE Census — 大規模シングルセルアトラスクエリ。
145
+
146
+ Parameters:
147
+ organism: str — 生物種
148
+ tissue: str — 組織
149
+ disease: str — 疾患
150
+ cell_type: str — 細胞型
151
+ gene_list: list[str] — 取得遺伝子リスト
152
+ max_cells: int — 最大細胞数
153
+ """
154
+ import cellxgene_census
155
+
156
+ census = cellxgene_census.open_soma()
157
+
158
+ # 観察フィルタ構築
159
+ obs_filters = []
160
+ if tissue:
161
+ obs_filters.append(f"tissue == '{tissue}'")
162
+ if disease:
163
+ obs_filters.append(f"disease == '{disease}'")
164
+ if cell_type:
165
+ obs_filters.append(f"cell_type == '{cell_type}'")
166
+
167
+ obs_filter = " and ".join(obs_filters) if obs_filters else None
168
+
169
+ # 遺伝子フィルタ
170
+ var_filter = None
171
+ if gene_list:
172
+ genes_str = "', '".join(gene_list)
173
+ var_filter = f"feature_name in ['{genes_str}']"
174
+
175
+ adata = cellxgene_census.get_anndata(
176
+ census,
177
+ organism=organism,
178
+ obs_value_filter=obs_filter,
179
+ var_value_filter=var_filter,
180
+ obs_column_names=[
181
+ "cell_type", "tissue", "disease",
182
+ "donor_id", "dataset_id", "assay",
183
+ ],
184
+ )
185
+
186
+ if adata.n_obs > max_cells:
187
+ import numpy as np
188
+ idx = np.random.choice(adata.n_obs, max_cells, replace=False)
189
+ adata = adata[idx].copy()
190
+
191
+ census.close()
192
+ print(f"CELLxGENE Census: {adata.n_obs} cells × {adata.n_vars} genes")
193
+ return adata
194
+ ```
195
+
196
+ ## 4. 細胞型構成解析
197
+
198
+ ```python
199
+ import scanpy as sc
200
+
201
+
202
+ def cell_type_composition(adata, groupby="tissue", cell_type_col="cell_type"):
203
+ """
204
+ 細胞型構成の定量比較。
205
+
206
+ Parameters:
207
+ adata: AnnData — シングルセルデータ
208
+ groupby: str — グループ変数
209
+ cell_type_col: str — 細胞型カラム名
210
+ """
211
+ # 構成比計算
212
+ composition = (
213
+ adata.obs.groupby([groupby, cell_type_col])
214
+ .size()
215
+ .unstack(fill_value=0)
216
+ )
217
+ composition_pct = composition.div(composition.sum(axis=1), axis=0) * 100
218
+
219
+ print(f"Cell type composition: {composition.shape[0]} groups × "
220
+ f"{composition.shape[1]} cell types")
221
+ return composition_pct
222
+ ```
223
+
224
+ ## 5. HCA 統合パイプライン
225
+
226
+ ```python
227
+ def hca_atlas_pipeline(organ, disease=None, output_dir="results"):
228
+ """
229
+ HCA + CELLxGENE 統合アトラスパイプライン。
230
+
231
+ Parameters:
232
+ organ: str — 対象臓器
233
+ disease: str — 対象疾患
234
+ output_dir: str — 出力ディレクトリ
235
+ """
236
+ from pathlib import Path
237
+ output_dir = Path(output_dir)
238
+ output_dir.mkdir(parents=True, exist_ok=True)
239
+
240
+ # 1) HCA プロジェクト検索
241
+ projects = hca_search_projects(organ=organ, disease=disease)
242
+ projects.to_csv(output_dir / "hca_projects.csv", index=False)
243
+
244
+ # 2) CELLxGENE Census クエリ
245
+ adata = cellxgene_census_query(tissue=organ, disease=disease)
246
+
247
+ # 3) 前処理
248
+ sc.pp.normalize_total(adata, target_sum=1e4)
249
+ sc.pp.log1p(adata)
250
+ sc.pp.highly_variable_genes(adata, n_top_genes=2000)
251
+ adata = adata[:, adata.var["highly_variable"]].copy()
252
+ sc.pp.pca(adata)
253
+ sc.pp.neighbors(adata)
254
+ sc.tl.umap(adata)
255
+
256
+ # 4) 細胞型構成
257
+ composition = cell_type_composition(adata)
258
+ composition.to_csv(output_dir / "cell_type_composition.csv")
259
+
260
+ # 5) 保存
261
+ adata.write(output_dir / "hca_atlas.h5ad")
262
+
263
+ print(f"HCA atlas pipeline: {output_dir}")
264
+ return {"projects": projects, "adata": adata, "composition": composition}
265
+ ```
266
+
267
+ ---
268
+
269
+ ## ToolUniverse 連携
270
+
271
+ | TU Key | ツール名 | 連携内容 |
272
+ |--------|---------|---------|
273
+ | `hca_tools` | HCA Tools | プロジェクト検索・ファイルダウンロード |
274
+
275
+ ## パイプライン統合
276
+
277
+ ```
278
+ single-cell-genomics → human-cell-atlas → scvi-integration
279
+ (scanpy 標準) (HCA/CELLxGENE) (scVI 統合)
280
+ │ │ ↓
281
+ spatial-transcriptomics ───┘ cell-type-annotation
282
+ (Visium/MERFISH) │ (リファレンスマッピング)
283
+
284
+ gpu-singlecell
285
+ (大規模処理)
286
+ ```
287
+
288
+ ## パイプライン出力
289
+
290
+ | ファイル | 説明 | 次スキル |
291
+ |---------|------|---------|
292
+ | `results/hca_projects.csv` | HCA プロジェクト一覧 | → single-cell-genomics |
293
+ | `results/hca_atlas.h5ad` | アトラス AnnData | → scvi-integration |
294
+ | `results/cell_type_composition.csv` | 細胞型構成比 | → spatial-transcriptomics |
@@ -0,0 +1,263 @@
1
+ ---
2
+ name: scientific-metabolic-atlas
3
+ description: |
4
+ 代謝アトラススキル。Metabolic Atlas / Human-GEM REST API による
5
+ 代謝反応・代謝産物・コンパートメント検索、フラックス解析統合、
6
+ 代謝ネットワーク可視化。K-Dense 連携: metabolic-atlas。
7
+ tu_tools: []
8
+ kdense_ref: metabolic-atlas
9
+ ---
10
+
11
+ # Scientific Metabolic Atlas
12
+
13
+ Metabolic Atlas REST API を活用したゲノムスケール代謝モデル
14
+ (GEM) 解析パイプラインを提供する。
15
+
16
+ ## When to Use
17
+
18
+ - ヒト代謝反応・代謝産物を検索するとき
19
+ - Human-GEM のコンパートメント情報を取得するとき
20
+ - 代謝経路のネットワーク構造を解析するとき
21
+ - フラックスバランス解析 (FBA) の入力を準備するとき
22
+ - 代謝産物コネクティビティを可視化するとき
23
+ - 組織特異的代謝モデルを構築するとき
24
+
25
+ ---
26
+
27
+ ## Quick Start
28
+
29
+ ## 1. 代謝反応検索
30
+
31
+ ```python
32
+ import requests
33
+ import pandas as pd
34
+ import numpy as np
35
+
36
+ MA_BASE = "https://metabolicatlas.org/api/v2"
37
+
38
+
39
+ def metabolic_atlas_search_reactions(query, model="Human-GEM",
40
+ compartment=None, limit=50):
41
+ """
42
+ Metabolic Atlas — 代謝反応検索。
43
+
44
+ Parameters:
45
+ query: str — 検索クエリ (例: "glycolysis", "citrate")
46
+ model: str — GEM モデル名
47
+ compartment: str — コンパートメント (例: "cytosol", "mitochondria")
48
+ limit: int — 最大結果数
49
+ """
50
+ url = f"{MA_BASE}/search"
51
+ params = {
52
+ "query": query,
53
+ "model": model,
54
+ "type": "reaction",
55
+ "limit": limit,
56
+ }
57
+ resp = requests.get(url, params=params, timeout=30)
58
+ resp.raise_for_status()
59
+ data = resp.json()
60
+
61
+ results = []
62
+ for r in data.get("results", data) if isinstance(data, dict) else data:
63
+ rxn = r if isinstance(r, dict) else {}
64
+ row = {
65
+ "reaction_id": rxn.get("id", ""),
66
+ "name": rxn.get("name", ""),
67
+ "equation": rxn.get("equation", ""),
68
+ "subsystem": rxn.get("subsystem", ""),
69
+ "compartment": rxn.get("compartment", ""),
70
+ "gene_rule": rxn.get("geneRule", ""),
71
+ "lower_bound": rxn.get("lowerBound", None),
72
+ "upper_bound": rxn.get("upperBound", None),
73
+ }
74
+ if compartment and compartment.lower() not in str(
75
+ row.get("compartment", "")).lower():
76
+ continue
77
+ results.append(row)
78
+
79
+ df = pd.DataFrame(results[:limit])
80
+ print(f"Metabolic Atlas reactions: {len(df)} results "
81
+ f"(query={query})")
82
+ return df
83
+ ```
84
+
85
+ ## 2. 代謝産物検索
86
+
87
+ ```python
88
+ def metabolic_atlas_search_metabolites(query, model="Human-GEM",
89
+ limit=50):
90
+ """
91
+ Metabolic Atlas — 代謝産物検索。
92
+
93
+ Parameters:
94
+ query: str — 検索クエリ (例: "glucose", "ATP")
95
+ model: str — GEM モデル名
96
+ limit: int — 最大結果数
97
+ """
98
+ url = f"{MA_BASE}/search"
99
+ params = {
100
+ "query": query,
101
+ "model": model,
102
+ "type": "metabolite",
103
+ "limit": limit,
104
+ }
105
+ resp = requests.get(url, params=params, timeout=30)
106
+ resp.raise_for_status()
107
+ data = resp.json()
108
+
109
+ results = []
110
+ for m in data.get("results", data) if isinstance(data, dict) else data:
111
+ met = m if isinstance(m, dict) else {}
112
+ results.append({
113
+ "metabolite_id": met.get("id", ""),
114
+ "name": met.get("name", ""),
115
+ "formula": met.get("formula", ""),
116
+ "charge": met.get("charge", None),
117
+ "compartment": met.get("compartment", ""),
118
+ "chebi_id": met.get("chebiId", ""),
119
+ "kegg_id": met.get("keggId", ""),
120
+ })
121
+
122
+ df = pd.DataFrame(results[:limit])
123
+ print(f"Metabolic Atlas metabolites: {len(df)} results "
124
+ f"(query={query})")
125
+ return df
126
+ ```
127
+
128
+ ## 3. 代謝ネットワーク解析
129
+
130
+ ```python
131
+ import networkx as nx
132
+
133
+
134
+ def metabolic_atlas_network(subsystem, model="Human-GEM"):
135
+ """
136
+ Metabolic Atlas — サブシステム代謝ネットワーク構築。
137
+
138
+ Parameters:
139
+ subsystem: str — サブシステム名 (例: "Glycolysis")
140
+ model: str — GEM モデル名
141
+ """
142
+ reactions = metabolic_atlas_search_reactions(
143
+ subsystem, model=model, limit=200)
144
+
145
+ G = nx.DiGraph()
146
+
147
+ for _, rxn in reactions.iterrows():
148
+ rxn_id = rxn["reaction_id"]
149
+ equation = str(rxn.get("equation", ""))
150
+
151
+ # 簡易パーサ: "A + B => C + D"
152
+ if "=>" in equation:
153
+ substrates_str, products_str = equation.split("=>", 1)
154
+ elif "=" in equation:
155
+ substrates_str, products_str = equation.split("=", 1)
156
+ else:
157
+ continue
158
+
159
+ substrates = [s.strip() for s in substrates_str.split("+")
160
+ if s.strip()]
161
+ products = [p.strip() for p in products_str.split("+")
162
+ if p.strip()]
163
+
164
+ G.add_node(rxn_id, type="reaction",
165
+ name=rxn.get("name", ""))
166
+
167
+ for s in substrates:
168
+ G.add_node(s, type="metabolite")
169
+ G.add_edge(s, rxn_id)
170
+
171
+ for p in products:
172
+ G.add_node(p, type="metabolite")
173
+ G.add_edge(rxn_id, p)
174
+
175
+ # ネットワーク統計
176
+ n_reactions = sum(1 for _, d in G.nodes(data=True)
177
+ if d.get("type") == "reaction")
178
+ n_metabolites = sum(1 for _, d in G.nodes(data=True)
179
+ if d.get("type") == "metabolite")
180
+
181
+ print(f"Metabolic network: {n_reactions} reactions, "
182
+ f"{n_metabolites} metabolites, {G.number_of_edges()} edges")
183
+ return G
184
+ ```
185
+
186
+ ## 4. 代謝アトラス統合パイプライン
187
+
188
+ ```python
189
+ def metabolic_atlas_pipeline(query, model="Human-GEM",
190
+ output_dir="results"):
191
+ """
192
+ 代謝アトラス統合パイプライン。
193
+
194
+ Parameters:
195
+ query: str — 代謝経路/サブシステム名
196
+ model: str — GEM モデル名
197
+ output_dir: str — 出力ディレクトリ
198
+ """
199
+ from pathlib import Path
200
+ output_dir = Path(output_dir)
201
+ output_dir.mkdir(parents=True, exist_ok=True)
202
+
203
+ # 1) 反応検索
204
+ reactions = metabolic_atlas_search_reactions(query, model=model)
205
+ reactions.to_csv(output_dir / "reactions.csv", index=False)
206
+
207
+ # 2) 代謝産物検索
208
+ metabolites = metabolic_atlas_search_metabolites(query, model=model)
209
+ metabolites.to_csv(output_dir / "metabolites.csv", index=False)
210
+
211
+ # 3) ネットワーク構築
212
+ G = metabolic_atlas_network(query, model=model)
213
+ nx.write_graphml(G, str(output_dir / "metabolic_network.graphml"))
214
+
215
+ # 4) ハブ代謝産物
216
+ met_nodes = [n for n, d in G.nodes(data=True)
217
+ if d.get("type") == "metabolite"]
218
+ hub_scores = {n: G.degree(n) for n in met_nodes}
219
+ hub_df = pd.DataFrame([
220
+ {"metabolite": k, "degree": v}
221
+ for k, v in sorted(hub_scores.items(),
222
+ key=lambda x: -x[1])[:20]
223
+ ])
224
+ hub_df.to_csv(output_dir / "hub_metabolites.csv", index=False)
225
+
226
+ print(f"Metabolic Atlas pipeline: {output_dir}")
227
+ return {
228
+ "reactions": reactions,
229
+ "metabolites": metabolites,
230
+ "network": G,
231
+ "hubs": hub_df,
232
+ }
233
+ ```
234
+
235
+ ---
236
+
237
+ ## K-Dense 連携
238
+
239
+ | K-Dense Key | 参照内容 |
240
+ |-------------|---------|
241
+ | `metabolic-atlas` | 代謝モデル構造・反応データベース |
242
+
243
+ ## パイプライン統合
244
+
245
+ ```
246
+ metabolic-modeling → metabolic-atlas → systems-biology
247
+ (COBRA/FBA) (Human-GEM) (統合モデリング)
248
+ │ │ ↓
249
+ pathway-enrichment ─────┘ gene-expression
250
+ (KEGG/Reactome) │ (発現データ)
251
+
252
+ multi-omics
253
+ (メタボロミクス統合)
254
+ ```
255
+
256
+ ## パイプライン出力
257
+
258
+ | ファイル | 説明 | 次スキル |
259
+ |---------|------|---------|
260
+ | `results/reactions.csv` | 代謝反応一覧 | → metabolic-modeling |
261
+ | `results/metabolites.csv` | 代謝産物一覧 | → pathway-enrichment |
262
+ | `results/metabolic_network.graphml` | 代謝ネットワーク | → systems-biology |
263
+ | `results/hub_metabolites.csv` | ハブ代謝産物 | → multi-omics |