Agent skill

Cbioportal Database

by jaechang-hits in jaechang-hits/SciAgent-Skills

Cancer genomics (TCGA et al.) via cBioPortal REST API. An agent skill from jaechang-hits/SciAgent-Skills.

AGPL-3.0Auto-check passedResearch & Science

Install Cbioportal Database

skills CLI
$ npx skills add jaechang-hits/SciAgent-Skills --skill cbioportal-database -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jaechang-hits/SciAgent-Skills cbioportal-database --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/genomics-bioinformatics/databases/cbioportal-database .claude/skills/cbioportal-database && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
cbioportal-database
GitHub stars
374
Used in
1 other repo
Token cost
~8.2k tokens
SKILL.md length
1,145 words
Files
1
Skills in repo
169
Repo updated
First seen
Licence
AGPL-3.0

At a glance

Cancer genomics (TCGA et al.) via cBioPortal REST API. An agent skill from jaechang-hits/SciAgent-Skills.

  • Works in 5 steps: Fetch sample IDs before data queries:… → Verify profile IDs from the API: Profile… → Chunk large sample sets: The API can… → …
  • Survival analysis
  • SKILL.md covers Overview, When to Use, Prerequisites and Quick Start, plus 9 more sections
  • Calls pip; reaches cbioportal.org

What it does

Cbioportal Database is an agent skill from jaechang-hits/SciAgent-Skills. Cancer genomics (TCGA et al.) via cBioPortal REST API. Retrieve somatic mutations, CNAs, expression, clinical data (survival/stage/treatment) across thousands of studies. Use for TMB, oncoprints, survival analysis. For population frequencies use gnomad-database; for drug-gene interactions use opentargets-database.

Its SKILL.md is about 8.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Research & Science, covering Bioinformatics and REST APIs. The repository describes itself as: 197 bioinformatics & life science skills for Claude Code and AI agents — BixBench 92.0% accuracy. RNA-seq, single-cell, drug discovery, proteomics, and more. Powers OmicsHorizon. The licence is AGPL-3.0.

When your agent uses it

  • Survival analysis
  • Tasks that involve Bioinformatics
  • Tasks that involve REST APIs

Example prompts

  • “/cbioportal-database”

Requirements

  • Python 3

Workflow steps

5 steps, taken from the first numbered list in SKILL.md.

  1. Fetch sample IDs before data queries: All mutation and molecular data endpoints require explicit sampleIds. Retrieve them with GET…
  2. Verify profile IDs from the API: Profile IDs are not guaranteed to follow the _mutations / _gistic pattern in every study. Always confirm…
  3. Chunk large sample sets: The API can time out on requests with thousands of sample IDs. Batch requests in chunks of 500 samples with…
  4. Use Entrez IDs, not Hugo symbols, in data fetch endpoints: The mutation and molecular data endpoints accept entrezGeneIds (integers)…
  5. Don't hard-code Entrez IDs: Gene IDs can be looked up dynamically via the API. Hard-coded IDs become incorrect if the gene model changes…

What it can do on your machine

Read from SKILL.md and the folder at commit 82c862c. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • pip

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • cbioportal.org

    Also links to:

    • doi.org
    • github.com
    • cell.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Cbioportal Database loads about 8.2k tokens when it runs. Until then it costs about 84 tokens; SKILL.md has 1,145 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~84
When it runs · the whole SKILL.md, loaded when a task matches
~8.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from jaechang-hits/SciAgent-Skills at commit 82c862c, republished under its AGPL-3.0 licence (© jaechang-hits). 1,145 words, ~8,191 tokens.

