mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-30 05:18:11 +08:00
add context sensitivity to annotation "label" menu item (#1015)
* cache common results to reduce jank * add util function in support of annotation labelling * enable/disable annotation edit menus per issue 972; improve formatting * PR review requests
This commit is contained in:
@@ -3,8 +3,8 @@ import _ from "lodash";
|
||||
import Crossfilter from "../util/typedCrossfilter";
|
||||
import {
|
||||
World,
|
||||
ControlsHelpers as CH,
|
||||
AnnotationsHelpers as AH
|
||||
ControlsHelpers,
|
||||
AnnotationsHelpers
|
||||
} from "../util/stateManager";
|
||||
import {
|
||||
layoutDimensionName,
|
||||
@@ -37,13 +37,16 @@ const CrossfilterReducerBase = (
|
||||
const { userDefinedGenes, diffexpGenes } = prevSharedState.controls;
|
||||
const { world } = nextSharedState;
|
||||
let { crossfilter } = prevSharedState.resetCache;
|
||||
crossfilter = CH.createGeneDimensions(
|
||||
crossfilter = ControlsHelpers.createGeneDimensions(
|
||||
userDefinedGenes,
|
||||
diffexpGenes,
|
||||
world,
|
||||
crossfilter
|
||||
);
|
||||
crossfilter = AH.createWritableAnnotationDimensions(world, crossfilter);
|
||||
crossfilter = AnnotationsHelpers.createWritableAnnotationDimensions(
|
||||
world,
|
||||
crossfilter
|
||||
);
|
||||
return crossfilter;
|
||||
}
|
||||
|
||||
@@ -57,7 +60,7 @@ const CrossfilterReducerBase = (
|
||||
world,
|
||||
layoutChoice.currentDimNames
|
||||
);
|
||||
crossfilter = CH.createGeneDimensions(
|
||||
crossfilter = ControlsHelpers.createGeneDimensions(
|
||||
userDefinedGenes,
|
||||
diffexpGenes,
|
||||
world,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { unassignedCategoryLabel } from "../globals";
|
||||
import {
|
||||
World,
|
||||
ControlsHelpers as CH,
|
||||
AnnotationsHelpers as AH
|
||||
ControlsHelpers,
|
||||
AnnotationsHelpers
|
||||
} from "../util/stateManager";
|
||||
|
||||
const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
@@ -35,7 +35,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
Object.keys(action.expressionData)
|
||||
)
|
||||
];
|
||||
varData = CH.pruneVarDataCache(varData, allTheGenesWeNeed);
|
||||
varData = ControlsHelpers.pruneVarDataCache(varData, allTheGenesWeNeed);
|
||||
return { ...state, varData };
|
||||
}
|
||||
|
||||
@@ -63,9 +63,14 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
let data;
|
||||
if (categoryToDuplicate) {
|
||||
/* duplicate the named annotation */
|
||||
schema = AH.dupObsAnnoSchema(state.schema, categoryToDuplicate, name, {
|
||||
writable: true
|
||||
});
|
||||
schema = AnnotationsHelpers.dupObsAnnoSchema(
|
||||
state.schema,
|
||||
categoryToDuplicate,
|
||||
name,
|
||||
{
|
||||
writable: true
|
||||
}
|
||||
);
|
||||
/* if we are duplicating a non-writable annotation, it may not have an unassigned category */
|
||||
const s = schema.annotations.obsByName[categoryToDuplicate];
|
||||
if (s.categories.indexOf(unassignedCategoryLabel) === -1) {
|
||||
@@ -75,7 +80,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
} else {
|
||||
/* else, all are unassined */
|
||||
const categories = [unassignedCategoryLabel];
|
||||
schema = AH.addObsAnnoSchema(state.schema, name, {
|
||||
schema = AnnotationsHelpers.addObsAnnoSchema(state.schema, name, {
|
||||
name,
|
||||
categories,
|
||||
type: "categorical",
|
||||
@@ -92,7 +97,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
/* change the name of an obs annotation category */
|
||||
const name = action.metadataField;
|
||||
const newName = action.newCategoryText;
|
||||
if (!AH.isUserAnnotation(state, name))
|
||||
if (!AnnotationsHelpers.isUserAnnotation(state, name))
|
||||
throw new Error("unable to edit read-only annotation");
|
||||
if (typeof newName !== "string" || newName.length === 0)
|
||||
throw new Error("user annotations require string name");
|
||||
@@ -101,8 +106,8 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
...state.schema.annotations.obsByName[name],
|
||||
name: newName
|
||||
};
|
||||
const schema = AH.addObsAnnoSchema(
|
||||
AH.removeObsAnnoSchema(state.schema, name),
|
||||
const schema = AnnotationsHelpers.addObsAnnoSchema(
|
||||
AnnotationsHelpers.removeObsAnnoSchema(state.schema, name),
|
||||
newName,
|
||||
colSchema
|
||||
);
|
||||
@@ -113,10 +118,10 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
case "annotation: delete category": {
|
||||
/* delete annotation category from schema and obsAnnotations */
|
||||
const name = action.metadataField;
|
||||
if (!AH.isUserAnnotation(state, name))
|
||||
if (!AnnotationsHelpers.isUserAnnotation(state, name))
|
||||
throw new Error("unable to delete read-only annotation");
|
||||
|
||||
const schema = AH.removeObsAnnoSchema(state.schema, name);
|
||||
const schema = AnnotationsHelpers.removeObsAnnoSchema(state.schema, name);
|
||||
const obsAnnotations = state.obsAnnotations.dropCol(name);
|
||||
return { ...state, schema, obsAnnotations };
|
||||
}
|
||||
@@ -124,7 +129,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
case "annotation: add new label to category": {
|
||||
const annotationName = action.metadataField;
|
||||
const newLabelName = action.newLabelText;
|
||||
if (!AH.isUserAnnotation(state, annotationName))
|
||||
if (!AnnotationsHelpers.isUserAnnotation(state, annotationName))
|
||||
throw new Error("unable to modify read-only annotation");
|
||||
if (typeof newLabelName !== "string" || newLabelName.length === 0)
|
||||
throw new Error(
|
||||
@@ -132,7 +137,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
);
|
||||
|
||||
/* add the new label to the annotation */
|
||||
const schema = AH.addObsAnnoCategory(
|
||||
const schema = AnnotationsHelpers.addObsAnnoCategory(
|
||||
state.schema,
|
||||
annotationName,
|
||||
newLabelName
|
||||
@@ -144,7 +149,7 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
const annotationName = action.metadataField;
|
||||
const oldLabelName = action.label;
|
||||
const newLabelName = action.editedLabel;
|
||||
if (!AH.isUserAnnotation(state, annotationName))
|
||||
if (!AnnotationsHelpers.isUserAnnotation(state, annotationName))
|
||||
throw new Error("unable to modify read-only annotation");
|
||||
if (typeof newLabelName !== "string" || newLabelName.length === 0)
|
||||
throw new Error(
|
||||
@@ -152,14 +157,18 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
);
|
||||
|
||||
/* remove old label, add new label */
|
||||
const schema = AH.addObsAnnoCategory(
|
||||
AH.removeObsAnnoCategory(state.schema, annotationName, oldLabelName),
|
||||
const schema = AnnotationsHelpers.addObsAnnoCategory(
|
||||
AnnotationsHelpers.removeObsAnnoCategory(
|
||||
state.schema,
|
||||
annotationName,
|
||||
oldLabelName
|
||||
),
|
||||
annotationName,
|
||||
newLabelName
|
||||
);
|
||||
|
||||
/* change all values in obsAnnotation */
|
||||
const obsAnnotations = AH.setLabelByValue(
|
||||
const obsAnnotations = AnnotationsHelpers.setLabelByValue(
|
||||
state.obsAnnotations,
|
||||
annotationName,
|
||||
oldLabelName,
|
||||
@@ -173,20 +182,20 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
/* delete the label from the annotation, and set all cells with this value to unassigned */
|
||||
const annotationName = action.metadataField;
|
||||
const labelName = action.label;
|
||||
if (!AH.isUserAnnotation(state, annotationName))
|
||||
if (!AnnotationsHelpers.isUserAnnotation(state, annotationName))
|
||||
throw new Error("unable to modify read-only annotation");
|
||||
if (labelName === unassignedCategoryLabel)
|
||||
throw new Error("may not remove the unassigned label");
|
||||
|
||||
/* remove the category from the schema */
|
||||
const schema = AH.removeObsAnnoCategory(
|
||||
const schema = AnnotationsHelpers.removeObsAnnoCategory(
|
||||
state.schema,
|
||||
annotationName,
|
||||
labelName
|
||||
);
|
||||
|
||||
/* set all values to unassigned in obsAnnotations */
|
||||
const obsAnnotations = AH.setLabelByValue(
|
||||
const obsAnnotations = AnnotationsHelpers.setLabelByValue(
|
||||
state.obsAnnotations,
|
||||
annotationName,
|
||||
labelName,
|
||||
@@ -207,8 +216,12 @@ const Universe = (state = null, action, nextSharedState, prevSharedState) => {
|
||||
const worldMask = crossfilter.allSelectedMask();
|
||||
const mask = World.worldEqUniverse(world, state)
|
||||
? worldMask
|
||||
: AH.worldToUniverseMask(worldMask, world.obsAnnotations, state.nObs);
|
||||
const obsAnnotations = AH.setLabelByMask(
|
||||
: AnnotationsHelpers.worldToUniverseMask(
|
||||
worldMask,
|
||||
world.obsAnnotations,
|
||||
state.nObs
|
||||
);
|
||||
const obsAnnotations = AnnotationsHelpers.setLabelByMask(
|
||||
state.obsAnnotations,
|
||||
metadataField,
|
||||
mask,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { unassignedCategoryLabel } from "../globals";
|
||||
import {
|
||||
World,
|
||||
ControlsHelpers as CH,
|
||||
AnnotationsHelpers as AH
|
||||
ControlsHelpers,
|
||||
AnnotationsHelpers
|
||||
} from "../util/stateManager";
|
||||
import clip from "../util/clip";
|
||||
import quantile from "../util/quantile";
|
||||
@@ -92,7 +92,7 @@ const WorldReducer = (
|
||||
Object.keys(action.expressionData)
|
||||
)
|
||||
];
|
||||
unclippedVarData = CH.pruneVarDataCache(
|
||||
unclippedVarData = ControlsHelpers.pruneVarDataCache(
|
||||
unclippedVarData,
|
||||
allTheGenesWeNeed
|
||||
);
|
||||
@@ -208,7 +208,7 @@ const WorldReducer = (
|
||||
/* set all values to to new label */
|
||||
const unclipped = {
|
||||
...state.unclipped,
|
||||
obsAnnotations: AH.setLabelByValue(
|
||||
obsAnnotations: AnnotationsHelpers.setLabelByValue(
|
||||
state.unclipped.obsAnnotations,
|
||||
metadataField,
|
||||
oldLabelName,
|
||||
@@ -229,7 +229,7 @@ const WorldReducer = (
|
||||
/* set all values to unassigned in obsAnnotations */
|
||||
const unclipped = {
|
||||
...state.unclipped,
|
||||
obsAnnotations: AH.setLabelByValue(
|
||||
obsAnnotations: AnnotationsHelpers.setLabelByValue(
|
||||
state.unclipped.obsAnnotations,
|
||||
metadataField,
|
||||
label,
|
||||
@@ -249,7 +249,7 @@ const WorldReducer = (
|
||||
const mask = crossfilter.allSelectedMask();
|
||||
const unclipped = {
|
||||
...state.unclipped,
|
||||
obsAnnotations: AH.setLabelByMask(
|
||||
obsAnnotations: AnnotationsHelpers.setLabelByMask(
|
||||
state.unclipped.obsAnnotations,
|
||||
metadataField,
|
||||
mask,
|
||||
|
||||
Reference in New Issue
Block a user