Convert a multi-sample VCF of single cells into an AnnData h5ad.
Install with pip, mamba, conda, or run directly with pixi:
pixi exec \
--channel conda-forge \
--channel bioconda \
annatar --help
Introduction
The tool annatar reads a multi-sample VCF or BCF, with cells as samples, and writes one h5ad with cells by variants.
Each ALT allele becomes a variant, and numeric FORMAT fields become sparse layers.
VEP annotation is optional. When the VCF has INFO/CSQ, one consequence per variant becomes typed columns in var.
The h5ad can sit next to other single-cell modalities in a MuData keyed on cell barcode.
Quick Start
Convert a VCF of cells:
annatar 'cells.vcf.gz' 'cells.h5ad'
For a VEP-annotated VCF, prioritize effects in a gene set and leave out CSQ subfields:
annatar \
--genes 'panel-genes.txt' \
--exclude-field 'INFO/CSQ/Existing_variation' \
--exclude-field 'INFO/CSQ/SOMATIC' \
'cells.vep.vcf.gz' \
'cells.h5ad'
Excluding INFO/CSQ drops all VEP annotation.
Merging Libraries
Merge the h5ad files of several libraries into one:
annatar merge --output 'merged.h5ad' 'a.h5ad' 'b.h5ad'
Cells become barcode-library, named after each file, and obs['library'] holds the library's name.
Variants are the union of the libraries, sorted by VCF header contig order, then start, end, ref and alt.
The columns n_cells_covered, n_cells_alt, ref_reads and alt_reads are recounted from the merged layers.
Any other var value on a shared variant, such as qual or an INFO field, comes from the first library holding it, and later libraries fill only the columns that library lacks entirely.
A column that is text in one library and numeric in another stays text.
The X matrix and the layers keep every stored value, since neither stores a zero.
Python
Convert a VCF into an in-memory AnnData:
import annatar
adata = annatar.read_vcf('cells.vcf.gz')
Merge libraries into an in-memory AnnData:
merged = annatar.concat(['a.h5ad', 'b.h5ad'])
Output
| Slot | Contents |
|---|---|
X |
Copies of each ALT in each cell's called genotype, capped at its read count |
layers |
Called copies as GT, and numeric FORMAT fields, such as AD_ref, AD_alt and DP |
obs |
Per-cell counts, n_sites_covered and n_sites_alt |
var |
One row per ALT allele, named chrom:pos:ref:alt |
uns |
Provenance and the encoding of X |
Genotypes
The X matrix holds the number of copies of the ALT in the called genotype, capped at that ALT's read count, so 0/1 is 1, and 1/1 is 2 with two or more alt reads and 1 with one.
Hom-ref and uncalled cells are not stored, and neither is a call with no alt reads, where a missing alt count (.) is zero.
So X > 0 means a called carrier with alt reads, and X.sum() never exceeds the alt reads.
A haploid ALT call is 1, so X == 2 does not find it.
Beside it, layers['GT'] holds the copies as the VCF called them.
The other layers are read counts, with zeros and missing values not stored.
At a variant a cell is a carrier (X > 0, or AD_alt > 0 for reads), reference (AD_ref > 0 with no X or AD_alt), or has no data.
A cell with reads but no call keeps them in the layers, and AD_alt counts alt reads in cells called 0/0.
Variants
The start and end columns are 0-based and half-open, as in BED, while a variant's chrom:pos:ref:alt name keeps the VCF's 1-based position.
Every ALT gets its own row, whether it is an SNV, indel, MNV, symbolic ALT or breakend.
The placeholder alleles *, <*> and <NON_REF> get no row.
The VCF must declare FORMAT/AD.
VEP Annotation
VEP is optional.
When the VCF has INFO/CSQ, one consequence per variant is added to var with its VEP subfield names, along with these columns:
| Column | Meaning |
|---|---|
consequence_rank |
Severity of the consequence, where lower is more severe |
is_coding |
The consequence is coding |
is_lof |
The consequence is loss of function |
pick_tier |
mane_select, mane_plus_clinical, canonical or other |
worst_panel_impact |
Highest IMPACT among the --genes panel genes |
Column types are fixed for VEP 116, so a column has the same type in every file. Other VEP versions run with a warning.
MuData Example
Color the cells that carry a pathogenic TP53 variant on a chromatin UMAP, with a VCF and a chromatin h5ad in docs/example/ that share cell barcodes.
Both files are simulated, because this project has no real dataset yet that links chromatin to mutations by cell barcode, so read the figure as a demonstration and not a result.
From a clone of this repository, convert the VCF:
annatar 'docs/example/cells.vcf.gz' 'cells.h5ad'
A MuData object lines the modalities up by cell barcode, and cells with no reads at these variants stay gray:
import anndata as ad
import mudata as md
import muon
import numpy as np
mu = md.MuData({'atac': ad.read_h5ad('docs/example/cells.atac.h5ad'), 'variants': ad.read_h5ad('cells.h5ad')})
variants = mu['variants']
pathogenic = {'Pathogenic', 'Likely_pathogenic', 'Pathogenic/Likely_pathogenic'}
hits = (variants.var['SYMBOL'] == 'TP53') & variants.var['ClinVar_CLNSIG'].isin(pathogenic)
alt = np.asarray(variants[:, hits].layers['AD_alt'].sum(axis=1)).ravel()
ref = np.asarray(variants[:, hits].layers['AD_ref'].sum(axis=1)).ravel()
variants.obs['TP53'] = np.select([alt > 0, ref > 0], ['carrier', 'reference only'], default=None)
mu.pull_obs()
colors = {
'T cell': '#2a78d6', 'Monocyte': '#1baf7a', 'Tumor': '#e34948', 'B cell': '#104281', 'NK cell': '#eda100',
'carrier': '#e34948', 'reference only': '#b5b1ab',
}
muon.pl.embedding(
mu,
basis='atac:X_umap',
color=['atac:cell_type', 'variants:TP53'],
title=['Cell Type (Simulated Data)', 'TP53 State (Simulated Data)'],
palette=colors,
na_color='#e9e7e2',
size=18,
edgecolor='white',
linewidth=0.35,
frameon=False,
)
Development and Testing
See the contributing guide for more information.
Metadata
Release files for annatar 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| annatar-0.1.0.tar.gz | 112.5 kB | With provenance | Details for annatar-0.1.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| annatar-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64 | Details for annatar-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl |
| annatar-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ x86-64 | Details for annatar-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
| annatar-0.1.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details for annatar-0.1.0-cp311-abi3-macosx_11_0_arm64.whl |
| annatar-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details for annatar-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl |
Total release size: 7.1 MB
Release files / annatar-0.1.0.tar.gz
| Download URL | annatar-0.1.0.tar.gz |
|---|---|
| Size | 112.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a7f54e312035a2b4c37433c0e638f7ae69b36e6fbd927c78e9e4c23eb54b1a4d
|
|
BLAKE2b-256 checksum How to use checksums |
27b58c271b78acbb8970ca0b23d08996bbfbde40d8a0f3f3d3b5fa4effcc04a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / annatar-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl
| Download URL | annatar-0.1.0-cp311-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
10da56191a2225f1a592d5b69ce06f55530010e5b07e61da3b43345d9dc03bc2
|
|
BLAKE2b-256 checksum How to use checksums |
65f75db49097a8354b0c456afd73438edec7a809adb237f7d11c1e487a7aea32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / annatar-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | annatar-0.1.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6d63e58b7624c507953600455b14823e33a4032b22503a34662fd1af3726feee
|
|
BLAKE2b-256 checksum How to use checksums |
136998efe84e223809e9aad1d45a1d8fadba1293145690904da3f1b3fcf60eec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / annatar-0.1.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | annatar-0.1.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
cb6fac6132254d1d0db62ba2617ab0a8d12a03eb3dc6c0e4ea95a9f536e59e91
|
|
BLAKE2b-256 checksum How to use checksums |
c88b25e8414245f4a0efbd92a1acd77efd0d233fe47f8a4072f1e05e7215bb38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logRelease files / annatar-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | annatar-0.1.0-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
78825b2e382466f4c4cd230599941033dce1d60d77ea5c368731e7c058fb442d
|
|
BLAKE2b-256 checksum How to use checksums |
ae5512860dfa11cbe8923dbc469b0e03f4844f34cb9c3d4efbf8c6acbcb445d8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logSecurity for annatar 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 5 files in this release have been uploaded with provenance metadata.
Attestation for annatar-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 5, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.