Download SKILL.mdSave it as .claude/skills/cbioportal-database/SKILL.md (or your agent's skills folder).
name
cbioportal-database
description
Cancer genomics (TCGA et al.) via cBioPortal REST API. Retrieve somatic mutations, CNAs, expression, clinical data (survival/stage/treatment) across thousands of studies. Use for TMB, oncoprints, survival analysis. For population frequencies use gnomad-database; for drug-gene interactions use opentargets-database.
license
AGPL-3.0

cBioPortal Database

Overview

cBioPortal for Cancer Genomics is a public repository of cancer genomics data including TCGA, ICGC, and hundreds of curated studies spanning 100+ cancer types. It provides somatic mutation profiles, copy number alterations (CNA), gene expression, clinical data (survival, stage, treatment history), and methylation data for tens of thousands of patient samples. Data is accessible via a REST API at https://www.cbioportal.org/api/ with no authentication required.

When to Use

  • Retrieving somatic mutation profiles (variant type, amino acid change) for a gene across TCGA studies
  • Querying copy number alteration data (amplification, deep deletion) for candidate cancer driver genes
  • Accessing clinical data — overall survival, disease-free survival, tumor stage — for survival curve analysis
  • Identifying which cancer studies have molecular profiling data for a specific cancer type (e.g., breast, lung)
  • Downloading gene expression (RNA-seq FPKM/RSEM) data from specific TCGA cohorts for differential expression analysis
  • Correlating genomic alterations with clinical outcomes in a specific study
  • Use omics-plotting SKILL to render bar charts, mutation-frequency heatmaps, and Kaplan–Meier curves from the query results
  • Use gnomad-database instead when you need population-level variant allele frequencies in healthy individuals
  • For drug-gene interaction lookups use opentargets-database; cBioPortal provides the genomic alteration data, not drug interaction annotations

Prerequisites

  • Python packages: requests, pandas, matplotlib
  • Data requirements: Entrez gene symbols (e.g., TP53), cBioPortal study IDs (e.g., tcga_brca), molecular profile IDs
  • Environment: internet connection; no API key required
  • Rate limits: no strict rate limits; use time.sleep(0.2) between batch requests for polite access
bash
pip install requests pandas matplotlib

Quick Start

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    """GET request to cBioPortal REST API, returns parsed JSON."""
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

# List available cancer types
cancer_types = cbio_get("cancer-types")
print(f"Total cancer types: {len(cancer_types)}")
# Total cancer types: 87

# Find TCGA breast cancer study
studies = cbio_get("studies", params={"keyword": "breast"})
brca = [s for s in studies if "tcga_brca" in s["studyId"]]
if brca:
    s = brca[0]
    print(f"Study: {s['name']}")
    print(f"  studyId: {s['studyId']}")
    print(f"  Samples: {s['allSampleCount']}")
# Study: Breast Invasive Carcinoma (TCGA, PanCancer Atlas)
#   studyId: brca_tcga_pan_can_atlas_2018
#   Samples: 1084

Core API

Query 1: Cancer Types and Studies

List available cancer types and find studies by cancer type or keyword.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

# Get all cancer types
cancer_types = cbio_get("cancer-types")
ct_df = pd.DataFrame(cancer_types)[["cancerTypeId", "name", "dedicatedColor"]]
print(f"Cancer types: {len(ct_df)}")
print(ct_df.head(5).to_string(index=False))

# Find all studies for a cancer type
lung_studies = cbio_get("studies", params={"keyword": "lung adenocarcinoma"})
print(f"\nLung adenocarcinoma studies: {len(lung_studies)}")
for s in lung_studies[:3]:
    print(f"  {s['studyId']:40s}  n={s['allSampleCount']}")
python
# Get detailed study metadata including available data types
study_id = "brca_tcga_pan_can_atlas_2018"
study = cbio_get(f"studies/{study_id}")
print(f"Study: {study['name']}")
print(f"  Reference genome: {study.get('referenceGenome', 'n/a')}")
print(f"  All sample count: {study['allSampleCount']}")

# List molecular profiles for the study
profiles = cbio_get("molecular-profiles", params={"studyId": study_id})
print(f"\nMolecular profiles ({len(profiles)} total):")
for p in profiles:
    print(f"  {p['molecularProfileId']:55s}  [{p['molecularAlterationType']}]")
Query 2: Somatic Mutations

Retrieve mutation data for a gene or set of genes in a study's mutation profile.

python
import requests, json
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_post(endpoint, body):
    """POST request to cBioPortal REST API."""
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=60)
    r.raise_for_status()
    return r.json()

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

# Get all samples for a study
study_id = "brca_tcga_pan_can_atlas_2018"
samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples]
print(f"Total samples: {len(sample_ids)}")

# Mutation profile ID follows pattern: {studyId}_mutations
profile_id = f"{study_id}_mutations"

# Fetch mutations for TP53 (Entrez gene ID = 7157)
body = {
    "sampleIds": sample_ids[:200],   # first 200 samples
    "entrezGeneIds": [7157]           # TP53
}
mutations = cbio_post(f"molecular-profiles/{profile_id}/mutations/fetch", body)
print(f"TP53 mutations in first 200 samples: {len(mutations)}")

# Summarize by mutation type
mut_df = pd.DataFrame(mutations)
print("\nMutation type distribution:")
print(mut_df["mutationType"].value_counts().head(8).to_string())
# Missense_Mutation    102
# Nonsense_Mutation     28
# Splice_Site           14
# Frame_Shift_Del       12
Query 3: Copy Number Alterations

Fetch discrete CNA data (amplification = 2, gain = 1, diploid = 0, loss = -1, deep deletion = -2).

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=60)
    r.raise_for_status()
    return r.json()

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"
# CNA profile: discrete copy number data
cna_profile_id = f"{study_id}_gistic"   # GISTIC-derived discrete CNA

samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples][:300]

# Fetch CNA for ERBB2 (Entrez 2064) and MYC (Entrez 4609)
body = {
    "sampleIds": sample_ids,
    "entrezGeneIds": [2064, 4609]   # ERBB2, MYC
}
cna_data = cbio_post(
    f"molecular-profiles/{cna_profile_id}/molecular-data/fetch", body
)
print(f"CNA records retrieved: {len(cna_data)}")

