pbzarr
What is this?
pbzarr is a library for storing and analyzing genomic measurements at base-pair resolution. It stores measurements in two-dimensional arrays: one dimension for genomic position, and another for samples or other labels. You can run calculations across either dimension or both.
pbzarr uses Zarr, an existing format for compressed arrays. It adds conventions for genomic coordinates and column labels, plus tools to import and analyze the data.
Motivation
Most bioinformatics files (BAM, BED, bigWig) hold data for one sample. And this makes sense, because most primary bionformatics analyses (i.e alignment) are sample independent. But many downstream analyses need comparisons across samples, over the whole genome or in regions of interest. That means opening each sample's files, reading the relevant data, performing computations, and storing the result.
Often these analyses are exploratory. We run them several times as we decide which samples to include, which regions to look at, or where to set a threshold. With a few regions or a small sample set, this is not that big of a deal. But as cohorts and region sets grow, more work goes into reading the files and bringing the measurements together. During exploratory analysis, we can repeat that work every time we ask a slightly different question, even though the underlying measurements have not changed.
pbzarr builds on the idea that these analyses often need the same two-dimensional array: one dimension for genomic position, and another for samples. pbzarr builds this array for the whole genome once and stores it in compressed chunks using Zarr. Each analysis can then read the regions and samples it needs, without rebuilding the array from individual sample files.
This also has a few useful side effects:
- Xarray lets us attach genomic positions, sample names, and other labels to the dimensions, and organize different measurements together.
- Dask lets us run calculations in parallel, on one machine or across a cluster.
- Zarr supports local and cloud storage. We can read the chunks we need from the cloud without downloading the whole dataset.
Data model
pbzarr uses the dataset model of xarray. In this model, a dataset holds many variables, and the variables share the same coordinates. In pbzarr, the collection is the dataset, each track is one variable, and the coordinates are genomic positions.
A track has at most two dimensions: genomic position and one explicitly labeled column axis. The column axis is homogeneous, so every column shares the track's data type, fill value, and compression settings. It can label samples from several input sources, or label BED columns that a schema groups into one track. Those two axes cannot appear together because that would require a rank-3 track; grouped BED-column imports therefore accept one source only. When values need different data types or settings, each kind goes into its own track. For example, depth, mapping quality, and a mask become three tracks in one collection.
Each track records its own genome. Tracks that record the same genome have the same length and the same base order, so pbzarr can open them together and calculate across them. See format for more details.
Python examples
Import d4 files
import pbzarr
pbzarr.create_store("depth.pbz")
pbzarr.import_d4(
"depth.pbz",
"depth",
[("brain.d4", "brain"), ("liver.d4", "liver")],
column_dim="sample",
)
This creates a depth track with one row per genomic position and one column per sample.
Read a region
depth = pbzarr.open("depth.pbz/depth")
window = depth.pbz.region("chr1:100000-101000")
brain = depth.pbz.region("chr1:100000-101000", column="brain")
values = window.compute()
pbz uses zero-based, half-open coordinates.
Calculate statistics over regions
peaks = [
("chr1", 100000, 100200),
("chr1", 150000, 150300),
("chr2", 200000, 200150),
]
peak_means = depth.pbz.reduce_regions(peaks, "mean")
result = peak_means.compute()
The result has one mean for each peak and sample. Other reductions include sum, min, max, count, std, var, median, and quantile.
Dask keeps reads and calculations lazy until compute(). The computed result must still fit in memory.
Open a collection
Opening a track returns an xarray.Dataset. Opening a collection returns an xarray.DataTree whose children are tracks.
study = pbzarr.open("study.pbz")
depth = study["depth"].to_dataset()
mask = study["mask"].to_dataset()
Each track records its own genome. Tracks with matching genomes can be used together.
Import other files
pbzarr.create_store("signals.pbz")
pbzarr.import_bigwig("signals.pbz", "signal", "sample.bw")
pbzarr.create_store("scores.pbz")
pbzarr.import_bed(
"scores.pbz",
"sites.bed.gz",
genome="genome.fai",
track="score",
column="score",
dtype="float32",
)
BED imports need a .fai or chromosome-sizes file because BED does not record chromosome lengths.
CLI examples
Import a bigWig file into a signal track:
pbz import bigwig -o signal.pbz --track signal sample.bw
The import reads chromosome lengths from the bigWig header and stores values as float32. Uncovered bases contain NaN.
Import several files as labeled columns:
pbz import bigwig -o cohort.pbz --track signal -c sample brain.bw:brain liver.bw:liver
All sources must describe the same genome. Without explicit labels, the import uses each file's stem as its column label.
The command accepts the same import options as pbz import d4. These include --file-list, --threads, chunk and shard sizes, --codecs, --scales, and --no-progress.
Preview the tracks and storage layout without writing a store:
pbz import bigwig -o cohort.pbz --track signal --file-list sources.tsv --dry-run
The source list contains one path per line, optionally followed by a tab and a label. If any source has a label, all sources must have labels.
Format
A .pbz collection is a Zarr v3 directory. Each child directory is a track.
study.pbz/
├── zarr.json
├── depth/
│ ├── zarr.json
│ ├── values
│ ├── offsets
│ ├── contigs
│ └── sample
└── mask/
├── zarr.json
├── values
├── offsets
└── contigs
Each track group holds a fixed set of arrays:
values: the data, with contigs concatenated along the position axis in genome order. The shape is(L,)for a track without columns or(L, n_columns)with them, whereLis the total length of the track's genome.contigs: the contig names, in the same order.offsets: an int64 index with one entry more thancontigs.offsets[i]is the first row of contigi, sooffsets[i+1] - offsets[i]is its length and the last entry equalsL.- a column-label array, named after the column dimension (
sampleabove). Present only when the track has columns.
Every track declares one data type and one fill value, and positions with no data hold the fill value. The values array is chunked and compressed with Blosc (zstd with byte shuffle) by default; imports can override the codec pipeline and chunk grid with standard Zarr v3 metadata (--codecs on the CLI, codecs= in Python). For a track with columns, chunks extend across columns as well as positions, so values from different samples compress together.
Region reads are index arithmetic. The rows for chr2:10-20 are offsets[i] + 10 up to offsets[i] + 20, where i is the index of chr2 in contigs. All coordinates are zero-based and half-open.
A track's genome is the list of (contig name, length) pairs defined by contigs and offsets. There is no genome at the collection level: each track carries its own, and two tracks in one collection can cover different genomes. Each track also stores a genome checksum, the MD5 of its contig names and lengths sorted by name. Two tracks record the same genome exactly when their checksums are equal, and pbzarr applies this test whenever it aligns or combines tracks. A track can also store a genome name such as hg38, but the name is a human-readable label and has no part in the checksum.
A track's zarr.json holds this metadata: the format version, the genome checksum and name, the coordinate convention, and the names of the index arrays. pbzarr writes the metadata block last during an import, so the block also marks the track as complete. A track group without it is incomplete, and opening a collection skips it.
See the design document for the full file rules and Rust API.
Status
pbzarr is under active development and has not reached version 1.0. The API and file rules can change. Remote writes and variable chunk sizes are planned.
Links
- Rust API
- Design
- d4
- Motivating issues: mask generation, cross-sample compression, and per-base sample statistics
Development note
The per-base Zarr format that pbzarr standardizes was first prototyped by hand in clam, where the initial concepts (the contig-major layout, cohort-shaped tracks, and the zarr/ndarray I/O path) were fleshed out before AI tooling was introduced. pbzarr lifts those concepts into a dedicated, spec-driven library.
From that point, development of pbzarr was heavily assisted by Claude (Anthropic), accelerating the library implementation, d4 import, tests, and documentation. The architecture, domain knowledge, and direction remain the author's own; Claude was used as an accelerant, not an author.
Metadata
Release files for pbzarr 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pbzarr-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ x86-64 | Details for pbzarr-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl |
| pbzarr-0.7.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64 | Details for pbzarr-0.7.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
Total release size: 13.6 MB
Release files / pbzarr-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl
| Download URL | pbzarr-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 5.0 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
1dd57e1a32fac5d3f89e8b801e22d0689520173d0730e21d75bac17e9f3218d1
|
|
BLAKE2b-256 checksum How to use checksums |
1cf48b3fa489d1c663c2dfc61e8fdf00c78ccfc73c4d163d60ff1f551b3e3c22
|
| 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 Oct 22, 2026.
Transparency logRelease files / pbzarr-0.7.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
| Download URL | pbzarr-0.7.0-cp311-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
|---|---|
| Size | 8.6 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
9e5fb52058f13d5a9674b474da1fe6137831ab061785312914c6bc2aa099dff8
|
|
BLAKE2b-256 checksum How to use checksums |
c0a44cde633baea35ae9851434098a87f72361cbb37f5abdbaf9374fa148097b
|
| 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 Oct 22, 2026.
Transparency logSecurity for pbzarr 0.7.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 2 files in this release have been uploaded with provenance metadata.
Attestation for pbzarr-0.7.0-cp311-abi3-manylinux_2_28_x86_64.whl
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 Oct 22, 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.