mcpField
A
alterlab-gtex

alterlab-gtex

github.com/alterlab-ieu数据与数据库7866 次安装5 周前更新
代码仓库

关于 alterlab-gtex

alterlab-gtex 是用于查询 GTEx 组织表达与遗传调控数据的研究技能,适合分析基因表达、eQTL 和 sQTL,可通过 GTEx REST API 与数据下载获取信息。

主要功能

  1. 01按组织查询基因中位表达量
  2. 02查询基因和变异的 eQTL
  3. 03获取 sQTL 关联与 eGene
  4. 04列出组织并解析基因标识符
  5. 05使用 GTEx v10 和 v8 数据集

适用场景

  1. 01判断 GWAS 变异调控哪些基因
  2. 02比较基因在不同组织的表达
  3. 03查找组织特异性 eQTL 或 sQTL 关联

安装

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

$npx skills add https://github.com/alterlab-ieu/alterlab-academic-skills --skill alterlab-gtex

安装后在 Claude Code 中输入/alterlab-gtex确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
api_reference.md
scripts/
query_gtex.py

详细介绍

GTEx 数据库

概述

基因型-组织表达(GTEx)项目提供了一项综合资源,可用于研究近 1,000 名个体的 54 种非患病人体组织中的组织特异性基因表达和遗传调控。GTEx v10(最新版本)可帮助研究人员了解遗传变异如何以组织特异性的方式调控基因表达(eQTL)和剪接(sQTL),这对于解读 GWAS 位点和识别调控机制至关重要。

主要资源:

何时使用此技能

以下情况可使用 GTEx:

  • GWAS 位点解读:通过 eQTL 确定非编码 GWAS 变异调控的基因
  • 组织特异性表达:比较基因在 54 种人体组织中的表达水平
  • eQTL 共定位:检验 GWAS 信号和 eQTL 信号是否具有相同的因果变异
  • 多组织 eQTL 分析:查找在多个组织中调控表达的变异
  • 剪接 QTL(sQTL):识别影响剪接比例的变异
  • 组织特异性分析:确定哪些组织表达感兴趣的基因
  • 基因表达探索:获取各组织中归一化后的表达水平(TPM)
不适用的情况
场景改用
经整理的性状-变异关联、已报告的性状、研究来源信息alterlab-gwas
群体等位基因频率、LoF 约束(pLI/LOEUF)alterlab-gnomad
基因/转录本模型、VEP 后果、ID 映射alterlab-ensembl
有遗传学依据的靶点-疾病证据评分(包括共定位/L2G)alterlab-opentargets
单细胞表达图谱(细胞类型分辨率)alterlab-cellxgene

核心功能

1. GTEx REST API v2

基础 URL:https://gtexportal.org/api/v2/

该 API 返回 JSON,无需身份验证。所有端点均支持分页。

import requests

BASE_URL = "https://gtexportal.org/api/v2"

def gtex_get(endpoint, params=None):
    """Make a GET request to the GTEx API."""
    url = f"{BASE_URL}/{endpoint}"
    response = requests.get(url, params=params, headers={"Accept": "application/json"})
    response.raise_for_status()
    return response.json()
2. 按组织查询基因表达
import requests
import pandas as pd

def get_gene_expression_by_tissue(gencode_id, dataset_id="gtex_v10"):
    """Get median gene expression across all tissues (versioned GENCODE ID required)."""
    url = "https://gtexportal.org/api/v2/expression/medianGeneExpression"
    params = {
        "gencodeId": gencode_id,
        "datasetId": dataset_id,
        "itemsPerPage": 100
    }
    response = requests.get(url, params=params)
    data = response.json()

    records = data.get("data", [])
    df = pd.DataFrame(records)
    if not df.empty:
        # v2 returns tissueSiteDetailId (not a display-name column), median, unit, geneSymbol
        df = df[["geneSymbol", "tissueSiteDetailId", "median", "unit"]].sort_values(
            "median", ascending=False
        )
    return df

# Example: get expression of APOE across tissues (v10 = GENCODE v39; APOE keeps .10 here)
df = get_gene_expression_by_tissue("ENSG00000130203.10")  # APOE GENCODE ID
print(df.head(10))
# Output: tissueSiteDetailId, median TPM, sorted by highest expression
3. eQTL 查询
import requests
import pandas as pd

def query_eqtl(gene_id, tissue_id=None, dataset_id="gtex_v10"):
    """Query significant eQTLs for a gene, optionally filtered by tissue."""
    url = "https://gtexportal.org/api/v2/association/singleTissueEqtl"
    params = {
        "gencodeId": gene_id,
        "datasetId": dataset_id,
        "itemsPerPage": 250
    }
    if tissue_id:
        params["tissueSiteDetailId"] = tissue_id

    all_results = []
    page = 0
    while True:
        params["page"] = page
        response = requests.get(url, params=params)
        data = response.json()
        results = data.get("data", [])
        if not results:
            break
        all_results.extend(results)
        if len(results) < params["itemsPerPage"]:
            break
        page += 1

    df = pd.DataFrame(all_results)
    if not df.empty:
        df = df.sort_values("pValue", ascending=True)
    return df

