mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-30 19:08:11 +08:00
gene set summary progress (#2127)
* revert removal of cache control headers * checkpoint work on revising summary route * add summary query support to annoMatrix * summarize route cleanup * add mising file * clean up summarize route * add summary histogram * update deps * lint * more lint * lint * manage crossfiler during gene set state changes * remove obsolete debugging code * correctly perform async watch in histogram * better error handling
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
||||
userInfo: state.userInfo,
|
||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
||||
writableGenesetsEnabled: !(
|
||||
state.config?.parameters?.["annotations_genesets_readonly"] ?? true
|
||||
state.config?.parameters?.annotations_genesets_readonly ?? true
|
||||
),
|
||||
}))
|
||||
class FilenameDialog extends React.Component {
|
||||
|
||||
@@ -11,7 +11,7 @@ import FilenameDialog from "./filenameDialog";
|
||||
error: state.autosave?.error,
|
||||
writableCategoriesEnabled: state.config?.parameters?.annotations ?? false,
|
||||
writableGenesetsEnabled: !(
|
||||
state.config?.parameters?.["annotations_genesets_readonly"] ?? true
|
||||
state.config?.parameters?.annotations_genesets_readonly ?? true
|
||||
),
|
||||
annoMatrix: state.annoMatrix,
|
||||
genesets: state.genesets,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { connect, shallowEqual } from "react-redux";
|
||||
import * as d3 from "d3";
|
||||
import Async from "react-async";
|
||||
import memoize from "memoize-one";
|
||||
@@ -14,9 +14,9 @@ import StillLoading from "./loading";
|
||||
import ErrorLoading from "./error";
|
||||
|
||||
@connect((state, ownProps) => {
|
||||
const { isObs, isUserDefined, isDiffExp, field } = ownProps;
|
||||
const { isObs, isUserDefined, isDiffExp, isGeneSetSummary, field } = ownProps;
|
||||
const myName = makeContinuousDimensionName(
|
||||
{ isObs, isUserDefined, isDiffExp },
|
||||
{ isObs, isUserDefined, isDiffExp, isGeneSetSummary },
|
||||
field
|
||||
);
|
||||
return {
|
||||
@@ -28,6 +28,10 @@ import ErrorLoading from "./error";
|
||||
};
|
||||
})
|
||||
class HistogramBrush extends React.PureComponent {
|
||||
static watchAsync(props, prevProps) {
|
||||
return !shallowEqual(props.watchProps, prevProps.watchProps);
|
||||
}
|
||||
|
||||
/* memoized closure to prevent HistogramHeader unecessary repaint */
|
||||
handleColorAction = memoize((dispatch) => (field, isObs) => {
|
||||
if (isObs) {
|
||||
@@ -71,7 +75,14 @@ class HistogramBrush extends React.PureComponent {
|
||||
onBrush = (selection, x, eventType) => {
|
||||
const type = `continuous metadata histogram ${eventType}`;
|
||||
return () => {
|
||||
const { dispatch, field, isObs, isUserDefined, isDiffExp } = this.props;
|
||||
const {
|
||||
dispatch,
|
||||
field,
|
||||
isObs,
|
||||
isUserDefined,
|
||||
isDiffExp,
|
||||
isGeneSetSummary,
|
||||
} = this.props;
|
||||
|
||||
// ignore programmatically generated events
|
||||
if (!d3.event.sourceEvent) return;
|
||||
@@ -88,6 +99,7 @@ class HistogramBrush extends React.PureComponent {
|
||||
isObs,
|
||||
isUserDefined,
|
||||
isDiffExp,
|
||||
isGeneSetSummary,
|
||||
},
|
||||
};
|
||||
dispatch(
|
||||
@@ -98,7 +110,14 @@ class HistogramBrush extends React.PureComponent {
|
||||
|
||||
onBrushEnd = (selection, x) => {
|
||||
return () => {
|
||||
const { dispatch, field, isObs, isUserDefined, isDiffExp } = this.props;
|
||||
const {
|
||||
dispatch,
|
||||
field,
|
||||
isObs,
|
||||
isUserDefined,
|
||||
isDiffExp,
|
||||
isGeneSetSummary,
|
||||
} = this.props;
|
||||
const minAllowedBrushSize = 10;
|
||||
const smallAmountToAvoidInfiniteLoop = 0.1;
|
||||
|
||||
@@ -138,6 +157,7 @@ class HistogramBrush extends React.PureComponent {
|
||||
isObs,
|
||||
isUserDefined,
|
||||
isDiffExp,
|
||||
isGeneSetSummary,
|
||||
},
|
||||
};
|
||||
dispatch(
|
||||
@@ -300,19 +320,37 @@ class HistogramBrush extends React.PureComponent {
|
||||
}
|
||||
|
||||
createQuery() {
|
||||
const { isObs, field, annoMatrix } = this.props;
|
||||
const { isObs, isGeneSetSummary, field, setGenes, annoMatrix } = this.props;
|
||||
const { schema } = annoMatrix;
|
||||
if (isObs) {
|
||||
return ["obs", field];
|
||||
}
|
||||
const varIndex = schema?.annotations?.var?.index;
|
||||
if (!varIndex) return null;
|
||||
|
||||
if (isGeneSetSummary) {
|
||||
return [
|
||||
"X",
|
||||
{
|
||||
summarize: {
|
||||
method: "mean",
|
||||
field: "var",
|
||||
column: varIndex,
|
||||
values: setGenes,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
// else, we assume it is a gene expression
|
||||
return [
|
||||
"X",
|
||||
{
|
||||
field: "var",
|
||||
column: varIndex,
|
||||
value: field,
|
||||
where: {
|
||||
field: "var",
|
||||
column: varIndex,
|
||||
value: field,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -333,6 +371,7 @@ class HistogramBrush extends React.PureComponent {
|
||||
continuousSelectionRange,
|
||||
isObs,
|
||||
mini,
|
||||
setGenes,
|
||||
} = this.props;
|
||||
const {
|
||||
margin,
|
||||
@@ -346,7 +385,11 @@ class HistogramBrush extends React.PureComponent {
|
||||
const showScatterPlot = isDiffExp || isUserDefined;
|
||||
|
||||
return (
|
||||
<Async watch={annoMatrix} promiseFn={this.fetchAsyncProps}>
|
||||
<Async
|
||||
watchFn={HistogramBrush.watchAsync}
|
||||
promiseFn={this.fetchAsyncProps}
|
||||
watchProps={{ annoMatrix, setGenes }}
|
||||
>
|
||||
<Async.Pending initial>
|
||||
<StillLoading displayName={field} zebra={zebra} />
|
||||
</Async.Pending>
|
||||
|
||||
@@ -53,12 +53,7 @@ class Gene extends React.Component {
|
||||
|
||||
handleDeleteGeneFromSet = () => {
|
||||
const { dispatch, gene, geneset } = this.props;
|
||||
|
||||
dispatch({
|
||||
type: "geneset: delete genes",
|
||||
genesetName: geneset,
|
||||
geneSymbols: [gene],
|
||||
});
|
||||
dispatch(actions.genesetDeleteGenes(geneset, [gene]));
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { memoize } from "../../util/dataframe/util";
|
||||
import Truncate from "../util/truncate";
|
||||
import * as globals from "../../globals";
|
||||
import GenesetMenus from "./menus/genesetMenus";
|
||||
import HistogramBrush from "../brushableHistogram";
|
||||
|
||||
@connect((state, ownProps) => {
|
||||
return {
|
||||
@@ -163,18 +164,25 @@ class GeneSet extends React.Component {
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{isOpen && !toggleSummaryHisto
|
||||
? _.map(setGenes, (gene) => {
|
||||
return (
|
||||
<Gene
|
||||
key={gene}
|
||||
gene={gene}
|
||||
geneset={setName}
|
||||
isDiffexp={isDiffexp}
|
||||
{isOpen &&
|
||||
(!toggleSummaryHisto
|
||||
? _.map(setGenes, (gene) => {
|
||||
return (
|
||||
<Gene
|
||||
key={gene}
|
||||
gene={gene}
|
||||
geneset={setName}
|
||||
isDiffexp={isDiffexp}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: setGenes.length > 0 && (
|
||||
<HistogramBrush
|
||||
isGeneSetSummary
|
||||
field={setName}
|
||||
setGenes={setGenes}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { connect } from "react-redux";
|
||||
import AnnoDialog from "../../annoDialog";
|
||||
import LabelInput from "../../labelInput";
|
||||
import parseBulkGeneString from "../../../util/parseBulkGeneString";
|
||||
import actions from "../../../actions";
|
||||
|
||||
@connect((state) => ({
|
||||
genesetsUI: state.genesetsUI,
|
||||
@@ -36,11 +37,7 @@ class AddGeneToGenesetDialogue extends React.PureComponent {
|
||||
});
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: "geneset: add genes",
|
||||
genesetName: geneset,
|
||||
genes: genesTmpHardcodedFormat,
|
||||
});
|
||||
dispatch(actions.genesetAddGenes(geneset, genesTmpHardcodedFormat));
|
||||
dispatch({
|
||||
type: "geneset: disable add new genes mode",
|
||||
});
|
||||
|
||||
@@ -77,6 +77,26 @@ class AddGenes extends React.Component {
|
||||
this.updateState(prevProps);
|
||||
}
|
||||
|
||||
handleClick(g) {
|
||||
const { dispatch, userDefinedGenes } = this.props;
|
||||
const { geneNames } = this.state;
|
||||
if (!g) return;
|
||||
const gene = g.target;
|
||||
if (userDefinedGenes.indexOf(gene) !== -1) {
|
||||
postUserErrorToast("That gene already exists");
|
||||
} else if (userDefinedGenes.length > globals.maxUserDefinedGenes) {
|
||||
postUserErrorToast(
|
||||
`That's too many genes, you can have at most ${globals.maxUserDefinedGenes} user defined genes`
|
||||
);
|
||||
} else if (geneNames.indexOf(gene) === undefined) {
|
||||
postUserErrorToast("That doesn't appear to be a valid gene name.");
|
||||
} else {
|
||||
dispatch({ type: "single user defined gene start" });
|
||||
dispatch(actions.requestUserDefinedGene(gene));
|
||||
dispatch({ type: "single user defined gene complete" });
|
||||
}
|
||||
}
|
||||
|
||||
_genesToUpper = (listGenes) => {
|
||||
// Has to be a Map to preserve index
|
||||
const upperGenes = new Map();
|
||||
@@ -190,26 +210,6 @@ class AddGenes extends React.Component {
|
||||
return "Apod, Cd74, ...";
|
||||
}
|
||||
|
||||
handleClick(g) {
|
||||
const { dispatch, userDefinedGenes } = this.props;
|
||||
const { geneNames } = this.state;
|
||||
if (!g) return;
|
||||
const gene = g.target;
|
||||
if (userDefinedGenes.indexOf(gene) !== -1) {
|
||||
postUserErrorToast("That gene already exists");
|
||||
} else if (userDefinedGenes.length > globals.maxUserDefinedGenes) {
|
||||
postUserErrorToast(
|
||||
`That's too many genes, you can have at most ${globals.maxUserDefinedGenes} user defined genes`
|
||||
);
|
||||
} else if (geneNames.indexOf(gene) === undefined) {
|
||||
postUserErrorToast("That doesn't appear to be a valid gene name.");
|
||||
} else {
|
||||
dispatch({ type: "single user defined gene start" });
|
||||
dispatch(actions.requestUserDefinedGene(gene));
|
||||
dispatch({ type: "single user defined gene complete" });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { userDefinedGenesLoading } = this.props;
|
||||
const { tab, bulkAdd, activeItem, status, geneNames } = this.state;
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import AnnoDialog from "../../annoDialog";
|
||||
import LabelInput from "../../labelInput";
|
||||
import actions from "../../../actions";
|
||||
|
||||
@connect((state) => ({
|
||||
annotations: state.annotations,
|
||||
@@ -56,11 +57,7 @@ class CreateGenesetDialogue extends React.PureComponent {
|
||||
});
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: "geneset: add genes",
|
||||
genesetName,
|
||||
genes: genesTmpHardcodedFormat,
|
||||
});
|
||||
dispatch(actions.genesetAddGenes(genesetName, genesTmpHardcodedFormat));
|
||||
}
|
||||
dispatch({
|
||||
type: "geneset: disable create geneset mode",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "@blueprintjs/core";
|
||||
|
||||
import * as globals from "../../../globals";
|
||||
import actions from "../../../actions";
|
||||
import AddGeneToGenesetDialogue from "./addGeneToGenesetDialogue";
|
||||
|
||||
@connect((state) => {
|
||||
@@ -44,7 +45,7 @@ class GenesetMenus extends React.PureComponent {
|
||||
|
||||
handleDeleteCategory = () => {
|
||||
const { dispatch, geneset } = this.props;
|
||||
dispatch({ type: "geneset: delete", genesetName: geneset });
|
||||
dispatch(actions.genesetDelete(geneset));
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
@@ -303,13 +303,6 @@ class Graph extends React.Component {
|
||||
window.removeEventListener("resize", this.handleResize);
|
||||
}
|
||||
|
||||
setReglCanvas = (canvas) => {
|
||||
this.reglCanvas = canvas;
|
||||
this.setState({
|
||||
...Graph.createReglState(canvas),
|
||||
});
|
||||
};
|
||||
|
||||
handleResize = () => {
|
||||
const { state } = this.state;
|
||||
const viewport = this.getViewportDimensions();
|
||||
@@ -321,14 +314,6 @@ class Graph extends React.Component {
|
||||
});
|
||||
};
|
||||
|
||||
getViewportDimensions = () => {
|
||||
const { viewportRef } = this.props;
|
||||
return {
|
||||
height: viewportRef.clientHeight,
|
||||
width: viewportRef.clientWidth,
|
||||
};
|
||||
};
|
||||
|
||||
handleCanvasEvent = (e) => {
|
||||
const { camera, projectionTF } = this.state;
|
||||
if (e.type !== "wheel") e.preventDefault();
|
||||
@@ -340,6 +325,143 @@ class Graph extends React.Component {
|
||||
}
|
||||
};
|
||||
|
||||
handleBrushDragAction() {
|
||||
/*
|
||||
event describing brush position:
|
||||
@-------|
|
||||
| |
|
||||
| |
|
||||
|-------@
|
||||
*/
|
||||
// ignore programatically generated events
|
||||
if (d3.event.sourceEvent === null || !d3.event.selection) return;
|
||||
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
const s = d3.event.selection;
|
||||
const northwest = this.mapScreenToPoint(s[0]);
|
||||
const southeast = this.mapScreenToPoint(s[1]);
|
||||
const [minX, maxY] = northwest;
|
||||
const [maxX, minY] = southeast;
|
||||
dispatch(
|
||||
actions.graphBrushChangeAction(layoutChoice.current, {
|
||||
minX,
|
||||
minY,
|
||||
maxX,
|
||||
maxY,
|
||||
northwest,
|
||||
southeast,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
handleBrushStartAction() {
|
||||
// Ignore programatically generated events.
|
||||
if (!d3.event.sourceEvent) return;
|
||||
|
||||
const { dispatch } = this.props;
|
||||
dispatch(actions.graphBrushStartAction());
|
||||
}
|
||||
|
||||
handleBrushEndAction() {
|
||||
// Ignore programatically generated events.
|
||||
if (!d3.event.sourceEvent) return;
|
||||
|
||||
/*
|
||||
coordinates will be included if selection made, null
|
||||
if selection cleared.
|
||||
*/
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
const s = d3.event.selection;
|
||||
if (s) {
|
||||
const northwest = this.mapScreenToPoint(s[0]);
|
||||
const southeast = this.mapScreenToPoint(s[1]);
|
||||
const [minX, maxY] = northwest;
|
||||
const [maxX, minY] = southeast;
|
||||
dispatch(
|
||||
actions.graphBrushEndAction(layoutChoice.current, {
|
||||
minX,
|
||||
minY,
|
||||
maxX,
|
||||
maxY,
|
||||
northwest,
|
||||
southeast,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(actions.graphBrushDeselectAction(layoutChoice.current));
|
||||
}
|
||||
}
|
||||
|
||||
handleBrushDeselectAction() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphBrushDeselectAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleLassoStart() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoStartAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
// when a lasso is completed, filter to the points within the lasso polygon
|
||||
handleLassoEnd(polygon) {
|
||||
const minimumPolygonArea = 10;
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
|
||||
if (
|
||||
polygon.length < 3 ||
|
||||
Math.abs(d3.polygonArea(polygon)) < minimumPolygonArea
|
||||
) {
|
||||
// if less than three points, or super small area, treat as a clear selection.
|
||||
dispatch(actions.graphLassoDeselectAction(layoutChoice.current));
|
||||
} else {
|
||||
dispatch(
|
||||
actions.graphLassoEndAction(
|
||||
layoutChoice.current,
|
||||
polygon.map((xy) => this.mapScreenToPoint(xy))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleLassoCancel() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoCancelAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleLassoDeselectAction() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoDeselectAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleDeselectAction() {
|
||||
const { selectionTool } = this.props;
|
||||
if (selectionTool === "brush") this.handleBrushDeselectAction();
|
||||
if (selectionTool === "lasso") this.handleLassoDeselectAction();
|
||||
}
|
||||
|
||||
handleOpacityRangeChange(e) {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "change opacity deselected cells in 2d graph background",
|
||||
data: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
setReglCanvas = (canvas) => {
|
||||
this.reglCanvas = canvas;
|
||||
this.setState({
|
||||
...Graph.createReglState(canvas),
|
||||
});
|
||||
};
|
||||
|
||||
getViewportDimensions = () => {
|
||||
const { viewportRef } = this.props;
|
||||
return {
|
||||
height: viewportRef.clientHeight,
|
||||
width: viewportRef.clientWidth,
|
||||
};
|
||||
};
|
||||
|
||||
createToolSVG = () => {
|
||||
/*
|
||||
Called from componentDidUpdate. Create the tool SVG, and return any
|
||||
@@ -589,128 +711,6 @@ class Graph extends React.Component {
|
||||
];
|
||||
}
|
||||
|
||||
handleBrushDragAction() {
|
||||
/*
|
||||
event describing brush position:
|
||||
@-------|
|
||||
| |
|
||||
| |
|
||||
|-------@
|
||||
*/
|
||||
// ignore programatically generated events
|
||||
if (d3.event.sourceEvent === null || !d3.event.selection) return;
|
||||
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
const s = d3.event.selection;
|
||||
const northwest = this.mapScreenToPoint(s[0]);
|
||||
const southeast = this.mapScreenToPoint(s[1]);
|
||||
const [minX, maxY] = northwest;
|
||||
const [maxX, minY] = southeast;
|
||||
dispatch(
|
||||
actions.graphBrushChangeAction(layoutChoice.current, {
|
||||
minX,
|
||||
minY,
|
||||
maxX,
|
||||
maxY,
|
||||
northwest,
|
||||
southeast,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
handleBrushStartAction() {
|
||||
// Ignore programatically generated events.
|
||||
if (!d3.event.sourceEvent) return;
|
||||
|
||||
const { dispatch } = this.props;
|
||||
dispatch(actions.graphBrushStartAction());
|
||||
}
|
||||
|
||||
handleBrushEndAction() {
|
||||
// Ignore programatically generated events.
|
||||
if (!d3.event.sourceEvent) return;
|
||||
|
||||
/*
|
||||
coordinates will be included if selection made, null
|
||||
if selection cleared.
|
||||
*/
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
const s = d3.event.selection;
|
||||
if (s) {
|
||||
const northwest = this.mapScreenToPoint(s[0]);
|
||||
const southeast = this.mapScreenToPoint(s[1]);
|
||||
const [minX, maxY] = northwest;
|
||||
const [maxX, minY] = southeast;
|
||||
dispatch(
|
||||
actions.graphBrushEndAction(layoutChoice.current, {
|
||||
minX,
|
||||
minY,
|
||||
maxX,
|
||||
maxY,
|
||||
northwest,
|
||||
southeast,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
dispatch(actions.graphBrushDeselectAction(layoutChoice.current));
|
||||
}
|
||||
}
|
||||
|
||||
handleBrushDeselectAction() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphBrushDeselectAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleLassoStart() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoStartAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
// when a lasso is completed, filter to the points within the lasso polygon
|
||||
handleLassoEnd(polygon) {
|
||||
const minimumPolygonArea = 10;
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
|
||||
if (
|
||||
polygon.length < 3 ||
|
||||
Math.abs(d3.polygonArea(polygon)) < minimumPolygonArea
|
||||
) {
|
||||
// if less than three points, or super small area, treat as a clear selection.
|
||||
dispatch(actions.graphLassoDeselectAction(layoutChoice.current));
|
||||
} else {
|
||||
dispatch(
|
||||
actions.graphLassoEndAction(
|
||||
layoutChoice.current,
|
||||
polygon.map((xy) => this.mapScreenToPoint(xy))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleLassoCancel() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoCancelAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleLassoDeselectAction() {
|
||||
const { dispatch, layoutChoice } = this.props;
|
||||
dispatch(actions.graphLassoDeselectAction(layoutChoice.current));
|
||||
}
|
||||
|
||||
handleDeselectAction() {
|
||||
const { selectionTool } = this.props;
|
||||
if (selectionTool === "brush") this.handleBrushDeselectAction();
|
||||
if (selectionTool === "lasso") this.handleLassoDeselectAction();
|
||||
}
|
||||
|
||||
handleOpacityRangeChange(e) {
|
||||
const { dispatch } = this.props;
|
||||
dispatch({
|
||||
type: "change opacity deselected cells in 2d graph background",
|
||||
data: e.target.value,
|
||||
});
|
||||
}
|
||||
|
||||
renderCanvas = renderThrottle(() => {
|
||||
const {
|
||||
regl,
|
||||
|
||||
@@ -11,7 +11,7 @@ import { selectableCategoryNames } from "../../util/stateManager/controlsHelpers
|
||||
datasetTitle: state.config?.displayNames?.dataset ?? "",
|
||||
aboutURL: state.config?.links?.["about-dataset"],
|
||||
isOpen: state.controls.datasetDrawer,
|
||||
dataPortalProps: state.config?.["corpora_props"],
|
||||
dataPortalProps: state.config?.corpora_props,
|
||||
};
|
||||
})
|
||||
class InfoDrawer extends PureComponent {
|
||||
|
||||
@@ -169,7 +169,7 @@ const InfoFormat = React.memo(
|
||||
({ datasetTitle, singleValueCategories, aboutURL, dataPortalProps = {} }) => {
|
||||
if (
|
||||
["1.0.0", "1.1.0"].indexOf(
|
||||
dataPortalProps.version?.["corpora_schema_version"]
|
||||
dataPortalProps.version?.corpora_schema_version
|
||||
) === -1
|
||||
) {
|
||||
dataPortalProps = {};
|
||||
|
||||
@@ -13,15 +13,14 @@ const DATASET_TITLE_FONT_SIZE = 14;
|
||||
@connect((state) => {
|
||||
const { corpora_props: corporaProps } = state.config;
|
||||
const correctVersion =
|
||||
["1.0.0", "1.1.0"].indexOf(
|
||||
corporaProps?.version?.["corpora_schema_version"]
|
||||
) > -1;
|
||||
["1.0.0", "1.1.0"].indexOf(corporaProps?.version?.corpora_schema_version) >
|
||||
-1;
|
||||
return {
|
||||
datasetTitle: state.config?.displayNames?.dataset ?? "",
|
||||
libraryVersions: state.config?.["library_versions"],
|
||||
libraryVersions: state.config?.library_versions,
|
||||
aboutLink: state.config?.links?.["about-dataset"],
|
||||
tosURL: state.config?.parameters?.["about_legal_tos"],
|
||||
privacyURL: state.config?.parameters?.["about_legal_privacy"],
|
||||
tosURL: state.config?.parameters?.about_legal_tos,
|
||||
privacyURL: state.config?.parameters?.about_legal_privacy,
|
||||
title: correctVersion ? corporaProps?.title : undefined,
|
||||
};
|
||||
})
|
||||
|
||||
@@ -11,7 +11,7 @@ import CellSetButton from "./cellSetButtons";
|
||||
celllist1: state.differential?.celllist1,
|
||||
celllist2: state.differential?.celllist2,
|
||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
||||
diffexpCellcountMax: state.config?.limits?.["diffexp_cellcount_max"],
|
||||
diffexpCellcountMax: state.config?.limits?.diffexp_cellcount_max,
|
||||
}))
|
||||
class DiffexpButtons extends React.PureComponent {
|
||||
computeDiffExp = () => {
|
||||
|
||||
@@ -40,7 +40,7 @@ import { getEmbSubsetView } from "../../util/stateManager/viewStackHelpers";
|
||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
||||
celllist1: state.differential.celllist1,
|
||||
celllist2: state.differential.celllist2,
|
||||
libraryVersions: state.config?.["library_versions"],
|
||||
libraryVersions: state.config?.library_versions,
|
||||
auth: state.config?.authentication,
|
||||
userInfo: state.userInfo,
|
||||
undoDisabled: state["@@undoable/past"].length === 0,
|
||||
@@ -50,8 +50,8 @@ import { getEmbSubsetView } from "../../util/stateManager/viewStackHelpers";
|
||||
diffexpMayBeSlow:
|
||||
state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
||||
showCentroidLabels: state.centroidLabels.showLabels,
|
||||
tosURL: state.config?.parameters?.["about_legal_tos"],
|
||||
privacyURL: state.config?.parameters?.["about_legal_privacy"],
|
||||
tosURL: state.config?.parameters?.about_legal_tos,
|
||||
privacyURL: state.config?.parameters?.about_legal_privacy,
|
||||
categoricalSelection: state.categoricalSelection,
|
||||
enableReembedding:
|
||||
state.config?.parameters?.["enable-reembedding"] ?? false,
|
||||
|
||||
@@ -303,9 +303,11 @@ class Scatterplot extends React.PureComponent {
|
||||
return [
|
||||
"X",
|
||||
{
|
||||
field: "var",
|
||||
column: varIndex,
|
||||
value: geneName,
|
||||
where: {
|
||||
field: "var",
|
||||
column: varIndex,
|
||||
value: geneName,
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
import { storageGet, storageSet, KEYS } from "../util/localStorage";
|
||||
|
||||
@connect((state) => ({
|
||||
tosURL: state.config?.parameters?.["about_legal_tos"],
|
||||
privacyURL: state.config?.parameters?.["about_legal_privacy"],
|
||||
tosURL: state.config?.parameters?.about_legal_tos,
|
||||
privacyURL: state.config?.parameters?.about_legal_privacy,
|
||||
}))
|
||||
class TermsPrompt extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
||||
Reference in New Issue
Block a user