mcpField
M
metabolomics-workbench-database

metabolomics-workbench-database

github.com/jaechang-hits数据与数据库38470 次安装1 周前更新
代码仓库

关于 metabolomics-workbench-database

这是面向代谢组学研究者的 Metabolomics Workbench REST API 使用技能,可查询化合物、研究及相关注释。它涵盖 RefMet 名称标准化和基于 m/z 的候选物检索,并说明了 API 的格式与端点注意事项。

主要功能

  1. 01按化合物标识符查询记录
  2. 02按条件发现代谢组学研究
  3. 03将名称标准化为 RefMet
  4. 04按 m/z 与离子类型检索候选物
  5. 05获取研究代谢物表及注释

适用场景

  1. 01将自由文本名称映射为标准代谢物记录
  2. 02根据质谱峰值查找候选化合物
  3. 03查找检测特定代谢物的研究
  4. 04下载研究数据用于本地分析

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill metabolomics-workbench-database

安装后在 Claude Code 中输入/metabolomics-workbench-database确认已加载。

详细介绍

Metabolomics Workbench Database — REST API 访问

概述

Metabolomics Workbench(MW)REST API 位于 https://www.metabolomicsworkbench.org/rest/,提供 UCSD 托管的 4,200 多项代谢组学研究数据,这些研究由 NIH Common Fund 资助。URL 模式为 /{context}/{input_item}/{input_value}/{output_item}/{format}。上下文包括 compound、refmet、moverz、study、analysis、metabolite、gene、protein。实时测试发现以下值得注意的特性:

  • compound/name/{x} 会被拒绝——name 不是允许的 input_item。请使用 pubchem_cid、kegg_id、inchi_key、hmdb_id、regno、lm_id、formula、smiles 或 abbrev。对于自由文本输入,请先通过 refmet/match/{x} 处理。
  • refmet/name/{x}/all 要求使用精确的 RefMet 名称(例如 Glucose,而不是 D-glucose);请先使用 refmet/match/{x} 进行模糊标准化。
  • moverz/{REFMET|LIPIDS|MB}/{mz}/{ion}/{tol}/txt 返回 TSV 文本(没有 JSON 版本)。
  • 旧示例中展示的 metstat/filter/... 端点会返回 []——请改用 study/{context}/{value}/summary(或 /metabolites)并在客户端进行筛选。

无需身份验证。

适用场景

  • 按 PubChem CID、KEGG ID、InChIKey、HMDB ID、分子式或 SMILES 搜索代谢物记录
  • 按物种、疾病、last_name、机构、分析类型或极性发现研究
  • 将代谢物名称标准化为 RefMet 命名法,以便跨研究整合
  • 使用支持加合物匹配的方式(moverz),根据 MS m/z 值识别未知化合物
  • 从已发表的研究中获取实验代谢物表(分析结果、丰度数据)
  • 查询与代谢组学通路关联的基因/蛋白注释
  • 下载原始 mwTab 文件以供本地分析
  • 如需使用 NMR/MS 谱解析本地 22 万代谢物 XML,请改用 hmdb-database
  • 如需实时查询 1.1 亿种化合物的属性,请改用 pubchem-compound-search

先决条件

  • Python 包:requests、pandas
  • 无需 API 密钥:可公开访问
  • 速率限制:MW 不实施严格限制;批量请求之间请添加 time.sleep(0.3)
  • 基础 URL:https://www.metabolomicsworkbench.org/rest
pip install requests pandas

快速入门

import requests

BASE = "https://www.metabolomicsworkbench.org/rest"

# Two-step free-text → compound (the API rejects compound/name/...)
def lookup_by_name(name):
    # 1) Normalise to RefMet name
    r = requests.get(f"{BASE}/refmet/match/{name}", timeout=30)
    r.raise_for_status()
    refmet = r.json()
    if not refmet.get("refmet_name"):
        return None
    # 2) Pull full compound record by RefMet name (or by pubchem_cid)
    r2 = requests.get(f"{BASE}/refmet/name/{refmet['refmet_name']}/all", timeout=30)
    rec = r2.json() if r2.json() else {}
    return rec if isinstance(rec, dict) else None

c = lookup_by_name("glucose")
print(f"{c['name']}: formula={c['formula']}, PubChem CID={c['pubchem_cid']}, "
      f"InChIKey={c['inchi_key']}")
# Glucose: formula=C6H12O6, PubChem CID=5793, InChIKey=WQZGKKKJIJFFOK-GASJEMHNSA-N

