@nahisaho/satori 0.16.0 → 0.18.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 +83 -41
- package/package.json +1 -1
- package/src/.github/skills/scientific-alphafold-structures/SKILL.md +256 -0
- package/src/.github/skills/scientific-arrayexpress-expression/SKILL.md +264 -0
- package/src/.github/skills/scientific-crossref-metadata/SKILL.md +313 -0
- package/src/.github/skills/scientific-encode-screen/SKILL.md +315 -0
- package/src/.github/skills/scientific-environmental-geodata/SKILL.md +255 -0
- package/src/.github/skills/scientific-geo-expression/SKILL.md +274 -0
- package/src/.github/skills/scientific-gtex-tissue-expression/SKILL.md +271 -0
- package/src/.github/skills/scientific-gwas-catalog/SKILL.md +267 -0
- package/src/.github/skills/scientific-human-cell-atlas/SKILL.md +294 -0
- package/src/.github/skills/scientific-icgc-cancer-data/SKILL.md +351 -0
- package/src/.github/skills/scientific-metabolic-atlas/SKILL.md +263 -0
- package/src/.github/skills/scientific-paleobiology/SKILL.md +265 -0
- package/src/.github/skills/scientific-parasite-genomics/SKILL.md +280 -0
- package/src/.github/skills/scientific-pharmgkb-pgx/SKILL.md +306 -0
- package/src/.github/skills/scientific-semantic-scholar/SKILL.md +298 -0
- package/src/.github/skills/scientific-squidpy-advanced/SKILL.md +251 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-encode-screen
|
|
3
|
+
description: |
|
|
4
|
+
ENCODE / ChIP-Atlas エピゲノムアトラススキル。ENCODE REST API
|
|
5
|
+
実験・ファイル・バイオサンプル検索、SCREEN cis 制御エレメント、
|
|
6
|
+
ChIP-Atlas エンリッチメント解析、エピゲノムアノテーション統合。
|
|
7
|
+
ToolUniverse 連携: encode, chipatlas。
|
|
8
|
+
tu_tools:
|
|
9
|
+
- key: encode
|
|
10
|
+
name: ENCODE
|
|
11
|
+
description: ENCODE プロジェクトの実験・バイオサンプル・ファイルデータ検索
|
|
12
|
+
- key: chipatlas
|
|
13
|
+
name: ChIP-Atlas
|
|
14
|
+
description: ChIP-seq/ATAC-seq エンリッチメント解析・ピークブラウザ
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Scientific ENCODE / SCREEN / ChIP-Atlas
|
|
18
|
+
|
|
19
|
+
ENCODE REST API / SCREEN / ChIP-Atlas を活用したエピゲノム
|
|
20
|
+
アトラス統合解析パイプラインを提供する。
|
|
21
|
+
|
|
22
|
+
## When to Use
|
|
23
|
+
|
|
24
|
+
- ENCODE 実験データ (ChIP-seq/ATAC-seq/DNase) を検索するとき
|
|
25
|
+
- SCREEN cCRE (candidate cis-Regulatory Elements) を照会するとき
|
|
26
|
+
- ChIP-Atlas で転写因子結合・ヒストン修飾エンリッチメントを解析するとき
|
|
27
|
+
- バリアントの制御領域アノテーションを強化するとき
|
|
28
|
+
- エピゲノムデータを下流のクロマチン解析に統合するとき
|
|
29
|
+
- 組織/細胞型特異的エピゲノムプロファイルを比較するとき
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
## 1. ENCODE 実験検索・ファイル取得
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
import requests
|
|
39
|
+
import pandas as pd
|
|
40
|
+
import json
|
|
41
|
+
|
|
42
|
+
ENCODE_BASE = "https://www.encodeproject.org"
|
|
43
|
+
HEADERS = {"Accept": "application/json"}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def encode_search_experiments(assay_title=None, biosample=None,
|
|
47
|
+
target=None, organism="Homo sapiens",
|
|
48
|
+
limit=50):
|
|
49
|
+
"""
|
|
50
|
+
ENCODE — 実験メタデータ検索。
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
assay_title: str — アッセイ種別 (例: "ChIP-seq", "ATAC-seq")
|
|
54
|
+
biosample: str — バイオサンプル (例: "K562")
|
|
55
|
+
target: str — ターゲット (例: "CTCF")
|
|
56
|
+
organism: str — 生物種
|
|
57
|
+
limit: int — 最大結果数
|
|
58
|
+
"""
|
|
59
|
+
url = f"{ENCODE_BASE}/search/"
|
|
60
|
+
params = {
|
|
61
|
+
"type": "Experiment",
|
|
62
|
+
"status": "released",
|
|
63
|
+
"replicates.library.biosample.donor.organism.scientific_name": organism,
|
|
64
|
+
"limit": limit,
|
|
65
|
+
"format": "json",
|
|
66
|
+
}
|
|
67
|
+
if assay_title:
|
|
68
|
+
params["assay_title"] = assay_title
|
|
69
|
+
if biosample:
|
|
70
|
+
params["biosample_ontology.term_name"] = biosample
|
|
71
|
+
if target:
|
|
72
|
+
params["target.label"] = target
|
|
73
|
+
|
|
74
|
+
resp = requests.get(url, params=params, headers=HEADERS, timeout=30)
|
|
75
|
+
resp.raise_for_status()
|
|
76
|
+
data = resp.json()
|
|
77
|
+
|
|
78
|
+
results = []
|
|
79
|
+
for exp in data.get("@graph", []):
|
|
80
|
+
results.append({
|
|
81
|
+
"accession": exp.get("accession", ""),
|
|
82
|
+
"assay": exp.get("assay_title", ""),
|
|
83
|
+
"biosample": exp.get("biosample_summary", ""),
|
|
84
|
+
"target": exp.get("target", {}).get("label", ""),
|
|
85
|
+
"status": exp.get("status", ""),
|
|
86
|
+
"lab": exp.get("lab", {}).get("title", ""),
|
|
87
|
+
"date_released": exp.get("date_released", ""),
|
|
88
|
+
"files_count": len(exp.get("files", [])),
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
df = pd.DataFrame(results)
|
|
92
|
+
print(f"ENCODE: {len(df)} experiments found")
|
|
93
|
+
return df
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def encode_get_files(experiment_accession, file_type="bigWig",
|
|
97
|
+
output_type="signal p-value", assembly="GRCh38"):
|
|
98
|
+
"""
|
|
99
|
+
ENCODE — 実験ファイル URL 取得。
|
|
100
|
+
|
|
101
|
+
Parameters:
|
|
102
|
+
experiment_accession: str — 実験アクセッション
|
|
103
|
+
file_type: str — ファイルタイプ
|
|
104
|
+
output_type: str — 出力タイプ
|
|
105
|
+
assembly: str — アセンブリ
|
|
106
|
+
"""
|
|
107
|
+
url = f"{ENCODE_BASE}/search/"
|
|
108
|
+
params = {
|
|
109
|
+
"type": "File",
|
|
110
|
+
"dataset": f"/experiments/{experiment_accession}/",
|
|
111
|
+
"file_format": file_type,
|
|
112
|
+
"output_type": output_type,
|
|
113
|
+
"assembly": assembly,
|
|
114
|
+
"status": "released",
|
|
115
|
+
"format": "json",
|
|
116
|
+
}
|
|
117
|
+
resp = requests.get(url, params=params, headers=HEADERS, timeout=30)
|
|
118
|
+
resp.raise_for_status()
|
|
119
|
+
data = resp.json()
|
|
120
|
+
|
|
121
|
+
files = []
|
|
122
|
+
for f in data.get("@graph", []):
|
|
123
|
+
files.append({
|
|
124
|
+
"accession": f.get("accession", ""),
|
|
125
|
+
"file_format": f.get("file_format", ""),
|
|
126
|
+
"output_type": f.get("output_type", ""),
|
|
127
|
+
"assembly": f.get("assembly", ""),
|
|
128
|
+
"href": ENCODE_BASE + f.get("href", ""),
|
|
129
|
+
"file_size": f.get("file_size", 0),
|
|
130
|
+
"biological_replicate": f.get("biological_replicates", []),
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
df = pd.DataFrame(files)
|
|
134
|
+
print(f"ENCODE files ({experiment_accession}): {len(df)} files")
|
|
135
|
+
return df
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 2. SCREEN cCRE 検索
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
SCREEN_BASE = "https://api.wenglab.org/screen/v2"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def screen_ccre_search(gene=None, region=None, biosample=None,
|
|
145
|
+
assembly="GRCh38"):
|
|
146
|
+
"""
|
|
147
|
+
SCREEN — candidate cis-Regulatory Element 検索。
|
|
148
|
+
|
|
149
|
+
Parameters:
|
|
150
|
+
gene: str — 遺伝子名 (例: "TP53")
|
|
151
|
+
region: str — ゲノム領域 (例: "chr17:7668421-7687490")
|
|
152
|
+
biosample: str — バイオサンプル名
|
|
153
|
+
assembly: str — アセンブリ
|
|
154
|
+
"""
|
|
155
|
+
url = f"{SCREEN_BASE}/search"
|
|
156
|
+
query = {"assembly": assembly}
|
|
157
|
+
|
|
158
|
+
if gene:
|
|
159
|
+
query["gene"] = gene
|
|
160
|
+
if region:
|
|
161
|
+
chrom, pos = region.split(":")
|
|
162
|
+
start, end = pos.split("-")
|
|
163
|
+
query["coordinates"] = {
|
|
164
|
+
"chromosome": chrom,
|
|
165
|
+
"start": int(start),
|
|
166
|
+
"end": int(end),
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
resp = requests.post(url, json=query, timeout=30)
|
|
170
|
+
resp.raise_for_status()
|
|
171
|
+
data = resp.json()
|
|
172
|
+
|
|
173
|
+
ccres = []
|
|
174
|
+
for cre in data.get("data", []):
|
|
175
|
+
ccres.append({
|
|
176
|
+
"accession": cre.get("accession", ""),
|
|
177
|
+
"chromosome": cre.get("chrom", ""),
|
|
178
|
+
"start": cre.get("start", 0),
|
|
179
|
+
"end": cre.get("end", 0),
|
|
180
|
+
"ccre_class": cre.get("group", ""),
|
|
181
|
+
"dnase_zscore": cre.get("dnase_zscore", None),
|
|
182
|
+
"h3k4me3_zscore": cre.get("h3k4me3_zscore", None),
|
|
183
|
+
"h3k27ac_zscore": cre.get("h3k27ac_zscore", None),
|
|
184
|
+
"ctcf_zscore": cre.get("ctcf_zscore", None),
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
df = pd.DataFrame(ccres)
|
|
188
|
+
print(f"SCREEN cCREs: {len(df)} elements")
|
|
189
|
+
return df
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## 3. ChIP-Atlas エンリッチメント解析
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
CHIPATLAS_BASE = "https://chip-atlas.org/api"
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def chipatlas_enrichment(gene_list, cell_type=None,
|
|
199
|
+
antigen_class="TFs and others",
|
|
200
|
+
genome="hg38", threshold=5):
|
|
201
|
+
"""
|
|
202
|
+
ChIP-Atlas — 遺伝子リストのエンリッチメント解析。
|
|
203
|
+
|
|
204
|
+
Parameters:
|
|
205
|
+
gene_list: list[str] — 遺伝子リスト
|
|
206
|
+
cell_type: str — 細胞型 (None = 全細胞型)
|
|
207
|
+
antigen_class: str — 抗原クラス
|
|
208
|
+
genome: str — ゲノムアセンブリ
|
|
209
|
+
threshold: int — 距離閾値 (kb)
|
|
210
|
+
"""
|
|
211
|
+
url = f"{CHIPATLAS_BASE}/enrichment"
|
|
212
|
+
payload = {
|
|
213
|
+
"genome": genome,
|
|
214
|
+
"geneList": gene_list,
|
|
215
|
+
"antigenClass": antigen_class,
|
|
216
|
+
"distanceThreshold": threshold * 1000,
|
|
217
|
+
}
|
|
218
|
+
if cell_type:
|
|
219
|
+
payload["cellType"] = cell_type
|
|
220
|
+
|
|
221
|
+
resp = requests.post(url, json=payload, timeout=60)
|
|
222
|
+
resp.raise_for_status()
|
|
223
|
+
data = resp.json()
|
|
224
|
+
|
|
225
|
+
results = []
|
|
226
|
+
for hit in data.get("results", []):
|
|
227
|
+
results.append({
|
|
228
|
+
"antigen": hit.get("antigen", ""),
|
|
229
|
+
"cell_type": hit.get("cellType", ""),
|
|
230
|
+
"experiment_id": hit.get("experimentId", ""),
|
|
231
|
+
"p_value": hit.get("pValue", 1.0),
|
|
232
|
+
"log_p": hit.get("logPValue", 0),
|
|
233
|
+
"overlap_genes": hit.get("overlapGenes", 0),
|
|
234
|
+
"total_peaks": hit.get("totalPeaks", 0),
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
df = pd.DataFrame(results)
|
|
238
|
+
df = df.sort_values("p_value")
|
|
239
|
+
print(f"ChIP-Atlas enrichment: {len(df)} TF/antigen hits")
|
|
240
|
+
return df
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## 4. ENCODE + SCREEN + ChIP-Atlas 統合パイプライン
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
def encode_epigenome_pipeline(gene_name, biosample="K562",
|
|
247
|
+
output_dir="results"):
|
|
248
|
+
"""
|
|
249
|
+
ENCODE/SCREEN/ChIP-Atlas エピゲノム統合パイプライン。
|
|
250
|
+
|
|
251
|
+
Parameters:
|
|
252
|
+
gene_name: str — 遺伝子名
|
|
253
|
+
biosample: str — バイオサンプル
|
|
254
|
+
output_dir: str — 出力ディレクトリ
|
|
255
|
+
"""
|
|
256
|
+
from pathlib import Path
|
|
257
|
+
output_dir = Path(output_dir)
|
|
258
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
259
|
+
|
|
260
|
+
# 1) SCREEN cCRE
|
|
261
|
+
ccres = screen_ccre_search(gene=gene_name)
|
|
262
|
+
ccres.to_csv(output_dir / "screen_ccres.csv", index=False)
|
|
263
|
+
|
|
264
|
+
# 2) ENCODE 実験
|
|
265
|
+
experiments = encode_search_experiments(
|
|
266
|
+
assay_title="ChIP-seq",
|
|
267
|
+
biosample=biosample,
|
|
268
|
+
target="H3K27ac",
|
|
269
|
+
)
|
|
270
|
+
experiments.to_csv(output_dir / "encode_experiments.csv", index=False)
|
|
271
|
+
|
|
272
|
+
# 3) ChIP-Atlas エンリッチメント
|
|
273
|
+
enrichment = chipatlas_enrichment(
|
|
274
|
+
gene_list=[gene_name],
|
|
275
|
+
cell_type=biosample,
|
|
276
|
+
)
|
|
277
|
+
enrichment.to_csv(output_dir / "chipatlas_enrichment.csv", index=False)
|
|
278
|
+
|
|
279
|
+
print(f"ENCODE epigenome pipeline: {output_dir}")
|
|
280
|
+
return {
|
|
281
|
+
"ccres": ccres,
|
|
282
|
+
"experiments": experiments,
|
|
283
|
+
"enrichment": enrichment,
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## ToolUniverse 連携
|
|
290
|
+
|
|
291
|
+
| TU Key | ツール名 | 連携内容 |
|
|
292
|
+
|--------|---------|---------|
|
|
293
|
+
| `encode` | ENCODE | 実験・バイオサンプル・ファイル検索 |
|
|
294
|
+
| `chipatlas` | ChIP-Atlas | 転写因子エンリッチメント解析 |
|
|
295
|
+
|
|
296
|
+
## パイプライン統合
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
regulatory-genomics → encode-screen → epigenomics-chromatin
|
|
300
|
+
(RegulomeDB/ReMap) (ENCODE/SCREEN) (ChIP/ATAC bulk)
|
|
301
|
+
│ │ ↓
|
|
302
|
+
variant-interpretation ───┘ scatac-signac
|
|
303
|
+
(ACMG バリアント) │ (scATAC-seq)
|
|
304
|
+
↓
|
|
305
|
+
gene-regulatory-network
|
|
306
|
+
(GRN 推定)
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## パイプライン出力
|
|
310
|
+
|
|
311
|
+
| ファイル | 説明 | 次スキル |
|
|
312
|
+
|---------|------|---------|
|
|
313
|
+
| `results/screen_ccres.csv` | cCRE アノテーション | → variant-interpretation |
|
|
314
|
+
| `results/encode_experiments.csv` | ENCODE 実験メタデータ | → epigenomics-chromatin |
|
|
315
|
+
| `results/chipatlas_enrichment.csv` | TF エンリッチメント | → gene-regulatory-network |
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scientific-environmental-geodata
|
|
3
|
+
description: |
|
|
4
|
+
環境地理空間データスキル。SoilGrids REST API による土壌特性
|
|
5
|
+
取得、WorldClim/CHELSA 気候データ、生物多様性-環境モデリング
|
|
6
|
+
統合。直接 REST API 連携 (TU 外)。
|
|
7
|
+
tu_tools: []
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scientific Environmental Geodata
|
|
11
|
+
|
|
12
|
+
SoilGrids・WorldClim 等の地球観測/環境データ API を活用した
|
|
13
|
+
生態学的環境モデリングパイプラインを提供する。
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- グローバル土壌特性 (pH, SOC, 粘土含量) を取得するとき
|
|
18
|
+
- バイオクリマティック変数 (BIO1-BIO19) を取得するとき
|
|
19
|
+
- 種分布モデル (SDM) の環境変数を準備するとき
|
|
20
|
+
- 気候変動シナリオの生息地適性を評価するとき
|
|
21
|
+
- 環境ニッチモデリングを実施するとき
|
|
22
|
+
- 土壌-植生-気候の相互作用を解析するとき
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
## 1. SoilGrids 土壌特性取得
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
import requests
|
|
32
|
+
import pandas as pd
|
|
33
|
+
import numpy as np
|
|
34
|
+
|
|
35
|
+
SOILGRIDS_BASE = "https://rest.isric.org/soilgrids/v2.0"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def soilgrids_get_properties(lat, lon, properties=None,
|
|
39
|
+
depths=None, values=None):
|
|
40
|
+
"""
|
|
41
|
+
SoilGrids — 地点の土壌特性取得。
|
|
42
|
+
|
|
43
|
+
Parameters:
|
|
44
|
+
lat: float — 緯度
|
|
45
|
+
lon: float — 経度
|
|
46
|
+
properties: list[str] — 土壌特性 (例: ["phh2o", "soc", "clay"])
|
|
47
|
+
depths: list[str] — 深度 (例: ["0-5cm", "5-15cm"])
|
|
48
|
+
values: list[str] — 値の種類 (例: ["mean", "Q0.05", "Q0.95"])
|
|
49
|
+
"""
|
|
50
|
+
if properties is None:
|
|
51
|
+
properties = ["phh2o", "soc", "clay", "sand", "nitrogen",
|
|
52
|
+
"bdod", "cec", "ocd"]
|
|
53
|
+
if depths is None:
|
|
54
|
+
depths = ["0-5cm", "5-15cm", "15-30cm", "30-60cm"]
|
|
55
|
+
if values is None:
|
|
56
|
+
values = ["mean", "Q0.05", "Q0.95"]
|
|
57
|
+
|
|
58
|
+
url = f"{SOILGRIDS_BASE}/properties/query"
|
|
59
|
+
params = {
|
|
60
|
+
"lat": lat,
|
|
61
|
+
"lon": lon,
|
|
62
|
+
"property": properties,
|
|
63
|
+
"depth": depths,
|
|
64
|
+
"value": values,
|
|
65
|
+
}
|
|
66
|
+
resp = requests.get(url, params=params, timeout=30)
|
|
67
|
+
resp.raise_for_status()
|
|
68
|
+
data = resp.json()
|
|
69
|
+
|
|
70
|
+
results = []
|
|
71
|
+
for layer in data.get("properties", {}).get("layers", []):
|
|
72
|
+
prop_name = layer.get("name", "")
|
|
73
|
+
unit = layer.get("unit_measure", {})
|
|
74
|
+
conversion = unit.get("mapped_units", "")
|
|
75
|
+
for depth_info in layer.get("depths", []):
|
|
76
|
+
row = {
|
|
77
|
+
"property": prop_name,
|
|
78
|
+
"depth": depth_info.get("label", ""),
|
|
79
|
+
"unit": conversion,
|
|
80
|
+
}
|
|
81
|
+
for val_key, val_val in depth_info.get("values", {}).items():
|
|
82
|
+
row[val_key] = val_val
|
|
83
|
+
results.append(row)
|
|
84
|
+
|
|
85
|
+
df = pd.DataFrame(results)
|
|
86
|
+
print(f"SoilGrids ({lat}, {lon}): {len(df)} records, "
|
|
87
|
+
f"{len(properties)} properties")
|
|
88
|
+
return df
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 2. WorldClim バイオクリマティック変数
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import rasterio
|
|
95
|
+
from rasterio.sample import sample_gen
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def worldclim_get_bioclim(lat, lon, resolution="2.5m",
|
|
99
|
+
data_dir="worldclim"):
|
|
100
|
+
"""
|
|
101
|
+
WorldClim — バイオクリマティック変数取得。
|
|
102
|
+
|
|
103
|
+
Parameters:
|
|
104
|
+
lat: float — 緯度
|
|
105
|
+
lon: float — 経度
|
|
106
|
+
resolution: str — 空間解像度 ("30s", "2.5m", "5m", "10m")
|
|
107
|
+
data_dir: str — WorldClim データディレクトリ
|
|
108
|
+
"""
|
|
109
|
+
from pathlib import Path
|
|
110
|
+
bio_dir = Path(data_dir) / f"wc2.1_{resolution}_bio"
|
|
111
|
+
|
|
112
|
+
bioclim_names = {
|
|
113
|
+
1: "Annual Mean Temperature",
|
|
114
|
+
2: "Mean Diurnal Range",
|
|
115
|
+
3: "Isothermality",
|
|
116
|
+
4: "Temperature Seasonality",
|
|
117
|
+
5: "Max Temperature Warmest Month",
|
|
118
|
+
6: "Min Temperature Coldest Month",
|
|
119
|
+
7: "Temperature Annual Range",
|
|
120
|
+
8: "Mean Temperature Wettest Quarter",
|
|
121
|
+
9: "Mean Temperature Driest Quarter",
|
|
122
|
+
10: "Mean Temperature Warmest Quarter",
|
|
123
|
+
11: "Mean Temperature Coldest Quarter",
|
|
124
|
+
12: "Annual Precipitation",
|
|
125
|
+
13: "Precipitation Wettest Month",
|
|
126
|
+
14: "Precipitation Driest Month",
|
|
127
|
+
15: "Precipitation Seasonality",
|
|
128
|
+
16: "Precipitation Wettest Quarter",
|
|
129
|
+
17: "Precipitation Driest Quarter",
|
|
130
|
+
18: "Precipitation Warmest Quarter",
|
|
131
|
+
19: "Precipitation Coldest Quarter",
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
results = []
|
|
135
|
+
for bio_num, bio_name in bioclim_names.items():
|
|
136
|
+
tif_path = bio_dir / f"wc2.1_{resolution}_bio_{bio_num}.tif"
|
|
137
|
+
if not tif_path.exists():
|
|
138
|
+
continue
|
|
139
|
+
with rasterio.open(tif_path) as src:
|
|
140
|
+
vals = list(sample_gen(src, [(lon, lat)]))
|
|
141
|
+
value = vals[0][0] if vals else None
|
|
142
|
+
results.append({
|
|
143
|
+
"variable": f"BIO{bio_num}",
|
|
144
|
+
"name": bio_name,
|
|
145
|
+
"value": value,
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
df = pd.DataFrame(results)
|
|
149
|
+
print(f"WorldClim ({lat}, {lon}): {len(df)} bioclim variables")
|
|
150
|
+
return df
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 3. 種分布モデル環境変数統合
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
def sdm_environmental_stack(occurrences_df, lat_col="latitude",
|
|
157
|
+
lon_col="longitude", buffer_deg=0.5):
|
|
158
|
+
"""
|
|
159
|
+
SDM — 種の出現記録に対する環境変数スタック生成。
|
|
160
|
+
|
|
161
|
+
Parameters:
|
|
162
|
+
occurrences_df: pd.DataFrame — 種出現記録
|
|
163
|
+
lat_col: str — 緯度カラム名
|
|
164
|
+
lon_col: str — 経度カラム名
|
|
165
|
+
buffer_deg: float — バッファ距離 (度)
|
|
166
|
+
"""
|
|
167
|
+
results = []
|
|
168
|
+
for _, row in occurrences_df.iterrows():
|
|
169
|
+
lat, lon = row[lat_col], row[lon_col]
|
|
170
|
+
|
|
171
|
+
# SoilGrids
|
|
172
|
+
soil = soilgrids_get_properties(lat, lon,
|
|
173
|
+
properties=["phh2o", "soc", "clay"])
|
|
174
|
+
soil_mean = {}
|
|
175
|
+
for _, s in soil.iterrows():
|
|
176
|
+
if s.get("depth") == "0-5cm":
|
|
177
|
+
soil_mean[f"soil_{s['property']}"] = s.get("mean", None)
|
|
178
|
+
|
|
179
|
+
# WorldClim (if available)
|
|
180
|
+
bioclim = {}
|
|
181
|
+
try:
|
|
182
|
+
bio_df = worldclim_get_bioclim(lat, lon)
|
|
183
|
+
bioclim = {r["variable"]: r["value"]
|
|
184
|
+
for _, r in bio_df.iterrows()}
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
combined = {
|
|
189
|
+
lat_col: lat,
|
|
190
|
+
lon_col: lon,
|
|
191
|
+
**soil_mean,
|
|
192
|
+
**bioclim,
|
|
193
|
+
}
|
|
194
|
+
results.append(combined)
|
|
195
|
+
|
|
196
|
+
df = pd.DataFrame(results)
|
|
197
|
+
print(f"SDM env stack: {len(df)} points, {len(df.columns)} variables")
|
|
198
|
+
return df
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 4. 環境地理空間統合パイプライン
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
def environmental_geodata_pipeline(occurrences_csv, output_dir="results"):
|
|
205
|
+
"""
|
|
206
|
+
環境地理空間統合パイプライン。
|
|
207
|
+
|
|
208
|
+
Parameters:
|
|
209
|
+
occurrences_csv: str — 種出現記録 CSV パス
|
|
210
|
+
output_dir: str — 出力ディレクトリ
|
|
211
|
+
"""
|
|
212
|
+
from pathlib import Path
|
|
213
|
+
output_dir = Path(output_dir)
|
|
214
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
215
|
+
|
|
216
|
+
occ = pd.read_csv(occurrences_csv)
|
|
217
|
+
print(f"Occurrences: {len(occ)} records")
|
|
218
|
+
|
|
219
|
+
# 環境変数スタック
|
|
220
|
+
env_df = sdm_environmental_stack(occ)
|
|
221
|
+
env_df.to_csv(output_dir / "env_stack.csv", index=False)
|
|
222
|
+
|
|
223
|
+
# 環境空間要約
|
|
224
|
+
summary = env_df.describe().T
|
|
225
|
+
summary.to_csv(output_dir / "env_summary.csv")
|
|
226
|
+
|
|
227
|
+
print(f"Environmental pipeline: {output_dir}")
|
|
228
|
+
return {"occurrences": occ, "env_stack": env_df, "summary": summary}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## ToolUniverse 連携
|
|
234
|
+
|
|
235
|
+
直接 REST API 使用 (SoilGrids, WorldClim は ToolUniverse 外)。
|
|
236
|
+
|
|
237
|
+
## パイプライン統合
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
environmental-ecology → environmental-geodata → marine-ecology
|
|
241
|
+
(GBIF/iNaturalist) (SoilGrids/WorldClim) (OBIS/WoRMS)
|
|
242
|
+
│ │ ↓
|
|
243
|
+
phylogenetics ───────────────┘ biodiversity-indices
|
|
244
|
+
(系統情報) │ (多様性指標)
|
|
245
|
+
↓
|
|
246
|
+
species-distribution-model
|
|
247
|
+
(SDM 統合)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## パイプライン出力
|
|
251
|
+
|
|
252
|
+
| ファイル | 説明 | 次スキル |
|
|
253
|
+
|---------|------|---------|
|
|
254
|
+
| `results/env_stack.csv` | 環境変数スタック | → species-distribution-model |
|
|
255
|
+
| `results/env_summary.csv` | 環境空間要約 | → environmental-ecology |
|