UNPKG

higlass-zarr-datafetchers

Version:
177 lines (176 loc) 6.2 kB
// src/ZarrMultivecDataFetcher.js import { open as zarrOpen, root as zarrRoot, get as zarrGet, slice, FetchStore } from "zarrita"; function multivecChunksToTileDenseArray(chunks, tileShape, isRow) { const fullTileLength = isRow ? tileShape[1] : tileShape[0] * tileShape[1]; const fullTileArray = new Float32Array(fullTileLength); let offset = 0; if (isRow) { for (const chunk of chunks) { const chunkData = chunk.data; fullTileArray.set(chunkData, offset); offset += chunkData.length; } } else { const numSamples = tileShape[0]; for (let sampleI = 0; sampleI < numSamples; sampleI++) { for (const chunk of chunks) { const chunkData = chunk.data.subarray(sampleI * chunk.stride[0], (sampleI + 1) * chunk.stride[0]); fullTileArray.set(chunkData, offset); offset += chunkData.length; } } } return fullTileArray; } var ZarrMultivecDataFetcher = function ZarrMultivecDataFetcher2(HGC, ...args) { if (!new.target) { throw new Error( 'Uncaught TypeError: Class constructor cannot be invoked without "new"' ); } const { slugid } = HGC.libraries; const { absToChr, parseChromsizesRows, genomicRangeToChromosomeChunks, DenseDataExtrema1D, minNonZero, maxNonZero } = HGC.utils; class ZarrMultivecDataFetcherClass { constructor(dataConfig) { this.dataConfig = dataConfig; this.trackUid = slugid.nice(); if (dataConfig.hasStoreRoot) { this.storeRoot = Promise.resolve(ZarrMultivecDataFetcher2.urlToStoreRoot[dataConfig.url]); } else if (dataConfig.url) { const { url, options = {} } = dataConfig; this.store = new FetchStore(url, options); this.storeRoot = Promise.resolve(zarrRoot(this.store)); } if (dataConfig.row !== void 0) { this.row = dataConfig.row; } } tilesetInfo(callback) { this.tilesetInfoLoading = true; return this.storeRoot.then((root) => zarrOpen(root)).then((grp) => { const attrs = grp.attrs; this.tilesetInfoLoading = false; const chromSizes = attrs.multiscales.map((d) => [d.name, d.metadata.chromsize]); const finalChrom = attrs.multiscales[attrs.multiscales.length - 1]; const maxPos = finalChrom.metadata.chromoffset + finalChrom.metadata.chromsize; const tileSize = attrs.shape[1]; const retVal = { ...attrs, shape: [attrs.shape[1], attrs.shape[0]], chromSizes, tile_size: tileSize, max_width: maxPos, min_pos: [0], max_pos: [maxPos], max_zoom: Math.ceil(Math.log(maxPos / tileSize) / Math.log(2)) }; if (callback) { callback(retVal); } return retVal; }).catch((err) => { this.tilesetInfoLoading = false; if (callback) { callback({ error: `Error parsing zarr multivec: ${err}` }); } }); } fetchTilesDebounced(receivedTiles, tileIds) { const tiles = {}; const validTileIds = []; const tilePromises = []; for (const tileId of tileIds) { const parts = tileId.split("."); const z = parseInt(parts[0], 10); const x = parseInt(parts[1], 10); if (Number.isNaN(x) || Number.isNaN(z)) { console.warn("Invalid tile zoom or position:", z, x); continue; } validTileIds.push(tileId); tilePromises.push(this.tile(z, x, tileId)); } Promise.all(tilePromises).then((values) => { for (let i = 0; i < values.length; i++) { const validTileId = validTileIds[i]; tiles[validTileId] = values[i]; tiles[validTileId].tilePositionId = validTileId; } receivedTiles(tiles); }); return tiles; } tile(z, x, tileId) { const { storeRoot } = this; return this.tilesetInfo().then((tsInfo) => { const resolution = +tsInfo.resolutions[z]; const tileSize = +tsInfo.tile_size; const binSize = resolution; const tileStart = x * tileSize * resolution; const tileEnd = tileStart + tileSize * resolution; const chromSizes = tsInfo.chromSizes; const chromInfo = parseChromsizesRows(chromSizes); const [chrStart, chrStartPos] = absToChr(tileStart, chromInfo); const [chrEnd, chrEndPos] = absToChr(tileEnd, chromInfo); const genomicStart = { chr: chrStart, pos: chrStartPos }; const genomicEnd = { chr: chrEnd, pos: chrEndPos }; const chrChunks = genomicRangeToChromosomeChunks( chromSizes, genomicStart, genomicEnd, binSize, tileSize ); return Promise.all( chrChunks.map(([chrName, zStart, zEnd]) => { return storeRoot.then((root) => zarrOpen(root.resolve(`/chromosomes/${chrName}/${resolution}/`), { kind: "array" })).then((arr) => this.row !== void 0 ? zarrGet(arr, [this.row, slice(zStart, zEnd)]) : zarrGet(arr, [null, slice(zStart, zEnd)])); }) ).then((chunks) => { const dense = multivecChunksToTileDenseArray(chunks, [tsInfo.shape[1], tsInfo.shape[0]], this.row !== void 0); return Promise.resolve({ dense, denseDataExtrema: new DenseDataExtrema1D(dense), dtype: "float32", min_value: Math.min.apply(null, dense), max_value: Math.max.apply(null, dense), minNonZero: minNonZero(dense), maxNonZero: maxNonZero(dense), server: null, size: 1, shape: tsInfo.shape, tileId, tilePos: [x], tilePositionId: tileId, tilesetUid: null, zoomLevel: z }); }); }); } } return new ZarrMultivecDataFetcherClass(...args); }; ZarrMultivecDataFetcher.config = { type: "zarr-multivec" }; ZarrMultivecDataFetcher.urlToStoreRoot = {}; var ZarrMultivecDataFetcher_default = ZarrMultivecDataFetcher; export { ZarrMultivecDataFetcher_default as ZarrMultivecDataFetcher }; //# sourceMappingURL=index.js.map