核心 API

模块 1:化合物查询

compound/{input_item}/{input_value}/all/json——input_item 必须是 regno、formula、inchi_key、lm_id、pubchem_cid、hmdb_id、kegg_id、smiles、abbrev 中的一个。服务器会拒绝旧版的 name 输入。

import requests

BASE = "https://www.metabolomicsworkbench.org/rest"

# By PubChem CID
r = requests.get(f"{BASE}/compound/pubchem_cid/5793/all/json", timeout=30)
glucose = r.json()
print(f"PubChem 5793 -> {glucose['name']}, formula={glucose['formula']}, "
      f"HMDB={glucose.get('hmdb_id')}, KEGG={glucose.get('kegg_id')}")

# By KEGG ID
r = requests.get(f"{BASE}/compound/kegg_id/C00031/all/json", timeout=30)
print("KEGG C00031 ->", r.json()["name"])

# By InChIKey
r = requests.get(f"{BASE}/compound/inchi_key/WQZGKKKJIJFFOK-GASJEMHNSA-N/all/json", timeout=30)
print("InChIKey -> regno:", r.json()["regno"])
# Compound by formula returns a paged dict (multiple matches)
import requests
BASE = "https://www.metabolomicsworkbench.org/rest"
r = requests.get(f"{BASE}/compound/formula/C6H12O6/all/json", timeout=30)
matches = r.json()
print(f"Compounds with formula C6H12O6: {len(matches)}")
for k in list(matches)[:3]:
    print(f"  regno={matches[k]['regno']}  name={matches[k]['name']}")
模块 2:研究发现

study/{input_item}/{input_value}/{output}——input_item 包括 study_id、study_title、last_name、institute、analysis_id、metabolite_id、kegg_id、refmet_name。output 包括 summary、metabolites、factors、data、available_studies、species、disease。对于 study_id,summary 返回字典(有多个 accession 时以 accession 为键);对于 last_name/institute,则返回列表。

import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

# Single-study summary — `study/study_id/{id}/summary` returns a flat dict
# (keys: study_id, study_title, species, institute, analysis_type, ...)
r = requests.get(f"{BASE}/study/study_id/ST000001/summary", timeout=30)
s = r.json()
print(f"{s['study_id']}: {s['study_title'][:60]}")
print(f"  Species : {s.get('species')}  Institute: {s.get('institute')}")
print(f"  Submit  : {s.get('submission_date')}")
# Studies that detected a metabolite — `study/refmet_name/{x}/summary` returns
# a thin index of (refmet_name, kegg_id, study_id) rows. Chain study_id → full summary
# to get title and species.
import requests, pandas as pd
BASE = "https://www.metabolomicsworkbench.org/rest"
r = requests.get(f"{BASE}/study/refmet_name/Glucose/summary", timeout=60)
d = r.json()
rows = list(d.values()) if isinstance(d, dict) else d
print(f"Studies referencing 'Glucose': {len(rows)}")
print(pd.DataFrame(rows).head(5).to_string(index=False))
# refmet_name kegg_id  study_id
#     Glucose  C00031  ST000001
#     Glucose  C00031  ST000002
#     ...
模块 3:RefMet 标准化

refmet/match/{user_text} 是模糊标准化器——返回标准 RefMet 记录(但不含 pubchem_cid/kegg_id)。refmet/name/{exact_refmet_name}/all 返回包含 ID 在内的完整记录。请将两者作为两步处理流程使用。

import requests

BASE = "https://www.metabolomicsworkbench.org/rest"

def normalise_to_refmet(user_text):
    r = requests.get(f"{BASE}/refmet/match/{user_text}", timeout=30)
    r.raise_for_status()
    m = r.json()
    if not m or not m.get("refmet_name"):
        return None
    return m["refmet_name"]

def refmet_full(refmet_name):
    r = requests.get(f"{BASE}/refmet/name/{refmet_name}/all", timeout=30)
    r.raise_for_status()
    rec = r.json()
    return rec if isinstance(rec, dict) and rec else None

name = normalise_to_refmet("alpha-D-glucose")  # -> 'Glucose'
print(f"Normalised: {name}")
rec = refmet_full(name)
print(f"  PubChem CID : {rec['pubchem_cid']}")
print(f"  InChIKey    : {rec['inchi_key']}")
print(f"  Super class : {rec['super_class']} / {rec['main_class']} / {rec['sub_class']}")
模块 4:研究筛选(替代失效的 metstat)

