Use the Python client with Scanpy/AnnData objects.
Preprocessing your data
CyteType requires differential expression results computed per cluster before submission.
import scanpy as sc
# Assumes adata already has normalized counts in adata.X
# and cluster labels in adata.obs["leiden"]
sc.tl.rank_genes_groups(
adata,
groupby="leiden",
method="wilcoxon",
key_added="rank_genes_leiden",
n_genes=100,
)
# If gene symbols are stored separately from var_names:
# adata.var["gene_symbols"] = adata.var_names # or set during load
Initializing the annotator
The initialization step validates your data and precomputes expression percentages. This can take a few minutes on large datasets but only needs to run once per object.
from cytetype import CyteType
annotator = CyteType(
adata,
group_key="leiden", # column in adata.obs with cluster labels
rank_key="rank_genes_leiden", # key in adata.uns with DE results
gene_symbols_column="gene_symbols", # column in adata.var with gene symbols
n_top_genes=50, # top marker genes per cluster
aggregate_metadata=True, # include obs metadata in context
min_percentage=10, # min % threshold for metadata
coordinates_key="X_umap", # key in adata.obsm for UMAP coordinates
max_cells_per_group=1000, # cells sampled per cluster for visualization
auth_token=None, # Bearer token (if your deployment requires one)
)
Running annotation
The study_context is the most important parameter for annotation quality. Describe your tissue, organism, disease state, and experimental setup in one or two sentences.
adata = annotator.run(
study_context="Human colorectal cancer biopsy, tumor microenvironment, 10X Genomics 5' scRNA-seq, treatment-naive patients",
metadata={
"Study": "My TME atlas",
"GEO": "https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GSE123456",
"DOI": "https://doi.org/10.1038/example"
},
n_parallel_clusters=4, # increase for faster annotation (watch rate limits)
results_prefix="cytetype", # prefix for result columns
timeout_seconds=7200,
show_progress=True,
)
Accessing results
After a successful run, annotations are stored in your object and can be accessed immediately.
# Annotation columns added to adata.obs:
# cytetype_annotation_leiden — cell type label
# cytetype_cellOntologyTerm_leiden — Cell Ontology term name
# cytetype_cellOntologyTermID_leiden — CL:xxxxxxx ID
# cytetype_cellState_leiden — functional state
import json
results = json.loads(adata.uns["cytetype_results"]["result"])
for ann in results["annotations"]:
print(ann["clusterId"], ann["annotation"], ann["ontologyTermID"])
# If you need to re-fetch results after disconnecting:
results = annotator.get_results()
💡 Tip: Jobs continue running on the server even after your local session disconnects. Use annotator.get_results() to retrieve results after reconnecting.
Custom LLM configuration
By default CyteType uses its own hosted model. You can bring your own LLM from any supported provider.
# Single LLM configuration
adata = annotator.run(
study_context="...",
llm_configs=[{
"provider": "openai",
"name": "gpt-4o",
"apiKey": "sk-...",
"baseUrl": "https://api.openai.com/v1", # optional
"modelSettings": {"temperature": 0.0, "max_tokens": 4096}
}]
)
# Multiple providers (different agents can use different models)
adata = annotator.run(
study_context="...",
llm_configs=[
{
"provider": "anthropic",
"name": "claude-3-5-sonnet-20241022",
"apiKey": "sk-ant-...",
"targetAgents": ["annotator", "reviewer"]
},
{
"provider": "openai",
"name": "gpt-4o-mini",
"apiKey": "sk-...",
"targetAgents": ["summarizer", "clinician"]
}
]
)
# AWS Bedrock
adata = annotator.run(
study_context="...",
llm_configs=[{
"provider": "bedrock",
"name": "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
"awsAccessKeyId": "AKIA...",
"awsSecretAccessKey": "...",
"awsDefaultRegion": "us-east-1"
}]
)
Supported providers: anthropic, bedrock, fireworks, google, groq, huggingface, mistral, openai, openrouter, vertex, xai.
Authentication
For deployments that require a bearer token (private or enterprise instances):
# Pass at initialization (applies to all run() calls)
annotator = CyteType(adata, group_key="leiden", auth_token="your-token")
# Or override at run time
adata = annotator.run(study_context="...", auth_token="your-token")
Learn more