bakana
Version:
Backend for kana's single-cell analyses. This supports single or multiple samples, execution in Node.js or the browser, in-memory caching of results for iterative analyses, and serialization to/from file for redistribution.
120 lines (108 loc) • 3.96 kB
JavaScript
import * as bioc from "bioconductor";
import * as df from "./DataFrame.js";
import { MockSparseMatrix, MockNormalizedMatrix } from "./assays.js";
import { MockReducedDimensionMatrix } from "./reducedDimensions.js";
export async function formatSingleCellExperiment(state, { reportOneIndex = false, storeModalityColumnData = false } = {}) {
let all_rowdata = state.inputs.fetchFeatureAnnotations();
let modalities = Object.keys(all_rowdata);
let main = "RNA";
if (!(main in all_rowdata)) {
main = modalities[0];
}
let all_metadata = {};
for (const m of modalities) {
all_metadata[m] = new bioc.List;
}
let all_coldata = df.formatColumnData(
state,
modalities,
main,
all_metadata,
storeModalityColumnData
);
// Setting up the SEs.
let all_se = {}
for (const m of modalities) {
let mat = state.cell_filtering.fetchFilteredMatrix().get(m);
let assays = { counts: new MockSparseMatrix(mat) };
let reddim = {};
let metadata;
if (m in all_metadata) {
metadata = all_metadata[m];
} else {
metadata = new bioc.List;
}
let step = null;
switch (m) {
case "RNA":
step = state.rna_normalization;
break;
case "ADT":
step = state.adt_normalization;
break;
case "CRISPR":
step = state.crispr_normalization;
break;
}
if (step !== null) {
let sf = step.fetchSizeFactors();
assays.logcounts = new MockNormalizedMatrix(mat, sf);
}
step = null;
switch (m) {
case "RNA":
step = state.rna_pca;
break;
case "ADT":
step = state.adt_pca;
break;
case "CRISPR":
step = state.crispr_pca;
break;
}
if (step !== null) {
let pcs = step.fetchPCs();
reddim.pca = new MockReducedDimensionMatrix(pcs.numberOfCells(), pcs.numberOfPCs(), pcs.principalComponents({ copy: "view" }));
let tv = pcs.totalVariance();
metadata.set("pca", { variance_explained: pcs.varianceExplained({ copy: "view" }).map(x => x / tv) }, { inPlace: true });
}
all_se[m] = new bioc.SingleCellExperiment(
assays,
{
rowData: all_rowdata[m],
rowNames: all_rowdata[m].rowNames(),
columnData: all_coldata[m],
columnNames: all_coldata[m].rowNames(),
metadata: metadata,
reducedDimensions: reddim
}
);
}
// Saving the dimensionality reduction results.
for (const name of [ "tsne", "umap" ]) {
let res = await state[name].fetchResults({ copy: false });
let payload = new Float64Array(res.x.length * 2);
payload.set(res.x);
payload.set(res.y, res.x.length);
all_se[main].setReducedDimension(name, new MockReducedDimensionMatrix(res.x.length, 2, payload), { inPlace: true });
}
// Saving extra metadata.
{
let customs = state.custom_selections.fetchSelections({ copy: true, force: "Int32Array" });
if (reportOneIndex) {
for (const [k, v] of Object.entries(customs)) { // incrementing by 1, if requested.
v.forEach((x, i) => { v[i] = x + 1; });
}
}
let meta = all_se[main].metadata();
meta.set("custom_selections", customs, { inPlace: true });
all_se[main].setMetadata(meta, { inPlace: true });
}
let main_se = all_se[main];
for (const mod of modalities) {
if (mod !== main) {
main_se.setAlternativeExperiment(mod, all_se[mod], { inPlace: true });
}
}
return main_se;
}