API reference#
The complete public Python API. See Reading VCZ for a worked, example-driven introduction to opening datasets and iterating variants, and Format conversion for the VCF, PLINK and BGEN writers.
Quickfind#
Querying VCZ data#
|
Open a Zarr store with configurable backends. |
|
Central reader for VCZ (Zarr-based VCF) files. |
|
Bcftools |
Detecting missing and fill sentinels#
|
Return a boolean array indicating which values are missing sentinels. |
|
Return a boolean array indicating which values are end-of-vector (fill) sentinels. |
|
Drop trailing fill from a 1-D array. |
Converting to VCF, PLINK and BGEN#
|
Write the VCF text for |
|
Write PLINK 1 binary fileset for |
|
Write an Oxford BGEN payload for |
Complete reference#
- vcztools.open_zarr(file_or_url: str | Path, /, *, mode: str = 'r', zarr_format: int | None = None, backend_storage: str | None = None, storage_options: dict | None = None)#
Open a Zarr store with configurable backends.
An already-built
zarr.Grouporzarr.abc.store.Storeis passed through (wrapped inzarr.open()for the latter).Otherwise resolution depends on
backend_storage:None(default — local-only):.zippath →zarr.storage.ZipStore; local path →zarr.storage.LocalStore. URLs (str with://) and non-emptystorage_optionsraise."fsspec": explicitzarr.storage.FsspecStorevia itsfrom_urlclassmethod. Local paths becomefile://URIs.storage_optionsis forwarded to fsspec."obstore":zarr.storage.ObjectStoreoverobstore.store.from_url.storage_optionsis unpacked as kwargs tofrom_url(e.g.client_options,retry_config)."icechunk": an Icechunk storage built bymake_icechunk_storage.storage_optionsis forwarded to the chosen storage constructor (S3 / Azure); for local Icechunk paths non-empty options raise.
- class vcztools.VczReader(root, *, readahead_workers: int | None = None, readahead_bytes: int | None = None)#
Central reader for VCZ (Zarr-based VCF) files.
Owns the zarr root and provides metadata properties and variant iteration at both chunk and row granularity, via
variant_chunks()andvariants().The reader starts with no configured selection — every real sample and every variant is iterated by default. Call
set_samples()to restrict the sample selection before iterating.Use as a context manager (
with VczReader(root) as reader:) so the reader’s resources are released deterministically on exit.Virtual fields#
Besides stored arrays, these computed variant-axis fields may be named in
variant_chunks()fieldsor in a filter expression. Availability depends on the store; seevirtual_field_names. They are addressable by name but never auto-emitted whenfieldsisNone.variant_indexGlobal (store-wide) 0-based index of the variant.
variant_ACAllele count in genotypes.
variant_ANTotal number of alleles in called genotypes.
variant_AFAllele frequency.
variant_NSNumber of samples with data.
variant_N_ALTNumber of non-empty ALT alleles.
variant_N_MISSINGNumber of samples with all-missing genotypes.
variant_F_MISSINGFraction of samples with all-missing genotypes.
Parameters#
- root
An already-opened
zarr.Grouppointing at the VCZ dataset. Usevcztools.open_zarr()to open a path (local, remote, or zip) with the desired backend before constructing the reader.- readahead_workers
Worker count for the readahead thread pool.
None(default) uses32. The pool is created at construction; this parameter has no post-init knob.- readahead_bytes
Cap, in bytes, on the cross-chunk readahead window.
None(default) uses 256 MiB.0pins pipeline depth at 1 (one chunk prefetched ahead of the consumer); the pipeline cannot go lower.
- property sample_ids#
Selected sample IDs as a numpy array, in selection order.
- set_samples(sample_ids, *, complement=False, ignore_missing_samples=False) None#
Configure the sample selection by sample ID.
sample_idsis a sequence of sample names, in the order the caller wants them in the output. An empty sequence is valid and means “no samples in output”. Withcomplement=Truethe selection is every non-null sample except those named, in header order.Unknown names raise
ValueErrorunlessignore_missing_samples=True, in which case they are dropped with a warning. Duplicate names raise (non-complement) or are deduped (complement). Null (sample_id == "") samples are never selectable: the empty string is the reserved null-sample ID and requesting it raisesValueError. Not callingset_samples()(orset_sample_indexes()) selects every non-null sample.Must be called before iterating; raises
RuntimeErrorif the selection is already configured. Selecting a proper subset makes sample-dependent virtual fields (AC/AN/AF/NS…) recompute to reflect the subset on the next iteration. Seevariant_chunks().
- set_sample_indexes(sample_indexes) None#
Configure the sample selection by raw integer index.
The lower-level counterpart of
set_samples(): accepts a list or ndarray of integer indexes into the VCZsample_idarray, in the order the caller wants. An empty sequence is valid and means “no samples in output”. Out-of-range indexes raiseValueError, as does any index referring to a null sample (sample_id == ""). Duplicates are permitted. Must be called before iterating; raisesRuntimeErrorif the selection is already configured.
- set_variants(variants) None#
Configure the variant selection.
Accepts a sorted 1-D array of global variant indexes, which is bucketed into a chunk plan internally. A pre-built chunk plan (a
listofChunkRead) may also be passed for callers that already have one, e.g. from a region/target query.May be called multiple times; each call replaces the prior selection. A
variant_chunks()generator already iterating is unaffected — it snapshots the plan at start.
- set_variant_filter(variant_filter: VariantFilter | None) None#
Configure (or clear) the variant filter.
variant_filteris any object implementing theVariantFilterprotocol (e.g. aBcftoolsFilter), orNoneto clear a previously-set filter. By default a sample-scope filter evaluates over the user’s sample selection (bcftools queryFMT-scope post-subset semantics).May be called multiple times; each call replaces the prior filter. A
variant_chunks()generator already iterating is unaffected — it snapshots the filter at start.
- materialise_variant_filter() None#
Resolve the configured variant filter into a fixed selection.
Iterates
variant_chunks()collecting the global indexes of surviving variants, then replaces(variant_filter, variant_chunk_plan)with a chunk plan over those variants. No-op if no filter is configured.Only variant-scope filters are supported. Sample-scope filters require the per-cell mask emitted during iteration; resolve them by iterating
variant_chunks()directly. RaisesValueErroron a sample-scope filter.
- property contig_ids#
Contig IDs as a numpy StringDType array.
- property num_samples: int#
Total samples in the store (raw axis length, before any sample selection or null-sample filtering).
- property raw_sample_ids: ndarray#
Full
sample_idarray from the store, including any null-string entries. For the post-subset order used when encoding rows, seesample_ids.
- property field_names: frozenset[str]#
Set of real (Zarr-backed) field names present in the store.
Virtual fields (e.g.
variant_ACon a store without a storedvariant_ACarray) are not included here even thoughvariant_chunks()can yield them — they are addressable by name but not auto-discovered by the default-emit path. Seevirtual_field_namesfor the available virtual set.
- property virtual_field_names: frozenset[str]#
Names of virtual fields whose dependencies are satisfied by the current store.
A name appears here when every dependency of its registry entry is present in the store; genotype-derived fields such as
variant_N_MISSINGare therefore absent on annotations-only stores that lackcall_genotype. These names can be requested in thefieldsargument ofvariant_chunks().
- get_field_info(name: str) FieldInfo#
Return a
FieldInfosnapshot for the named field. Reads Zarr metadata on first access, then memoizes per-field. RaisesKeyErrorif the field is absent.For a stored field, returns the real on-disk metadata. For a virtual field with no stored counterpart, synthesises
FieldInfofrom the registry entry. For a virtual field that also exists as a stored array, the stored array wins (itsattrs.descriptionis preserved); the registry only substitutes its description if the stored array has none.
- variant_chunks(*, fields: list[str] | None = None, start: int = 0, force_recompute=False)#
Yield
dict[str, np.ndarray]per variant chunk that passes the current sample and variant selection.fieldsnames the fields to read;None(default) emits every stored field. A field’s value spans the variants axis (and, for FORMAT fields, the selected samples axis).startis an offset into the sequence of variant chunks: iteration begins at thestart-th chunk.start=0(default) iterates every chunk; astartpast the last chunk yields nothing; negativestartraisesValueError.force_recomputecontrols recomputation of virtual fields (seevirtual_field_names) that have a same-named stored array.Truerecomputes every requested virtual field; an iterable scopes it to the named fields;False(default) forces none. A virtual field with no stored counterpart is always computed. When a sample subset is active, a sample-dependent virtual field (AC,AN,AF,NS,N_MISSING,F_MISSING) is recomputed to reflect the subset even withforce_recompute=False, so a filter on the field and its emitted value always agree.The returned iterator overlaps the consumer’s per-chunk work with the assembly of the next chunk;
close()it promptly to release the in-flight chunk. Argument validation is eager:start < 0andfields == []are reported on the call itself rather than on the firstnext().Virtual fields (see
virtual_field_names) may be named infieldsalongside stored arrays."variant_index"is one: its per-chunk array holds the global (store-wide)int64index of each surviving variant. Virtual fields are not auto-emitted whenfieldsisNone.
- variants(*, fields: list[str] | None = None, force_recompute=False)#
Yield dict[str, scalar/1d-array] per variant row.
force_recomputeis forwarded tovariant_chunks().
- class vcztools.FieldInfo(name: str, dtype: dtype, shape: tuple[int, ...], dims: tuple[str, ...], attrs: dict)#
Schema snapshot for a single store field.
Materialized once per field via
VczReader.get_field_info()and cached on the reader. External callers (VCF header generation, etc.) should never reach into the Zarr store for metadata themselves — go through this dataclass instead.
- vcztools.is_missing(arr: ndarray) ndarray#
Return a boolean array indicating which values are missing sentinels.
- vcztools.is_fill(arr: ndarray) ndarray#
Return a boolean array indicating which values are end-of-vector (fill) sentinels. Flag (boolean) fields have no fill, so the mask is all-False for them.
- vcztools.trim_fill(arr: ndarray) ndarray#
Drop trailing fill from a 1-D array.
Returns a view up to and including the last non-fill element, or an empty slice if every element is fill. Only trailing fill is trimmed; interior fill (a malformed vector) is left in place.
- class vcztools.VariantFilter(*args, **kwargs)#
Variant-filter interface consumed by
vcztools.VczReader.Implementations need not inherit from this Protocol — any object that provides the three members below will satisfy it. The reader uses
referenced_fieldsto decide which VCZ arrays to fetch andscopeto decide how to combine the mask returned byevaluate()with the per-variant region/target mask.A
"variant"-scope filter MUST return a 1-D bool array of lengthn_variants. A"sample"-scope filter MUST return a 2-D bool array of shape(n_variants, n_samples). By default the filter sees the user’s sample selection (bcftools querysemantics).
- class vcztools.BcftoolsFilter(reader, *, include=None, exclude=None)#
Bcftools
-i/-eexpression compiled into aVariantFilter.Accepts the same expression syntax as
bcftools view -i/-e. Mutually exclusive: only one ofincludeorexcludemay be non-None. When neither is set the filter is a no-op; callers should skip the filter in that case rather than evaluate it.The first argument is the target
VczReader. Itsfield_namesandvirtual_field_namesform the resolution surface the parser uses to map bare VCF names likeDPto their VCZ equivalents (call_DPvsvariant_DP). Both expression parsing and field-name resolution happen at instantiation time.
- vcztools.write_vcf(reader, output, *, header_only: bool = False, no_header: bool = False, no_version: bool = False, encode_threads: int | None = None, fill_tags: frozenset | None = None) None#
Write the VCF text for
readertooutput.outputis either a filesystem path (str/pathlib.Path) or a writable text file-like object (anything with a.writemethod, includingsys.stdout); paths are opened in text mode. VCF output is plain, uncompressed text.Unlike
write_plink()andwrite_bgen(), a configured variant filter on the reader does not need to be resolved first: records are streamed and filtered on the fly, so both a configured variant filter and a sample subset are honoured as-is.header_only=Truewrites only the VCF header (the##meta lines and the#CHROMcolumn line) and no variant records.no_header=Truesuppresses the header entirely, emitting only the variant records.no_version=Trueomits the vcztools version and command line from the header.For bcftools
view -Gsemantics — omitting theFORMATfield and every sample column from both the header and the records — clear the reader’s sample selection first withreader.set_samples([]).encode_threadssizes the worker pool that encodes each chunk’s records;None(default) selects the default (4). Encoded blocks are written in record order so the output is deterministic.fill_tagsis a set of VCF INFO tag names (e.g.{"AC", "AN"}) to emit as recomputed values, overriding any stored counterpart and injecting the corresponding INFO header lines. A tag with no corresponding virtual field available for the store raisesValueError.
- vcztools.write_plink(reader, output, *, bim: bool = True, fam: bool = True)#
Write PLINK 1 binary fileset for
readerunder stemoutput.outputis a filesystem stem (strorpathlib.Path) taken verbatim —"foo"producesfoo.bedplus, by default,foo.bimandfoo.fam. The.bedpayload is always written;bimandfamtoggle the matching sidecars.The reader’s variant filter, if any, must already be resolved into a fixed selection via
materialise_variant_filter(); a still-configured filter raisesNotImplementedError. This keeps BIM rows and BED rows aligned. Sample-scope filters are not supported in PLINK 1 binary output: the.bedformat is fixed-width per variant, so per-sample filtering doesn’t translate.
- vcztools.write_bgen(reader, output, *, sample_path=None, bgi_path=None, embed_header_samples: bool | None = None, compression_level: int | None = None, encode_threads: int | None = None, unphased: bool = False, variant_id_field: str | None = None, fixed_variant_size: bool = False, total_string_length: int | None = None, pad_byte: bytes | None = None)#
Write an Oxford BGEN payload for
readertooutput.outputis either a filesystem path (str/pathlib.Path) or a writable binary file-like object (anything with a.writemethod, includingsys.stdout.buffer); paths are opened viavcztools.utils.open_file_like()in"wb"mode. The function never seeks the output.sample_pathandbgi_pathrequest the optional Oxford.sampletext sidecar and the bgenix.bgen.bgiSQLite sidecar at the given filesystem paths;None(default) skips that sidecar. The.sampleis written first; the.bgiis written last using the variant-block byte offsets accumulated while streaming the BGEN payload.The reader’s variant filter, if any, must already be resolved into a fixed selection via
materialise_variant_filter(); a still-configured filter raisesNotImplementedError. This keeps variant-block ordering and.bgientries aligned with the BGEN payload.Variant scope: biallelic only (multi-allelic raises
ValueError). Genotype source: hard calls fromcall_genotypeencoded as 1.0 probability on the called genotype (8-bit precision round-trips exactly). Phase: per-variant fromcall_genotype_phasedif the field exists in the store; otherwise unphased.embed_header_samplescontrols whether the BGEN header carries sample IDs. When False, theSAMPLE_IDS_PRESENTflag is cleared and the sample-id block is omitted. Most downstream tools require sample IDs from either the BGEN header or a.samplesidecar; if neither is produced the function logs a warning.compression_levelis forwarded tozlib.compress()for each variant’s genotype probability block; accepts-1..9(-1= zlib default ≈ level 6;0= stored, still framed as zlib;9= maximum). The default is1— fast compression — on the variable-size path, and0(the only valid value) on thefixed_variant_size=Truepath. Hard-call BGEN payloads are short, low-entropy byte runs (mostly 1.0/0.0 in 8-bit form, repeated across samples), so the marginal compression above level 1 is small relative to the CPU cost: level 6 (zlib default) typically shrinks the file by ~10-30% but spends several times more CPU. Since the BGEN flag word always advertisesCOMPRESSION_ZLIBregardless of level, every reader handles the output.encode_threadssizes the worker pool that runs per-slice_prepare_chunk()+ per-variant_encode_variant_blockfor each chunk. Slice bytes are written back to the output in variant order on the main thread so byte layout and.bgioffsets stay deterministic.Noneselects the default (4).unphased=Trueforces every variant’s phased flag to0, ignoringcall_genotype_phasedif present. Use this when the downstream tool only accepts unphased BGEN (e.g. qctool’s-snp-stats, whoseToGPsetter rejects per-haplotype-per- allele probabilities).variant_id_fieldchooses which BGEN slot —"rsid"(default) or"varid"— carries the zarrvariant_id. The other slot is the padding field; on the variable-size path it is written as the literal"."for every variant, on the fixed-size path it isb"." + pad_byte * (slack - 1)per variant.fixed_variant_size=Trueswitches output to the random-access fixed-stride encoding produced byBgenEncoder— every variant block is exactly28 + total_string_length + zlib_stored_size(geno_size)bytes wide. The path requires uniform ploidy across the store (all haploid or all diploid); mixed-ploidy stores must leavefixed_variant_size=False. Requirescompression_levelto beNone(default) or0— any other value raisesValueError.total_string_lengthoverridesBgenEncoder’s default combined byte budget (64) for the five BGEN string slots whenfixed_variant_size=True. Only valid alongsidefixed_variant_size=True.pad_byteoverridesBgenEncoder’s default padding byte (b".") used to fill the padding slot beyond its leadingb".". Only valid alongsidefixed_variant_size=True.
- class vcztools.FormatEncoder(reader: VczReader, *, bytes_per_variant: int, prefix_bytes: bytes, iterator_fields: list[str], encode_threads: int | None = None, encode_block_bytes: int | None = None)#
Fixed-size, random-access byte-stream encoder over a VCZ store.
Abstract base of
BedEncoderandBgenEncoder; not instantiated directly. Provides the shared streaming API — POSIX-styleread(), bulkwrite_to(), and the size properties — while each subclass supplies the format-specific encoding of a single variant chunk.Construction is I/O-free; bytes are produced lazily as they are read. A single encoder is not thread-safe, but multiple encoders may share one
VczReader, each running an independent variant-chunk iteration. Use as a context manager (with BedEncoder(reader) as enc:) so the encoder’s iterator and thread pool are torn down on exit;close()does the same and does not close the underlying reader.- close() None#
Tear down the active chunk iterator, shut down the encode thread pool, and drop iterator state. Does not close the underlying reader. Idempotent.
- read(off: int, size: int) bytes#
Return up to
sizebytes from the virtual stream atoff.POSIX-read semantics:
b""ifoff >= total_sizeorsize == 0sizeclamped to the end of the streamoff < 0orsize < 0raisesValueError
Reads whose start falls in the loaded chunk or the immediately- next plan chunk are served by slicing chunk-resident bytes, advancing the running iterator one chunk at a time as needed. Reads whose start is further away rebuild the iterator at the chunk containing
off.
- try_cached_read(off: int, size: int) bytes | None#
Return
self[off : off + size]iff it can be served from in-memory state (prefix bytes and/or the currently-loaded chunk) without advancing the variant iterator. ReturnNoneotherwise.Safe to call without external synchronisation: the return is either the correct bytes or
None. The method takes one atomic snapshot of the published chunk state, so a concurrentread()advancing the iterator on another thread either completes before the snapshot (reader sees the new chunk) or after (reader sees the old chunk); the reader never sees a half-updated state mixing one chunk’s bytes with another chunk’s start offset.POSIX-read semantics matching
read()for arg validation and EOF: returnsb""ifoff >= total_sizeorsize == 0;sizeis clamped to the end of the stream; negativeofforsizeraisesValueError; closed encoder raisesRuntimeError.
- write_to(out, off: int | None = None, size: int | None = None) int#
Stream
selftoout(a writable file-like with awrite(bytes)method) and return the number of bytes written.Defaults to writing the entire encoded stream. Pass
offand/orsizeto limit to a sub-range:off=None→ starts at byte 0.size=None→ writes throughtotal_size.
Validation and EOF semantics match
read():offandsizemust be non-negative;sizeis clamped to the end of the stream; reads past EOF write nothing. The stream is read and written in fixed-size blocks.
- class vcztools.BedEncoder(reader: VczReader, *, encode_threads: int | None = None, encode_block_bytes: int | None = None)#
Bases:
FormatEncoderPLINK 1
.bedbyte-stream encoder over a VCZ store.Thin
FormatEncodersubclass: the base class supplies the chunk-resident state machine, POSIX-styleread(), iterator restart/advance arbitration, thread-pool lifecycle, and prefix (magic) serving.BedEncoderplugs in PLINK 1’s 3-byte magic prefix and the C-kernel encode of one variant chunk.Scope is the
.bedstream only. For the companion.bimand.famfiles, usewrite_bim()andwrite_fam()directly.Honours
set_samples()andset_variants()configured on the reader before construction. Withset_variants, the encoded.bedcovers exactly the selected variants in chunk-plan order;bed_sizeandnum_variantsreflect the selection.Biallelic checking is performed lazily as chunks are decoded; multi-allelic variants raise
ValueErrorduringread(), not at construction.set_variant_filter()is not yet supported and raisesNotImplementedErrorat construction; apply predicate filters externally before passing the reader in.Per-chunk PLINK encoding parallelises across variant-axis sub-blocks via a
concurrent.futures.ThreadPoolExecutorowned by the encoder.encode_threads(default 4) sets the pool size;encode_block_bytes(default 1 MiB) is the input-bytes target per sub-block. Chunks at or below the threshold encode synchronously on the calling thread.The 1 MiB block default targets typical L2 cache size; PLINK encoding is a tight memory-walk loop and benefits from each thread’s working set fitting in L2. Bump for very wide cohorts if profiling shows scheduling overhead dominates encode time.
- property bed_size: int#
Total
.bedsize in bytes (alias oftotal_size).
- class vcztools.BgenEncoder(reader: VczReader, *, total_string_length: int | None = None, pad_byte: bytes | None = None, variant_id_field: str | None = None, embed_header_samples: bool = True, encode_threads: int | None = None, encode_block_bytes: int | None = None, unphased: bool = False)#
Bases:
FormatEncoderRandom-access, fixed-size BGEN byte-stream encoder over a VCZ store.
Thin
FormatEncodersubclass: the base class supplies the chunk-resident state machine, POSIX-styleread(), iterator restart/advance arbitration, thread-pool lifecycle, and prefix (BGEN header) serving.BgenEncoderplugs in the layout-2 header bytes and the per-chunk fixed-size variant encoding.The byte stream is a valid BGEN layout-2 file with the compression flag set to
ZLIB. Every variant block uses zlib level 0 (stored, no DEFLATE) so the compressed payload size is a deterministic function of the uncompressed genotype block size — the variant block is therefore exactlybytes_per_variantbytes wide andbyte offset → variant indexis O(1):- bytes_per_variant
= 28 + total_string_length + zlib_stored_size(geno_size)
geno_size = 10 + (uniform_ploidy + 1) * num_samples
where the constant 28 = 3 * 2 (string length prefixes, uint16) + 4 (position) + 2 (K) + 2 * 4 (allele length prefixes, uint32) + 2 * 4 (C and D length prefixes, uint32).
uniform_ploidyis derived fromreader.call_genotype.shape[2]and is either 1 (haploid;geno_size = 10 + 2 * num_samples) or 2 (diploid;geno_size = 10 + 3 * num_samples).The five BGEN string fields (varid, rsid, chrom, allele1, allele2) share a single
total_string_lengthbudget per variant. Four of them — chrom, allele1, allele2, and whichever of varid/rsid is selected byvariant_id_field— are emitted at their actual UTF-8 byte lengths. The fifth slot is the padding field, holdingb"." + pad_byte * (slack - 1)whereslackis whatever’s left oftotal_string_lengthafter the other four. If a variant’s actual content sums pasttotal_string_length - 1(i.e. the padding field can’t even fit its leading"."), encoding raisesValueError. Defaults are tuned for biobank biallelic SNP arrays:total_string_length=64,pad_byte=b".",variant_id_field="rsid".Variant scope: biallelic and uniform ploidy.
call_genotypemust haveshape[2] == 1(haploid) orshape[2] == 2(diploid). Even within the diploid path, every sample must remain diploid — a chunk that contains the-2haploid-padding sentinel raisesNotImplementedErroron read; usewrite_bgen()for mixed-ploidy stores. Multi-allelic input raisesValueErrorlazily as chunks are decoded.The encoder serves only the
.bgenbyte stream. The matching bgenix.bgiSQLite sidecar can be produced by passingvariant_offsets(computed from the encoder’s fixed-size layoutheader_size + i * bytes_per_variant) to the module-levelwrite_bgi(). The.samplesidecar is produced bywrite_sample().set_variant_filter()is not supported and raisesNotImplementedErrorat construction; materialise the filter or useset_variantsfirst. Unlikewrite_bgen(), the encoder is I/O-free in__init__.unphased=Trueforces every variant’s phased flag to0, ignoringcall_genotype_phasedif present — seewrite_bgen()for the use case.- property bgen_size: int#
Total
.bgensize in bytes (alias oftotal_size).
- property header_size: int#
BGEN header byte length (alias of
prefix_size).
- property pad_byte: bytes#
Single byte used to fill the padding slot beyond its leading
b".". Defaultb".", never the NUL byte.
- property total_string_length: int#
Combined byte budget for the five BGEN string slots —
write_bgi()needs this to reproduce the per-variant padding the encoder wrote into the unused id slot.
- property variant_id_field: str#
Which BGEN id slot (
"rsid"or"varid") the encoder routesvariant_idinto; the other slot is the padding field.
- property variant_offsets: ndarray#
Byte boundaries of every variant block in the encoded BGEN stream, of shape
(num_variants + 1,): variantioccupies[variant_offsets[i], variant_offsets[i+1]). Suitable forwrite_bgi().
- vcztools.write_bim(reader, output)#
Write the PLINK
.bimvariant sidecar forreadertooutput.outputis a filesystem path (str/pathlib.Path) or a writable text file-like object. Tab-separated, one row per variant: chromosome, variant ID (.when absent), genetic position (always0), base-pair position, A1 (= ALT), A2 (= REF). Chromosome names are normalised to plink 2’s--make-bedoutput (chr1→1,chrM→MT, non-standard contigs unchanged); monomorphic rows emit.in the A1 slot. Multi-allelic variants raiseValueError.
- vcztools.write_fam(reader, output)#
Write the PLINK
.famsample sidecar forreadertooutput.outputis a filesystem path (str/pathlib.Path) or a writable text file-like object. The on-disk format is tab-separated, one row per sample, with FamilyID = IndividualID = the sample ID (the BOLT-LMM / qctool convention; accepted by PLINK 2, REGENIE, and BOLT-LMM without family-aware flags). The remaining four columns (FatherID, MotherID, Sex, Phenotype) are0/0/0/-9. Whitespace in any sample ID is rejected — the FAM format is whitespace-separated.
- vcztools.write_bgi(reader, output, variant_offsets, *, variant_id_field: str = 'rsid', total_string_length: int | None = None, pad_byte: bytes = b'.')#
Write the bgenix
.bgen.bgiSQLite sidecar forreader.outputis a filesystem path (str/pathlib.Path); the SQLite database is created at that location (file-like objects are not supported —sqlite3.connectneeds a real path). If the file already exists, it is unlinked first so the schema can be recreated without primary-key conflicts.variant_offsetsis an integer array of lengthnum_variants + 1giving the byte boundaries of each variant block: variantioccupies[variant_offsets[i], variant_offsets[i+1]). UseBgenEncoder.variant_offsetsfor the fixed-size encoder path, or the cumulative sum of per-variant block sizes (plus the BGEN prefix length) for the variable-sizewrite_bgen()path.variant_id_fieldmirrorswrite_bgen()/BgenEncoder: when"rsid"(default),variant_idpopulates the .bgirsidcolumn directly; when"varid", the BGENrsidslot was the padding field at encode time, so the .bgirsidcolumn carries the same padding bytes the BGEN file holds.total_string_lengthandpad_byteare the same parameters as onBgenEncoderand reconstruct the per-variant padding strings:Nonematcheswrite_bgen()’s single-byte"."padding, an integer matches the encoder’s"." + pad_byte * (slack - 1)pattern.Variant-metadata columns (chromosome, position, rsid, alleles) are read via the reader’s standard
variant_chunksAPI and assembled as numpy arrays; per-row tuples are streamed into SQLite via a generator so peak memory stays at the column arrays rather than an N-row tuple list. Variant scope is biallelic only; multi-allelic raisesValueErrorlazily on the chunk containing the offending row.
- vcztools.write_sample(reader, output)#
Write the Oxford
.sampletext forreadertooutput.outputis a filesystem path (str/pathlib.Path) or a writable text file-like object. The minimal sample file: two header rows (ID_1 ID_2 missingand0 0 0), then one row per sample withID_1andID_2both set to the sample name (matches the--double-idstyle) and themissingcolumn set to0. Whitespace in sample IDs is rejected (the file format is whitespace-separated).