diff --git a/js/index.js b/js/index.js index a4bfac1a..e9d39a06 100644 --- a/js/index.js +++ b/js/index.js @@ -29,7 +29,7 @@ export * from "./suggestCrisprQcFilters.js"; export * from "./filterCells.js"; export * from "./computeClrm1Factors.js"; -export * from "./logNormCounts.js"; +export * from "./normalizeCounts.js"; export * from "./modelGeneVariances.js"; export * from "./chooseHvgs.js"; diff --git a/js/logNormCounts.js b/js/normalizeCounts.js similarity index 88% rename from js/logNormCounts.js rename to js/normalizeCounts.js index 1d377a59..2529e15b 100644 --- a/js/logNormCounts.js +++ b/js/normalizeCounts.js @@ -12,6 +12,7 @@ import * as wasm from "./wasm.js"; * 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. @@ -19,10 +20,11 @@ import * as wasm from "./wasm.js"; * 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 log-transformed normalized expression values. + * @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 logNormCounts(x, options = {}) { - const { sizeFactors = null, allowZeros = false, allowNonFinite = false, ...others } = options; +export function normalizeCounts(x, options = {}) { + const { sizeFactors = null, log = true, allowZeros = false, allowNonFinite = false, ...others } = options; utils.checkOtherOptions(others); var sf_data; @@ -41,7 +43,7 @@ export function logNormCounts(x, options = {}) { } output = gc.call( - module => module.normalize_counts(x.matrix, sf_data.offset, allowZeros, allowNonFinite), + module => module.normalize_counts(x.matrix, sf_data.offset, log, allowZeros, allowNonFinite), x.constructor ); @@ -58,11 +60,11 @@ export function logNormCounts(x, options = {}) { /** * Center size factors in preparation for log-transformation. - * This is usually called by {@linkcode logNormCounts} internally, but can also be directly called by users to reconstitute the size factors used in the log-normalized matrix. + * This is usually called by {@linkcode normalizeCounts} internally, but can also be directly called by users to reconstitute the size factors used in the log-normalized matrix. * * @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 containing the block assignment for each cell, see {@linkcode logNormCounts}. + * @param {?(Int32WasmArray|Array|TypedArray)} [options.block=null] - Array containing the block assignment for each cell, see {@linkcode normalizeCounts}. * @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. diff --git a/src/normalize_counts.cpp b/src/normalize_counts.cpp index fe0351c5..d824f813 100644 --- a/src/normalize_counts.cpp +++ b/src/normalize_counts.cpp @@ -25,7 +25,7 @@ void center_size_factors(size_t n, uintptr_t ptr, bool use_blocks, uintptr_t blo } } -NumericMatrix normalize_counts(const NumericMatrix& mat, uintptr_t size_factors, bool allow_zero, bool allow_non_finite) { +NumericMatrix normalize_counts(const NumericMatrix& mat, uintptr_t size_factors, bool log, bool allow_zero, bool allow_non_finite) { const double* sfptr = reinterpret_cast(size_factors); std::vector sf(sfptr, sfptr + mat.ncol()); @@ -40,6 +40,7 @@ NumericMatrix normalize_counts(const NumericMatrix& mat, uintptr_t size_factors, scran_norm::sanitize_size_factors(sf.size(), sf.data(), san_opt); scran_norm::NormalizeCountsOptions norm_opt; + norm_opt.log = log; return NumericMatrix(scran_norm::normalize_counts(mat.ptr, std::move(sf), norm_opt)); } diff --git a/tests/chooseHvgs.test.js b/tests/chooseHvgs.test.js index 4ef6770c..f5349567 100644 --- a/tests/chooseHvgs.test.js +++ b/tests/chooseHvgs.test.js @@ -10,7 +10,7 @@ test("chooseHvgs works correctly", () => { var ncells = 100; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var res = scran.modelGeneVariances(norm); var output = scran.chooseHvgs(res, { number: 101 }); diff --git a/tests/modelGeneVariances.test.js b/tests/modelGeneVariances.test.js index 473bf29a..22c39d74 100644 --- a/tests/modelGeneVariances.test.js +++ b/tests/modelGeneVariances.test.js @@ -10,7 +10,7 @@ test("Variance modelling works as expected", () => { var ncells = 100; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var res = scran.modelGeneVariances(norm); // Some cursory tests. @@ -32,7 +32,7 @@ test("Variance modelling works as expected with blocking", () => { var ncells = 100; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var block = new Array(ncells); var half = ncells / 2; diff --git a/tests/logNormCounts.test.js b/tests/normalizeCounts.test.js similarity index 91% rename from tests/logNormCounts.test.js rename to tests/normalizeCounts.test.js index 2c74fe1e..5844e774 100644 --- a/tests/logNormCounts.test.js +++ b/tests/normalizeCounts.test.js @@ -10,7 +10,7 @@ test("Log-normalization works as expected", () => { var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); expect(norm.constructor.name).toBe(mat.constructor.name); expect(norm.numberOfRows()).toBe(mat.numberOfRows()); expect(norm.numberOfColumns()).toBe(mat.numberOfColumns()); @@ -40,7 +40,7 @@ test("Log-normalization works as expected with pre-supplied size factors", () => sf[i] = Math.random(); } - var norm = scran.logNormCounts(mat, { sizeFactors: sf }); + var norm = scran.normalizeCounts(mat, { sizeFactors: sf }); expect(norm.constructor.name).toBe(mat.constructor.name); expect(norm.numberOfRows()).toBe(mat.numberOfRows()); expect(norm.numberOfColumns()).toBe(mat.numberOfColumns()); @@ -89,10 +89,10 @@ test("Log-normalization behaves with zeros", () => { var empty = new Float64Array(ncells); empty.fill(0); - expect(() => scran.logNormCounts(mat, { sizeFactors: empty })).toThrow("zero"); + expect(() => scran.normalizeCounts(mat, { sizeFactors: empty })).toThrow("zero"); // Now trying with allowed zeros. - let out = scran.logNormCounts(mat, { sizeFactors: empty, allowZeros: true }); + let out = scran.normalizeCounts(mat, { sizeFactors: empty, allowZeros: true }); let ocol = out.column(0); let rcol = mat.column(0); for (var i = 0; i < ngenes; i++) { diff --git a/tests/scoreGsdecon.test.js b/tests/scoreGsdecon.test.js index 6ee6e593..ef8ecb4e 100644 --- a/tests/scoreGsdecon.test.js +++ b/tests/scoreGsdecon.test.js @@ -9,7 +9,7 @@ test("scoreGsdecon works as expected with Uint8Array inputs", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); let features = new Uint8Array(ngenes); features.fill(1, 10, 20); @@ -25,7 +25,7 @@ test("scoreGsdecon gives different results after scaling", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); let features = new Uint8Array(ngenes); features.fill(1, 10, 20); @@ -40,7 +40,7 @@ test("scoreGsdecon works with blocking", () => { var ngenes = 1000; var ncells = 50; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); let features = new Uint8Array(ngenes); features.fill(1, 0, 5); diff --git a/tests/scoreMarkers.test.js b/tests/scoreMarkers.test.js index dae564cd..8a6b08d5 100644 --- a/tests/scoreMarkers.test.js +++ b/tests/scoreMarkers.test.js @@ -9,7 +9,7 @@ test("scoreMarkers works as expected", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var groups = []; for (var i = 0; i < ncells; i++) { @@ -40,7 +40,7 @@ test("scoreMarkers works with a log-fold change threshold", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var groups = []; for (var i = 0; i < ncells; i++) { @@ -67,7 +67,7 @@ test("scoreMarkers works after turning off AUCs", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var groups = []; for (var i = 0; i < ncells; i++) { @@ -96,7 +96,7 @@ test("scoreMarkers works with maximum and medians", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var groups = []; for (var i = 0; i < ncells; i++) { @@ -118,7 +118,7 @@ test("scoreMarkers works as expected with blocking", () => { var ngenes = 1000; var ncells = 20; var mat = simulate.simulateMatrix(ngenes, ncells); - var norm = scran.logNormCounts(mat); + var norm = scran.normalizeCounts(mat); var groups = []; for (var i = 0; i < ncells; i++) {