gene set summary progress (#2127)

* revert removal of cache control headers

* checkpoint work on revising summary route

* add summary query support to annoMatrix

* summarize route cleanup

* add mising file

* clean up summarize route

* add summary histogram

* update deps

* lint

* more lint

* lint

* manage crossfiler during gene set state changes

* remove obsolete debugging code

* correctly perform async watch in histogram

* better error handling
This commit is contained in:
Bruce Martin
2021-03-30 14:43:53 -07:00
committed by GitHub
parent bfb9e1edcc
commit ae30b66123
47 changed files with 28628 additions and 9109 deletions
+2 -2
View File
@@ -396,9 +396,9 @@ export const saveGenesetsAction = () => async (dispatch, getState) => {
const { lastTid, genesets } = state.genesets;
const genesetsAreAvailable =
config?.parameters?.["annotations_genesets"] ?? false;
config?.parameters?.annotations_genesets ?? false;
const genesetsReadonly =
config?.parameters?.["annotations_genesets_readonly"] ?? true;
config?.parameters?.annotations_genesets_readonly ?? true;
if (!genesetsAreAvailable || genesetsReadonly) {
// our non-save was completed!
return dispatch({
+126
View File
@@ -0,0 +1,126 @@
/*
Action creators for gene sets
Primarily used to keep the crossfilter and underlying data in sync with the UI.
The behavior manifest in these action creators:
Delete a gene set, will
* drop index & clear selection state on the gene set summary
* drop index & clear selection state of each gene in the geneset
Delete a gene from a gene set, will:
* drop index & clear selection state on the gene set summary
* drop index & clear selection state on the gene
Add a gene to a gene set, will:
* drop index & clear selection state on the gene set summary
* will NOT touch the selection state for the gene
Note that crossfilter indices are lazy created, as needed.
*/
export const genesetDelete = (genesetName) => (dispatch, getState) => {
const state = getState();
const { genesets } = state;
const gs = genesets?.genesets?.get(genesetName) ?? {};
const geneSymbols = Array.from(gs.genes.keys());
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
dispatch({
type: "geneset: delete",
genesetName,
obsCrossfilter,
annoMatrix: obsCrossfilter.annoMatrix,
});
};
export const genesetAddGenes = (genesetName, genes) => (dispatch, getState) => {
const state = getState();
const { obsCrossfilter: prevObsCrossfilter } = state;
const obsCrossfilter = dropGenesetSummaryDimension(
prevObsCrossfilter,
state,
genesetName
);
dispatch({
type: "continuous metadata histogram cancel",
continuousNamespace: { isGeneSetSummary: true },
selection: genesetName,
});
return dispatch({
type: "geneset: add genes",
genesetName,
genes,
obsCrossfilter,
annoMatrix: obsCrossfilter.annoMatrix,
});
};
export const genesetDeleteGenes = (genesetName, geneSymbols) => (
dispatch,
getState
) => {
const state = getState();
const obsCrossfilter = dropGeneset(dispatch, state, genesetName, geneSymbols);
return dispatch({
type: "geneset: delete genes",
genesetName,
geneSymbols,
obsCrossfilter,
annoMatrix: obsCrossfilter.annoMatrix,
});
};
/*
Private
*/
function dropGenesetSummaryDimension(obsCrossfilter, state, genesetName) {
const { annoMatrix, genesets } = state;
const varIndex = annoMatrix.schema.annotations?.var?.index;
const gs = genesets?.genesets?.get(genesetName) ?? {};
const genes = Array.from(gs.genes.keys());
const query = {
summarize: {
method: "mean",
field: "var",
column: varIndex,
values: genes,
},
};
return obsCrossfilter.dropDimension("X", query);
}
function dropGeneDimension(obsCrossfilter, state, gene) {
const { annoMatrix } = state;
const varIndex = annoMatrix.schema.annotations?.var?.index;
const query = {
where: {
field: "var",
column: varIndex,
value: gene,
},
};
return obsCrossfilter.dropDimension("X", query);
}
function dropGeneset(dispatch, state, genesetName, geneSymbols) {
const { obsCrossfilter: prevObsCrossfilter } = state;
const obsCrossfilter = geneSymbols.reduce(
(crossfilter, gene) => dropGeneDimension(crossfilter, state, gene),
dropGenesetSummaryDimension(prevObsCrossfilter, state, genesetName)
);
dispatch({
type: "continuous metadata histogram cancel",
continuousNamespace: { isGeneSetSummary: true },
selection: genesetName,
});
geneSymbols.forEach((g) =>
dispatch({
type: "continuous metadata histogram cancel",
continuousNamespace: { isUserDefined: true },
selection: g,
})
);
return obsCrossfilter;
}
+6 -2
View File
@@ -13,6 +13,7 @@ import * as selnActions from "./selection";
import * as annoActions from "./annotation";
import * as viewActions from "./viewStack";
import * as embActions from "./embedding";
import * as genesetActions from "./geneset";
/*
return promise fetching user-configured colors
@@ -58,7 +59,7 @@ async function genesetsFetch(dispatch, config) {
genesets: [],
tid: 0,
};
if (config?.parameters?.["annotations_genesets"] ?? false) {
if (config?.parameters?.annotations_genesets ?? false) {
fetchJson("genesets").then((response) => {
dispatch({
type: "geneset: initial load",
@@ -111,7 +112,7 @@ const doInitialDataLoad = () =>
});
dispatch({ type: "initial data load complete" });
const defaultEmbedding = config?.parameters?.["default_embedding"];
const defaultEmbedding = config?.parameters?.default_embedding;
const layoutSchema = schema?.schema?.layout?.obs ?? [];
if (
defaultEmbedding &&
@@ -269,4 +270,7 @@ export default {
needToSaveObsAnnotations: annoActions.needToSaveObsAnnotations,
layoutChoiceAction: embActions.layoutChoiceAction,
setCellSetFromSelection: selnActions.setCellSetFromSelection,
genesetDelete: genesetActions.genesetDelete,
genesetAddGenes: genesetActions.genesetAddGenes,
genesetDeleteGenes: genesetActions.genesetDeleteGenes,
};