Streamline conversion of clinical and genomic data into cBioPortal-compatible formats
Project description
cBioFormatter
A Python package for streamlined preparation and formatting of clinical and molecular genomic data for upload to cBioPortal.
Overview
cBioFormatter simplifies the process of converting your genomic data into cBioPortal-compatible formats. Designed for data scientists with basic Python knowledge, this package handles all the complexity of cBioPortal file formatting, validation, and metadata generation.
What it does:
- Converts clinical data (patient and sample attributes) into cBioPortal format
- Processes VCF files into MAF format for mutation data
- Generates all required metadata files automatically
- Validates your study using cBioPortal's official validator
- Creates case lists for sample grouping
What you need:
- Basic Python knowledge (pandas DataFrames, module imports)
- Your clinical data (Excel, CSV, database query, anything that can be converted to a pandas DataFrame)
- VCF files for mutation data (optional)
- mafsmith installed (for VCF processing, optional)
Installation
pip install cbioportal-formatter
Additional requirements:
- mafsmith (for mutation data processing, if using VCF files) - see mafsmith repo
Development
For local development, clone the repository and install in editable mode with dev dependencies.
Using uv (recommended)
uv is a fast Python package manager. If you don't have it installed:
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Then set up the project:
git clone https://github.com/getwilds/cbioformatter.git
cd cbioformatter
uv sync --extra dev
To run commands in the virtual environment:
uv run pytest # Run tests
uv run pytest --cov # Run tests with coverage
uv run ruff check . # Run linter
uv run ruff format . # Format code
uv run ipython # Interactive Python shell (or: uv run python)
Using pip
git clone https://github.com/getwilds/cbioformatter.git
cd cbioformatter
python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
pip install -e ".[dev]"
To run tests and linting:
pytest # Run tests
pytest --cov # Run tests with coverage
ruff check . # Run linter
ruff format . # Format code
ipython # Interactive Python shell (or: python)
Quick Start
Basic Study with Clinical Data Only
import pandas as pd
from cbioformatter import ClinicalStudy
# Prepare your sample-level clinical data
# (typically loaded from a CSV, Excel file, or database query)
sample_df = pd.DataFrame({
'SAMPLE_ID': ['S001', 'S002', 'S003'],
'PATIENT_ID': ['P001', 'P001', 'P002'],
'TUMOR_TYPE': ['Primary', 'Metastasis', 'Primary'],
'AGE_AT_DIAGNOSIS': [45, 45, 67]
})
# sample_df looks like:
# | SAMPLE_ID | PATIENT_ID | TUMOR_TYPE | AGE_AT_DIAGNOSIS |
# |-----------|------------|------------|------------------|
# | S001 | P001 | Primary | 45 |
# | S002 | P001 | Metastasis | 45 |
# | S003 | P002 | Primary | 67 |
# Prepare your patient-level clinical data (optional)
patient_df = pd.DataFrame({
'PATIENT_ID': ['P001', 'P002'],
'SEX': ['Female', 'Male'],
'ETHNICITY': ['Hispanic', 'Asian']
})
# patient_df looks like:
# | PATIENT_ID | SEX | ETHNICITY |
# |------------|--------|-----------|
# | P001 | Female | Hispanic |
# | P002 | Male | Asian |
# Create and validate the study
study = ClinicalStudy(
study_id="brca_ocdo_2026",
name="Breast Cancer Study (Office of the Chief Data Officer 2026)",
description="Clinical and genomic data from breast cancer patients",
cancer_type="brca", # must be a valid cBioPortal cancer type
genome_build="GRCh38", # Options: "GRCh37", "hg19", or "GRCh38"
sample_data=sample_df,
patient_data=patient_df # optional
)
# Validate the study (generates temp files, runs validator, cleans up)
result = study.validate()
if result.is_valid:
print("✓ Study is valid!")
print(f"Validation report: {result.report_path}")
# Write files to disk
study.write_files(output_dir="./my_studies")
print(f"Study files written to: ./my_studies/brca_ocdo_2026/")
else:
print("✗ Validation failed. Check the report for details:")
print(f"Report: {result.report_path}")
Study with Mutation Data
# Add VCF file paths to your sample DataFrame
sample_df = pd.DataFrame({
'SAMPLE_ID': ['S001', 'S002', 'S003'],
'PATIENT_ID': ['P001', 'P001', 'P002'],
'TUMOR_TYPE': ['Primary', 'Metastasis', 'Primary'],
'VCF_PATH': [
'/data/vcf/S001.vcf',
'/data/vcf/S002.vcf',
None # This sample has no mutation data
]
})
# The rest is identical - mutation data is automatically detected
study = ClinicalStudy(
study_id="brca_ocdo_2026",
name="Breast Cancer Study (Office of the Chief Data Officer 2026)",
description="Clinical and genomic data from breast cancer patients",
cancer_type="brca",
genome_build="GRCh38",
sample_data=sample_df
)
result = study.validate()
if result.is_valid:
study.write_files(output_dir="./my_studies")
Features
Clinical Data Handling
Required columns:
SAMPLE_IDin sample DataFrame (must be unique)PATIENT_IDin patient DataFrame if provided (must be unique)
Smart defaults:
- If
patient_datais not provided, it's auto-generated from uniquePATIENT_IDvalues insample_data - If
PATIENT_IDcolumn is missing fromsample_data, each sample is assigned its own patient (PATIENT_ID = SAMPLE_ID) - Column names are automatically cleaned for cBioPortal compatibility while preserving display names
- Data types are automatically inferred: NUMBER (int/float), BOOLEAN (bool), STRING (everything else)
Validation:
- Ensures all
SAMPLE_IDvalues are unique - Ensures all
PATIENT_IDvalues are unique (if patient data provided) - Validates referential integrity (all patient IDs in samples exist in patient data)
- Failures raise clear exceptions with specific issues identified
Mutation Data Processing
Input: VCF files (one per sample)
How it works:
- Add a
VCF_PATHcolumn to yoursample_dataDataFrame with file paths - VCF files are automatically converted to MAF format using mafsmith
- All MAF files are concatenated into a single mutation file
- Sample IDs are correctly mapped to
Tumor_Sample_Barcode
Flexible data availability:
- If
VCF_PATHcolumn is missing entirely → no mutation data included - If some samples have VCF paths and others don't → mutation data included only for samples with valid paths
- At least one valid VCF path must be provided if the column exists
Requirements:
- mafsmith must be installed (see the mafsmith repo for build instructions;
cargo build --releaseproduces a single binary) - Reference data for your genome build must be downloaded:
mafsmith fetch --genome grch38populates~/.mafsmith/GRCh38/(~3.8 GB). If the FASTA index is missing, build it withsamtools faidx - VCF files must match the specified genome build (
GRCh37orGRCh38) - Optionally pass
ref_fasta_path=...toClinicalStudy(or setCBIOFORMATTER_REF_FASTA) to override the bundled reference
Known limitation: mafsmith's embedded annotation (fastVEP) does not currently populate the optional SWISSPROT column. As a result, cBioPortal's Pfam-domain mutations view will not be available for mafsmith-produced studies until nf-osi/mafsmith closes that gap. Mutations still load and display normally; only the Pfam diagram is affected.
Study Validation
The validate() method:
- Creates temporary files in cBioPortal format
- Runs the official cBioPortal validator (from cBioPortal datahub-study-curation-tools)
- Generates an HTML validation report
- Cleans up temporary files
- Returns a validation result object
Validation result object:
result.is_valid # True if validation passed (clean or warnings-only)
result.report_path # Path to HTML validation report
result.errors # Errors AND/OR warnings emitted by the validator
is_valid is True for a clean validation and for warnings-only results; in the warnings-only case, result.errors is populated and write_files(validate=True) proceeds with a UserWarning. Errors (validator exit code 1 or 2) raise ValidationError from write_files(validate=True) and study files are not written.
Validator acquisition: The cBioPortal validator is AGPL-3.0 licensed and lives in a separate repository, so cbioformatter does not bundle it. On first validate() call, the validator is cloned into ~/.cache/cbioformatter/validator/ (~5 MB, requires git and internet). Subsequent calls reuse the cache.
For air-gapped or CI environments, pre-clone the validator and set CBIOFORMATTER_VALIDATOR_PATH:
git clone --depth 1 https://github.com/cBioPortal/datahub-study-curation-tools.git
export CBIOFORMATTER_VALIDATOR_PATH=$(pwd)/datahub-study-curation-tools/validation/validator
File Output
The write_files() method generates a complete cBioPortal study directory:
my_studies/
└── brca_ocdo_2026/
├── meta_study.txt
├── meta_clinical_patient.txt
├── data_clinical_patient.txt
├── meta_clinical_sample.txt
├── data_clinical_sample.txt
├── meta_mutations.txt # if mutation data provided
├── data_mutations.txt # if mutation data provided
├── case_lists/
│ ├── cases_all.txt
│ └── cases_sequenced.txt # if mutation data provided
Parameters:
output_dir(default:".") - Base directory for output. Study files are created in{output_dir}/{study_id}/validate(default:True) - IfTrue, runs validation before writing files. Set toFalseto skip validation (use with caution).
API Reference
ClinicalStudy
ClinicalStudy(
study_id: str,
name: str,
description: str,
cancer_type: str,
genome_build: str,
sample_data: pd.DataFrame,
patient_data: pd.DataFrame = None
)
Parameters:
study_id: Unique identifier for the study (no spaces, lowercase recommended)name: Human-readable study namedescription: Brief description of the studycancer_type: Valid cBioPortal cancer type (see cBioPortal documentation)genome_build: Reference genome build. Accepts UCSC names ("hg19","hg38","mm10") or NCBI/Ensembl aliases ("GRCh37","GRCh38","GRCm38"); aliases are translated to the UCSC form on write since cBioPortal's validator only accepts UCSC namessample_data: pandas DataFrame with sample-level clinical attributes. Must includeSAMPLE_ID. Optionally includesPATIENT_IDandVCF_PATHpatient_data: Optional pandas DataFrame with patient-level clinical attributes. Must includePATIENT_IDif provided
Methods:
validate()
Validates the study using cBioPortal's official validator.
Returns: ValidationResult object with:
is_valid(bool): Whether validation passedreport_path(str): Path to HTML validation reporterrors(list): List of validation errors if validation failed
write_files(output_dir=".", validate=True)
Writes all study files to disk.
Parameters:
output_dir(str): Base output directory (default: current directory)validate(bool): If True, runs validation before writing files (default: True)
Returns: Path to the created study directory ({output_dir}/{study_id}/)
Raises:
ValidationErrorifvalidate=Trueand the cBioPortal validator reports errors. Study files are not written. Passvalidate=Falseto skip validation.
Example Workflow
See the example notebook for a complete walkthrough using simulated data.
Supported Data Types (Current Version)
- ✅ Clinical data (patient and sample attributes)
- ✅ Mutation data (VCF → MAF conversion)
- ⏳ Copy number alterations (CNA) - planned for future release
- ⏳ Gene expression data - planned for future release
- ⏳ Methylation data - planned for future release
Requirements
- Python 3.10+
- pandas
- mafsmith (optional, for VCF processing)
External Tools
This package relies on the following external tools for mutation data processing:
mafsmith (optional, for VCF processing):
- Required only if you're including mutation data from VCF files
- Build from source per the mafsmith repo (
cargo build --release) - After install, download reference data with
mafsmith fetch --genome grch38(orgrch37/grcm39) - Includes embedded fastVEP annotation — no separate VEP install needed
- Known limitation: the optional
SWISSPROTcolumn is not populated, so cBioPortal's Pfam-domain mutations view will be unavailable
Troubleshooting
Common Issues
"SAMPLE_ID duplicates found"
- Ensure all values in your
SAMPLE_IDcolumn are unique - Check for accidentally duplicated rows in your data
"PATIENT_ID 'P123' not found in patient data"
- Every patient ID referenced in sample data must exist in patient data
- If you didn't provide patient data, this shouldn't happen (it's auto-generated)
"VCF file not found: /path/to/file.vcf"
- Check that all file paths in the
VCF_PATHcolumn are correct - Ensure files are accessible from your current working directory
"Could not locate mafsmith"
- Build mafsmith following the mafsmith repo and ensure the resulting binary is on your
PATH, or setCBIOFORMATTER_MAFSMITH_PATHto its location
"Cannot read FASTA index reference.fa.fai"
- mafsmith's
fetchmay not generate a FASTA index. Build it manually withsamtools faidx ~/.mafsmith/<genome>/reference.fa
Validation fails with complex errors
- Review the HTML validation report at the path provided
- Common issues: incorrect cancer type, malformed column names, missing required fields
Contributing
Contributions welcome! Please see CONTRIBUTING.md for guidelines.
License
MIT License - see LICENSE for details.
Citation
If you use cBioFormatter in your research, please mention the GitHub repository:
cBioFormatter: https://github.com/getwilds/cbioportal-formatter
Future aim: We plan to submit cBioFormatter to the Journal of Open Source Software (JOSS) for peer review. Once published, a formal citation will be provided here.
Contact
Fred Hutch users:
- FH-Data Slack: #cbioportal-support channel (or reach out to Taylor Firman or Emma Bishop)
- Research Computing Data House Call
External users:
- Email: wilds@fredhutch.org
- Issues: GitHub Issues
- Questions: GitHub Discussions
Acknowledgments
- Built to support the Fred Hutch Cancer Center cBioPortal instance
- Uses cBioPortal's official validation tools
- Part of the WILDS ecosystem
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cbioformatter-0.3.0.tar.gz.
File metadata
- Download URL: cbioformatter-0.3.0.tar.gz
- Upload date:
- Size: 25.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce5a3fa5cfe57d299a27347fc3ce56bc9ce0a905e96c897d12b9efc81171314a
|
|
| MD5 |
77bafc558d05654d5ce1ea07b04b46ac
|
|
| BLAKE2b-256 |
dc73d1cbefc0532a14c2d4524f17b074a44599303c037db79fbeb4211856d4f5
|
Provenance
The following attestation bundles were made for cbioformatter-0.3.0.tar.gz:
Publisher:
publish.yml on getwilds/cbioformatter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cbioformatter-0.3.0.tar.gz -
Subject digest:
ce5a3fa5cfe57d299a27347fc3ce56bc9ce0a905e96c897d12b9efc81171314a - Sigstore transparency entry: 1916337910
- Sigstore integration time:
-
Permalink:
getwilds/cbioformatter@d718d0ce4622880b9730999e51aed0a7a8e408ea -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/getwilds
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d718d0ce4622880b9730999e51aed0a7a8e408ea -
Trigger Event:
release
-
Statement type:
File details
Details for the file cbioformatter-0.3.0-py3-none-any.whl.
File metadata
- Download URL: cbioformatter-0.3.0-py3-none-any.whl
- Upload date:
- Size: 25.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51bbf02e54dcbc7b718efb857a34a96dcd7b5218054b3db19bbf041d09802298
|
|
| MD5 |
3a936330bc71a5f05f3ca53ae116eef0
|
|
| BLAKE2b-256 |
b7c6094a6e0c492fde0162e94e79748bcbbf90314dedaed35e8883eb492d1af2
|
Provenance
The following attestation bundles were made for cbioformatter-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on getwilds/cbioformatter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cbioformatter-0.3.0-py3-none-any.whl -
Subject digest:
51bbf02e54dcbc7b718efb857a34a96dcd7b5218054b3db19bbf041d09802298 - Sigstore transparency entry: 1916338160
- Sigstore integration time:
-
Permalink:
getwilds/cbioformatter@d718d0ce4622880b9730999e51aed0a7a8e408ea -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/getwilds
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d718d0ce4622880b9730999e51aed0a7a8e408ea -
Trigger Event:
release
-
Statement type: