mcpField
A
alterlab-cbioportal

alterlab-cbioportal

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

alterlab-cbioportal について

alterlab-cbioportalは、cBioPortal REST APIを通じて公開研究データを調べるがんゲノム研究向けスキルです。変異、コピー数変化、臨床データを扱い、研究単位やパンキャンサーの解析に利用できます。

主な機能

  1. 01研究と分子プロファイルの一覧
  2. 02変異とコピー数変化の取得
  3. 03患者の臨床データ取得
  4. 04遺伝子変化頻度の解析
  5. 05生存解析とパンキャンサー解析

活用シーン

  1. 01がん種間で遺伝子変異頻度を比較
  2. 02ゲノム変化と臨床変数の関連を調査
  3. 03変異状態別に生存を解析
  4. 04がんゲノム研究用の研究データを取得

インストール

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

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

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

同梱ファイル

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

evals/
evals.json
references/
study_exploration.md
scripts/
query_cbioportal.py

詳細

cBioPortal データベース

概要

cBioPortal for Cancer Genomics(https://www.cbioportal.org/)は、多次元のがんゲノムデータを探索、可視化、解析するためのオープンアクセスリソースです。The Cancer Genome Atlas(TCGA)、AACR Project GENIE、MSK-IMPACT、その他数百件のがん研究のデータを収載しており、数千件のがんサンプルについて、変異、コピー数異常(CNA)、構造変異、mRNA/タンパク質発現、メチル化、臨床データを網羅しています。

主なリソース:

このスキルを使用する場面

以下の場合は cBioPortal を使用します。

  • 変異の全体像:あるがん種で、特定の遺伝子に変異がある割合はどのくらいですか?
  • がん遺伝子/TSG の検証:ある遺伝子は、がんで頻繁に変異、増幅、または欠失していますか?
  • 共変異パターン:遺伝子 A と遺伝子 B の変異は、相互排他的ですか、それとも同時に生じますか?
  • 生存分析:ある遺伝子の変異は、患者の転帰の改善または悪化と関連していますか?
  • 変異プロファイル:ある遺伝子には、どのような種類の変異(ミスセンス、短縮、増幅、欠失)が影響していますか?
  • パンキャンサー解析:がん種間で変異頻度を比較する
  • 臨床的関連性:ゲノム変異を臨床変数(病期、グレード、治療反応)に関連付ける
  • TCGA/GENIE の探索:TCGA および臨床シーケンシングデータセットに体系的にアクセスする
対象外
シナリオ代わりに使用
生殖細胞系列バリアントの病原性/臨床的意義alterlab-clinvar
COSMIC Cancer Gene Census、変異シグネチャ(SBS)、キュレーション済み体細胞変異カタログalterlab-cosmic
がん細胞株における CRISPR/RNAi による遺伝子依存性(必須性)alterlab-depmap
集約された標的–疾患関連エビデンスと創薬可能性alterlab-opentargets

主な機能

1. cBioPortal REST API

ベース URL:https://www.cbioportal.org/api

API は RESTful で、JSON を返します。公開データには API キーは不要です。

import requests

BASE_URL = "https://www.cbioportal.org/api"
HEADERS = {"Accept": "application/json", "Content-Type": "application/json"}

def cbioportal_get(endpoint, params=None):
    url = f"{BASE_URL}/{endpoint}"
    response = requests.get(url, params=params, headers=HEADERS)
    response.raise_for_status()
    return response.json()

def cbioportal_post(endpoint, body):
    url = f"{BASE_URL}/{endpoint}"
    response = requests.post(url, json=body, headers=HEADERS)
    response.raise_for_status()
    return response.json()
2. 研究の閲覧
def get_all_studies():
    """List all available cancer studies.

    The public portal hosts 540+ studies (2026-09), so a pageSize of 500 would
    silently truncate the list; ask for more than you expect.
    """
    return cbioportal_get("studies", {"pageSize": 100000})

# Each study has:
# studyId: unique identifier (e.g., "brca_tcga")
# name: human-readable name
# description: dataset description
# cancerTypeId: cancer type abbreviation
# referenceGenome: hg19 or hg38
# allSampleCount: samples in the study
# (pass projection=DETAILED to also get pmid, citation, sequencedSampleCount, ...)

studies = get_all_studies()
print(f"Total studies: {len(studies)}")

# Common TCGA study IDs — each cancer has several versions:
#   *_tcga                     original TCGA Firehose Legacy (e.g. brca_tcga)
#   *_tcga_pan_can_atlas_2018  harmonized PanCancer Atlas (preferred for pan-cancer work)
#   *_tcga_gdc                 GDC re-processed data
# e.g. brca_tcga, luad_tcga, coadread_tcga, gbm_tcga, prad_tcga, skcm_tcga

# Filter for TCGA studies
tcga_studies = [s for s in studies if "tcga" in s["studyId"]]
print([s["studyId"] for s in tcga_studies[:10]])
3. 分子プロファイル

各研究には、変異、CNA、発現など、複数の分子プロファイルがあります。

def get_molecular_profiles(study_id):
    """Get all molecular profiles for a study."""
    return cbioportal_get(f"studies/{study_id}/molecular-profiles")

profiles = get_molecular_profiles("brca_tcga")
for p in profiles:
    print(f"  {p['molecularProfileId']}: {p['name']} ({p['molecularAlterationType']})")

# Alteration types:
# MUTATION_EXTENDED — somatic mutations
# COPY_NUMBER_ALTERATION — CNA (GISTIC)
# MRNA_EXPRESSION — mRNA expression
# PROTEIN_LEVEL — RPPA protein expression
# STRUCTURAL_VARIANT — fusions/rearrangements
4. 変異データ
def get_mutations(molecular_profile_id, entrez_gene_ids, sample_list_id=None):
    """Get mutations for specified genes in a molecular profile."""
    body = {
        "entrezGeneIds": entrez_gene_ids,
        "sampleListId": sample_list_id or molecular_profile_id.replace("_mutations", "_all")
    }
    return cbioportal_post(
        f"molecular-profiles/{molecular_profile_id}/mutations/fetch",
        body
    )

# BRCA1 Entrez ID is 672, TP53 is 7157, PTEN is 5728
mutations = get_mutations("brca_tcga_mutations", entrez_gene_ids=[7157])  # TP53

# Each mutation record contains:
# patientId, sampleId, entrezGeneId (the nested gene.hugoGeneSymbol only
#   appears with ?projection=DETAILED on the fetch URL)
# mutationType (Missense_Mutation, Nonsense_Mutation, Frame_Shift_Del, etc.)
# proteinChange (e.g., "R175H"), variantType
# ncbiBuild, chr, startPosition, endPosition, referenceAllele, variantAllele
# mutationStatus (Somatic/Germline)
# tumorAltCount, tumorRefCount (read counts — there is no VAF field; derive it)

import pandas as pd
df = pd.DataFrame(mutations)
df["vaf"] = df["tumorAltCount"] / (df["tumorAltCount"] + df["tumorRefCount"])
print(df[["patientId", "mutationType", "proteinChange", "vaf"]].head())
print(f"\nMutation types:\n{df['mutationType'].value_counts()}")
5. コピー数異常データ
def get_cna(molecular_profile_id, entrez_gene_ids):
    """Get discrete CNA data (GISTIC: -2, -1, 0, 1, 2)."""
    body = {
        "entrezGeneIds": entrez_gene_ids,
        "sampleListId": molecular_profile_id.replace("_gistic", "_all").replace("_cna", "_all")
    }
    return cbioportal_post(
        f"molecular-profiles/{molecular_profile_id}/discrete-copy-number/fetch",
        body
    )

# GISTIC values:
# -2 = Deep deletion (homozygous loss)
# -1 = Shallow deletion (heterozygous loss)
#  0 = Diploid (neutral)
#  1 = Low-level gain
#  2 = High-level amplification

cna_data = get_cna("brca_tcga_gistic", entrez_gene_ids=[1956])  # EGFR
df_cna = pd.DataFrame(cna_data)
print(df_cna["value"].value_counts())
6. 変異頻度(OncoPrint 形式)
def get_alteration_frequency(study_id, gene_symbols, alteration_types=None):
    """Compute alteration frequencies for genes across a cancer study."""
    import requests, pandas as pd

    # Denominator = samples profiled for mutations (cBioPortal's own convention).
    # 'all_cases_in_study' also counts unsequenced samples and deflates the
    # frequency (brca_tcga: 1,108 samples in study vs 982 sequenced).
    samples = requests.get(
        f"{BASE_URL}/studies/{study_id}/sample-lists",
        headers=HEADERS
    ).json()
    by_category = {s["category"]: s["sampleListId"] for s in samples}
    sample_list_id = (by_category.get("all_cases_with_mutation_data")
                      or by_category.get("all_cases_in_study"))
    total_samples = len(requests.get(
        f"{BASE_URL}/sample-lists/{sample_list_id}/sample-ids",
        headers=HEADERS
    ).json())

    # Get gene Entrez IDs. /genes/fetch takes a plain JSON array of identifiers
    # plus a geneIdType query param; symbols WITHOUT the param resolve to [].
    gene_data = requests.post(
        f"{BASE_URL}/genes/fetch",
        params={"geneIdType": "HUGO_GENE_SYMBOL"},
        json=gene_symbols,
        headers=HEADERS
    ).json()
    # Response order is not guaranteed; map by symbol.
    entrez_by_symbol = {g["hugoGeneSymbol"]: g["entrezGeneId"] for g in gene_data}
    entrez_ids = [entrez_by_symbol[g] for g in gene_symbols if g in entrez_by_symbol]

    # Get mutations
    mutation_profile = f"{study_id}_mutations"
    mutations = get_mutations(mutation_profile, entrez_ids, sample_list_id)

    freq = {}
    for g_symbol, e_id in entrez_by_symbol.items():
        # Count samples (not patients) so numerator and denominator match.
        mutated = len(set(m["sampleId"] for m in mutations if m["entrezGeneId"] == e_id))
        freq[g_symbol] = mutated / total_samples * 100

    return freq

# Example
freq = get_alteration_frequency("brca_tcga", ["TP53", "PIK3CA", "BRCA1", "BRCA2"])
for gene, pct in sorted(freq.items(), key=lambda x: -x[1]):
    print(f"  {gene}: {pct:.1f}%")
7. 臨床データ

グローバルな /clinical-data/fetch エンドポイントは POST のみ です(GET では HTTP 405 が返されます)。 1 件の研究で最も簡単にデータを取得するには、研究ごとの GET エンドポイントを使用します。このエンドポイントは、{patientId, studyId, clinicalAttributeId, value} レコードのリストを返します。

def get_patient_clinical_data(study_id, attribute_ids):
    """Patient-level clinical data via the per-study GET endpoint.

    GET /studies/{studyId}/clinical-data?clinicalDataType=PATIENT&attributeId=...
    accepts a single attributeId, so we query each and concatenate.
    """
    records = []
    for attr in attribute_ids:
        records += cbioportal_get(
            f"studies/{study_id}/clinical-data",
            {"clinicalDataType": "PATIENT", "attributeId": attr, "pageSize": 100000},
        )
    return records

# Clinical attributes include:
# OS_STATUS, OS_MONTHS, DFS_STATUS, DFS_MONTHS (survival)
# AJCC_PATHOLOGIC_TUMOR_STAGE, GRADE, AGE, SEX, RACE
# Study-specific attributes vary — list them with get_clinical_attributes().
# GOTCHA: OS_STATUS / DFS_STATUS are encoded "1:DECEASED" / "0:LIVING"
# (event:label), not bare 0/1 — split on ":" before survival analysis.

def get_clinical_attributes(study_id):
    """List all available clinical attributes for a study."""
    return cbioportal_get(f"studies/{study_id}/clinical-attributes")

クエリワークフロー

ワークフロー 1:がん種における遺伝子変異プロファイル
import requests, pandas as pd

def alteration_profile(study_id, gene_symbol):
    """Full alteration profile for a gene in a cancer study."""

    # 1. Get gene Entrez ID (plain array body + geneIdType param)
    gene_info = requests.post(
        f"{BASE_URL}/genes/fetch",
        params={"geneIdType": "HUGO_GENE_SYMBOL"},
        json=[gene_symbol],
        headers=HEADERS
    ).json()[0]
    entrez_id = gene_info["entrezGeneId"]

    # 2. Get mutations
    mutations = get_mutations(f"{study_id}_mutations", [entrez_id])
    mut_df = pd.DataFrame(mutations) if mutations else pd.DataFrame()

    # 3. Get CNAs
    cna = get_cna(f"{study_id}_gistic", [entrez_id])
    cna_df = pd.DataFrame(cna) if cna else pd.DataFrame()

    # 4. Summary
    n_mut = len(set(mut_df["patientId"])) if not mut_df.empty else 0
    n_amp = len(cna_df[cna_df["value"] == 2]) if not cna_df.empty else 0
    n_del = len(cna_df[cna_df["value"] == -2]) if not cna_df.empty else 0

    return {"mutations": n_mut, "amplifications": n_amp, "deep_deletions": n_del}

result = alteration_profile("brca_tcga", "PIK3CA")
print(result)
ワークフロー 2:パンキャンサー遺伝子変異頻度
import requests, pandas as pd

def pan_cancer_mutation_freq(gene_symbol, cancer_study_ids=None):
    """Mutation frequency of a gene across multiple cancer types."""
    studies = get_all_studies()
    if cancer_study_ids:
        studies = [s for s in studies if s["studyId"] in cancer_study_ids]

    results = []
    for study in studies[:20]:  # Limit for demo
        try:
            freq = get_alteration_frequency(study["studyId"], [gene_symbol])
            results.append({
                "study": study["studyId"],
                "cancer": study.get("cancerTypeId", ""),
                "mutation_pct": freq.get(gene_symbol, 0)
            })
        except Exception:
            pass

    df = pd.DataFrame(results).sort_values("mutation_pct", ascending=False)
    return df
ワークフロー 3:変異ステータス別の生存分析
import requests, pandas as pd

def survival_by_mutation(study_id, gene_symbol):
    """Get survival data split by mutation status."""
    # This workflow fetches clinical and mutation data for downstream analysis

    gene_info = requests.post(
        f"{BASE_URL}/genes/fetch",
        params={"geneIdType": "HUGO_GENE_SYMBOL"},
        json=[gene_symbol],
        headers=HEADERS
    ).json()[0]
    entrez_id = gene_info["entrezGeneId"]

    mutations = get_mutations(f"{study_id}_mutations", [entrez_id])
    mutated_patients = set(m["patientId"] for m in mutations)

    # Patient-level survival via the per-study GET endpoint (clinical-data/fetch
    # is POST-only — a GET there returns HTTP 405).
    clinical = get_patient_clinical_data(study_id, ["OS_MONTHS", "OS_STATUS"])
    clinical_df = pd.DataFrame(clinical)

    os_wide = clinical_df.pivot(index="patientId", columns="clinicalAttributeId", values="value")
    # OS_STATUS is encoded as "1:DECEASED" / "0:LIVING"; split off the 0/1 event flag.
    if "OS_STATUS" in os_wide:
        os_wide["OS_EVENT"] = os_wide["OS_STATUS"].str.startswith("1").astype("Int64")
    os_wide["OS_MONTHS"] = pd.to_numeric(os_wide.get("OS_MONTHS"), errors="coerce")
    os_wide["mutated"] = os_wide.index.isin(mutated_patients)

    return os_wide

主な API エンドポイントの概要

エンドポイント説明
GET /studiesすべての研究を一覧表示
GET /studies/{studyId}/molecular-profiles研究の分子プロファイル
POST /molecular-profiles/{profileId}/mutations/fetch変異データを取得
POST /molecular-profiles/{profileId}/discrete-copy-number/fetchCNA データを取得
POST /molecular-profiles/{profileId}/molecular-data/fetch発現データを取得
GET /studies/{studyId}/clinical-attributes利用可能な臨床変数
GET /studies/{studyId}/clinical-data1 件の研究の臨床データ(1 回の呼び出しにつき attributeId は 1 つ)
POST /clinical-data/fetch?clinicalDataType=PATIENT複数の研究にまたがる臨床データ(POST のみ。GET → 405)
POST /genes/fetch?geneIdType=HUGO_GENE_SYMBOLシンボルを Entrez ID に解決(本文は通常の JSON 配列。例:["TP53"])
GET /studies/{studyId}/sample-listsサンプルリスト

ベストプラクティス

  • 研究 ID を確認する:Swagger UI または GET /studies を使って、正しい研究 ID を確認します
  • サンプルリストを使用する:各研究には all サンプルリストとそのサブセットがあります。適切なリストを必ず指定してください
  • TCGA と GENIE の違い:TCGA のデータは網羅的ですが古く、GENIE にはより新しい臨床シーケンシングデータがあります。ただし、コンソーシアムのリリースデータは、キー不要の公開 API ではなく、別の https://genie.cbioportal.org ポータルで公開されています(ログインが必要です)
  • Entrez 遺伝子 ID:API は Entrez ID を使用します。POST /genes/fetch?geneIdType=HUGO_GENE_SYMBOL でシンボルから変換してください。リクエストボディはプレーンな JSON 配列(["TP53","KRAS"])である必要があります。オブジェクト形式の [{"hugoGeneSymbol":...}] は HTTP 400 を返し、geneIdType を省略すると、シンボルに対して [] がエラーなく返されます。レスポンスの順序は保証されないため、結果を hugoGeneSymbol で元のデータに対応付けてください。
  • 404 に対処する:一部の研究では、特定の分子プロファイルが存在しない場合があります
  • レート制限:大量のクエリには待ち時間を設けてください。大規模な解析では、データファイルのダウンロードを検討してください

データのダウンロード

大規模な解析では、研究データを直接ダウンロードしてください(以前の cbioportal-datahub.s3.amazonaws.com リンクは現在 403 を返します):

# Download TCGA BRCA (PanCancer Atlas) data
wget https://datahub.assets.cbioportal.org/brca_tcga_pan_can_atlas_2018.tar.gz

追加リソース

スクリプト

scripts/query_cbioportal.py — cBioPortal REST API(公開、キー不要)用の実行可能なヘルパー:

python scripts/query_cbioportal.py studies --filter tcga
python scripts/query_cbioportal.py profiles brca_tcga
python scripts/query_cbioportal.py mutations brca_tcga_mutations --genes 7157,672

コメント