旧版 metstat/filter/... 端点会返回 []。请改用 study 上下文端点,并在客户端进行筛选。

import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

def study_ids_for_metabolite(refmet_name):
    """Return the study_id list that report a given RefMet name."""
    r = requests.get(f"{BASE}/study/refmet_name/{refmet_name}/summary", timeout=60)
    r.raise_for_status()
    d = r.json()
    rows = list(d.values()) if isinstance(d, dict) else d
    return sorted({row["study_id"] for row in rows if row.get("study_id")})

def study_summary(study_id):
    """Pull full summary (title, species, institute, dates) for one study_id.
    Response is a flat dict with keys study_id/study_title/species/institute/..."""
    return requests.get(f"{BASE}/study/study_id/{study_id}/summary", timeout=30).json()

# Find glucose studies, then enrich the first few
ids = study_ids_for_metabolite("Glucose")
print(f"Studies referencing 'Glucose': {len(ids)}")
rows = [study_summary(sid) for sid in ids[:5]]
df = pd.DataFrame(rows)
print(df[["study_id", "study_title", "species"]].head().to_string(index=False))
模块 5:m/z 前体搜索(moverz)

moverz/{REFMET|LIPIDS|MB}/{mz}/{ion}/{tolerance}/txt 返回制表符分隔的文本(不是 JSON)。第一个数据库选择器(REFMET、LIPIDS 或 MB)为必填项——若将 mz 放在第一段,服务器会拒绝请求。

import requests, io, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

def moverz_search(db, mz, ion, tolerance=0.005):
    """Search precursor m/z in REFMET / LIPIDS / MB and return a DataFrame.
    Response is TSV text — no JSON variant."""
    assert db in {"REFMET", "LIPIDS", "MB"}
    r = requests.get(f"{BASE}/moverz/{db}/{mz}/{ion}/{tolerance}/txt", timeout=30)
    r.raise_for_status()
    return pd.read_csv(io.StringIO(r.text), sep="\t")

df = moverz_search("REFMET", 180.063, "M+H", 0.005)
print(f"Candidates at m/z 180.063 [M+H]+ (REFMET): {len(df)}")
print(df.head(5).to_string(index=False))
# Same query against the LIPIDS database
import requests, io, pandas as pd
BASE = "https://www.metabolomicsworkbench.org/rest"
r = requests.get(f"{BASE}/moverz/LIPIDS/760.585/M+H/0.01/txt", timeout=30)
df_lipids = pd.read_csv(io.StringIO(r.text), sep="\t")
print(f"Lipid candidates at m/z 760.585: {len(df_lipids)}")
print(df_lipids.head(3).to_string(index=False))
模块 6:基因和蛋白质
import requests

BASE = "https://www.metabolomicsworkbench.org/rest"

r = requests.get(f"{BASE}/gene/gene_symbol/HMGCR/all", timeout=30)
g = r.json()
print(f"{g['gene_symbol']} -> MGP: {g.get('mgp_id')}  ({g.get('gene_name', '')[:60]})")

# Protein by UniProt accession
r2 = requests.get(f"{BASE}/protein/uniprot_id/P04035/all", timeout=30)
p = r2.json()
print(f"UniProt P04035: {p.get('protein_name', '')[:60]}  organism={p.get('organism')}")

关键概念

各上下文允许的 input_item 值
上下文有效的 input_item说明
compoundregno、formula、inchi_key、lm_id、pubchem_cid、hmdb_id、kegg_id、smiles、abbrev不接受 name——请先使用 refmet/match
refmetmatch、name、formula、exactmass、inchi_key、pubchem_cid、regnomatch 为模糊匹配;name 需要规范的 RefMet 名称
studystudy_id、study_title、last_name、institute、analysis_id、metabolite_id、kegg_id、refmet_name对 study_id,summary 返回以 accession 为键的字典;对 last_name/institute,则返回列表
moverz(路径)REFMET / LIPIDS / MB第一段是数据库,而不是 mz
genegene_id、gene_symbol、gene_name、mgp_id返回字典
proteinmgp_id、gene_id、uniprot_id、gene_symbol返回字典
输出类型约定
  • 当输入标识符唯一(例如 study_id)时,output=summary 返回字典;不唯一(例如 last_name)时,则返回列表。
  • 在 study/.../summary 后附加 /json 会将响应切换为 TSV。省略格式后缀——默认格式为 JSON。
  • moverz 仅输出 /txt(TSV);没有 JSON 格式。
