mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-06 13:28:13 +08:00
improve selection interaction with clip changes (#744)
* brush interactions with underlying dataframe updates improved * improve comment * reset selection state upon clip
This commit is contained in:
@@ -38,12 +38,11 @@ class HistogramBrush extends React.Component {
|
|||||||
return varData.col(field);
|
return varData.col(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
calcHistogramCache = memoize((world, field) => {
|
calcHistogramCache = memoize((col, field) => {
|
||||||
/*
|
/*
|
||||||
recalculate expensive stuff, notably bins, summaries, etc.
|
recalculate expensive stuff, notably bins, summaries, etc.
|
||||||
*/
|
*/
|
||||||
const histogramCache = {};
|
const histogramCache = {};
|
||||||
const col = HistogramBrush.getColumn(world, field);
|
|
||||||
const values = col.asArray();
|
const values = col.asArray();
|
||||||
const summary = col.summarize();
|
const summary = col.summarize();
|
||||||
const { min: domainMin, max: domainMax } = summary;
|
const { min: domainMin, max: domainMax } = summary;
|
||||||
@@ -87,23 +86,42 @@ class HistogramBrush extends React.Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const { field, world, continuousSelection } = this.props;
|
const { field, world, continuousSelection } = this.props;
|
||||||
const { x, y, bins, svgRef } = this._histogram;
|
const { x, y, bins, svgRef } = this._histogram;
|
||||||
|
let { brushXselection, brushX } = this.state;
|
||||||
|
let forceBrushUpdate = false;
|
||||||
|
|
||||||
if (world !== prevProps.world) {
|
/*
|
||||||
this.renderAxesBrushBins(x, y, bins, svgRef, field);
|
Update our axis if the underlying dataframe column has changed
|
||||||
|
*/
|
||||||
|
const dfColumn = HistogramBrush.getColumn(world, field);
|
||||||
|
const oldDfColumn = HistogramBrush.getColumn(
|
||||||
|
prevProps.world,
|
||||||
|
prevProps.field
|
||||||
|
);
|
||||||
|
if (dfColumn !== oldDfColumn) {
|
||||||
|
({ brushXselection, brushX } = this.renderAxesBrushBins(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
bins,
|
||||||
|
svgRef,
|
||||||
|
field
|
||||||
|
));
|
||||||
|
forceBrushUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if the selection has changed, ensure that the brush correctly reflects
|
if the selection has changed, ensure that the brush correctly reflects
|
||||||
the underlying selection.
|
the underlying selection.
|
||||||
*/
|
*/
|
||||||
if (continuousSelection !== prevProps.continuousSelection) {
|
if (
|
||||||
|
forceBrushUpdate ||
|
||||||
|
continuousSelection !== prevProps.continuousSelection
|
||||||
|
) {
|
||||||
const { isObs, isUserDefined, isDiffExp } = this.props;
|
const { isObs, isUserDefined, isDiffExp } = this.props;
|
||||||
const myName = makeContinuousDimensionName(
|
const myName = makeContinuousDimensionName(
|
||||||
{ isObs, isUserDefined, isDiffExp },
|
{ isObs, isUserDefined, isDiffExp },
|
||||||
field
|
field
|
||||||
);
|
);
|
||||||
const range = continuousSelection[myName];
|
const range = continuousSelection[myName];
|
||||||
const { brushXselection, brushX } = this.state;
|
|
||||||
if (brushXselection) {
|
if (brushXselection) {
|
||||||
const selection = d3.brushSelection(brushXselection.node());
|
const selection = d3.brushSelection(brushXselection.node());
|
||||||
if (!range && selection) {
|
if (!range && selection) {
|
||||||
@@ -140,6 +158,8 @@ class HistogramBrush extends React.Component {
|
|||||||
|
|
||||||
// ignore programmatically generated events
|
// ignore programmatically generated events
|
||||||
if (!d3.event.sourceEvent) return;
|
if (!d3.event.sourceEvent) return;
|
||||||
|
// ignore cascading events, which are programmatically generated
|
||||||
|
if (d3.event.sourceEvent.sourceEvent) return;
|
||||||
|
|
||||||
if (d3.event.selection) {
|
if (d3.event.selection) {
|
||||||
dispatch({
|
dispatch({
|
||||||
@@ -175,6 +195,8 @@ class HistogramBrush extends React.Component {
|
|||||||
|
|
||||||
// ignore programmatically generated events
|
// ignore programmatically generated events
|
||||||
if (!d3.event.sourceEvent) return;
|
if (!d3.event.sourceEvent) return;
|
||||||
|
// ignore cascading events, which are programmatically generated
|
||||||
|
if (d3.event.sourceEvent.sourceEvent) return;
|
||||||
|
|
||||||
if (d3.event.selection) {
|
if (d3.event.selection) {
|
||||||
let _range;
|
let _range;
|
||||||
@@ -222,7 +244,8 @@ class HistogramBrush extends React.Component {
|
|||||||
|
|
||||||
drawHistogram(svgRef) {
|
drawHistogram(svgRef) {
|
||||||
const { field, world } = this.props;
|
const { field, world } = this.props;
|
||||||
const histogramCache = this.calcHistogramCache(world, field);
|
const col = HistogramBrush.getColumn(world, field);
|
||||||
|
const histogramCache = this.calcHistogramCache(col, field);
|
||||||
const { x, y, bins } = histogramCache;
|
const { x, y, bins } = histogramCache;
|
||||||
this._histogram = { x, y, bins, svgRef };
|
this._histogram = { x, y, bins, svgRef };
|
||||||
}
|
}
|
||||||
@@ -348,7 +371,9 @@ class HistogramBrush extends React.Component {
|
|||||||
svg.selectAll(".axis path").style("stroke", "rgb(230,230,230)");
|
svg.selectAll(".axis path").style("stroke", "rgb(230,230,230)");
|
||||||
svg.selectAll(".axis line").style("stroke", "rgb(230,230,230)");
|
svg.selectAll(".axis line").style("stroke", "rgb(230,230,230)");
|
||||||
|
|
||||||
this.setState({ brushX, brushXselection });
|
const newState = { brushX, brushXselection };
|
||||||
|
this.setState(newState);
|
||||||
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ const CategoricalSelection = (
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "initial data load complete (universe exists)":
|
case "initial data load complete (universe exists)":
|
||||||
case "set World to current selection":
|
case "set World to current selection":
|
||||||
case "reset World to eq Universe": {
|
case "reset World to eq Universe":
|
||||||
|
case "set clip quantiles": {
|
||||||
const { world } = nextSharedState;
|
const { world } = nextSharedState;
|
||||||
return ControlsHelpers.createCategoricalSelection(
|
return ControlsHelpers.createCategoricalSelection(
|
||||||
maxCategoryItems(prevSharedState),
|
maxCategoryItems(prevSharedState),
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import { makeContinuousDimensionName } from "../util/nameCreators";
|
|||||||
|
|
||||||
const ContinuousSelection = (state = {}, action) => {
|
const ContinuousSelection = (state = {}, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "reset World to eq Universe": {
|
case "reset World to eq Universe":
|
||||||
|
case "set clip quantiles": {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
case "continuous metadata histogram start":
|
case "continuous metadata histogram start":
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const GraphSelection = (
|
|||||||
action
|
action
|
||||||
) => {
|
) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case "set clip quantiles":
|
||||||
case "reset World to eq Universe": {
|
case "reset World to eq Universe": {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
Reference in New Issue
Block a user