关于 emdb-database
emdb-database 是用于查询欧洲生物信息学研究所 EMDB 电子显微镜密度图档案的技能,适合结构生物学研究与数据整理。它结合关键词检索和单条目 JSON 数据,提供图谱元数据、拟合的 PDB 模型及引文信息。
主要功能
- 01按关键词检索 EMDB 条目
- 02获取分辨率、方法和样本信息
- 03读取密度图文件及地图头信息
- 04查询拟合的 PDB 原子模型
- 05提取条目引文和出版信息
适用场景
- 01查找特定蛋白或复合物的冷冻电镜图谱
- 02筛选特定生物或分辨率的结构条目
- 03获取图谱文件信息以便下载
- 04整理结构研究的元数据与引文
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill emdb-database安装后在 Claude Code 中输入/emdb-database确认已加载。
详细介绍
EMDB 数据库
概览
EBI 的电子显微镜数据银行(EMDB)存档大分子复合物的三维电子显微镜密度图——主要是冷冻电镜(cryo-EM)和冷冻电子断层扫描(cryo-ET)数据(30,000 多个条目:核糖体、膜蛋白、病毒和大型复合物)。数据可通过两个服务访问:
- EMDB 条目 API(
https://www.ebi.ac.uk/emdb/api/entry/{EMD-XXXXX})——每个条目的规范 JSON,包含元数据、密度图头信息、拟合的 PDB 列表和引文。/map、/fitted、/publications等子端点不存在——这些数据都包含在同一条目响应中。 - EBI Search WS(
https://www.ebi.ac.uk/ebisearch/ws/rest/emdb)——真正的关键词搜索后端(基础端点https://www.ebi.ac.uk/emdb/api/search/会忽略查询,仅返回最近的条目)。
无需身份验证或 API 密钥。
适用场景
- 按关键词查找冷冻电镜密度图(例如,“刺突蛋白”“70S 核糖体”)
- 获取
.map.gz密度文件的下载 URL,以便在 ChimeraX / PyMOL 中使用 - 查找拟合到某个 EMDB 密度图中的 PDB 原子模型(以及反向查找)
- 获取条目元数据——分辨率、重构方法、物种、样本
- 按物种或分辨率阈值筛选并列出冷冻电镜结构
- 获取 EMDB 条目的主要引文(期刊、DOI、PubMed ID)
- 如果需要实验测定的原子坐标,请改用
pdb-database - 如果需要 AI 预测的结构,请使用
alphafold-database-access;EMDB 仅收录实验电子显微镜密度图
先决条件
- Python 包:
requests、pandas、matplotlib - 数据要求:EMDB 条目 ID(
EMD-XXXXX)、关键词搜索字符串或用于交叉引用的 PDB ID - 环境:需要互联网连接;无需 API 密钥
- 速率限制:未公布官方限制;在批量循环的请求之间添加
time.sleep(0.2),以礼貌地访问服务
pip install requests pandas matplotlib
快速开始
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
EBI_SEARCH = "https://www.ebi.ac.uk/ebisearch/ws/rest/emdb"
# Keyword search via EBI Search WS (NOT /emdb/api/search/, which ignores q=)
r = requests.get(EBI_SEARCH,
params={"query": "sars-cov-2 spike", "size": 5, "format": "json",
"fields": "id,name,resolution,em_method,organism"},
timeout=30)
r.raise_for_status()
res = r.json()
print(f"Total hits: {res['hitCount']}")
for e in res["entries"]:
f = e["fields"]
name = (f.get("name") or [""])[0][:60]
resol = (f.get("resolution") or ["?"])[0]
print(f" {e['id']}: {name} ({resol} Å)")
核心 API
查询 1:关键词搜索(EBI Search WS)
返回按 EMDB ID 编号的分页命中列表,每个条目包含所请求的 fields。
import requests, pandas as pd
EBI_SEARCH = "https://www.ebi.ac.uk/ebisearch/ws/rest/emdb"
def emdb_search(query, size=20, start=0,
fields="id,name,resolution,em_method,organism"):
r = requests.get(EBI_SEARCH,
params={"query": query, "size": size, "start": start,
"format": "json", "fields": fields},
timeout=30)
r.raise_for_status()
return r.json()
data = emdb_search("ribosome 70S", size=10)
rows = []
for e in data["entries"]:
f = e["fields"]
rows.append({
"emdb_id": e["id"],
"name": (f.get("name") or [""])[0],
"resolution_A": float((f.get("resolution") or [0])[0] or 0) or None,
"em_method": (f.get("em_method") or [""])[0],
"organism": (f.get("organism") or [""])[0],
})
df = pd.DataFrame(rows)
print(f"hitCount={data['hitCount']}; first {len(df)} rows:")
print(df.to_string(index=False))
# Paged retrieval — iterate `start` until exhausting hitCount
def emdb_search_all(query, size=100, max_pages=5,
fields="id,name,resolution,em_method"):
out = []
for page in range(max_pages):
d = emdb_search(query, size=size, start=page * size, fields=fields)
if not d["entries"]:
break
out.extend(d["entries"])
if len(out) >= d["hitCount"]:
break
return out
hits = emdb_search_all("ferritin", size=50, max_pages=2)
print(f"Pulled {len(hits)} ferritin entries")
查询 2:条目元数据
单个条目端点会在一个文档中返回所有元数据、密度图头信息、拟合的 PDB 列表和引文。请仔细读取字段路径——大多数字段都嵌套在其他字段中。
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
def emdb_entry(emdb_id):
r = requests.get(f"{EMDB_API}/entry/{emdb_id}", timeout=30)
r.raise_for_status()
return r.json()
e = emdb_entry("EMD-30210") # nsp12-nsp7-nsp8 + Remdesivir (RdRp)
print(f"Title : {e['admin']['title']}")
print(f"Status : {e['admin']['current_status']}")
print(f"Key dates : {e['admin'].get('key_dates')}")
sd = e["structure_determination_list"]["structure_determination"][0]
ip = sd["image_processing"][0]
res = ip["final_reconstruction"]["resolution"]
print(f"Method : {sd['method']}")
print(f"Resolution : {res['valueOf_']} {res['units']} (type: {res['res_type']})")
查询 3:密度图头信息 / 下载信息
entry["map"] 包含文件名、格式、体素网格、轴顺序、晶胞、等值面阈值和建议显示阈值。
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
m = e["map"]
print(f"Map file : {m.get('file')}") # e.g. emd_30210.map.gz
print(f"Format : {m.get('format')}") # 'CCP4'
print(f"Dimensions : {m.get('dimensions')}") # {'col': ..., 'row': ..., 'sec': ...}
print(f"Axis order : {m.get('axis_order')}") # {'fast': 'X', 'medium': 'Y', 'slow': 'Z'}
print(f"Contour list : {m.get('contour_list')}") # recommended threshold(s)
# Conventional FTP/HTTPS download URL pattern (mirror at EBI):
EMDB_FTP = "https://ftp.ebi.ac.uk/pub/databases/emdb/structures"
emdb_num = "EMD-30210"
print(f"Download URL : {EMDB_FTP}/{emdb_num}/map/{m['file']}")
查询 4:拟合的 PDB 原子模型
EMDB 会交叉引用拟合到密度图中的 PDB 条目。每个项目都包含 PDB ID 和关系标签(例如,FULLOVERLAP)。
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
pdblist = e.get("crossreferences", {}).get("pdb_list", {})
pdb_refs = pdblist.get("pdb_reference", []) if isinstance(pdblist, dict) else []
print(f"Fitted PDB entries: {len(pdb_refs)}")
for ref in pdb_refs:
in_frame = (ref.get("relationship") or {}).get("in_frame")
print(f" {ref['pdb_id'].upper():6s} relationship={in_frame}")
# 7BV2 relationship=FULLOVERLAP
查询 5:引文和出版物
主要引文位于 entry["crossreferences"]["citation_list"]。其结构因引文类型而异(期刊论文或预印本)。
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
citations = e.get("crossreferences", {}).get("citation_list", {})
primary = citations.get("primary_citation", {})
ct = primary.get("citation_type") or primary
title = (ct.get("title") or "").strip()
journal = ct.get("journal") or ct.get("book_title")
year = ct.get("year")
authors = [a.get("name") or a.get("name_str")
for a in (ct.get("author") or ct.get("author_order") or [])
if a]
xrefs = ct.get("external_references", []) or ct.get("xref", [])
doi = next((x.get("valueOf_") for x in xrefs if x.get("type") == "DOI"), None)
pmid = next((x.get("valueOf_") for x in xrefs if x.get("type") == "PUBMED"), None)
print(f"Title : {title[:80]}")
print(f"Journal : {journal} ({year})")
print(f"Authors : {', '.join(a for a in authors[:5] if a)}{'...' if len(authors) > 5 else ''}")
print(f"DOI : {doi}")
print(f"PMID : {pmid}")
查询 6:样本和物种
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
sample = e.get("sample", {})
sm_list = (sample.get("supramolecule_list") or {}).get("supramolecule", [])
for sm in sm_list:
ns = sm.get("natural_source") or sm.get("natural_source_list", {}).get("natural_source") or []
if isinstance(ns, dict):
ns = [ns]
for n in ns:
org = (n.get("organism") or {}).get("valueOf_")
print(f" Supramolecule '{sm.get('name', {}).get('valueOf_', '?')}': {org}")
核心概念
字段路径映射(/api/entry/{id} 文档)
| 内容 | 路径 |
|---|---|
| 标题 | admin.title |
| 发布日期 | admin.key_dates |
| 作者 | admin.authors_list.author[*].name/name_str |
| 电镜方法 | structure_determination_list.structure_determination[0].method(例如,singleParticle、tomography) |
| 分辨率 | structure_determination_list.structure_determination[0].image_processing[0].final_reconstruction.resolution.valueOf_(字符串,单位为 Å;转换为浮点数) |
| 密度图文件名 | map.file |
| 密度图格式/尺寸 | map.format / map.dimensions |
| 等值面阈值 | map.contour_list |
| 拟合的 PDB | crossreferences.pdb_list.pdb_reference[*].pdb_id |
| 引文 | crossreferences.citation_list.primary_citation.citation_type(期刊/年份/标题/作者/外部参考文献) |
| DOI/PubMed | …citation_type.external_references[],其中 type 为 {DOI, PUBMED} |
| 物种 | sample.supramolecule_list.supramolecule[*].natural_source[*].organism.valueOf_ |
搜索与条目
- 关键词搜索 → EBI Search WS (
/ebisearch/ws/rest/emdb)。使用此接口选择query=、size=、start=和fields=。 /emdb/api/search/不可靠——它会悄悄忽略q=,并返回最新发布的条目。不要依赖它。- 条目详情 →
/emdb/api/entry/{EMD-XXXXX}。没有/map、/fitted或/publications子端点——这些内容都在条目文档中。
常见工作流
工作流 1:筛选主题相关的分辨率
目标:查找高分辨率的 SARS-CoV-2 刺突蛋白条目,并报告其拟合的 PDB 模型。
import requests, time, pandas as pd
EBI_SEARCH = "https://www.ebi.ac.uk/ebisearch/ws/rest/emdb"
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
# Step 1: keyword search via EBI Search
hits = []
for start in (0, 50):
r = requests.get(EBI_SEARCH,
params={"query": "sars-cov-2 spike", "size": 50, "start": start,
"format": "json", "fields": "id,name,resolution"},
timeout=30)
r.raise_for_status()
hits.extend(r.json()["entries"])
time.sleep(0.2)
# Step 2: filter to resolution ≤ 3.0 Å (skip entries with missing field)
rows = []
for h in hits:
f = h["fields"]
name = (f.get("name") or [""])[0]
try:
resol = float((f.get("resolution") or [None])[0])
except (TypeError, ValueError):
continue
if resol <= 3.0:
rows.append({"emdb_id": h["id"], "resolution_A": resol, "name": name[:60]})
df = pd.DataFrame(rows).sort_values("resolution_A")
print(f"Spike entries ≤ 3.0 Å: {len(df)}")
print(df.head(10).to_string(index=False))
# Step 3: pull fitted PDB ids for the top 5
for emdb_id in df["emdb_id"].head(5):
e = requests.get(f"{EMDB_API}/entry/{emdb_id}", timeout=30).json()
pdblist = e.get("crossreferences", {}).get("pdb_list", {}) or {}
pdbs = [p["pdb_id"].upper() for p in pdblist.get("pdb_reference", [])]
print(f" {emdb_id} -> PDB: {', '.join(pdbs) if pdbs else '(none fitted)'}")
time.sleep(0.2)
工作流 2:构建队列元数据表
目标:针对一个查询,返回包含方法、分辨率、生物体和地图下载 URL 的 DataFrame——适用于综述论文。
import requests, time, pandas as pd
EBI_SEARCH = "https://www.ebi.ac.uk/ebisearch/ws/rest/emdb"
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
EMDB_FTP = "https://ftp.ebi.ac.uk/pub/databases/emdb/structures"
def cohort_table(query, size=10):
r = requests.get(EBI_SEARCH,
params={"query": query, "size": size, "format": "json", "fields": "id"},
timeout=30)
r.raise_for_status()
rows = []
for h in r.json()["entries"]:
emdb_id = h["id"]
e = requests.get(f"{EMDB_API}/entry/{emdb_id}", timeout=30).json()
sd = e["structure_determination_list"]["structure_determination"][0]
ip = sd["image_processing"][0]
try:
resol = float(ip["final_reconstruction"]["resolution"]["valueOf_"])
except (KeyError, ValueError, TypeError):
resol = None
m = e["map"]
rows.append({
"emdb_id": emdb_id,
"title": e["admin"]["title"][:60],
"method": sd.get("method"),
"resolution_A": resol,
"map_url": f"{EMDB_FTP}/{emdb_id}/map/{m['file']}" if m.get("file") else None,
})
time.sleep(0.2)
return pd.DataFrame(rows)
df = cohort_table("ribosome 70S bacterial", size=6)
print(df.to_string(index=False))
df.to_csv("emdb_cohort.csv", index=False)
关键参数
| 参数 | 端点 | 默认值 | 范围 / 选项 | 效果 |
|---|---|---|---|---|
query | EBI Search /emdb | 必填 | 文本搜索字符串 | 要匹配的关键词 |
size | EBI Search /emdb | 15 | 1–100 | 每页命中数 |
start | EBI Search /emdb | 0 | 非负整数 | 分页偏移量 |
fields | EBI Search /emdb | (子集) | 以逗号分隔的 EBI Search 字段 | 要返回的每条命中记录的字段(id,name,resolution,em_method,organism 等) |
format | EBI Search /emdb | json | json、xml | 响应格式 |
(路径){EMD-XXXXX} | /api/entry/{id} | 必填 | EMDB 登录号 | 单条目详情 |
最佳实践
- 关键词搜索始终使用 EBI Search WS。
https://www.ebi.ac.uk/emdb/api/search/会忽略q=,只返回最新发布的条目——依赖它会导致队列结果悄然出错。 - 没有子端点。 不要调用
/api/entry/{id}/map、/fitted、/publications或/api/statistics/——这些端点都会返回 404(/statistics/会返回 HTML)。所有内容都从单个条目文档中读取。 - 显式将
resolution.valueOf_转换为浮点数。 该字段是类似"2.5"的字符串;数值筛选需要显式转换(并使用try/except处理缺少值的条目)。 - EBI Search 字段值以列表形式返回。 即使是
name这样的单值字段,也会以{"name": ["..."]}的形式返回——始终索引[0]或进行拼接。 - 在逐条处理条目的循环中加入
time.sleep(0.2)。 虽然没有公布速率限制,但 API 托管在共享服务上;适当间隔可避免暂时出现 502 错误。 - 地图下载 URL 的格式为
https://ftp.ebi.ac.uk/pub/databases/emdb/structures/{EMDB_ID}/map/{file}——根据entry["map"]["file"]推导,不要硬编码。
常见用法
用法:PDB → EMDB 交叉引用
import requests
# Given an EMDB ID, get its fitted PDB; given a PDB ID, you'd query
# RCSB PDB /rest/v2/entry/{pdb_id} and read `rcsb_external_references.emdb_id`.
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
pdblist = e.get("crossreferences", {}).get("pdb_list") or {}
print({"emdb": e["emdb_id"],
"pdbs": [p["pdb_id"].upper() for p in pdblist.get("pdb_reference", [])]})
用法:某生物体的最高分辨率条目
import requests, time, pandas as pd
EBI_SEARCH = "https://www.ebi.ac.uk/ebisearch/ws/rest/emdb"
def best_by_organism(organism, size=50):
r = requests.get(EBI_SEARCH,
params={"query": f'organism:"{organism}"', "size": size,
"format": "json", "fields": "id,name,resolution"},
timeout=30)
r.raise_for_status()
rows = []
for h in r.json()["entries"]:
f = h["fields"]
try:
resol = float((f.get("resolution") or [None])[0])
except (TypeError, ValueError):
continue
rows.append({"emdb_id": h["id"], "resolution_A": resol,
"name": (f.get("name") or [""])[0][:60]})
return pd.DataFrame(rows).sort_values("resolution_A").reset_index(drop=True)
df = best_by_organism("Saccharomyces cerevisiae", size=20)
print(df.head(8).to_string(index=False))
用法:引文导出(适用于 BibTeX)
import requests
EMDB_API = "https://www.ebi.ac.uk/emdb/api"
e = requests.get(f"{EMDB_API}/entry/EMD-30210", timeout=30).json()
ct = (e.get("crossreferences", {})
.get("citation_list", {})
.get("primary_citation", {})
.get("citation_type")) or {}
authors = [a.get("name") or a.get("name_str")
for a in (ct.get("author") or ct.get("author_order") or [])]
xrefs = ct.get("external_references", []) or ct.get("xref", [])
doi = next((x.get("valueOf_") for x in xrefs if x.get("type") == "DOI"), "")
print({"title": (ct.get("title") or "").strip(),
"journal": ct.get("journal"),
"year": ct.get("year"),
"authors_n": len(authors),
"doi": doi})
故障排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
搜索 EMDB 时出现 KeyError: 'results' 或 'numFound' | /api/search/ 返回原始 JSON 数组,并忽略 q= | 使用 EBI Search WS(/ebisearch/ws/rest/emdb)——包装对象为 {hitCount, entries, facets} |
/api/entry/{id}/map(或 /fitted、/publications)返回 HTTP 404 | 这些子端点不存在 | 从单条条目响应中读取 entry["map"]、entry["crossreferences"]["pdb_list"]、entry["crossreferences"]["citation_list"] |
| 分辨率以字符串形式返回 | EMDB 将数值字段存储为字符串 | 使用 float(entry[...]['resolution']['valueOf_'])——并用 try/except 包裹 |
| EBI Search 的字段看起来像单元素列表 | EBI Search 会将多值字段作为列表返回 | 读取 f["name"][0](或使用 (... or [""])[0] 作为后备) |
EBI Search 返回空的 entries | 字段限定符错误或有拼写错误 | 移除字段限定符,使用纯文本搜索;访问 https://www.ebi.ac.uk/ebisearch/ 检查 |
/api/statistics/ 返回 HTML 响应 | /statistics/ 返回的是 HTML,而不是 JSON | 此端点供 Web UI 使用;不要以编程方式调用 |
某条目的 pdb_list 为 {} | 该图谱没有拟合的原子模型 | 这是正常情况——许多断层图 / 亚断层平均图都没有拟合的 PDB |
相关技能
pdb-database— RCSB PDB,提供 EMDB 交叉引用中的原子模型信息alphafold-database-access— AI 预测的结构(可补充实验性 EMDB 图谱)uniprot-protein-database— 确定 EMDB 样本的生物体 / 序列背景cellxgene-census— 可补充结构调查的组织 / 细胞类型表达数据
参考资料
- EBI 上的 EMDB — 浏览、下载、查看统计信息、提交数据
- EMDB 条目 API — 条目 JSON 示例
- EBI Search WS — EMDB — 关键词搜索文档
- EMDB FTP 镜像 — 密度图谱和元数据下载
- Lawson CL 等。《EMDB——电子显微镜数据银行》。Nucleic Acids Research 52(D1):D456–D465(2024)。https://doi.org/10.1093/nar/gkad1019
评论
支持 Markdown