# Example: Find eQTLs for PCSK9 (v10 GENCODE ID — version suffix must match the dataset)
df = query_eqtl("ENSG00000169174.11")
# v2 single-tissue eQTL fields: snpId, variantId, tissueSiteDetailId, nes, pValue, gencodeId
# (nes = normalized effect size of the alt allele; there is no separate slope/qval/maf here)
print(df[["snpId", "tissueSiteDetailId", "nes", "pValue", "gencodeId"]].head(20))
4. 按变异查询单组织 eQTL
import requests

def query_variant_eqtl(variant_id, tissue_id=None, dataset_id="gtex_v10"):
    """Get all eQTL associations for a specific variant."""
    url = "https://gtexportal.org/api/v2/association/singleTissueEqtl"
    params = {
        "variantId": variant_id,  # e.g., "chr1_55516888_G_GA_b38"
        "datasetId": dataset_id,
        "itemsPerPage": 250
    }
    if tissue_id:
        params["tissueSiteDetailId"] = tissue_id

    response = requests.get(url, params=params)
    return response.json()

# GTEx variant ID format: chr{chrom}_{pos}_{ref}_{alt}_b38
# Example: "chr17_43094692_G_A_b38"
5. 多组织 eQTL(eGenes)
import requests

def get_egenes(tissue_id, dataset_id="gtex_v10"):
    """Get all eGenes (genes with at least one significant eQTL) in a tissue."""
    url = "https://gtexportal.org/api/v2/association/egene"
    params = {
        "tissueSiteDetailId": tissue_id,
        "datasetId": dataset_id,
        "itemsPerPage": 500
    }

    all_egenes = []
    page = 0
    while True:
        params["page"] = page
        response = requests.get(url, params=params)
        data = response.json()
        batch = data.get("data", [])
        if not batch:
            break
        all_egenes.extend(batch)
        if len(batch) < params["itemsPerPage"]:
            break
        page += 1
    return all_egenes

# Example: all eGenes in whole blood
egenes = get_egenes("Whole_Blood")
print(f"Found {len(egenes)} eGenes in Whole Blood")
6. 组织列表
import requests

def get_tissues(dataset_id="gtex_v10"):
    """Get all available tissues with metadata."""
    url = "https://gtexportal.org/api/v2/dataset/tissueSiteDetail"
    params = {"datasetId": dataset_id, "itemsPerPage": 100}
    response = requests.get(url, params=params)
    return response.json()["data"]

tissues = get_tissues()
# Key fields: tissueSiteDetailId, tissueSiteDetail, colorHex, samplingSite
# Common tissue IDs:
# Whole_Blood, Brain_Cortex, Liver, Kidney_Cortex, Heart_Left_Ventricle,
# Lung, Muscle_Skeletal, Adipose_Subcutaneous, Colon_Transverse, ...
7. sQTL(剪接 QTL)
import requests

def query_sqtl(gene_id, tissue_id=None, dataset_id="gtex_v10"):
    """Query significant sQTLs for a gene."""
    url = "https://gtexportal.org/api/v2/association/singleTissueSqtl"
    params = {
        "gencodeId": gene_id,
        "datasetId": dataset_id,
        "itemsPerPage": 250
    }
    if tissue_id:
        params["tissueSiteDetailId"] = tissue_id

    response = requests.get(url, params=params)
    return response.json()

查询工作流

工作流 1:通过 eQTL 解读 GWAS 变异
  1. 确定 GWAS 变异(rs ID 或染色体位置)
  2. 转换为 GTEx 变异 ID 格式(chr{chrom}_{pos}_{ref}_{alt}_b38)
  3. 查询该变异在各组织中的所有 eQTL 关联
  4. 检查效应方向:GWAS 风险等位基因是否与 eQTL 效应等位基因相同?
  5. 确定组织优先级:选择与疾病在生物学上相关的组织
  6. 使用 coloc(R 包)和完整汇总统计数据进行共定位分析
import requests, pandas as pd

def interpret_gwas_variant(variant_id, dataset_id="gtex_v10"):
    """Find all genes regulated by a GWAS variant."""
    url = "https://gtexportal.org/api/v2/association/singleTissueEqtl"
    params = {"variantId": variant_id, "datasetId": dataset_id, "itemsPerPage": 500}
    response = requests.get(url, params=params)
    data = response.json()

    df = pd.DataFrame(data.get("data", []))
    if df.empty:
        return df
    return df[["geneSymbol", "tissueSiteDetailId", "nes", "pValue"]].sort_values("pValue")

