UNPKG

scran.js

Version:

Single cell RNA-seq analysis in Javascript

123 lines (105 loc) 5.52 kB
import * as gc from "./gc.js"; import * as utils from "./utils.js"; import * as wa from "wasmarrays.js"; import * as wasm from "./wasm.js"; import { columnSums } from "./matrixStats.js"; /** * Compute log-transformed normalized expression values. * * @param {ScranMatrix} x The count matrix, usually after filtering. * @param {object} [options={}] - Optional parameters. * @param {?(Float64WasmArray|Array|TypedArray)} [options.sizeFactors=null] - Array of positive numbers containing the size factor for each cell in `x`. * This should have length equal to the number of columns in `x`. * If centering is required, it should be applied with {@linkcode centerSizeFactors} - no additional centering is performed here. * If `null`, size factors are computed from the centered column sums of `x`. * @param {boolean} [options.log=true] - Whether to perform log-transformation. * @param {boolean} [options.allowZeros=false] - Whether size factors of zero should be allowed. * If `true`, size factors of zero are converted to the smallest non-zero size factor across all cells. * If `false`, an error is raised instead. * @param {boolean} [options.allowZeros=false] - Whether non-finite size factors should be allowed. * If `true`, size factors of infinity or NaN are converted to the largest non-zero size factor in the dataset or 1, respectively. * If `false`, an error is raised instead. * * @return {ScranMatrix} A matrix of the same type as `x` containing normalized expression values. * If `log = true`, the values in the matrix are log-transformed. */ export function normalizeCounts(x, options = {}) { const { sizeFactors = null, log = true, allowZeros = false, allowNonFinite = false, ...others } = options; utils.checkOtherOptions(others); var sf_data; var output; try { if (sizeFactors !== null) { sf_data = utils.wasmifyArray(sizeFactors, "Float64WasmArray"); if (sf_data.length != x.numberOfColumns()) { throw new Error("length of 'sizeFactors' must be equal to number of columns in 'x'"); } } else { sf_data = utils.createFloat64WasmArray(x.numberOfColumns()); columnSums(x, { buffer : sf_data }); wasm.call(module => module.center_size_factors(sf_data.length, sf_data.offset, false, 0, true)); // assume unblocked in the default case. } output = gc.call( module => module.normalize_counts(x.matrix, sf_data.offset, log, allowZeros, allowNonFinite), x.constructor ); } catch (e) { utils.free(output); throw e; } finally { utils.free(sf_data); } return output; } /** * Center size factors in preparation for log-transformation in {@linkcode normalizeCounts}. * * @param {TypedArray|WasmArray} sizeFactors - Array of non-negative size factors, one per cell. * @param {object} [options={}] - Optional parameters. * @param {?(Int32WasmArray|Array|TypedArray)} [options.block=null] - Array of length equal to `sizeFactors`, containing the block assignment for each cell. * If `toLowestBlock = true`, all size factors are scaled by the same value such that the block with the lowest mean size factor is centered. * Otherwise, the size factors in each block are centered separately. * @param {boolean} [options.asTypedArray=true] - Whether to return a Float64Array. * If `false`, a Float64WasmArray is returned instead. * @param {?Float64WasmArray} [options.buffer=null] - Buffer in which to store the output size factors. * Length should be equal to that of `sizeFactors`. * If `null`, an array is allocated by the function. * @param {boolean} [options.toLowestBlock=true] - Whether to scale the size factors so that the block with the lowest mean size factor is centered. * This preserves differences in scaling between blocks. * If `false`, each block of size factors is centered as if `centerSizeFactors` was called separately on each block. * * @return {Float64Array|Float64WasmArray} Array containing the centered size factors. * If `buffer` is supplied, the function returns `buffer` if `asTypedArray = false`, or a view on `buffer` if `asTypedArray = true`. */ export function centerSizeFactors(sizeFactors, options = {}) { let { block = null, asTypedArray = true, buffer = null, toLowestBlock = true, ...others } = options; utils.checkOtherOptions(others); let local_buffer = null; let block_data; try { if (buffer === null) { local_buffer = utils.createFloat64WasmArray(sizeFactors.length); buffer = local_buffer; } if (buffer !== sizeFactors) { buffer.set(sizeFactors instanceof wa.WasmArray ? sizeFactors.array() : sizeFactors); } var bptr = 0; var use_blocks = false; if (block !== null) { block_data = utils.wasmifyArray(block, "Int32WasmArray"); if (block_data.length != buffer.length) { throw new Error("'block' must be of length equal to that of 'sizeFactors'"); } use_blocks = true; bptr = block_data.offset; } wasm.call(module => module.center_size_factors(buffer.length, buffer.offset, use_blocks, bptr, toLowestBlock)); } catch(e) { utils.free(local_buffer); throw e; } finally { utils.free(block_data); } return utils.toTypedArray(buffer, local_buffer == null, asTypedArray); }