cna_df = pd.DataFrame(cna_data)
# CNA values: 2=amplification, 1=gain, 0=diploid, -1=loss, -2=deep deletion
cna_label = {2: "AMP", 1: "GAIN", 0: "DIPLOID", -1: "LOSS", -2: "HOMDEL"}

print("\nERBB2 CNA distribution:")
erbb2 = cna_df[cna_df["entrezGeneId"] == 2064]
erbb2_counts = erbb2["value"].map(lambda x: cna_label.get(int(x), str(x))).value_counts()
print(erbb2_counts.to_string())
# DIPLOID    210
# AMP         62
# GAIN        18
# LOSS        10
Query 4: Clinical Data

Retrieve per-sample or per-patient clinical attributes including survival, tumor stage, and treatment.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"

# List available clinical attributes for this study
attrs = cbio_get(f"studies/{study_id}/clinical-attributes")
attr_df = pd.DataFrame(attrs)[["clinicalAttributeId", "displayName", "datatype", "patientAttribute"]]
print(f"Clinical attributes: {len(attr_df)}")
# Show survival-related attributes
survival_attrs = attr_df[attr_df["clinicalAttributeId"].str.contains("SURVIVAL|MONTHS|STATUS", na=False)]
print(survival_attrs[["clinicalAttributeId", "displayName"]].to_string(index=False))

# Fetch OS_STATUS and OS_MONTHS for all patients
clinical = cbio_get(f"studies/{study_id}/clinical-data",
                    params={"clinicalDataType": "PATIENT",
                            "projection": "DETAILED"})
clin_df = pd.DataFrame(clinical)
# Pivot to patient × attribute matrix
clin_pivot = clin_df.pivot_table(
    index="patientId", columns="clinicalAttributeId",
    values="value", aggfunc="first"
)
print(f"\nPatients: {len(clin_pivot)}")
if "OS_STATUS" in clin_pivot.columns:
    print("OS status counts:")
    print(clin_pivot["OS_STATUS"].value_counts().to_string())
# OS status counts:
# 0:LIVING    765
# 1:DECEASED  319
Query 5: Gene Expression Data

Retrieve mRNA expression values (RSEM or FPKM) from RNA-seq profiles.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=60)
    r.raise_for_status()
    return r.json()

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"
# RNA-seq profile (RSEM normalized values)
rna_profile_id = f"{study_id}_rna_seq_v2_mrna_median_normed_log2"

samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples][:100]

# Fetch expression for ESR1 (Entrez 2099), ERBB2 (2064), PGR (5241)
body = {
    "sampleIds": sample_ids,
    "entrezGeneIds": [2099, 2064, 5241]   # ESR1, ERBB2, PGR
}
expr_data = cbio_post(
    f"molecular-profiles/{rna_profile_id}/molecular-data/fetch", body
)
expr_df = pd.DataFrame(expr_data)
print(f"Expression records: {len(expr_df)}")

# Pivot to gene × sample matrix
expr_pivot = expr_df.pivot_table(
    index="sampleId", columns="entrezGeneId", values="value"
)
expr_pivot.columns = ["ERBB2", "ESR1", "PGR"]   # rename by gene symbol
print(f"\nExpression matrix: {expr_pivot.shape}")
print(expr_pivot.describe().round(2))
Query 6: Gene Details and Batch Lookup

Look up gene metadata (symbol, Entrez ID, type) required to construct mutation and CNA queries.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=30)
    r.raise_for_status()
    return r.json()

# Single gene lookup by Hugo symbol
gene = cbio_get("genes/TP53")
print(f"TP53: entrezGeneId={gene['entrezGeneId']}, type={gene['type']}")
# TP53: entrezGeneId=7157, type=protein-coding

# Batch gene lookup — convert Hugo symbols to Entrez IDs
gene_symbols = ["BRCA1", "BRCA2", "TP53", "PIK3CA", "PTEN", "KRAS", "EGFR"]
body = {"geneIds": gene_symbols, "geneIdType": "HUGO_GENE_SYMBOL"}
gene_list = cbio_post("genes/fetch", body)

gene_map = {g["hugoGeneSymbol"]: g["entrezGeneId"] for g in gene_list}
gene_df = pd.DataFrame(gene_list)[["hugoGeneSymbol", "entrezGeneId", "type"]]
print(f"\nResolved {len(gene_df)} genes:")
print(gene_df.to_string(index=False))
# hugoGeneSymbol  entrezGeneId            type
#          BRCA1         672   protein-coding
#          BRCA2         675   protein-coding
#           TP53        7157   protein-coding
Query 7: Visualization — Mutation Frequency Barplot

Compute mutation frequency across TCGA studies for a cancer driver gene, then read skills/data-visualization/omics-plotting/SKILL.md and follow its "Box / Violin / Bar" recipe on the exported CSV (→ figures/TP53_mutation_frequency.png).