refmet/match 与 refmet/name 的区别
  • refmet/match/{user_text}——模糊匹配。始终返回包含 refmet_name、formula、exactmass 和分类信息的单个字典。不包含 pubchem_cid/inchi_key。
  • refmet/name/{exact_refmet_name}/all——需要规范的 RefMet 名称。返回包含完整 ID 的记录。如果名称不是规范名称,则返回空列表。

常见工作流

工作流 1:自由文本 → 完整化合物记录
import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

def resolve_to_compound(user_text):
    # 1) Normalise via refmet/match
    rm = requests.get(f"{BASE}/refmet/match/{user_text}", timeout=30).json()
    if not rm.get("refmet_name"):
        return None
    name = rm["refmet_name"]
    # 2) Fetch full RefMet record (includes pubchem_cid / inchi_key)
    full = requests.get(f"{BASE}/refmet/name/{name}/all", timeout=30).json()
    if not isinstance(full, dict) or not full:
        return None
    # 3) Optionally pull the matching compound record via PubChem CID
    cid = full.get("pubchem_cid")
    compound = None
    if cid:
        compound = requests.get(f"{BASE}/compound/pubchem_cid/{cid}/all/json",
                                timeout=30).json()
    return {
        "input": user_text,
        "refmet_name": name,
        "formula": full.get("formula"),
        "pubchem_cid": cid,
        "hmdb_id": compound.get("hmdb_id") if compound else None,
        "kegg_id": compound.get("kegg_id") if compound else None,
        "inchi_key": full.get("inchi_key"),
    }

queries = ["glucose", "alpha-D-glucose", "L-tyrosine", "cholesterol"]
df = pd.DataFrame([resolve_to_compound(q) for q in queries])
print(df.to_string(index=False))
df.to_csv("name_resolution.csv", index=False)
工作流 2:注释 MS 命中列表

目标:为一组测量所得的 m/z 值分配 RefMet 候选化合物。

import requests, io, pandas as pd, time

BASE = "https://www.metabolomicsworkbench.org/rest"

def annotate_peaks(mz_values, ion="M+H", tolerance=0.005):
    out = []
    for mz in mz_values:
        r = requests.get(f"{BASE}/moverz/REFMET/{mz}/{ion}/{tolerance}/txt", timeout=30)
        if r.status_code != 200 or not r.text.strip():
            time.sleep(0.3); continue
        df = pd.read_csv(io.StringIO(r.text), sep="\t")
        for _, row in df.iterrows():
            out.append({
                "query_mz": mz,
                "matched_mz": row["Matched m/z"],
                "delta": row["Delta"],
                "name": row["Name"],
                "formula": row["Formula"],
                "ion": row["Ion"],
                "main_class": row.get("Main class"),
            })
        time.sleep(0.3)
    return pd.DataFrame(out)

peaks = [180.063, 166.086, 90.055]   # glucose, phenylalanine, alanine
df_ann = annotate_peaks(peaks)
print(df_ann.head(10).to_string(index=False))
df_ann.to_csv("ms_annotations.csv", index=False)
工作流 3:查找检测到某种代谢物的研究
import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

def studies_with(refmet_name, enrich_n=20):
    """Return a DataFrame: study_id rows that report the metabolite, enriched with
    title + species for the first `enrich_n` IDs (via study/study_id/.../summary)."""
    r = requests.get(f"{BASE}/study/refmet_name/{refmet_name}/summary", timeout=60)
    r.raise_for_status()
    d = r.json()
    rows = list(d.values()) if isinstance(d, dict) else d
    ids = sorted({row["study_id"] for row in rows if row.get("study_id")})
    enriched = []
    for sid in ids[:enrich_n]:
        enriched.append(requests.get(
            f"{BASE}/study/study_id/{sid}/summary", timeout=30).json())
    return pd.DataFrame(enriched)

df = studies_with("Glucose", enrich_n=20)
print(f"Glucose-detecting studies (first 20 enriched): {len(df)}")
print(df.groupby("species").size().sort_values(ascending=False).head(8))

关键参数

参数端点默认值范围 / 选项效果
context路径必填compound、refmet、moverz、study、analysis、metabolite、gene、proteinAPI 上下文选择器
input_item路径必填取决于上下文(参见“各上下文允许的 input_item 值”)标识符类型
input_value路径必填字符串实际标识符或值
output_item路径allall、summary、metabolites、factors、data 等要返回的内容
format路径(因情况而异)json、txtmoverz 仅输出 txt;不要在 study/.../summary 后附加 /json
mz / ion / tolerancemoverz 路径必填float / M+H、M-H、M+Na、M+K 等 / float质量容差,单位为 Da

