mcpField
J
jaspar-database

jaspar-database

github.com/leonchaox数据与数据库99470 次安装15 周前更新
代码仓库

关于 jaspar-database

jaspar-database 是一项通过 REST API 查询 JASPAR 转录因子结合谱的技能,面向基因调控研究。它可检索矩阵,并用于扫描 DNA 序列或评估变异对预测结合的影响。

主要功能

  1. 01搜索转录因子结合谱
  2. 02获取 PFM 矩阵
  3. 03将 PFM 转换为 PWM
  4. 04扫描 DNA 序列中的基序
  5. 05扫描 DNA 双链
  6. 06比较变异前后的结合预测

适用场景

  1. 01预测启动子中的结合位点
  2. 02评估变异对基序的影响
  3. 03分析 ChIP-seq 峰中的基序
  4. 04比较同一转录因子家族的谱

安装

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

$npx skills add https://github.com/leonchaox/qinyan-academic-skills --skill jaspar-database

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

附带文件references/api_reference.md

详细介绍

JASPAR 数据库

概述

JASPAR(https://jaspar.elixir.no/)是经过整理、非冗余的转录因子(TF)结合谱开放访问数据库的行业标杆,这些结合谱以位置频率矩阵(PFM)的形式存储。JASPAR 2024 收录了 164 种真核生物的 1,210 个非冗余 TF 结合谱。每个谱均通过实验获得(ChIP-seq、SELEX、HT-SELEX、蛋白质结合微阵列等),并经过严格验证。

核心资源:

何时使用此技能

以下情况可使用 JASPAR:

  • 预测 TF 结合位点:扫描 DNA 序列,查找 TF 的潜在结合位点
  • 调控变异解读:GWAS/eQTL 变异是否会破坏 TF 结合基序?
  • 启动子/增强子分析:预测哪些 TF 会结合调控元件?
  • 构建基因调控网络:通过基序扫描将 TF 与其靶基因关联起来
  • TF 家族分析:比较 TF 家族内的结合谱(例如,所有同源异型框因子)
  • ChIP-seq 分析:查找在 ChIP-seq 峰中富集的已知 TF 基序
  • ENCODE/ATAC-seq 解读:将开放染色质区域与 TF 结合谱匹配

核心功能

1. JASPAR REST API

基础 URL:https://jaspar.elixir.no/api/v1/

import requests

BASE_URL = "https://jaspar.elixir.no/api/v1"

def jaspar_get(endpoint, params=None):
    url = f"{BASE_URL}/{endpoint}"
    response = requests.get(url, params=params, headers={"Accept": "application/json"})
    response.raise_for_status()
    return response.json()
2. 搜索 TF 谱
def search_jaspar(
    tf_name=None,
    species=None,
    collection="CORE",
    tf_class=None,
    tf_family=None,
    page=1,
    page_size=25
):
    """Search JASPAR for TF binding profiles."""
    params = {
        "collection": collection,
        "page": page,
        "page_size": page_size,
        "format": "json"
    }
    if tf_name:
        params["name"] = tf_name
    if species:
        params["species"] = species  # Use taxonomy ID or name, e.g., "9606" for human
    if tf_class:
        params["tf_class"] = tf_class
    if tf_family:
        params["tf_family"] = tf_family

    return jaspar_get("matrix", params)

# Examples:
# Search for human CTCF profile
ctcf = search_jaspar("CTCF", species="9606")
print(f"Found {ctcf['count']} CTCF profiles")

# Search for all homeobox TFs in human
hox_tfs = search_jaspar(tf_class="Homeodomain", species="9606")

# Search for a TF family
nfkb = search_jaspar(tf_family="NF-kappaB")
3. 获取特定矩阵(PFM/PWM)
def get_matrix(matrix_id):
    """Fetch a specific JASPAR matrix by ID (e.g., 'MA0139.1' for CTCF)."""
    return jaspar_get(f"matrix/{matrix_id}/")

# Example: Get CTCF matrix
ctcf_matrix = get_matrix("MA0139.1")

# Matrix structure:
# {
#   "matrix_id": "MA0139.1",
#   "name": "CTCF",
#   "collection": "CORE",
#   "tax_group": "vertebrates",
#   "pfm": { "A": [...], "C": [...], "G": [...], "T": [...] },
#   "consensus": "CCGCGNGGNGGCAG",
#   "length": 19,
#   "species": [{"tax_id": 9606, "name": "Homo sapiens"}],
#   "class": ["C2H2 zinc finger factors"],
#   "family": ["BEN domain factors"],
#   "type": "ChIP-seq",
#   "uniprot_ids": ["P49711"]
# }
4. 将 PFM/PWM 下载为矩阵
import numpy as np

def get_pwm(matrix_id, pseudocount=0.8):
    """
    Fetch a PFM from JASPAR and convert to PWM (log-odds).
    Returns numpy array of shape (4, L) in order A, C, G, T.
    """
    matrix = get_matrix(matrix_id)
    pfm = matrix["pfm"]

    # Convert PFM to numpy
    pfm_array = np.array([pfm["A"], pfm["C"], pfm["G"], pfm["T"]], dtype=float)

    # Add pseudocount
    pfm_array += pseudocount

    # Normalize to get PPM
    ppm = pfm_array / pfm_array.sum(axis=0, keepdims=True)

    # Convert to PWM (log-odds relative to background 0.25)
    background = 0.25
    pwm = np.log2(ppm / background)

    return pwm, matrix["name"]

# Example
pwm, name = get_pwm("MA0139.1")  # CTCF
print(f"PWM for {name}: shape {pwm.shape}")
max_score = pwm.max(axis=0).sum()
print(f"Maximum possible score: {max_score:.2f} bits")
5. 扫描 DNA 序列以查找 TF 结合位点
import numpy as np
from typing import List, Tuple

NUCLEOTIDE_MAP = {'A': 0, 'C': 1, 'G': 2, 'T': 3,
                  'a': 0, 'c': 1, 'g': 2, 't': 3}

def scan_sequence(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8) -> List[dict]:
    """
    Scan a DNA sequence for TF binding sites using a PWM.

    Args:
        sequence: DNA sequence string
        pwm: PWM array (4 x L) in ACGT order
        threshold_pct: Fraction of max score to use as threshold (0-1)

    Returns:
        List of hits with position, score, and matched sequence
    """
    motif_len = pwm.shape[1]
    max_score = pwm.max(axis=0).sum()
    min_score = pwm.min(axis=0).sum()
    threshold = min_score + threshold_pct * (max_score - min_score)

    hits = []
    seq = sequence.upper()

    for i in range(len(seq) - motif_len + 1):
        subseq = seq[i:i + motif_len]
        # Skip if contains non-ACGT
        if any(c not in NUCLEOTIDE_MAP for c in subseq):
            continue

        score = sum(pwm[NUCLEOTIDE_MAP[c], j] for j, c in enumerate(subseq))

        if score >= threshold:
            relative_score = (score - min_score) / (max_score - min_score)
            hits.append({
                "position": i + 1,  # 1-based
                "score": score,
                "relative_score": relative_score,
                "sequence": subseq,
                "strand": "+"
            })

    return hits

# Example: Scan a promoter sequence for CTCF binding sites
promoter = "AGCCCGCGAGGNGGCAGTTGCCTGGAGCAGGATCAGCAGATC"
pwm, name = get_pwm("MA0139.1")
hits = scan_sequence(promoter, pwm, threshold_pct=0.75)
for hit in hits:
    print(f"  Position {hit['position']}: {hit['sequence']} (score: {hit['score']:.2f}, {hit['relative_score']:.0%})")
6. 扫描两条链
def reverse_complement(seq: str) -> str:
    complement = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C', 'N': 'N'}
    return ''.join(complement.get(b, 'N') for b in reversed(seq.upper()))

def scan_both_strands(sequence: str, pwm: np.ndarray, threshold_pct: float = 0.8):
    """Scan forward and reverse complement strands."""
    fwd_hits = scan_sequence(sequence, pwm, threshold_pct)
    for h in fwd_hits:
        h["strand"] = "+"

    rev_seq = reverse_complement(sequence)
    rev_hits = scan_sequence(rev_seq, pwm, threshold_pct)
    seq_len = len(sequence)
    for h in rev_hits:
        h["strand"] = "-"
        h["position"] = seq_len - h["position"] - len(h["sequence"]) + 2  # Convert to fwd coords

    all_hits = fwd_hits + rev_hits
    return sorted(all_hits, key=lambda x: x["position"])
7. 变异对 TF 结合的影响
def variant_tfbs_impact(ref_seq: str, alt_seq: str, pwm: np.ndarray,
                          tf_name: str, threshold_pct: float = 0.7):
    """
    Assess impact of a SNP on TF binding by comparing ref vs alt sequences.
    Both sequences should be centered on the variant with flanking context.
    """
    ref_hits = scan_both_strands(ref_seq, pwm, threshold_pct)
    alt_hits = scan_both_strands(alt_seq, pwm, threshold_pct)

    max_ref = max((h["score"] for h in ref_hits), default=None)
    max_alt = max((h["score"] for h in alt_hits), default=None)

    result = {
        "tf": tf_name,
        "ref_max_score": max_ref,
        "alt_max_score": max_alt,
        "ref_has_site": len(ref_hits) > 0,
        "alt_has_site": len(alt_hits) > 0,
    }
    if max_ref and max_alt:
        result["score_change"] = max_alt - max_ref
        result["effect"] = "gained" if max_alt > max_ref else "disrupted"
    elif max_ref and not max_alt:
        result["effect"] = "disrupted"
    elif not max_ref and max_alt:
        result["effect"] = "gained"
    else:
        result["effect"] = "no_site"

    return result

查询工作流

工作流 1:查找启动子中的所有 TF 结合位点
import requests, numpy as np

# 1. Get relevant TF matrices (e.g., all human TFs in CORE collection)
response = requests.get(
    "https://jaspar.elixir.no/api/v1/matrix/",
    params={"species": "9606", "collection": "CORE", "page_size": 500, "page": 1}
)
matrices = response.json()["results"]

# 2. For each matrix, compute PWM and scan promoter
promoter = "CCCGCCCGCCCGCCGCCCGCAGTTAATGAGCCCAGCGTGCC"  # Example

all_hits = []
for m in matrices[:10]:  # Limit for demo
    pwm_data = requests.get(f"https://jaspar.elixir.no/api/v1/matrix/{m['matrix_id']}/").json()
    pfm = pfm_data["pfm"]
    pfm_arr = np.array([pfm["A"], pfm["C"], pfm["G"], pfm["T"]], dtype=float) + 0.8
    ppm = pfm_arr / pfm_arr.sum(axis=0)
    pwm = np.log2(ppm / 0.25)

    hits = scan_sequence(promoter, pwm, threshold_pct=0.8)
    for h in hits:
        h["tf_name"] = m["name"]
        h["matrix_id"] = m["matrix_id"]
    all_hits.extend(hits)

print(f"Found {len(all_hits)} TF binding sites")
for h in sorted(all_hits, key=lambda x: -x["score"])[:5]:
    print(f"  {h['tf_name']} ({h['matrix_id']}): pos {h['position']}, score {h['score']:.2f}")
工作流 2:SNP 对 TF 结合的影响(调控变异分析)
  1. 获取 SNP 两侧的基因组序列(每侧 ±20 bp)
  2. 构建 ref 和 alt 序列
  3. 使用所有相关 TF PWM 进行扫描
  4. 报告因 SNP 而新产生或消失结合的 TF
工作流 3:基序富集分析
  1. 确定一组峰序列(例如,来自 ChIP-seq 或 ATAC-seq)
  2. 使用 JASPAR PWM 扫描所有峰
  3. 比较峰序列与背景序列中的命中率
  4. 报告显著富集的基序(Fisher 精确检验或 FIMO 风格评分)

可用集合

集合说明谱数量
CORE非冗余、高质量谱~1,210
UNVALIDATED通过实验获得但尚未验证~500
PHYLOFACTS系统发育上保守的位点~50
CNE保守非编码元件~30
POLIIRNA Pol II 结合谱~20
FAMTF 家族代表性谱~170
SPLICE剪接因子谱~20

最佳实践

  • 大多数分析使用 CORE 集合——其验证最充分且非冗余
  • 阈值选择:从头预测通常使用最高分的 80%;高置信度分析使用 90%
  • 始终扫描两条链——TF 可以沿任一方向结合
  • 变异分析时提供侧翼序列:每侧至少包含(基序长度 - 1)bp
  • 考虑背景:PWM 分数基于均匀(0.25)背景;应根据实际 GC 含量进行调整
  • 条件允许时使用 ChIP-seq 数据交叉验证——基序扫描会产生许多假阳性
  • 使用 Biopython 的 motifs 模块进行完整功能的扫描:from Bio import motifs

Additional Resources

评论

支持 Markdown