python
import requests, time
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=60)
    r.raise_for_status()
    return r.json()

# Focus on a curated set of TCGA PanCancer Atlas studies
STUDIES = {
    "brca_tcga_pan_can_atlas_2018": "BRCA",
    "luad_tcga_pan_can_atlas_2018": "LUAD",
    "coad_tcga_pan_can_atlas_2018": "COAD",
    "prad_tcga_pan_can_atlas_2018": "PRAD",
    "gbm_tcga_pan_can_atlas_2018": "GBM",
}

GENE_ENTREZ = 7157   # TP53
GENE_SYMBOL = "TP53"

rows = []
for study_id, label in STUDIES.items():
    try:
        samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
        sample_ids = [s["sampleId"] for s in samples]
        n_total = len(sample_ids)
        profile_id = f"{study_id}_mutations"
        body = {"sampleIds": sample_ids, "entrezGeneIds": [GENE_ENTREZ]}
        muts = cbio_post(f"molecular-profiles/{profile_id}/mutations/fetch", body)
        mutated_samples = len({m["sampleId"] for m in muts})
        rows.append({"study": label, "n_mutated": mutated_samples,
                     "n_total": n_total,
                     "freq": mutated_samples / n_total * 100})
        time.sleep(0.2)
    except Exception as e:
        print(f"  Skipping {study_id}: {e}")

df = pd.DataFrame(rows).sort_values("freq", ascending=True)
df.to_csv(f"{GENE_SYMBOL}_mutation_frequency.csv", index=False)
print(df[["study", "n_mutated", "n_total", "freq"]].to_string(index=False))
# Render with the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Box / Violin / Bar" recipe (horizontal bar of freq by study).

Key Concepts

cBioPortal Data Model

cBioPortal organizes data in a three-tier hierarchy: Cancer Studies → Molecular Profiles → Sample-level data. A single study (e.g., brca_tcga_pan_can_atlas_2018) contains multiple molecular profiles, each covering one data type. Before querying mutation or expression data, always retrieve the molecular profile list with GET /molecular-profiles?studyId={studyId} to confirm the correct profile ID.

Molecular Profile ID Conventions
Data TypeTypical Profile ID SuffixAlteration Type
Somatic mutations_mutationsMUTATION_EXTENDED
Discrete CNA (GISTIC)_gisticCOPY_NUMBER_ALTERATION
Continuous CNA (log2)_log2CNACOPY_NUMBER_ALTERATION
RNA-seq (log2 RSEM)_rna_seq_v2_mrna_median_normed_log2MRNA_EXPRESSION
Methylation_methylation_hm27 or _hm450METHYLATION

Not all studies have all profile types. Always verify with GET /molecular-profiles?studyId={studyId}.

Entrez Gene IDs

The REST API mutation and molecular data endpoints require Entrez Gene IDs (integers), not Hugo symbols. Use GET /genes/{hugoSymbol} or POST /genes/fetch to resolve symbols to IDs before batch queries.

Common Workflows

Workflow 1: Somatic Mutation Landscape for a Gene Panel

Goal: Retrieve mutations for multiple cancer driver genes across an entire TCGA study and export to CSV.

python
import requests, time
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=120)
    r.raise_for_status()
    return r.json()

study_id = "luad_tcga_pan_can_atlas_2018"
profile_id = f"{study_id}_mutations"

# Resolve gene symbols to Entrez IDs
gene_symbols = ["KRAS", "EGFR", "TP53", "BRAF", "STK11", "KEAP1", "RB1"]
gene_list = cbio_post("genes/fetch",
                       {"geneIds": gene_symbols, "geneIdType": "HUGO_GENE_SYMBOL"})
gene_map = {g["entrezGeneId"]: g["hugoGeneSymbol"] for g in gene_list}
entrez_ids = list(gene_map.keys())

# Fetch all samples
samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples]
print(f"Study: {study_id} — {len(sample_ids)} samples")

# Batch mutations in chunks of 500 samples to avoid timeouts
chunk_size = 500
all_muts = []
for i in range(0, len(sample_ids), chunk_size):
    chunk = sample_ids[i:i + chunk_size]
    body = {"sampleIds": chunk, "entrezGeneIds": entrez_ids}
    muts = cbio_post(f"molecular-profiles/{profile_id}/mutations/fetch", body)
    all_muts.extend(muts)
    time.sleep(0.1)

mut_df = pd.DataFrame(all_muts)
mut_df["hugoSymbol"] = mut_df["entrezGeneId"].map(gene_map)
print(f"Total mutations: {len(mut_df)}")
print("\nMutation counts per gene:")
print(mut_df.groupby("hugoSymbol")["sampleId"].nunique()
      .sort_values(ascending=False).to_string())

mut_df.to_csv(f"{study_id}_driver_mutations.csv", index=False)
print(f"\nSaved: {study_id}_driver_mutations.csv")
Workflow 2: Survival Analysis — CNA Status vs. Overall Survival