最佳实践

  1. 自由文本输入请先使用 refmet/match。 服务器不接受 compound/name/...(name 不是允许的 input_item)。
  2. moverz 仅支持 TSV。 使用 pd.read_csv(io.StringIO(r.text), sep="\t") 进行解析——切勿对响应调用 .json()。
  3. 不要在 study/.../summary 后附加 /json。 默认格式为 JSON;附加后缀会将响应切换为 TSV。
  4. refmet/name/{x}/all 需要规范的 RefMet 名称。 如果有用户输入的文本,请先通过 refmet/match 处理。
  5. 按分子式分页的化合物结果以 '1'、'2'……作为键——请遍历 dict.values(),或传入 pd.DataFrame.from_dict(orient="index")。
  6. 批量循环中始终使用 time.sleep(0.3)——虽然没有公布速率限制,但该服务器由多个用户共用。

常用示例

示例:跨数据库 ID 映射(PubChem ↔ KEGG ↔ HMDB)
import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"

def cross_refs(refmet_name):
    rm = requests.get(f"{BASE}/refmet/name/{refmet_name}/all", timeout=30).json()
    if not isinstance(rm, dict) or not rm:
        return None
    cid = rm.get("pubchem_cid")
    if not cid:
        return {"refmet": refmet_name, "pubchem_cid": None}
    c = requests.get(f"{BASE}/compound/pubchem_cid/{cid}/all/json", timeout=30).json()
    return {"refmet": refmet_name,
            "pubchem_cid": cid,
            "kegg_id": c.get("kegg_id"),
            "hmdb_id": c.get("hmdb_id"),
            "inchi_key": rm.get("inchi_key")}

df = pd.DataFrame([cross_refs(n) for n in ["Glucose", "L-Tyrosine", "Cholesterol"]])
print(df.to_string(index=False))
示例:提取研究的代谢物表格
import requests, pandas as pd

BASE = "https://www.metabolomicsworkbench.org/rest"
r = requests.get(f"{BASE}/study/study_id/ST000001/metabolites", timeout=60)
r.raise_for_status()
rows = list(r.json().values())
df = pd.DataFrame(rows)
print(f"ST000001 metabolites: {len(df)}")
print(df[["analysis_id", "analysis_summary", "metabolite_name", "refmet_name"]].head(5).to_string(index=False))
示例:基因 → 代谢组学通路
import requests

BASE = "https://www.metabolomicsworkbench.org/rest"
g = requests.get(f"{BASE}/gene/gene_symbol/HMGCR/all", timeout=30).json()
print({k: g.get(k) for k in ["gene_symbol", "gene_id", "mgp_id",
                              "gene_name", "gene_synonyms"]})

故障排查

问题原因解决方案
"This input item (name) is not allowed..."compound/name/... 会被拒绝使用允许的 input_item 值之一(pubchem_cid、kegg_id、inchi_key、hmdb_id 等);对于自由文本,请先通过 refmet/match/{x} 查询
moverz 响应出现 JSONDecodeErrormoverz 返回的是 TSV 文本,而非 JSON使用 pd.read_csv(io.StringIO(r.text), sep="\t") 解析
refmet/name/{x}/all 返回空列表需要使用规范的 RefMet 名称(区分大小写)先通过 refmet/match/{user_text} 规范化,再将 refmet_name 填入 refmet/name/.../all
metstat/filter/... 返回 []端点语法无法使用使用 `study/{refmet_name
study/.../summary 返回 TSV 而非 JSON/json 后缀会切换为 TSV删除末尾的 /json——默认返回 JSON
按分子式查询化合物时返回字典而非列表服务会将多个匹配结果分页为 {'1': {...}, '2': {...}}遍历 dict.values()(或使用 pd.DataFrame.from_dict(d, orient='index'))
refmet/match 响应缺少 pubchem_cidmatch 返回的是精简记录使用 refmet/name/{refmet_name}/all 获取完整记录

相关技能

  • hmdb-database — 本地 HMDB XML(22 万种代谢物、NMR/MS 光谱、疾病关联),用于离线查询
  • pubchem-compound-search — 通过 PubChemPy 查询通用化合物属性(超过 1.1 亿种化合物)
  • kegg-database — 与 MW 的研究/代谢物查询结果互补的通路和直系同源数据
  • chembl-database-bioactivity — 相同化合物的生物活性数据

参考资料

评论

支持 Markdown