mcpField
A
alterlab-jaspar

alterlab-jaspar

github.com/alterlab-ieuデータ・データベース7866 回インストール5 週間前に更新
リポジトリ

alterlab-jaspar について

alterlab-jasparは、JASPAR REST APIからキュレーション済み転写因子結合プロファイルを取得するスキルです。行列の検索を通じて、モチーフスキャン、調節変異の評価、濃縮解析を支援します。

主な機能

  1. 01転写因子プロファイル検索
  2. 02PFM行列の取得
  3. 03PFMからPWMへの変換
  4. 04DNA配列のモチーフスキャン
  5. 05両鎖のスキャン
  6. 06変異による結合部位への影響評価

活用シーン

  1. 01プロモーター内の転写因子結合部位のスキャン
  2. 02SNPによるモチーフ結合への影響評価
  3. 03ChIP-seqまたはATAC-seqピークのモチーフ濃縮解析

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/alterlab-jasparを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

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

詳細

JASPAR データベース

概要

JASPAR(https://jaspar.elixir.no/)は、精選され、重複のない転写因子(TF)結合プロファイルを位置頻度行列(PFM)として保存する、ゴールドスタンダードのオープンアクセスデータベースです。現在のリリースである JASPAR 2026 では、CORE プロファイルが265件追加され、UNVALIDATED から41件が昇格し、6つの分類群にわたる最新バージョンの CORE プロファイルは2,633件となりました(ライブ API が返す件数です)。各プロファイルは、ChIP-seq、SELEX、HT-SELEX、タンパク質結合マイクロアレイなどの実験から得られ、精選されています。JASPAR 2026 では、ディープラーニング(DL)コレクションも公開されました。これは240種類のヒト TF を対象とする ENCODE ChIP-seq で学習した1,259件の BPNet モデルで、ウェブサイトから閲覧・ダウンロードできますが、/api/v1/matrix/ では公開されていません。

主なリソース:

スクリプト

scripts/query_jaspar.py — JASPAR REST API にクエリを送信します(標準ライブラリのみを使用し、JSON を stdout に出力します)。

python scripts/query_jaspar.py search --name CTCF --species 9606   # latest-version profiles only
python scripts/query_jaspar.py search --name CTCF --all-versions   # include historical versions
python scripts/query_jaspar.py matrix MA0139.1                     # fetch a matrix (PFM)

search のデフォルトは version=latest(プロファイルごとに1行)です。過去のすべてのバージョンを表示するには、--all-versions を指定します。--species は API の tax_id パラメーターに対応します(NCBI 分類 ID)。

このスキルを使う場合

次の場合に JASPAR を使用します。

  • TF 結合部位の予測:DNA 配列をスキャンし、TF の結合候補部位を探します
  • 調節バリアントの解釈:GWAS/eQTL バリアントが TF 結合モチーフを破壊するかを調べます
  • プロモーター/エンハンサー解析:調節エレメントに結合すると予測される TF を調べます
  • 遺伝子調節ネットワークの構築:モチーフスキャンによって TF と標的遺伝子を関連付けます
  • TF ファミリー解析:TF ファミリー内の結合プロファイルを比較します(例:すべてのホメオボックス因子)
  • ChIP-seq 解析:ChIP-seq ピークで濃縮された既知の TF モチーフを探します
  • ENCODE/ATAC-seq の解釈:オープンクロマチン領域を TF 結合プロファイルに対応付けます
対象外
シナリオ代わりに使用
公開済み GWAS でバリアントが関連する形質alterlab-gwas
バリアントが組織内の遺伝子発現(eQTL)を変化させるかどうかalterlab-gtex
ゲノム配列、座標、または VEP の影響結果の取得alterlab-ensembl
ChIP-seq/ATAC-seq のカバレッジトラックとヒートマップの処理alterlab-deeptools
配列からの発現/クロマチンのディープラーニング予測alterlab-borzoi

主な機能

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:
        # NCBI taxonomy ID, e.g. "9606". The API silently ignores a `species=` param
        # (you get every taxon back), so it must be sent as `tax_id`.
        params["tax_id"] = species
    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. Class/family strings follow TFClass and
# must match exactly ("Homeodomain" returns 0 rows; the stored class is
# "Homeo domain factors") — read the "class" field of a known matrix to get it.
hox_tfs = search_jaspar(tf_class="Homeo domain factors", 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 (actual API fields; no "consensus" or "length" key — derive
# motif length from len(pfm["A"])):
# {
#   "matrix_id": "MA0139.1",
#   "name": "CTCF",
#   "base_id": "MA0139",
#   "version": 1,
#   "collection": "CORE",
#   "tax_group": "vertebrates",
#   "pfm": { "A": [...], "C": [...], "G": [...], "T": [...] },  # 19 columns for CTCF
#   "species": [{"tax_id": 9606, "name": "Homo sapiens"}],
#   "class": ["C2H2 zinc finger factors"],
#   "family": ["More than 3 adjacent zinc fingers"],
#   "type": "ChIP-seq",
#   "uniprot_ids": ["P49711"],
#   "pubmed_ids": ["17512414"],
#   "sequence_logo": "https://jaspar.elixir.no/static/logos/svg/MA0139.1.svg"
# }
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
# (windows containing non-ACGT bases such as N are skipped by scan_sequence)
promoter = "AGCCCGCGAGGTGGCAGTTGCCTGGAGCAGGATCAGCAGATC"
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)
#    tax_id (not species) filters by organism; page_size is capped at 1000
response = requests.get(
    "https://jaspar.elixir.no/api/v1/matrix/",
    params={"tax_id": "9606", "collection": "CORE", "version": "latest",
            "page_size": 1000, "page": 1, "format": "json"}
)
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
    matrix_data = requests.get(f"https://jaspar.elixir.no/api/v1/matrix/{m['matrix_id']}/").json()
    pfm = matrix_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 形式のスコアリング)

利用可能なコレクション

現在の JASPAR API は、2 つのコレクションを提供しています(GET /matrix/?collection=...&version=latest で件数を確認してください)。

コレクション説明最新バージョンのプロファイル数(2026-09)
CORE冗長性がなく、キュレーション済みで、実験的に検証されたプロファイル2,633
UNVALIDATED推定または実験から得られたものの、まだ検証されていないプロファイル約1,030

BPNet モデルを含む JASPAR 2026 Deep Learning(DL)コレクションは、マトリックス API ではなくウェブサイトで提供されています(モデルはダウンロード可能で、モチーフのスキャンには tangermeme フレームワークを使用します)。

レガシーコレクション(PHYLOFACTS、CNE、POLII、FAM、SPLICE)は以前の JASPAR 関連文献に登場しますが、現在の API では結果が 0 件になるため、これらに依存しないでください。

ベストプラクティス

  • ほとんどの解析では CORE コレクションを使用してください — 検証の信頼性が最も高く、冗長性もありません
  • 閾値の選択:新規予測では最大スコアの 80%、高信頼度の予測では 90%が一般的です
  • 必ず両方の鎖をスキャンしてください — TF はどちらの向きにも結合する可能性があります
  • バリアント解析ではフランキング領域を含めてください:両側に少なくとも(モチーフ長 - 1)bp を含めます
  • バックグラウンドを考慮してください:PWM スコアは一様な(0.25)バックグラウンドを基準とします。実際の GC 含量に応じて調整してください
  • 利用可能な場合は ChIP-seq データで交差検証してください — モチーフのスキャンでは偽陽性が多く発生します
  • 全機能を備えたスキャンには Biopython の motifs モジュールを使用してください:from Bio import motifs

追加リソース

コメント