Goal: Compare overall survival between patients with ERBB2 amplification vs. diploid/loss in TCGA BRCA.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=60)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"
cna_profile_id = f"{study_id}_gistic"

# Get all samples
samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples]

# Fetch ERBB2 CNA (Entrez 2064)
cna_data = cbio_post(
    f"molecular-profiles/{cna_profile_id}/molecular-data/fetch",
    {"sampleIds": sample_ids, "entrezGeneIds": [2064]}
)
cna_df = pd.DataFrame(cna_data)[["sampleId", "value"]].rename(columns={"value": "erbb2_cna"})
cna_df["erbb2_cna"] = cna_df["erbb2_cna"].astype(int)
cna_df["erbb2_status"] = cna_df["erbb2_cna"].map(
    {2: "Amplified", 1: "Gain", 0: "Diploid", -1: "Loss", -2: "Deep Deletion"})

# Fetch clinical data (OS_STATUS, OS_MONTHS)
clinical = cbio_get(f"studies/{study_id}/clinical-data",
                    params={"clinicalDataType": "PATIENT", "projection": "DETAILED"})
clin_df = pd.DataFrame(clinical)
clin_pivot = clin_df.pivot_table(
    index="patientId", columns="clinicalAttributeId", values="value", aggfunc="first"
).reset_index()

# Map samples to patients
sample_patient = cbio_get(f"studies/{study_id}/samples", params={"projection": "DETAILED"})
sp_df = pd.DataFrame(sample_patient)[["sampleId", "patientId"]]

# Merge CNA + clinical via patient ID
merged = (cna_df
          .merge(sp_df, on="sampleId")
          .merge(clin_pivot[["patientId", "OS_STATUS", "OS_MONTHS"]],
                 on="patientId", how="inner"))
merged = merged.dropna(subset=["OS_STATUS", "OS_MONTHS"])
merged["OS_MONTHS"] = pd.to_numeric(merged["OS_MONTHS"], errors="coerce")
merged["event"] = (merged["OS_STATUS"] == "1:DECEASED").astype(int)

# Survival table for the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Kaplan–Meier" recipe (columns: time, event, group)
km_input = (merged.loc[merged["erbb2_status"].isin(["Amplified", "Diploid"]),
                       ["OS_MONTHS", "event", "erbb2_status"]]
            .rename(columns={"OS_MONTHS": "time", "erbb2_status": "group"}))
km_input.to_csv("erbb2_survival.csv", index=False)
print(f"Survival table: {len(km_input)} patients -> erbb2_survival.csv")
print(km_input["group"].value_counts().to_string())
# Render with the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Kaplan–Meier" recipe -> figures/erbb2_survival.png
Workflow 3: Multi-Study Alteration Frequency Heatmap

Goal: Build a gene × cancer-type alteration frequency matrix across TCGA studies.

python
import requests, time
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=90)
    r.raise_for_status()
    return r.json()

STUDIES = {
    "brca_tcga_pan_can_atlas_2018": "BRCA",
    "luad_tcga_pan_can_atlas_2018": "LUAD",
    "coad_tcga_pan_can_atlas_2018": "COAD",
    "gbm_tcga_pan_can_atlas_2018":  "GBM",
}
GENE_SYMBOLS = ["TP53", "KRAS", "PIK3CA", "EGFR", "PTEN"]

# Resolve genes
gene_list = cbio_post("genes/fetch",
                       {"geneIds": GENE_SYMBOLS, "geneIdType": "HUGO_GENE_SYMBOL"})
gene_map = {g["entrezGeneId"]: g["hugoGeneSymbol"] for g in gene_list}
entrez_ids = list(gene_map.keys())

freq_matrix = pd.DataFrame(index=GENE_SYMBOLS, columns=list(STUDIES.values()), dtype=float)

for study_id, label in STUDIES.items():
    try:
        samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
        sample_ids = [s["sampleId"] for s in samples]
        n_total = len(sample_ids)
        profile_id = f"{study_id}_mutations"
        body = {"sampleIds": sample_ids, "entrezGeneIds": entrez_ids}
        muts = cbio_post(f"molecular-profiles/{profile_id}/mutations/fetch", body)
        mut_df = pd.DataFrame(muts) if muts else pd.DataFrame()
        for eid, symbol in gene_map.items():
            if mut_df.empty:
                freq_matrix.loc[symbol, label] = 0.0
            else:
                n_mut = mut_df[mut_df["entrezGeneId"] == eid]["sampleId"].nunique()
                freq_matrix.loc[symbol, label] = n_mut / n_total * 100
        time.sleep(0.2)
    except Exception as e:
        print(f"  {label}: {e}")

freq_matrix = freq_matrix.fillna(0).astype(float)
freq_matrix.to_csv("mutation_frequency_matrix.csv")
print(freq_matrix.to_string())
# Render with the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Expression heatmap" recipe (gene x cancer-type, YlOrRd,
# annotated) -> figures/mutation_frequency_heatmap.png

