layout change UI (#776)

* add layout to schema

* add layout choice action and reducer

* multi layout UI

* update unit tests

* add missing file

* update test schema

* fix duplicate test id

* fix tabs

* PR lint

* fix pytest
This commit is contained in:
Bruce Martin
2019-05-22 13:21:33 -07:00
committed by GitHub
parent 63af79d3f8
commit 2357d0c1b8
13 changed files with 223 additions and 63 deletions
+26 -4
View File
@@ -20,10 +20,11 @@ const CrossfilterReducer = (
) => {
switch (action.type) {
case "initial data load complete (universe exists)": {
const { world } = nextSharedState;
const { world, layoutChoice } = nextSharedState;
const crossfilter = World.createObsDimensions(
new Crossfilter(world.obsAnnotations),
world
world,
layoutChoice.currentDimNames
);
return crossfilter;
}
@@ -43,9 +44,13 @@ const CrossfilterReducer = (
case "set clip quantiles":
case "set World to current selection": {
const { userDefinedGenes, diffexpGenes } = prevSharedState.controls;
const { world } = nextSharedState;
const { world, layoutChoice } = nextSharedState;
let crossfilter = new Crossfilter(world.obsAnnotations);
crossfilter = World.createObsDimensions(crossfilter, world);
crossfilter = World.createObsDimensions(
crossfilter,
world,
layoutChoice.currentDimNames
);
crossfilter = ControlsHelpers.createGeneDimensions(
userDefinedGenes,
diffexpGenes,
@@ -55,6 +60,23 @@ const CrossfilterReducer = (
return crossfilter;
}
case "set layout choice": {
/*
when switching layouts:
- delete the existing XY index
- add the new XY index (which implicitly selects all on it)
*/
const { world, layoutChoice } = nextSharedState;
return state
.delDimension(layoutDimensionName("XY"))
.addDimension(
layoutDimensionName("XY"),
"spatial",
world.obsLayout.col(layoutChoice.currentDimNames[0]).asArray(),
world.obsLayout.col(layoutChoice.currentDimNames[1]).asArray()
);
}
case "request user defined gene success": {
const { world } = prevSharedState;
const gene = action.data.genes[0];
+2 -1
View File
@@ -7,7 +7,8 @@ const GraphSelection = (
) => {
switch (action.type) {
case "set clip quantiles":
case "reset World to eq Universe": {
case "reset World to eq Universe":
case "set layout choice": {
return {
...state,
selection: {
+28 -25
View File
@@ -12,6 +12,7 @@ import graphSelection from "./graphSelection";
import crossfilter from "./crossfilter";
import colors from "./colors";
import differential from "./differential";
import layoutChoice from "./layoutChoice";
import responsive from "./responsive";
import controls from "./controls";
import resetCache from "./resetCache";
@@ -19,31 +20,33 @@ import resetCache from "./resetCache";
import undoableConfig from "./undoableConfig";
const Reducer = undoable(
cascadeReducers([
["config", config],
["universe", universe],
["world", world],
["categoricalSelection", categoricalSelection],
["continuousSelection", continuousSelection],
["graphSelection", graphSelection],
["crossfilter", crossfilter],
["colors", colors],
["controls", controls],
["differential", differential],
["responsive", responsive],
["resetCache", resetCache]
]),
[
"world",
"categoricalSelection",
"continuousSelection",
"graphSelection",
"crossfilter",
"colors",
"controls",
"differential"
],
undoableConfig
cascadeReducers([
["config", config],
["universe", universe],
["world", world],
["layoutChoice", layoutChoice],
["categoricalSelection", categoricalSelection],
["continuousSelection", continuousSelection],
["graphSelection", graphSelection],
["crossfilter", crossfilter],
["colors", colors],
["controls", controls],
["differential", differential],
["responsive", responsive],
["resetCache", resetCache]
]),
[
"world",
"categoricalSelection",
"continuousSelection",
"graphSelection",
"crossfilter",
"colors",
"controls",
"differential",
"layoutChoice"
],
undoableConfig
);
const store = createStore(Reducer, applyMiddleware(thunk));
+50
View File
@@ -0,0 +1,50 @@
/*
we have a UI heuristic to pick the default layout, based on assumptions
about commonly used names. Preferentially, pick in the following order:
1. "umap"
2. "tsne"
3. "pca"
4. give up, use the first available
*/
function bestDefaultLayout(layouts) {
const preferredNames = ["umap", "tsne", "pca"];
const idx = preferredNames.findIndex(name => layouts.indexOf(name) !== -1);
if (idx !== -1) return preferredNames[idx];
return layouts[0];
}
const LayoutChoice = (
state = {
available: [], // all available choices
current: undefined, // name of the current layout, eg, 'umap'
currentDimNames: [] // dimension name
},
action,
nextSharedState
) => {
switch (action.type) {
case "initial data load complete (universe exists)":
case "reset World to eq Universe": {
// set default to default
const { schema } = nextSharedState.world;
const available = schema.layout.obs.map(v => v.name);
const current = bestDefaultLayout(available);
const currentDimNames = schema.layout.obsByName[current].dims;
return { available, current, currentDimNames };
}
case "set layout choice": {
const { schema } = nextSharedState.world;
const current = action.layoutChoice;
const currentDimNames = schema.layout.obsByName[current].dims;
return { ...state, current, currentDimNames };
}
default: {
return state;
}
}
};
export default LayoutChoice;
+3 -1
View File
@@ -72,7 +72,9 @@ const saveOnActions = new Set([
"store current cell selection as differential set 2",
"set World to current selection",
"set clip quantiles"
"set clip quantiles",
"set layout choice"
]);
/**