mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-03 03:08:12 +08:00
crossfilter
This commit is contained in:
@@ -42,8 +42,23 @@ class HistogramBrush extends React.Component {
|
|||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
|
|
||||||
}
|
}
|
||||||
onBrush(e) {
|
onBrush(selection, x) {
|
||||||
console.log('brushed', e)
|
return () => {
|
||||||
|
if (d3.event.selection) {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: "continuous metadata histogram brush",
|
||||||
|
selection: this.props.metadataField,
|
||||||
|
range: [x(d3.event.selection[0]), x(d3.event.selection[1])]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.props.dispatch({
|
||||||
|
type: "continuous metadata histogram brush",
|
||||||
|
selection: this.props.metadataField,
|
||||||
|
range: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
drawHistogram(svgRef) {
|
drawHistogram(svgRef) {
|
||||||
|
|
||||||
@@ -77,13 +92,12 @@ class HistogramBrush extends React.Component {
|
|||||||
.attr("height", function(d) { return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length); });
|
.attr("height", function(d) { return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length); });
|
||||||
|
|
||||||
if (!this.state.brush && !this.state.axis) {
|
if (!this.state.brush && !this.state.axis) {
|
||||||
console.log('whee')
|
|
||||||
const brush = d3.select(svgRef)
|
const brush = d3.select(svgRef)
|
||||||
.append('g')
|
.append('g')
|
||||||
.attr('class', 'brush')
|
.attr('class', 'brush')
|
||||||
.call(
|
.call(
|
||||||
d3.brushX()
|
d3.brushX()
|
||||||
.on('end', this.onBrush)
|
.on('end', this.onBrush(this.props.metadataField, x.invert).bind(this))
|
||||||
)
|
)
|
||||||
|
|
||||||
const xAxis = d3.select(svgRef)
|
const xAxis = d3.select(svgRef)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const updateCellSelectionMiddleware = (store) => {
|
|||||||
/* this is a hardcoded map of the things we need to keep an eye on and update global cell selection in response to */
|
/* this is a hardcoded map of the things we need to keep an eye on and update global cell selection in response to */
|
||||||
const filterJustChanged =
|
const filterJustChanged =
|
||||||
action.type === "continuous selection using parallel coords brushing" ||
|
action.type === "continuous selection using parallel coords brushing" ||
|
||||||
|
action.type === "continuous metadata histogram brush" ||
|
||||||
action.type === "graph brush selection change" ||
|
action.type === "graph brush selection change" ||
|
||||||
action.type === "graph brush deselect" ||
|
action.type === "graph brush deselect" ||
|
||||||
action.type === "categorical metadata filter deselect" ||
|
action.type === "categorical metadata filter deselect" ||
|
||||||
@@ -114,6 +115,49 @@ const updateCellSelectionMiddleware = (store) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Continuous histograms ___---^^^^--[------__]__---___
|
||||||
|
|
||||||
|
Create newContinuousUserDefinedRanges
|
||||||
|
Filter based on them
|
||||||
|
*/
|
||||||
|
|
||||||
|
let newContinuousUserDefinedRanges = s.controls.continuousUserDefinedRanges;
|
||||||
|
|
||||||
|
|
||||||
|
/* check if this is the action and take care of that metadata field */
|
||||||
|
if (action.type === "continuous metadata histogram brush") {
|
||||||
|
/*
|
||||||
|
was this a deselect? if so it will be null
|
||||||
|
was it a select? set the new range [20, 50]
|
||||||
|
we overload this because it is less if statements thru the whole system
|
||||||
|
but it's invisible here, thus comment.
|
||||||
|
*/
|
||||||
|
newContinuousUserDefinedRanges[action.selection] = action.range;
|
||||||
|
}
|
||||||
|
|
||||||
|
let activeContinuousHistogramFilters = [];
|
||||||
|
|
||||||
|
_.each(newContinuousUserDefinedRanges, (value, key, i) => {
|
||||||
|
if (value !== null) {
|
||||||
|
activeContinuousHistogramFilters.push(key)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/* see if there are others from previous... */
|
||||||
|
if (activeContinuousHistogramFilters.length > 0) {
|
||||||
|
_.each(activeContinuousHistogramFilters, (key) => {
|
||||||
|
_.each(newSelection, (cell, i) => {
|
||||||
|
if (
|
||||||
|
+cell[key] < newContinuousUserDefinedRanges[key][0] ||
|
||||||
|
+cell[key] > newContinuousUserDefinedRanges[key][1]
|
||||||
|
) {
|
||||||
|
newSelection[i]["__selected__"] = false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
1. figure out if the users have unchecked boxes
|
1. figure out if the users have unchecked boxes
|
||||||
2. put them in an array
|
2. put them in an array
|
||||||
@@ -183,18 +227,19 @@ const updateCellSelectionMiddleware = (store) => {
|
|||||||
if (inactiveCategories.length > 0) {
|
if (inactiveCategories.length > 0) {
|
||||||
_.each(inactiveCategories, (d) => {
|
_.each(inactiveCategories, (d) => {
|
||||||
_.each(newSelection, (cell, i) => {
|
_.each(newSelection, (cell, i) => {
|
||||||
if (""+cell[d.category] === ""+d.option) { /* nums and strings to strings */
|
if (""+cell[d.category] === ""+d.option) { /* nums and strings to strings -__- */
|
||||||
newSelection[i]["__selected__"] = false;
|
newSelection[i]["__selected__"] = false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let modifiedAction = Object.assign({}, action, {
|
let modifiedAction = Object.assign({}, action, {
|
||||||
newSelection,
|
newSelection,
|
||||||
newCategoricalAsBooleansMap,
|
newCategoricalAsBooleansMap,
|
||||||
|
newContinuousUserDefinedRanges,
|
||||||
}) /* append the result of all the filters to the action the user just triggered */
|
}) /* append the result of all the filters to the action the user just triggered */
|
||||||
|
|
||||||
return next(modifiedAction);
|
return next(modifiedAction);
|
||||||
|
|||||||
Vendored
+13
@@ -42,6 +42,7 @@ const Controls = (state = {
|
|||||||
we mutate this map in the actions below
|
we mutate this map in the actions below
|
||||||
*/
|
*/
|
||||||
const categoricalAsBooleansMap = {};
|
const categoricalAsBooleansMap = {};
|
||||||
|
const continuousUserDefinedRanges = {};
|
||||||
_.each(action.data.data.ranges, (value, key) => {
|
_.each(action.data.data.ranges, (value, key) => {
|
||||||
if (
|
if (
|
||||||
key !== "CellName" &&
|
key !== "CellName" &&
|
||||||
@@ -52,13 +53,20 @@ const Controls = (state = {
|
|||||||
optionsAsBooleans[_key] = true;
|
optionsAsBooleans[_key] = true;
|
||||||
})
|
})
|
||||||
categoricalAsBooleansMap[key] = optionsAsBooleans;
|
categoricalAsBooleansMap[key] = optionsAsBooleans;
|
||||||
|
} else if (
|
||||||
|
key !== "CellName" &&
|
||||||
|
value.range
|
||||||
|
) {
|
||||||
|
continuousUserDefinedRanges[key] = null;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
allCellsOnClient: action.data.data,
|
allCellsOnClient: action.data.data,
|
||||||
currentCellSelection,
|
currentCellSelection,
|
||||||
graphMap,
|
graphMap,
|
||||||
categoricalAsBooleansMap,
|
categoricalAsBooleansMap,
|
||||||
|
continuousUserDefinedRanges,
|
||||||
graphBrushSelection: null, /* if we are getting new cells from the server, the layout (probably? definitely?) just changed, so this is now irrelevant, and we WILL need to call a function to reset state of this kind when cells success happens */
|
graphBrushSelection: null, /* if we are getting new cells from the server, the layout (probably? definitely?) just changed, so this is now irrelevant, and we WILL need to call a function to reset state of this kind when cells success happens */
|
||||||
});
|
});
|
||||||
/* * * * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * * * *
|
||||||
@@ -84,6 +92,11 @@ const Controls = (state = {
|
|||||||
graphBrushSelection: null,
|
graphBrushSelection: null,
|
||||||
currentCellSelection: action.newSelection /* this comes from middleware */
|
currentCellSelection: action.newSelection /* this comes from middleware */
|
||||||
})
|
})
|
||||||
|
case "continuous metadata histogram brush":
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
newContinuousUserDefinedRanges: action.newContinuousUserDefinedRanges, /* this has already been applied in middleware but store it for next time */
|
||||||
|
currentCellSelection: action.newSelection /* this comes from middleware */
|
||||||
|
})
|
||||||
case "change opacity deselected cells in 2d graph background":
|
case "change opacity deselected cells in 2d graph background":
|
||||||
return Object.assign({}, state, {
|
return Object.assign({}, state, {
|
||||||
opacityForDeselectedCells: action.data,
|
opacityForDeselectedCells: action.data,
|
||||||
|
|||||||
Reference in New Issue
Block a user