wittgen-b2sc
Thin Python client for the WittGen B2SC API — submit a bulk RNA-seq job, poll it to
completion, and pull per-sample single-cell type proportions, gene scores and plots. Built to
the OpenAPI contract at https://www.wittgenbio.com/api/v1/openapi.json.
Install
pip install wittgen-b2sc # core
pip install "wittgen-b2sc[pandas]" # + DataFrame support
Installing from git requires access to the private platform repo, so it only works for WittGen staff and partners who have been granted it:
pip install "wittgen-b2sc[pandas] @ git+ssh://git@github.com/WittGen-Inc/wittgen-b2sc-platform.git#subdirectory=clients/wittgen-b2sc-python"
Authenticate
Create a per-user API key in the WittGen dashboard (it is shown once — store it as a secret).
from wittgen_b2sc import B2SCClient
client = B2SCClient(api_key="wgk_...")
Quickstart
# 1. Submit a job against a built-in reference dataset
job = client.submit_job("SLE_status_3000", source="reference_dataset")
job_id = job["job_id"]
# 2. Wait for the GPU pipeline, then for the R analysis stage.
# ~26 min for this SLE cohort; the 405-sample BRCA cohort takes over two hours.
client.wait_for_completion(job_id, wait_for_analysis=True)
# 3. Per-sample cell-type proportions as a tidy DataFrame
df = client.get_proportions(job_id, as_dataframe=True) # columns: sample, cell_type, proportion
print(df.head())
# 4. Gene scores and plots from the R stage, as presigned downloads
for f in client.list_files(job_id, category="r_outputs"):
print(f["name"], f["url"])
Databricks quickstart
Run inside a Databricks notebook. Store the key in a secret scope, never inline.
# Cell 1 — install
%pip install "wittgen-b2sc[pandas]"
# Cell 2 — client (key from a Databricks secret scope)
from wittgen_b2sc import B2SCClient
api_key = dbutils.secrets.get(scope="wittgen", key="b2sc_api_key")
client = B2SCClient(api_key=api_key)
# Cell 3 — submit + await + load as a Spark-ready pandas DataFrame
job = client.submit_job("SLE_status_3000", source="reference_dataset")
client.wait_for_completion(job["job_id"])
pdf = client.get_proportions(job["job_id"], as_dataframe=True)
sdf = spark.createDataFrame(pdf) # -> a Spark DataFrame you can join/aggregate/save to Delta
sdf.display()
API surface
| Method | Description |
|---|---|
list_models() |
Available disease models — read applies_to before submitting your own data |
list_atlases() |
Pre-computed public cohorts, ready to inspect |
get_usage() |
Your plan and remaining trial quota |
upload_file(path, content_type="text/plain") |
Upload your own matrix → input_file_key |
submit_job(disease_model, source, input_file_key=None, geo_accession=None, geo_file=None) |
Submit a job → job record |
get_job(job_id) |
Current status |
wait_for_completion(job_id, poll_interval=15, timeout=10800, wait_for_analysis=False) |
Poll until COMPLETED (or, with wait_for_analysis=True, until the R stage reaches R_COMPLETE) |
get_results_data(job_id) |
Aggregated summary (mean proportions across the cohort) + metadata |
get_proportions(job_id, fmt="long"|"wide", as_dataframe=False) |
Per-sample proportions |
list_files(job_id, category=None) |
Every artifact with a presigned URL — gene scores, plots, matrices |
Running a public GEO series
Give an accession and we resolve it to the gene-level expression matrix in that series, fetch it and run it:
job = client.submit_job("breast_cancer_cell_type3", source="geo", geo_accession="GSE81538")
A series carries whatever its submitter uploaded — GSE81538 has five supplementary files, only one
of which is the gene-level matrix. When several are plausible the call returns 422 with the
listing; retry with geo_file="..." naming one. Pass geo_file up front to override our choice.
The series is cached by accession, so the second person to run a given GSE does not wait for it again. Requires a provisioned plan: the data is public, the GPU run is not.
Pre-computed atlases
Some well-known cohorts are already run, so you can look at real output without waiting:
for a in client.list_atlases():
print(a["title"], a["source_citation"], a["n_samples"])
df = client.get_proportions(a["job_id"], as_dataframe=True)
They are read-only and owned by WittGen; everything else works on them like any job.
Analysing your own data
upload_file() wraps the two-step presigned-S3 handshake — the PUT is signed over its headers,
so hand-rolling it is easy to get wrong:
key = client.upload_file("my_cohort.tsv")
job = client.submit_job("SLE_status_3000", source="user_upload", input_file_key=key)
The matrix must be .txt/.csv/.tsv, under 2 GB, genes × samples, with HGNC symbols in the
gene column. Duplicate symbols — the ordinary result of an Ensembl→HGNC mapping — are collapsed by
summing their counts, the standard resolution for one gene measured across several loci; the
run reports how many rows were collapsed. Pre-aggregate yourself if you want different semantics.
Uploading requires a provisioned plan; self-serve accounts run the bundled reference datasets
(source="reference_dataset").
Know what the model is for
list_models() carries applies_to and not_applicable_to for each model. Read them before
submitting your own matrix or a GEO series:
A deconvolution model given the wrong tissue does not fail. It distributes proportions across the cell types it knows and returns a well-formed table that sums to 1.000. Feed liver to the PBMC model and you get plausible immune fractions for a sample that has none.
get_results_data() returns metadata.gene_coverage with a level of normal / low /
critical against the 78–84% both reference cohorts measure. That catches a gene-identifier or
species mismatch — it cannot tell you the tissue was right, because human liver matches HGNC
symbols just as well as human blood.
Order of operations
wait_for_completion returns as soon as the job is COMPLETED — proportions are ready at that
point. The R analysis stage (gene scores, plots) is triggered server-side and reaches
R_COMPLETE; pass wait_for_analysis=True to block for it, then collect the outputs:
client.wait_for_completion(job_id, wait_for_analysis=True)
for f in client.list_files(job_id, category="r_outputs"):
print(f["name"], f["url"])
The default timeout is 3 hours, which the workload needs: the SLE reference cohort reaches
R_COMPLETE in ~26 minutes, but the 405-sample BRCA cohort takes over two hours because its R
stage runs subcluster differential expression across all 15 cell types. A B2SCTimeout does not
cancel the job — it carries .elapsed and .last_status, and you can keep polling get_job().
Removed in 0.2.0
The AI clinical report (an Opus-written PDF) was removed from the product on 2026-08-04, and with
it generate_report(), wait_for_report() and download_report(). The deliverable is the R stage
output — proportions, gene scores and plots — via get_proportions() and list_files().
Calling a removed method raises B2SCRemovedError, which names the replacement and shows the
equivalent code. It subclasses both B2SCError and AttributeError, so hasattr() feature
detection correctly reports the method as absent while a direct call still explains itself.
The wait_for_report= parameter of wait_for_completion was only renamed, not removed — it
always waited for the R stage. It still works and warns.
Errors raise B2SCError (.status, .code); a poll timeout raises B2SCTimeout. A 409 from
get_proportions means the results are not produced yet — retry.
Data residency: genomic expression data is sensitive. Analysis runs in AWS us-east-1; confirm that placement with WittGen before sending patient-derived data. Note the API does not send your data to any third-party model provider — the AI report that did was removed in 0.2.0.
License
Apache-2.0 — see LICENSE. This client SDK is open source; the WittGen B2SC model and service it talks to remain proprietary. Copyright 2026 WittGen Biotechnologies.
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 wittgen_b2sc-0.3.0.tar.gz.
File metadata
- Download URL: wittgen_b2sc-0.3.0.tar.gz
- Upload date:
- Size: 22.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
246ffbee0eda7f163ae449d301ae5b1323f87bbec06d119acf3b7a98a9e9f968
|
|
| MD5 |
da8a63ad1872658d31221d8fc1b8e093
|
|
| BLAKE2b-256 |
518785300b28696bb63dd2b0b6f943fe7ccac2c4459482891385255fb4b9624c
|
File details
Details for the file wittgen_b2sc-0.3.0-py3-none-any.whl.
File metadata
- Download URL: wittgen_b2sc-0.3.0-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed29995c96cdc02cd43967971370823312b2c0cc53e9dd66bacb40f3bf302158
|
|
| MD5 |
d2831c65e75a0780f663dde31d3a860a
|
|
| BLAKE2b-256 |
e335ffb840499f2a604a645a3578a4aa17c4de047c8746840915e5737b0b4ad6
|