A standalone JavaScript reader and browser UI for the Zarr hierarchy produced by
magenpy.LDMatrix. The folder has no coupling to the Python package and can be
moved to its own repository later.
The reader understands magenpy's compact CSR-like representation:
matrix/
data strict upper-triangle correlations
indptr row offsets
metadata/
snps, a1, a2, maf, bp, cm, ldscore
root attrs Chromosome, Sample size, Genome build, LD estimator, ...
It uses Zarrita for lazy, chunk-aware access to Zarr v2 and v3 stores. Integer LD values are dequantized using the same scale as magenpy.
Variant metadata used for filtering and matching (snps, alleles, MAF, BP, cM,
and stored LD scores) is read once during validation and retained for the life of
the matrix. Concurrent requests for the same field share one read. Root metadata
such as chromosome is already resident in the opened Zarr group.
Consolidated metadata is enabled by default. For ZIP archives whose Zarr root is
nested (for example chr_22/.zmetadata), the archive store is scoped to that
directory before metadata discovery. Array and group descriptors are therefore
served from .zmetadata instead of separate HTTP range requests.
Remote ZIP initialization caches the archive tail and coalesces adjacent
indptr and variant-metadata entries into as few byte-range requests as
possible. matrix/data entries are excluded from this cache and from
coalescing, preserving exact lazy chunk reads during analysis.
Range reads map the requested variant pairs to physical matrix/data chunks,
fetch each relevant chunk once, and never scan the rest of the LD array. Dense
block assembly runs in an embedded WebAssembly kernel. Its auditable source is
native/ld_range.wat; after changing it, regenerate the
embedded module with npm run build:wasm.
Requires Node.js 20.19 or newer.
cd ld_browser
npm install
npm run devOpen the URL printed by Vite. You can select a local .zarr directory or Zarr
ZIP (the files stay in the browser), or enter an hf://, s3://, gs://,
gcs://, or HTTP(S) source. The built-in UK Biobank preset streams directly
from the Hugging Face archive.
In browsers that support showDirectoryPicker(), directory-backed Zarr stores
are read lazily through a read-only filesystem handle. Other browsers fall back
to the webkitdirectory file selector. The handle-based picker requires HTTPS
or a trusted local development origin such as localhost.
npm test
npm run buildThe normal test suite is offline. To additionally check the live public UKB archive on Hugging Face and Oxford HTTPS Zarr directory:
LD_BROWSER_LIVE_TEST=1 npm testimport { LDMatrix } from "./src/LDMatrix.js";
const ld = await LDMatrix.fromUrl("https://example.org/chr_22.zarr/");
await ld.validate();
console.log(ld.summary());
console.log(await ld.get("rs123", "rs456"));
console.log(await ld.getRow("rs123", { symmetric: true, returnIndices: true }));
const upper = await ld.denseBlock(1000, 1100, { symmetric: false });
const symmetric = await ld.denseBlock(1000, 1100);
const product = await ld.dot(new Float64Array(ld.nSnps).fill(1));
const scores = await ld.computeLdScores();Directory-style Zarr v2 stores can be streamed directly over HTTP(S):
const ukb = await LDMatrix.fromUrl(
"https://www.stats.ox.ac.uk/publication-data/sge/plmgrp/temp/LD_matrices/EUR/chr_22/",
);fromUri() accepts the same Hugging Face URI form as huggingface_hub. It
translates the URI to the Hub download endpoint and opens the nested chr_N
group used by the magenpy archives:
const ukb = await LDMatrix.fromUri(
"hf://datasets/shz9/ukb-ld/EUR/chr_22.zip",
);
// Pin a branch, tag, or full commit after the repository name.
const pinned = await LDMatrix.fromUri(
"hf://datasets/shz9/ukb-ld@18d7b11873dbccd9ba463004f4e48e0dcb46f04b/EUR/chr_22.zip",
);
// Private or gated repositories can use a read token.
const privateLd = await LDMatrix.fromHuggingFace(uri, { token: hfToken });Public S3 stores use virtual-hosted HTTPS URLs. The default region is
us-east-2, matching magenpy's Python S3 reader:
const s3Ld = await LDMatrix.fromUri(
"s3://my-public-bucket/ld/EUR/chr_22.zarr",
{ region: "eu-west-2" },
);
// Path-style S3-compatible service, such as MinIO or institutional storage.
const compatible = await LDMatrix.fromS3("s3://bucket/ld/chr_22.zarr", {
endpoint: "https://objects.example.org",
pathStyle: true,
});Public Google Cloud Storage directories and ZIPs accept either gs:// or
gcs://. Protected buckets may be opened with an OAuth bearer token:
const publicGcs = await LDMatrix.fromUri(
"gs://my-public-bucket/ld/EUR/chr_22.zarr",
);
const protectedGcs = await LDMatrix.fromGcs(
"gcs://my-protected-bucket/ld/EUR/chr_22.zarr",
{ token: googleOAuthToken },
);Browser sources must allow CORS. In particular, the Oxford HTTPS directory
shown above does not return an Access-Control-Allow-Origin header, so browsers
block direct reads from it; use the built-in Hugging Face archive or configure
the server to allow the browser application's origin. Remote ZIPs must also
support HEAD and byte-range requests. Private S3 stores require pre-signed
URLs or a custom Zarrita fetchOptions.fetch function that applies AWS SigV4
signing.
Node.js also has a local-path entry point:
import { fromPath } from "magenpy-ld-browser/node";
const directory = await fromPath("./chr_22.zarr");
const zipped = await fromPath("./chr_22.zip");LDMatrix.fromStore(store) accepts any Zarrita-compatible readable store. This
is useful for S3 gateways, reference stores, authenticated fetch wrappers, or
embedding the library in another application.
- Lazy metadata and upper-triangle row reads
- Numeric-index and rsID lookup
- Pairwise correlations with implicit symmetry and unit diagonal
- BP-range selection with the native upper triangle shown by default; symmetrization mirrors the cached block without another store read
- CSV export of the current heatmap (unmaterialized lower-triangle cells remain blank)
- Boolean/index masks and comma/newline-delimited SNP filtering
- Hosted UKB ancestry and chromosome presets
- Comparison of up to four same-chromosome matrices from any mix of local directories, local ZIPs, hosted presets, and custom cloud sources; shared variants are selected automatically, and matrices can be paired into upper/lower triangle heatmaps
- Variant metadata display including stored LD scores
- Interactive tagging-variant discovery from comma/newline-delimited rsIDs using an r² threshold, with CSV export
- Order-aware LD pruning of a supplied variant set using an r² threshold, with CSV export
- Streaming matrix-vector multiplication
- Corrected or uncorrected LD-score calculation
- Greedy LD pruning and tagging-variant discovery
- SNP-table generation and structural validation
- Async row iteration
After a matrix opens, the browser presents three analysis modes: regional LD visualization, variant pruning, and tagging-variant discovery. The latter two run against the primary matrix. Their sparse computations read correlation chunks in batches and do not construct a dense chromosome-wide matrix.
Hosted references are defined in src/hosted-references.json. Each entry
supplies its dataset details, matrix-structure note, population choices,
available chromosomes, defaults, and URI template; the hosted-matrix controls
are generated from that catalog. URI templates support {population} and
{chromosome} placeholders, whose selected values are URL-encoded before use.
Vite bundles this JSON during the static build, so it does not add a runtime
network request.
The implementation is intentionally read-only. Constructing or mutating an LD store remains the responsibility of magenpy/Python, where validation and quantization behavior are already established.