LOLA enrichment (Wasm)
Wasm bindings for gtars-lola â LOLA (Locus Overlap Analysis) enrichment testing, runnable entirely in the browser. Given a user set of regions, a universe, and a region database (built in memory from API-served BED data), computes Fisher's exact test enrichment of the user set against every database region set.
See the Rust gtars-lola reference for the full statistical details â Fisher's exact test via hypergeometric survival function, CMLE odds ratio, contingency table semantics, and compatibility notes with R LOLA. This page is a Wasm-focused binding reference.
In-memory only â no folder loading
The Wasm binding's LolaRegionDB is built entirely from in-memory data ({regions, name} entries passed in at construction). The Rust RegionDB::from_lola_folder loader is not available in Wasm â it requires a filesystem. In practice you'd fetch the region database from an API and pass the regions directly into the constructor, or build it from a pre-indexed IGD on the server side.
Import
import init, {
LolaRegionDB,
runLOLA,
checkUniverseAppropriateness,
} from '@databio/gtars';
await init();
LolaRegionDB
Construction
Construct from an array of { regions, name } objects, where regions is an array of [chr, start, end] tuples and name is the filename-like identifier:
const dbEntries = [
{
name: 'encode_k562_ctcf.bed',
regions: [
['chr1', 100, 200],
['chr1', 400, 500],
['chr2', 1000, 1100],
],
},
{
name: 'encode_hela_ctcf.bed',
regions: [
['chr1', 150, 250],
['chr2', 1050, 1150],
],
},
];
const db = new LolaRegionDB(dbEntries);
The constructor builds an IGD overlap index internally and wraps it with minimal annotation (filename only). To attach richer per-file metadata â cell type, tissue, antibody, etc. â build the annotated RegionDB on the Rust side and serve it through a different transport (e.g. a custom binary format), or expose a method that accepts RegionSetAnno objects alongside the regions.
Accessors
db.numRegionSets // number
db.listRegionSets() // string[] â filenames
db.collectionAnno // Array of { collectionname, collector, date, source, description } (empty for an in-memory DB)
// Extract region sets by 0-based index as a RegionSetList
// (pass null for "all sets"; names are populated from filenames)
const rsl = db.getRegionSets(null);
const rsl2 = db.getRegionSets([0, 5, 12]);
getRegionSets() returns a RegionSetList with .names populated from the database filenames.
runLOLA
Runs Fisher's exact test for every (user_set, db_set) pair and returns a column-oriented object suitable for dropping directly into a DataFrame or table.
runLOLA(
userSets: Array<Array<[string, number, number]>>,
universe: Array<[string, number, number]>,
regionDb: LolaRegionDB,
minOverlap?: number, // default 1
direction?: string, // "enrichment" (default) | "depletion"
): LolaResultColumnar
Parameters:
- userSets â array of user sets, where each user set is an array of [chr, start, end] tuples. Pass a single-element outer array [peaks] for a one-user-set analysis.
- universe â a single array of [chr, start, end] tuples representing the background.
- regionDb â a LolaRegionDB.
- minOverlap â minimum bp overlap to count as overlapping (default 1).
- direction â "enrichment" (default, P(X âĨ a), alternative "greater") or "depletion" (P(X ⤠a), alternative "less"). "less" is accepted as an alias for depletion; any other value (including "greater") runs enrichment.
Returns an object with parallel arrays (one entry per (user_set, db_set) pair) using camelCase keys:
| key | type | meaning |
|---|---|---|
userSet |
number[] |
0-based user-set index |
dbSet |
number[] |
0-based db-set index |
collection |
(string \| null)[] |
per-file annotation, usually null in Wasm |
pValueLog |
number[] |
-log10(p) from Fisher's exact test, capped at ~322 |
oddsRatio |
number[] |
CMLE odds ratio (matches R fisher.test()$estimate) |
support |
number[] |
overlap count between user set and db set |
rnkPv, rnkOr, rnkSup |
number[] |
1-based per-metric ranks within the user set |
maxRnk |
number[] |
max of the three ranks |
meanRnk |
number[] |
mean of the three ranks |
b, c, d |
number[] |
signed contingency values (can be negative) |
qValue |
(number \| null)[] |
BH-adjusted p-value (applied automatically inside runLOLA) |
description, cellType, tissue, antibody, treatment, dataSource |
(string \| null)[] |
per-file metadata |
filename |
string[] |
db set file name |
size |
number[] |
number of regions in the db set |
Like the Python binding, Wasm runLOLA auto-applies annotate_results + apply_fdr_correction internally â you don't need to call them separately. Rows come back sorted by descending pValueLog, then ascending meanRnk (matching R LOLA output order).
Usage example
import init, {
LolaRegionDB,
runLOLA,
RegionSet,
} from '@databio/gtars';
await init();
// Helper to convert a RegionSet to the tuple form LOLA expects
function toTuples(rs: RegionSet): Array<[string, number, number]> {
// Iterate rs and pull chr/start/end â or keep the original BedEntries
// if you still have them in scope from constructing the RegionSet.
// ...
}
// 1. Build the region database from API-fetched data
const dbEntries = await fetchDatabaseRegions(); // [{ name, regions }, ...]
const db = new LolaRegionDB(dbEntries);
// 2. Prepare user sets and universe as tuple arrays
const userSets = [userPeakTuples];
const universe = universeTuples;
// 3. Run enrichment
const results = runLOLA(userSets, universe, db, 1, 'enrichment');
// 4. Pivot to row-oriented view for rendering
const n = results.pValueLog.length;
for (let i = 0; i < n; i++) {
console.log(
`${results.filename[i]} ` +
`p=${results.pValueLog[i].toFixed(2)} ` +
`OR=${results.oddsRatio[i].toFixed(2)} ` +
`support=${results.support[i]}`
);
}
Negative contingency values
If your user set contains regions outside the universe, the contingency table produces negative b/c/d. The binding matches R LOLA's behavior â it logs a warning, stores the signed values, and returns pValueLog = 0.0, oddsRatio = NaN for that row. Pre-process with checkUniverseAppropriateness (below) to detect this before running enrichment.
checkUniverseAppropriateness
Diagnostic check â for each user set, reports what fraction of user-set regions overlap the universe and whether there are many-to-many mappings.
const report = checkUniverseAppropriateness(userSets, universe);
// Returns a column-oriented object:
// {
// userSet: number[],
// totalRegions: number[],
// regionsInUniverse: number[],
// coverage: number[], // 0.0 to 1.0 per user set
// manyToMany: number[], // count of user regions overlapping >1 universe region
// warnings: string[] // free-form warning messages, pooled across user sets
// }
const n = report.userSet.length;
for (let i = 0; i < n; i++) {
console.log(
`user set ${report.userSet[i]}: ` +
`${(report.coverage[i] * 100).toFixed(1)}% coverage, ` +
`${report.manyToMany[i]} many-to-many`
);
}
for (const w of report.warnings) {
console.warn('â ', w);
}
Warnings fire when coverage drops below 50% (severe) or 90% (moderate), or when any user region overlaps more than one universe region.
Rust-only helpers not exposed in Wasm
The Rust universe module has two additional helpers â redefine_user_sets (rewrite user sets in terms of universe regions) and build_restricted_universe (disjoint union of all user sets, for differential analysis). Neither is currently exposed in the Wasm binding. If you need them, you can replicate the logic client-side using RegionSetList operations from wasm/regionset, or request a binding.
See also
- wasm/regionset â
RegionSet,RegionSetList, and theConsensusBuilderused upstream of LOLA analyses. - gtars-lola â full Rust API reference, including the contingency table math, p-value computation, and CMLE odds ratio details.