Key Parameters

ParameterFunction/EndpointDefaultRange / OptionsEffect
studyIdAll study endpoints—any valid cBioPortal study IDSelects the cancer study
molecularProfileIdmutations/fetch, molecular-data/fetch—{studyId}_mutations, {studyId}_gistic, etc.Selects the data type profile
entrezGeneIdsmutations/fetch, molecular-data/fetch—list of integer Entrez IDsGenes to query; use POST /genes/fetch to resolve symbols
sampleIdsmutations/fetch, molecular-data/fetch—list of sample ID stringsSamples to retrieve; use GET /studies/{id}/samples for all
clinicalDataTypeclinical-data"SAMPLE""SAMPLE", "PATIENT"Whether to return sample-level or patient-level clinical attributes
projectionsamples, clinical-data"SUMMARY""ID", "SUMMARY", "DETAILED", "META"Response verbosity; "ID" fastest for ID-only fetches
keywordstudies""free textFilter studies by name/cancer type keyword
Show full SKILL.md (456 more words)Show less

Best Practices

  1. Fetch sample IDs before data queries: All mutation and molecular data endpoints require explicit sampleIds. Retrieve them with GET /studies/{studyId}/samples?projection=ID before each query.

  2. Verify profile IDs from the API: Profile IDs are not guaranteed to follow the _mutations / _gistic pattern in every study. Always confirm with GET /molecular-profiles?studyId={studyId} rather than guessing.

  3. Chunk large sample sets: The API can time out on requests with thousands of sample IDs. Batch requests in chunks of 500 samples with time.sleep(0.1) between chunks.

  4. Use Entrez IDs, not Hugo symbols, in data fetch endpoints: The mutation and molecular data endpoints accept entrezGeneIds (integers). Resolve symbols first with POST /genes/fetch.

  5. Don't hard-code Entrez IDs: Gene IDs can be looked up dynamically via the API. Hard-coded IDs become incorrect if the gene model changes. Use POST /genes/fetch to resolve gene symbols at runtime.

Common Recipes

Recipe: List All Molecular Profiles for a Study

When to use: Before running any data query — verify which profile IDs are available.

python
import requests

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"
profiles = cbio_get("molecular-profiles", params={"studyId": study_id})
for p in profiles:
    print(f"{p['molecularProfileId']:55s}  {p['molecularAlterationType']}")
# brca_tcga_pan_can_atlas_2018_mutations          MUTATION_EXTENDED
# brca_tcga_pan_can_atlas_2018_gistic             COPY_NUMBER_ALTERATION
# brca_tcga_pan_can_atlas_2018_log2CNA            COPY_NUMBER_ALTERATION
# brca_tcga_pan_can_atlas_2018_rna_seq_v2_mrna_median_normed_log2  MRNA_EXPRESSION
Recipe: Download Full Mutation MAF for a Study

When to use: Export all somatic mutations from a study into MAF-compatible format for downstream analysis.

python
import requests, time
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=60)
    r.raise_for_status()
    return r.json()

def cbio_post(endpoint, body):
    r = requests.post(f"{BASE_URL}/{endpoint}", json=body,
                      headers={"Accept": "application/json",
                               "Content-Type": "application/json"},
                      timeout=120)
    r.raise_for_status()
    return r.json()

study_id = "coad_tcga_pan_can_atlas_2018"
profile_id = f"{study_id}_mutations"

samples = cbio_get(f"studies/{study_id}/samples", params={"projection": "ID"})
sample_ids = [s["sampleId"] for s in samples]

all_mutations = []
for i in range(0, len(sample_ids), 300):
    chunk = sample_ids[i:i + 300]
    muts = cbio_post(f"molecular-profiles/{profile_id}/mutations/fetch",
                     {"sampleIds": chunk, "entrezGeneIds": []})  # empty = all genes
    all_mutations.extend(muts)
    time.sleep(0.1)

mut_df = pd.DataFrame(all_mutations)
cols = ["hugoGeneSymbol", "sampleId", "chr", "startPosition", "endPosition",
        "referenceAllele", "variantAllele", "mutationType",
        "proteinChange", "variantType"]
available = [c for c in cols if c in mut_df.columns]
mut_df[available].to_csv(f"{study_id}_mutations.csv", index=False)
print(f"Saved {len(mut_df)} mutations → {study_id}_mutations.csv")
Recipe: Query Patient-Level Clinical Attribute

When to use: Extract a specific clinical variable (e.g., tumor stage, age at diagnosis) for all patients.

python
import requests
import pandas as pd

BASE_URL = "https://www.cbioportal.org/api"

def cbio_get(endpoint, params=None):
    r = requests.get(f"{BASE_URL}/{endpoint}", params=params,
                     headers={"Accept": "application/json"}, timeout=30)
    r.raise_for_status()
    return r.json()

study_id = "brca_tcga_pan_can_atlas_2018"