# Example: rs2228145 (IL6R p.Asp358Ala). Resolve an rsID to the GTEx ID with
# GET /dataset/variant?snpId=rs2228145&datasetId=gtex_v10 -> "chr1_154454494_A_C_b38"
results = interpret_gwas_variant("chr1_154454494_A_C_b38")
if not results.empty:
    print(results.groupby("geneSymbol")["tissueSiteDetailId"].count().sort_values(ascending=False))
工作流 2:基因表达图谱
  1. 获取基因在所有组织中的中位表达量
  2. 确定主要表达部位
  3. 与疾病相关组织进行比较
  4. 下载原始数据以进行统计比较
工作流 3:组织特异性 eQTL 分析
  1. 选择与疾病相关的组织
  2. 查询该组织中的所有 eGene
  3. 与 GWAS 显著位点进行交叉比对
  4. 识别共定位信号

关键 API 端点

端点说明
/expression/medianGeneExpression按组织查询某个基因的中位数 TPM
/expression/geneExpression每种组织的完整表达分布
/association/singleTissueEqtl显著 eQTL 关联
/association/singleTissueSqtl显著 sQTL 关联
/association/egene某种组织中的 eGene
/dataset/tissueSiteDetail可用组织及其元数据
/reference/gene基因元数据;将基因符号解析为数据集版本对应的 GENCODE ID
/dataset/variant按 snpId(rsID)或 variantId 查询变异;返回 b38 GTEx ID

可用数据集

ID说明
gtex_v10GTEx v10(当前版本;946 名供体、54 种组织,其中 50 种组织绘制了 eQTL;GENCODE v39)
gtex_v8GTEx v8(948 名供体、838 名完成基因分型;54 种组织中有 49 种组织包含 eQTL;GENCODE v26)——版本较旧,但被广泛引用

最佳实践

  • GENCODE 版本后缀必须与数据集匹配(最容易踩坑之处):v10 对应 GENCODE v39,v8 对应 GENCODE v26,同一个基因在每个版本中的 .version 都不同。PCSK9 在 v10 中为 ENSG00000169174.11,而在 v8 中为 .10——查询时使用了错误的后缀会静默返回零条结果。通过 /reference/gene?geneId=SYMBOL&gencodeVersion=v39 按数据集解析正确的 ID(v8 使用 v26)。表达和 QTL 端点只接受带版本的 gencodeId 值——仅使用基因符号(例如 APOE)也会返回零行。
  • 始终传入 datasetId:省略此参数时,部分端点(/association/singleTissueSqtl、/dataset/tissueSiteDetail、/dataset/variant)仍会默认使用 gtex_v8,因此你会在不知情的情况下获取 v8 数据,而且 v10 的 GENCODE ID 会返回空结果。
  • GTEx 变异 ID 使用格式 chr{chrom}_{pos}_{ref}_{alt}_b38(GRCh38),与 rs ID 不同。
  • 处理分页:大型查询(例如,获取所有 eGene)需要逐页遍历。
  • 组织命名:API 调用时使用 tissueSiteDetailId(例如 Whole_Blood),而非显示名称。
  • FDR 阈值:GTEx 将 FDR < 0.05 的基因或关联判定为 eGene/eQTL。单组织 eQTL/sQTL 响应已筛选出显著关联对,并返回 pValue 和 nes(不含逐行 qval);每个基因的 qValue 则位于 /association/egene 端点中。
  • 效应大小:QTL 响应字段为 nes(替代等位基因的标准化效应大小),而非 slope;nes 为正表示替代等位基因对应更高的表达量。

数据下载(适用于大规模分析)

对于全基因组分析,请下载完整的汇总统计数据,而不要使用 API:

# All significant eQTLs (v10)
wget https://storage.googleapis.com/adult-gtex/bulk-qtl/v10/single-tissue-cis-qtl/GTEx_Analysis_v10_eQTL.tar

# Gene read counts (use ..._gene_tpm.gct.gz for TPM, ..._gene_median_tpm.gct.gz for per-tissue medians)
wget https://storage.googleapis.com/adult-gtex/bulk-gex/v10/rna-seq/GTEx_Analysis_v10_RNASeQCv2.4.2_gene_reads.gct.gz

其他资源

脚本

scripts/query_gtex.py — 可运行的 GTEx Portal API v2 辅助脚本(无需密钥):

python scripts/query_gtex.py gene APOE                     # symbol -> versioned GENCODE ID for gtex_v10
python scripts/query_gtex.py expression ENSG00000130203.10
python scripts/query_gtex.py eqtl ENSG00000169174.11 --tissue Liver   # v10 GENCODE ID
python scripts/query_gtex.py tissues

评论

支持 Markdown