mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-05 23:58:11 +08:00
refactor categorical controls state (#1549)
* refactor categorical controls state * lint * fix race condition in tests * fix typo * add missing update on subset * remove obsolete code * update jest and puppeteer major version; update all minors * update when label changes * remove lint from tests; increase timeouts in e2e tests * changes in response to PR review * lint * more PR comment changes * more PR comment fixes * lint * more PR comment resolutions
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
import { ControlsHelpers as CH } from "../util/stateManager";
|
||||
|
||||
const CategoricalSelection = (
|
||||
state,
|
||||
action,
|
||||
nextSharedState,
|
||||
prevSharedState
|
||||
) => {
|
||||
/*
|
||||
State is an object, with a key for each categorical annotation, and a
|
||||
value which is a Map of label->t/f, reflecting selection state for the label.
|
||||
|
||||
Label state default (if missing) is up to the component, but typically true.
|
||||
|
||||
{
|
||||
"louvain": Map(),
|
||||
...
|
||||
}
|
||||
*/
|
||||
const CategoricalSelection = (state, action, nextSharedState) => {
|
||||
switch (action.type) {
|
||||
case "initial data load complete (universe exists)":
|
||||
case "set World to current selection":
|
||||
@@ -13,11 +19,7 @@ const CategoricalSelection = (
|
||||
case "set clip quantiles": {
|
||||
const { world } = nextSharedState;
|
||||
const newState = CH.createCategoricalSelection(
|
||||
world,
|
||||
CH.selectableCategoryNames(
|
||||
world.schema,
|
||||
CH.maxCategoryItems(prevSharedState.config)
|
||||
)
|
||||
CH.selectableCategoryNames(world.schema)
|
||||
);
|
||||
return newState;
|
||||
}
|
||||
@@ -30,13 +32,12 @@ const CategoricalSelection = (
|
||||
const { world } = nextSharedState;
|
||||
const names = CH.selectableCategoryNames(
|
||||
world.schema,
|
||||
CH.maxCategoryItems(prevSharedState.config),
|
||||
dataframe.colIndex.labels()
|
||||
);
|
||||
if (names.length === 0) return state;
|
||||
return {
|
||||
...state,
|
||||
...CH.createCategoricalSelection(world, names),
|
||||
...CH.createCategoricalSelection(names),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,16 +45,12 @@ const CategoricalSelection = (
|
||||
/*
|
||||
Set the specific category in this field to false
|
||||
*/
|
||||
const newCategoryValueSelected = Array.from(
|
||||
state[action.metadataField].categoryValueSelected
|
||||
);
|
||||
newCategoryValueSelected[action.categoryIndex] = true;
|
||||
const { metadataField, label } = action;
|
||||
const newSelected = new Map(state[metadataField]);
|
||||
newSelected.set(label, true);
|
||||
const newCategoricalSelection = {
|
||||
...state,
|
||||
[action.metadataField]: {
|
||||
...state[action.metadataField],
|
||||
categoryValueSelected: newCategoryValueSelected,
|
||||
},
|
||||
[action.metadataField]: newSelected,
|
||||
};
|
||||
return newCategoricalSelection;
|
||||
}
|
||||
@@ -62,16 +59,12 @@ const CategoricalSelection = (
|
||||
/*
|
||||
Set the specific category in this field to false
|
||||
*/
|
||||
const newCategoryValueSelected = Array.from(
|
||||
state[action.metadataField].categoryValueSelected
|
||||
);
|
||||
newCategoryValueSelected[action.categoryIndex] = false;
|
||||
const { metadataField, label } = action;
|
||||
const newSelected = new Map(state[metadataField]);
|
||||
newSelected.set(label, false);
|
||||
const newCategoricalSelection = {
|
||||
...state,
|
||||
[action.metadataField]: {
|
||||
...state[action.metadataField],
|
||||
categoryValueSelected: newCategoryValueSelected,
|
||||
},
|
||||
[action.metadataField]: newSelected,
|
||||
};
|
||||
return newCategoricalSelection;
|
||||
}
|
||||
@@ -80,15 +73,13 @@ const CategoricalSelection = (
|
||||
/*
|
||||
set all categories in this field to false.
|
||||
*/
|
||||
const { metadataField, labels } = action;
|
||||
const { selected } = state[metadataField];
|
||||
const newSelected = new Map(selected);
|
||||
labels.forEach((label) => newSelected.set(label, false));
|
||||
const newCategoricalSelection = {
|
||||
...state,
|
||||
[action.metadataField]: {
|
||||
...state[action.metadataField],
|
||||
categorySelected: false,
|
||||
categoryValueSelected: Array.from(
|
||||
state[action.metadataField].categoryValueSelected
|
||||
).fill(false),
|
||||
},
|
||||
[action.metadataField]: newSelected,
|
||||
};
|
||||
return newCategoricalSelection;
|
||||
}
|
||||
@@ -97,25 +88,22 @@ const CategoricalSelection = (
|
||||
/*
|
||||
set all categories in this field to true.
|
||||
*/
|
||||
const { metadataField, labels } = action;
|
||||
const { selected } = state[metadataField];
|
||||
const newSelected = new Map(selected);
|
||||
labels.forEach((label) => newSelected.set(label, true));
|
||||
const newCategoricalSelection = {
|
||||
...state,
|
||||
[action.metadataField]: {
|
||||
...state[action.metadataField],
|
||||
categorySelected: true,
|
||||
categoryValueSelected: Array.from(
|
||||
state[action.metadataField].categoryValueSelected
|
||||
).fill(true),
|
||||
},
|
||||
[action.metadataField]: newSelected,
|
||||
};
|
||||
return newCategoricalSelection;
|
||||
}
|
||||
|
||||
case "annotation: create category": {
|
||||
const { world } = nextSharedState;
|
||||
const name = action.data;
|
||||
return {
|
||||
...state,
|
||||
...CH.createCategoricalSelection(world, [name]),
|
||||
...CH.createCategoricalSelection([name]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -138,12 +126,11 @@ const CategoricalSelection = (
|
||||
case "annotation: label edited":
|
||||
case "annotation: delete label": {
|
||||
/* need to rebuild the state for this annotation */
|
||||
const { world } = nextSharedState;
|
||||
const name = action.metadataField;
|
||||
const { [name]: _, ...partialState } = state;
|
||||
return {
|
||||
...partialState,
|
||||
...CH.createCategoricalSelection(world, [name]),
|
||||
...CH.createCategoricalSelection([name]),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -26,14 +26,7 @@ const centroidLabels = (state = initialState, action, sharedNextState) => {
|
||||
...state,
|
||||
labels:
|
||||
!!colorAccessor && showLabels && !!categoricalSelection[colorAccessor]
|
||||
? calcCentroid(
|
||||
world.obsAnnotations,
|
||||
world.obsLayout,
|
||||
colorAccessor,
|
||||
layoutChoice.currentDimNames,
|
||||
categoricalSelection,
|
||||
world.schema.annotations.obsByName
|
||||
)
|
||||
? calcCentroid(world, colorAccessor, layoutChoice.currentDimNames)
|
||||
: [],
|
||||
};
|
||||
|
||||
@@ -52,12 +45,9 @@ const centroidLabels = (state = initialState, action, sharedNextState) => {
|
||||
return {
|
||||
...state,
|
||||
labels: calcCentroid(
|
||||
world.obsAnnotations,
|
||||
world.obsLayout,
|
||||
world,
|
||||
colorAccessor,
|
||||
layoutChoice.currentDimNames,
|
||||
categoricalSelection,
|
||||
world.schema.annotations.obsByName
|
||||
layoutChoice.currentDimNames
|
||||
),
|
||||
showLabels,
|
||||
};
|
||||
|
||||
@@ -260,10 +260,9 @@ const CrossfilterReducerBase = (
|
||||
|
||||
case "categorical metadata filter select":
|
||||
case "categorical metadata filter deselect": {
|
||||
const { categoricalSelection } = nextSharedState;
|
||||
const cat = categoricalSelection[action.metadataField];
|
||||
const { categoryValues, categoryValueSelected } = cat;
|
||||
const values = categoryValues.filter((v, i) => categoryValueSelected[i]);
|
||||
const { labels, metadataField } = action;
|
||||
const selected = nextSharedState.categoricalSelection[metadataField];
|
||||
const values = labels.filter((label) => selected.get(label) ?? true);
|
||||
return state.select(obsAnnoDimensionName(action.metadataField), {
|
||||
mode: "exact",
|
||||
values,
|
||||
|
||||
@@ -3,12 +3,8 @@ const initialState = {
|
||||
categoryField: "",
|
||||
};
|
||||
|
||||
const pointDialation = (state = initialState, action, sharedNextState) => {
|
||||
const { categoricalSelection } = sharedNextState;
|
||||
const { metadataField, categoryIndex } = action;
|
||||
const categoryField =
|
||||
action.categoryField ||
|
||||
categoricalSelection?.[metadataField]?.categoryValues[categoryIndex];
|
||||
const pointDialation = (state = initialState, action) => {
|
||||
const { metadataField, label: categoryField } = action;
|
||||
|
||||
switch (action.type) {
|
||||
case "category value mouse hover start":
|
||||
|
||||
Reference in New Issue
Block a user