# Fetch a specific clinical attribute for all patients
attr_id = "TUMOR_STAGE"
clinical = cbio_get(f"studies/{study_id}/clinical-data",
                    params={"clinicalDataType": "PATIENT",
                            "projection": "DETAILED"})

clin_df = pd.DataFrame(clinical)
if "clinicalAttributeId" in clin_df.columns:
    stage_df = clin_df[clin_df["clinicalAttributeId"] == attr_id][["patientId", "value"]]
    print(f"Patients with {attr_id} annotation: {len(stage_df)}")
    print(stage_df["value"].value_counts().head(10).to_string())

Troubleshooting

ProblemCauseSolution
404 Not Found on profile endpointMolecular profile does not exist for studyList profiles with GET /molecular-profiles?studyId={id}; confirm the profile ID
Empty mutations listGene has no mutations in the selected samples/profileVerify study has a mutation profile; check sample IDs belong to the same study
requests.exceptions.TimeoutLarge sample set (>1000) in a single requestChunk requests to 300–500 samples; increase timeout to 120s
entrezGeneIds key error in responseHugo symbol passed instead of Entrez IDUse POST /genes/fetch to resolve symbols to integer Entrez IDs first
CNA values returned as stringsvalue field is string in JSONCast with pd.to_numeric() or int(value) before comparison
Expression profile not foundStudy uses non-standard profile namingCheck profile list; look for MRNA_EXPRESSION alteration type in GET /molecular-profiles
Survival analysis has many NA valuesClinical attribute absent for some patientsUse dropna() on OS columns; check attribute availability with GET /studies/{id}/clinical-attributes
  • gnomad-database — population variant allele frequencies for healthy cohorts (complement to cBioPortal somatic data)
  • cnvkit-copy-number — CNVkit pipeline for generating SEG/CNA files that can be loaded into cBioPortal
  • pydeseq2-differential-expression — differential expression analysis that can be applied to cBioPortal RNA-seq exports

References

© jaechang-hits, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/genomics-bioinformatics/databases/cbioportal-database of jaechang-hits/SciAgent-Skills.

Open the folder on GitHubat commit 82c862c

Used in 1 other repository

We found 1 copy of this SKILL.md (exact, near-identical or edited) in other folders, from 1 other GitHub owner. This page covers the copy in jaechang-hits/SciAgent-Skills, which our catalogue first saw on October 7, 2026.

Compare with similar skills

Cbioportal Database next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Cbioportal Database compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Cbioportal Database this skilljaechang-hits/SciAgent-Skills3741 repos~8.2kAutomated safety check: PassAGPL-3.0
UniProt Database Accessdavila7/claude-code-templates33k14 repos~1.7kAutomated safety check: PassMIT
Bio Ensembl RESTGPTomics/bioSkills1.2k2 repos~3.6kAutomated safety check: PassMIT
Pride FetchClawBio/ClawBio1.2k—~4.2kAutomated safety check: PassMIT
Ensembl Databaseaipoch/medical-research-skills1.9k—~1.5kAutomated safety check: PassMIT
Singlecell Portalaipoch/medical-research-skills1.9k—~1.2kAutomated safety check: PassMIT

Similar skills

  • UniProt Database Access

    davila7/claude-code-templates

    Queries the UniProt REST API directly to search proteins, fetch FASTA sequences, map IDs between databases and read Swiss-Prot and TrEMBL entries.

    33k GitHub starsUsed in 14 repos~1.7k tokens
    Research & ScienceAuto-check passed
  • Bio Ensembl REST

    GPTomics/bioSkills

    Query the Ensembl REST API for gene/transcript/protein lookup, sequence retrieval, comparative genomics (Compara), variant effect prediction (VEP), regulatory features, and cross-species…

    1.2k GitHub starsUsed in 2 repos~3.6k tokens
    Research & ScienceAuto-check passed
  • Pride Fetch

    ClawBio/ClawBio

    Query metadata and download data from the PRIDE Archive, EMBL-EBI's proteomics identifications database, via the PRIDE Archive REST API v3.

    1.2k GitHub stars~4.2k tokensUpdated yesterday
    Research & ScienceAuto-check passed
  • Ensembl Database

    aipoch/medical-research-skills

    Access Ensembl REST API for vertebrate genomic data; use when you need gene/ID lookups, sequence retrieval, variant effect prediction (VEP), or homology/assembly coordinate mapping.

    1.9k GitHub stars~1.5k tokensUpdated 23 days ago
    Research & ScienceAuto-check passed
  • Singlecell Portal

    aipoch/medical-research-skills

    Programmatically query public single-cell study metadata from the Broad Institute Single Cell Portal REST API when you need to search and filter datasets by organism, tissue, disease, or cell type…

    1.9k GitHub stars~1.2k tokensUpdated 23 days ago
    Research & ScienceAuto-check passed
  • Ena Database

    aipoch/medical-research-skills

    Access the European Nucleotide Archive (ENA) via REST APIs and FTP/Aspera to search and retrieve sequences, raw reads (FASTQ), assemblies, and metadata when you have accession IDs or need…

    1.9k GitHub stars~1.9k tokensUpdated 23 days ago
    Backend & APIsAuto-check passed

