mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-02 23:18:11 +08:00
subset embedding UI improvement (#1667)
* add user flag feature to annomatrix * add implicit subsetting for partial embeddings * lint * add embedding cell counts to embedding choice menu * layout
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
action creators related to embeddings choice
|
||||
*/
|
||||
|
||||
import { AnnoMatrixObsCrossfilter } from "../annoMatrix";
|
||||
import { _setEmbeddingSubset } from "../util/stateManager/viewStackHelpers";
|
||||
|
||||
export const layoutChoiceAction = (newLayoutChoice) => async (
|
||||
dispatch,
|
||||
getState
|
||||
) => {
|
||||
/*
|
||||
On layout choice, make sure we have selected all on the previous layout, AND the new
|
||||
layout.
|
||||
*/
|
||||
const { annoMatrix: prevAnnoMatrix } = getState();
|
||||
|
||||
const embeddingDf = await prevAnnoMatrix.base().fetch("emb", newLayoutChoice);
|
||||
const annoMatrix = _setEmbeddingSubset(prevAnnoMatrix, embeddingDf);
|
||||
const obsCrossfilter = await new AnnoMatrixObsCrossfilter(annoMatrix).select(
|
||||
"emb",
|
||||
newLayoutChoice,
|
||||
{
|
||||
mode: "all",
|
||||
}
|
||||
);
|
||||
dispatch({
|
||||
type: "set layout choice",
|
||||
layoutChoice: newLayoutChoice,
|
||||
obsCrossfilter,
|
||||
annoMatrix,
|
||||
});
|
||||
};
|
||||
@@ -12,6 +12,7 @@ import { loadUserColorConfig } from "../util/stateManager/colorHelpers";
|
||||
import * as selnActions from "./selection";
|
||||
import * as annoActions from "./annotation";
|
||||
import * as viewActions from "./viewStack";
|
||||
import * as embActions from "./embedding";
|
||||
|
||||
/*
|
||||
return promise fetching user-configured colors
|
||||
@@ -40,6 +41,15 @@ async function configFetch(dispatch) {
|
||||
});
|
||||
}
|
||||
|
||||
function prefetchEmbeddings(annoMatrix) {
|
||||
/*
|
||||
prefetch requests for all embeddings
|
||||
*/
|
||||
const { schema } = annoMatrix;
|
||||
const available = schema.layout.obs.map((v) => v.name);
|
||||
available.forEach((embName) => annoMatrix.prefetch("emb", embName));
|
||||
}
|
||||
|
||||
/*
|
||||
Application bootstrap
|
||||
*/
|
||||
@@ -57,6 +67,8 @@ const doInitialDataLoad = () =>
|
||||
const baseDataUrl = `${globals.API.prefix}${globals.API.version}`;
|
||||
const annoMatrix = new AnnoMatrixLoader(baseDataUrl, schema.schema);
|
||||
const obsCrossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
|
||||
prefetchEmbeddings(annoMatrix);
|
||||
|
||||
dispatch({
|
||||
type: "annoMatrix: init complete",
|
||||
annoMatrix,
|
||||
@@ -210,6 +222,6 @@ export default {
|
||||
annotationLabelCurrentSelection: annoActions.annotationLabelCurrentSelection,
|
||||
saveObsAnnotationsAction: annoActions.saveObsAnnotationsAction,
|
||||
needToSaveObsAnnotations: annoActions.needToSaveObsAnnotations,
|
||||
layoutChoiceAction: selnActions.layoutChoiceAction,
|
||||
layoutChoiceAction: embActions.layoutChoiceAction,
|
||||
setCellSetFromSelection: selnActions.setCellSetFromSelection,
|
||||
};
|
||||
|
||||
@@ -185,31 +185,6 @@ export const graphLassoEndAction = (embName, polygon) => async (
|
||||
});
|
||||
};
|
||||
|
||||
export const layoutChoiceAction = (newLayoutChoice) => async (
|
||||
dispatch,
|
||||
getState
|
||||
) => {
|
||||
/*
|
||||
On layout choice, make sure we have selected all on the previous layout, AND the new
|
||||
layout.
|
||||
*/
|
||||
const { obsCrossfilter: prevObsCrossfilter, layoutChoice } = getState();
|
||||
|
||||
let obsCrossfilter = await prevObsCrossfilter.select(
|
||||
"emb",
|
||||
layoutChoice.current,
|
||||
{ mode: "all" }
|
||||
);
|
||||
obsCrossfilter = await obsCrossfilter.select("emb", newLayoutChoice, {
|
||||
mode: "all",
|
||||
});
|
||||
dispatch({
|
||||
type: "set layout choice",
|
||||
layoutChoice: newLayoutChoice,
|
||||
obsCrossfilter,
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
Differential expression set selection
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,12 @@ stack multiple subsets.
|
||||
If these conventions change, code elsewhere (eg. menubar/clip.js) will need to
|
||||
change as well.
|
||||
*/
|
||||
import { AnnoMatrixObsCrossfilter, clip, isubsetMask } from "../annoMatrix";
|
||||
import { AnnoMatrixObsCrossfilter } from "../annoMatrix";
|
||||
import {
|
||||
_clipAnnoMatrix,
|
||||
_userSubsetAnnoMatrix,
|
||||
_userResetSubsetAnnoMatrix,
|
||||
} from "../util/stateManager/viewStackHelpers";
|
||||
|
||||
export const clipAction = (min, max) => (dispatch, getState) => {
|
||||
/*
|
||||
@@ -19,9 +24,7 @@ export const clipAction = (min, max) => (dispatch, getState) => {
|
||||
view is ALWAYS the top view.
|
||||
*/
|
||||
const { annoMatrix: prevAnnoMatrix } = getState();
|
||||
const annoMatrix = prevAnnoMatrix.isClipped
|
||||
? clip(prevAnnoMatrix.viewOf, min, max)
|
||||
: clip(prevAnnoMatrix, min, max);
|
||||
const annoMatrix = _clipAnnoMatrix(prevAnnoMatrix, min, max);
|
||||
const obsCrossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
|
||||
dispatch({
|
||||
type: "set clip quantiles",
|
||||
@@ -43,24 +46,10 @@ export const subsetAction = () => (dispatch, getState) => {
|
||||
annoMatrix: prevAnnoMatrix,
|
||||
obsCrossfilter: prevObsCrossfilter,
|
||||
} = getState();
|
||||
|
||||
let annoMatrix;
|
||||
if (prevAnnoMatrix.isClipped) {
|
||||
// if there is a clip view, pop it and reapply after we subset
|
||||
const { clipRange } = prevAnnoMatrix;
|
||||
annoMatrix = isubsetMask(
|
||||
prevAnnoMatrix.viewOf,
|
||||
prevObsCrossfilter.allSelectedMask()
|
||||
);
|
||||
annoMatrix = clip(annoMatrix, ...clipRange);
|
||||
} else {
|
||||
// else just push a subset view.
|
||||
annoMatrix = isubsetMask(
|
||||
prevAnnoMatrix,
|
||||
prevObsCrossfilter.allSelectedMask()
|
||||
);
|
||||
}
|
||||
|
||||
const annoMatrix = _userSubsetAnnoMatrix(
|
||||
prevAnnoMatrix,
|
||||
prevObsCrossfilter.allSelectedMask()
|
||||
);
|
||||
const obsCrossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
|
||||
dispatch({
|
||||
type: "subset to selection",
|
||||
@@ -77,20 +66,7 @@ export const resetSubsetAction = () => (dispatch, getState) => {
|
||||
*/
|
||||
|
||||
const { annoMatrix: prevAnnoMatrix } = getState();
|
||||
|
||||
const clipRange = prevAnnoMatrix.isClipped ? prevAnnoMatrix.clipRange : null;
|
||||
|
||||
/* pop all views */
|
||||
let annoMatrix = prevAnnoMatrix;
|
||||
while (annoMatrix.isView) {
|
||||
annoMatrix = annoMatrix.viewOf;
|
||||
}
|
||||
|
||||
/* re-apply the clip, if any */
|
||||
if (clipRange !== null) {
|
||||
annoMatrix = clip(annoMatrix, ...clipRange);
|
||||
}
|
||||
|
||||
const annoMatrix = _userResetSubsetAnnoMatrix(prevAnnoMatrix);
|
||||
const obsCrossfilter = new AnnoMatrixObsCrossfilter(annoMatrix);
|
||||
dispatch({
|
||||
type: "reset subset",
|
||||
|
||||
Reference in New Issue
Block a user