More from jaechang-hits/SciAgent-Skills

All 169 skills in this repo
  • Neb Irc Activation Energy

    jaechang-hits/SciAgent-Skills

    NEB-IRC activation energy pipeline for reaction barriers using GFN2-xTB and pysisyphus.

    374 GitHub stars~4k tokensUpdated 12 days ago
    Auto-check passed
  • Molecular Visualization 3dmol

    jaechang-hits/SciAgent-Skills

    3Dmol.js WebGL molecular visualization emitted as self-contained HTML.

    374 GitHub stars~3.2k tokensUpdated 12 days ago
    Auto-check passed
  • Cobrapy Metabolic Modeling

    jaechang-hits/SciAgent-Skills

    Constraint-based (COBRA) analysis of genome-scale metabolic models: FBA, FVA, knockouts, flux sampling, production envelopes, gapfilling, media optimization.

    374 GitHub starsUsed in 1 repo~4.9k tokens
    Auto-check passed
  • Rdkit Chemdraw Cdxml

    jaechang-hits/SciAgent-Skills

    Read, write, and edit ChemDraw CDX/CDXML files with RDKit's rdkit.Chem.rdChemDraw plus direct XML editing, always paired with a rendered PNG.

    374 GitHub stars~6.9k tokensUpdated 12 days ago
    Auto-check passed
  • Pubmed Database

    jaechang-hits/SciAgent-Skills

    Programmatic PubMed access via NCBI E-utilities REST API. An agent skill from jaechang-hits/SciAgent-Skills.

    374 GitHub starsUsed in 1 repo~4.4k tokens
    Auto-check passed
  • Sciagent Skill Creator

    jaechang-hits/SciAgent-Skills

    Scaffold a new SciAgent-Skills entry. An agent skill from jaechang-hits/SciAgent-Skills.

    374 GitHub stars~2.3k tokensUpdated 12 days ago
    Auto-check passed

Questions about Cbioportal Database

What does Cbioportal Database do?

Cancer genomics (TCGA et al.) via cBioPortal REST API. An agent skill from jaechang-hits/SciAgent-Skills. Cbioportal Database is an agent skill from jaechang-hits/SciAgent-Skills.) via cBioPortal REST API.

When should I use Cbioportal Database?

Cbioportal Database fits situations like: survival analysis; tasks that involve Bioinformatics; tasks that involve REST APIs.

How do I install Cbioportal Database in Claude Code?

Run `npx skills add jaechang-hits/SciAgent-Skills --skill cbioportal-database -a claude-code`. Or copy the skill folder (skills/genomics-bioinformatics/databases/cbioportal-database in jaechang-hits/SciAgent-Skills) into .claude/skills/cbioportal-database in your project. Claude Code loads it when a task matches its description.

How do I install Cbioportal Database in Codex?

Run `npx skills add jaechang-hits/SciAgent-Skills --skill cbioportal-database -a codex`. Or copy the skill folder (skills/genomics-bioinformatics/databases/cbioportal-database in jaechang-hits/SciAgent-Skills) into .agents/skills/cbioportal-database in your project. Codex loads it when a task matches its description.

Can I use Cbioportal Database in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jaechang-hits/SciAgent-Skills --skill cbioportal-database -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/cbioportal-database, .gemini/skills/cbioportal-database, .github/skills/cbioportal-database and .opencode/skills/cbioportal-database in your project.

What does Cbioportal Database need to run?

Going by SKILL.md and its folder, Cbioportal Database needs the command-line tools its instructions call (pip). Our summary lists: Python 3.

Does Cbioportal Database access the network?

SKILL.md names 4 domains. In commands or code: cbioportal.org; the agent is likely to contact it when it follows the instructions. As links in the text: doi.org, github.com and cell.com. This is read from the text; nothing was executed.

Is Cbioportal Database safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Cbioportal Database use?

Cbioportal Database is published under the AGPL-3.0 licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Cbioportal Database use?

About 8.2k tokens (SKILL.md is roughly 33k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Cbioportal Database?

Skills that share tags, products or a category with Cbioportal Database: UniProt Database Access (davila7/claude-code-templates, 33k stars), Bio Ensembl REST (GPTomics/bioSkills, 1.2k stars), Pride Fetch (ClawBio/ClawBio, 1.2k stars) and Ensembl Database (aipoch/medical-research-skills, 1.9k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Cbioportal Database?

jaechang-hits (a GitHub user) maintains it in jaechang-hits/SciAgent-Skills, which has 374 GitHub stars. The repository holds 169 skills in this directory. The repository was last updated on September 29, 2026.

Source: jaechang-hits/SciAgent-Skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.