mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-09 05:48:11 +08:00
render perf refinements (#1632)
* render performance improvements * improve render perf * remove logging * lint * improve memoziation
This commit is contained in:
@@ -284,4 +284,5 @@ export default {
|
|||||||
saveObsAnnotationsAction: annoActions.saveObsAnnotationsAction,
|
saveObsAnnotationsAction: annoActions.saveObsAnnotationsAction,
|
||||||
needToSaveObsAnnotations: annoActions.needToSaveObsAnnotations,
|
needToSaveObsAnnotations: annoActions.needToSaveObsAnnotations,
|
||||||
layoutChoiceAction: selnActions.layoutChoiceAction,
|
layoutChoiceAction: selnActions.layoutChoiceAction,
|
||||||
|
setCellSetFromSelection: selnActions.setCellSetFromSelection,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -209,3 +209,16 @@ export const layoutChoiceAction = (newLayoutChoice) => async (
|
|||||||
obsCrossfilter,
|
obsCrossfilter,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Differential expression set selection
|
||||||
|
*/
|
||||||
|
export const setCellSetFromSelection = (cellSetId) => (dispatch, getState) => {
|
||||||
|
const { obsCrossfilter } = getState();
|
||||||
|
const selected = obsCrossfilter.allSelectedLabels();
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: `store current cell selection as differential set ${cellSetId}`,
|
||||||
|
data: selected.length > 0 ? selected : null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -139,6 +139,32 @@ class Graph extends React.Component {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
computeHighlightFlags = memoize(
|
||||||
|
(nObs, pointDilationData, pointDilationLabel) => {
|
||||||
|
const flags = new Float32Array(nObs);
|
||||||
|
if (pointDilationData) {
|
||||||
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
|
if (pointDilationData[i] === pointDilationLabel) {
|
||||||
|
flags[i] = flagHighlight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
computeColorByFlags = memoize((nObs, colorByData) => {
|
||||||
|
const flags = new Float32Array(nObs);
|
||||||
|
if (colorByData) {
|
||||||
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
|
if (!Number.isFinite(colorByData[i])) {
|
||||||
|
flags[i] = flagNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
});
|
||||||
|
|
||||||
computePointFlags = memoize(
|
computePointFlags = memoize(
|
||||||
(crossfilter, colorByData, pointDilationData, pointDilationLabel) => {
|
(crossfilter, colorByData, pointDilationData, pointDilationLabel) => {
|
||||||
/*
|
/*
|
||||||
@@ -154,23 +180,25 @@ class Graph extends React.Component {
|
|||||||
continuous metadata, as they rely on different tests, and some of the flags
|
continuous metadata, as they rely on different tests, and some of the flags
|
||||||
(eg, isNaN) are meaningless in the face of categorical metadata.
|
(eg, isNaN) are meaningless in the face of categorical metadata.
|
||||||
*/
|
*/
|
||||||
const flags = this.computeSelectedFlags(
|
const nObs = crossfilter.size();
|
||||||
|
const flags = new Float32Array(nObs);
|
||||||
|
|
||||||
|
const selectedFlags = this.computeSelectedFlags(
|
||||||
crossfilter,
|
crossfilter,
|
||||||
flagSelected,
|
flagSelected,
|
||||||
0
|
0
|
||||||
).slice();
|
);
|
||||||
|
const highlightFlags = this.computeHighlightFlags(
|
||||||
|
nObs,
|
||||||
|
pointDilationData,
|
||||||
|
pointDilationLabel
|
||||||
|
);
|
||||||
|
const colorByFlags = this.computeColorByFlags(nObs, colorByData);
|
||||||
|
|
||||||
if (colorByData || pointDilationData) {
|
for (let i = 0; i < nObs; i += 1) {
|
||||||
for (let i = 0, len = flags.length; i < len; i += 1) {
|
flags[i] = selectedFlags[i] + highlightFlags[i] + colorByFlags[i];
|
||||||
if (pointDilationData) {
|
|
||||||
flags[i] +=
|
|
||||||
pointDilationData[i] === pointDilationLabel ? flagHighlight : 0;
|
|
||||||
}
|
|
||||||
if (colorByData) {
|
|
||||||
flags[i] += Number.isFinite(colorByData[i]) ? 0 : flagNaN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,25 +3,18 @@ import React from "react";
|
|||||||
import { AnchorButton, Tooltip } from "@blueprintjs/core";
|
import { AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { tooltipHoverOpenDelay } from "../../globals";
|
import { tooltipHoverOpenDelay } from "../../globals";
|
||||||
|
import actions from "../../actions";
|
||||||
|
|
||||||
@connect()
|
@connect((state) => ({
|
||||||
|
differential: state.differential,
|
||||||
|
}))
|
||||||
class CellSetButton extends React.PureComponent {
|
class CellSetButton extends React.PureComponent {
|
||||||
set() {
|
set() {
|
||||||
const {
|
const { differential, dispatch, eitherCellSetOneOrTwo } = this.props;
|
||||||
differential,
|
|
||||||
crossfilter,
|
|
||||||
dispatch,
|
|
||||||
eitherCellSetOneOrTwo,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
let set = crossfilter.allSelectedLabels();
|
|
||||||
if (set.length === 0) set = null;
|
|
||||||
if (!differential.diffExp) {
|
if (!differential.diffExp) {
|
||||||
/* diffexp needs to be cleared before we store a new set */
|
// disallow this action if the user has active differential expression results
|
||||||
dispatch({
|
dispatch(actions.setCellSetFromSelection(eitherCellSetOneOrTwo));
|
||||||
type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`,
|
|
||||||
data: set,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// jshint esversion: 6
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
Position,
|
Position,
|
||||||
@@ -11,7 +10,7 @@ import {
|
|||||||
import { tooltipHoverOpenDelay } from "../../globals";
|
import { tooltipHoverOpenDelay } from "../../globals";
|
||||||
import styles from "./menubar.css";
|
import styles from "./menubar.css";
|
||||||
|
|
||||||
function Clip(props) {
|
const Clip = React.memo((props) => {
|
||||||
const {
|
const {
|
||||||
pendingClipPercentiles,
|
pendingClipPercentiles,
|
||||||
clipPercentileMin,
|
clipPercentileMin,
|
||||||
@@ -129,6 +128,6 @@ function Clip(props) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default Clip;
|
export default Clip;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// jshint esversion: 6
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Button, ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
|
import { Button, ButtonGroup, AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||||
@@ -8,15 +7,13 @@ import actions from "../../actions";
|
|||||||
import CellSetButton from "./cellSetButtons";
|
import CellSetButton from "./cellSetButtons";
|
||||||
|
|
||||||
@connect((state) => ({
|
@connect((state) => ({
|
||||||
config: state.config,
|
|
||||||
crossfilter: state.obsCrossfilter,
|
|
||||||
differential: state.differential,
|
differential: state.differential,
|
||||||
celllist1: state.differential?.celllist1,
|
celllist1: state.differential?.celllist1,
|
||||||
celllist2: state.differential?.celllist2,
|
celllist2: state.differential?.celllist2,
|
||||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
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.Component {
|
class DiffexpButtons extends React.PureComponent {
|
||||||
computeDiffExp = () => {
|
computeDiffExp = () => {
|
||||||
const { dispatch, differential } = this.props;
|
const { dispatch, differential } = this.props;
|
||||||
if (differential.celllist1 && differential.celllist2) {
|
if (differential.celllist1 && differential.celllist2) {
|
||||||
@@ -42,13 +39,7 @@ class DiffexpButtons extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
/* diffexp-related buttons may be disabled */
|
/* diffexp-related buttons may be disabled */
|
||||||
const {
|
const { differential, diffexpMayBeSlow, diffexpCellcountMax } = this.props;
|
||||||
differential,
|
|
||||||
diffexpMayBeSlow,
|
|
||||||
diffexpCellcountMax,
|
|
||||||
crossfilter,
|
|
||||||
dispatch,
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const haveBothCellSets =
|
const haveBothCellSets =
|
||||||
!!differential.celllist1 && !!differential.celllist2;
|
!!differential.celllist1 && !!differential.celllist2;
|
||||||
@@ -72,17 +63,8 @@ class DiffexpButtons extends React.Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonGroup className={styles.menubarButton}>
|
<ButtonGroup className={styles.menubarButton}>
|
||||||
{/* eslint-disable react/jsx-props-no-spreading --- disable until eslint-config-airbnb v18.1.1*/}
|
<CellSetButton eitherCellSetOneOrTwo={1} />
|
||||||
<CellSetButton
|
<CellSetButton eitherCellSetOneOrTwo={2} />
|
||||||
{...{ differential, crossfilter, dispatch }}
|
|
||||||
eitherCellSetOneOrTwo={1}
|
|
||||||
/>
|
|
||||||
<CellSetButton
|
|
||||||
{...{ differential, crossfilter, dispatch }}
|
|
||||||
eitherCellSetOneOrTwo={2}
|
|
||||||
/>
|
|
||||||
{/* eslint-enable react/jsx-props-no-spreading --- end disable*/}
|
|
||||||
|
|
||||||
{!differential.diffExp ? (
|
{!differential.diffExp ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={warnMaxSizeExceeded ? tipMessageWarn : tipMessage}
|
content={warnMaxSizeExceeded ? tipMessageWarn : tipMessage}
|
||||||
|
|||||||
@@ -12,32 +12,44 @@ import Subset from "./subset";
|
|||||||
import UndoRedoReset from "./undoRedo";
|
import UndoRedoReset from "./undoRedo";
|
||||||
import DiffexpButtons from "./diffexpButtons";
|
import DiffexpButtons from "./diffexpButtons";
|
||||||
|
|
||||||
@connect((state) => ({
|
@connect((state) => {
|
||||||
annoMatrix: state.annoMatrix,
|
const { annoMatrix } = state;
|
||||||
crossfilter: state.obsCrossfilter,
|
const crossfilter = state.obsCrossfilter;
|
||||||
differential: state.differential,
|
const selectedCount = crossfilter.countSelected();
|
||||||
graphInteractionMode: state.controls.graphInteractionMode,
|
|
||||||
clipPercentileMin: Math.round(100 * (state.annoMatrix?.clipRange?.[0] ?? 0)),
|
const subsetPossible =
|
||||||
clipPercentileMax: Math.round(100 * (state.annoMatrix?.clipRange?.[1] ?? 1)),
|
selectedCount !== 0 && selectedCount !== crossfilter.size(); // ie, not all are selected
|
||||||
userDefinedGenes: state.controls.userDefinedGenes,
|
const subsetResetPossible =
|
||||||
diffexpGenes: state.controls.diffexpGenes,
|
annoMatrix.nObs !== annoMatrix.schema.dataframe.nObs;
|
||||||
colorAccessor: state.colors.colorAccessor,
|
|
||||||
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
return {
|
||||||
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
subsetPossible,
|
||||||
celllist1: state.differential.celllist1,
|
subsetResetPossible,
|
||||||
celllist2: state.differential.celllist2,
|
differential: state.differential,
|
||||||
libraryVersions: state.config?.["library_versions"],
|
graphInteractionMode: state.controls.graphInteractionMode,
|
||||||
undoDisabled: state["@@undoable/past"].length === 0,
|
clipPercentileMin: Math.round(100 * (annoMatrix?.clipRange?.[0] ?? 0)),
|
||||||
redoDisabled: state["@@undoable/future"].length === 0,
|
clipPercentileMax: Math.round(100 * (annoMatrix?.clipRange?.[1] ?? 1)),
|
||||||
aboutLink: state.config?.links?.["about-dataset"],
|
userDefinedGenes: state.controls.userDefinedGenes,
|
||||||
disableDiffexp: state.config?.parameters?.["disable-diffexp"] ?? false,
|
diffexpGenes: state.controls.diffexpGenes,
|
||||||
diffexpMayBeSlow: state.config?.parameters?.["diffexp-may-be-slow"] ?? false,
|
colorAccessor: state.colors.colorAccessor,
|
||||||
showCentroidLabels: state.centroidLabels.showLabels,
|
scatterplotXXaccessor: state.controls.scatterplotXXaccessor,
|
||||||
tosURL: state.config?.parameters?.["about_legal_tos"],
|
scatterplotYYaccessor: state.controls.scatterplotYYaccessor,
|
||||||
privacyURL: state.config?.parameters?.["about_legal_privacy"],
|
celllist1: state.differential.celllist1,
|
||||||
categoricalSelection: state.categoricalSelection,
|
celllist2: state.differential.celllist2,
|
||||||
}))
|
libraryVersions: state.config?.["library_versions"],
|
||||||
class MenuBar extends React.Component {
|
undoDisabled: state["@@undoable/past"].length === 0,
|
||||||
|
redoDisabled: state["@@undoable/future"].length === 0,
|
||||||
|
aboutLink: state.config?.links?.["about-dataset"],
|
||||||
|
disableDiffexp: state.config?.parameters?.["disable-diffexp"] ?? false,
|
||||||
|
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"],
|
||||||
|
categoricalSelection: state.categoricalSelection,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
class MenuBar extends React.PureComponent {
|
||||||
static isValidDigitKeyEvent(e) {
|
static isValidDigitKeyEvent(e) {
|
||||||
/*
|
/*
|
||||||
Return true if this event is necessary to enter a percent number input.
|
Return true if this event is necessary to enter a percent number input.
|
||||||
@@ -171,17 +183,14 @@ class MenuBar extends React.Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
subsetPossible = () => {
|
handleSubset = () => {
|
||||||
const { crossfilter } = this.props;
|
const { dispatch } = this.props;
|
||||||
const count = crossfilter.countSelected();
|
dispatch(actions.subsetAction());
|
||||||
return (
|
|
||||||
count !== 0 && count !== crossfilter.size() // ie, not all are selected
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
subsetResetPossible = () => {
|
handleSubsetReset = () => {
|
||||||
const { annoMatrix } = this.props;
|
const { dispatch } = this.props;
|
||||||
return annoMatrix.nObs !== annoMatrix.schema.dataframe.nObs;
|
dispatch(actions.resetSubsetAction());
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -201,6 +210,8 @@ class MenuBar extends React.Component {
|
|||||||
tosURL,
|
tosURL,
|
||||||
categoricalSelection,
|
categoricalSelection,
|
||||||
colorAccessor,
|
colorAccessor,
|
||||||
|
subsetPossible,
|
||||||
|
subsetResetPossible,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const { pendingClipPercentiles } = this.state;
|
const { pendingClipPercentiles } = this.state;
|
||||||
|
|
||||||
@@ -309,14 +320,10 @@ class MenuBar extends React.Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
<Subset
|
<Subset
|
||||||
subsetPossible={this.subsetPossible()}
|
subsetPossible={subsetPossible}
|
||||||
subsetResetPossible={this.subsetResetPossible()}
|
subsetResetPossible={subsetResetPossible}
|
||||||
handleSubset={() => {
|
handleSubset={this.handleSubset}
|
||||||
dispatch(actions.subsetAction());
|
handleSubsetReset={this.handleSubsetReset}
|
||||||
}}
|
|
||||||
handleSubsetReset={() => {
|
|
||||||
dispatch(actions.resetSubsetAction());
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
{disableDiffexp ? null : <DiffexpButtons />}
|
{disableDiffexp ? null : <DiffexpButtons />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import { Button, Popover, Menu, MenuItem, Position } from "@blueprintjs/core";
|
import { Button, Popover, Menu, MenuItem, Position } from "@blueprintjs/core";
|
||||||
import styles from "./menubar.css";
|
import styles from "./menubar.css";
|
||||||
|
|
||||||
function InformationMenu(props) {
|
const InformationMenu = React.memo((props) => {
|
||||||
const { libraryVersions, aboutLink, tosURL, privacyURL } = props;
|
const { libraryVersions, aboutLink, tosURL, privacyURL } = props;
|
||||||
return (
|
return (
|
||||||
<div className={`bp3-button-group ${styles.menubarButton}`}>
|
<div className={`bp3-button-group ${styles.menubarButton}`}>
|
||||||
@@ -72,6 +72,6 @@ function InformationMenu(props) {
|
|||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default InformationMenu;
|
export default InformationMenu;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { AnchorButton, ButtonGroup, Tooltip } from "@blueprintjs/core";
|
|||||||
import styles from "./menubar.css";
|
import styles from "./menubar.css";
|
||||||
import * as globals from "../../globals";
|
import * as globals from "../../globals";
|
||||||
|
|
||||||
function Subset(props) {
|
const Subset = React.memo((props) => {
|
||||||
const {
|
const {
|
||||||
subsetPossible,
|
subsetPossible,
|
||||||
subsetResetPossible,
|
subsetResetPossible,
|
||||||
@@ -41,6 +41,6 @@ function Subset(props) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default Subset;
|
export default Subset;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
// jshint esversion: 6
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { AnchorButton, Tooltip } from "@blueprintjs/core";
|
import { AnchorButton, Tooltip } from "@blueprintjs/core";
|
||||||
import { tooltipHoverOpenDelay } from "../../globals";
|
import { tooltipHoverOpenDelay } from "../../globals";
|
||||||
import styles from "./menubar.css";
|
import styles from "./menubar.css";
|
||||||
|
|
||||||
function InformationMenu(props) {
|
const UndoRedo = React.memo((props) => {
|
||||||
const { undoDisabled, redoDisabled, dispatch } = props;
|
const { undoDisabled, redoDisabled, dispatch } = props;
|
||||||
return (
|
return (
|
||||||
<div className={`bp3-button-group ${styles.menubarButton}`}>
|
<div className={`bp3-button-group ${styles.menubarButton}`}>
|
||||||
@@ -46,6 +45,6 @@ function InformationMenu(props) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default InformationMenu;
|
export default UndoRedo;
|
||||||
|
|||||||
@@ -117,6 +117,32 @@ class Scatterplot extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
computeHighlightFlags = memoize(
|
||||||
|
(nObs, pointDilationData, pointDilationLabel) => {
|
||||||
|
const flags = new Float32Array(nObs);
|
||||||
|
if (pointDilationData) {
|
||||||
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
|
if (pointDilationData[i] === pointDilationLabel) {
|
||||||
|
flags[i] = flagHighlight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
computeColorByFlags = memoize((nObs, colorByData) => {
|
||||||
|
const flags = new Float32Array(nObs);
|
||||||
|
if (colorByData) {
|
||||||
|
for (let i = 0, len = flags.length; i < len; i += 1) {
|
||||||
|
if (!Number.isFinite(colorByData[i])) {
|
||||||
|
flags[i] = flagNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
});
|
||||||
|
|
||||||
computePointFlags = memoize(
|
computePointFlags = memoize(
|
||||||
(crossfilter, colorByData, pointDilationData, pointDilationLabel) => {
|
(crossfilter, colorByData, pointDilationData, pointDilationLabel) => {
|
||||||
/*
|
/*
|
||||||
@@ -132,24 +158,25 @@ class Scatterplot extends React.PureComponent {
|
|||||||
continuous metadata, as they rely on different tests, and some of the flags
|
continuous metadata, as they rely on different tests, and some of the flags
|
||||||
(eg, isNaN) are meaningless in the face of categorical metadata.
|
(eg, isNaN) are meaningless in the face of categorical metadata.
|
||||||
*/
|
*/
|
||||||
|
const nObs = crossfilter.size();
|
||||||
|
|
||||||
const flags = this.computeSelectedFlags(
|
const selectedFlags = this.computeSelectedFlags(
|
||||||
crossfilter,
|
crossfilter,
|
||||||
flagSelected,
|
flagSelected,
|
||||||
0
|
0
|
||||||
).slice();
|
);
|
||||||
|
const highlightFlags = this.computeHighlightFlags(
|
||||||
|
nObs,
|
||||||
|
pointDilationData,
|
||||||
|
pointDilationLabel
|
||||||
|
);
|
||||||
|
const colorByFlags = this.computeColorByFlags(nObs, colorByData);
|
||||||
|
|
||||||
if (colorByData || pointDilationData) {
|
const flags = new Float32Array(nObs);
|
||||||
for (let i = 0, len = flags.length; i < len; i += 1) {
|
for (let i = 0; i < nObs; i += 1) {
|
||||||
if (pointDilationData) {
|
flags[i] = selectedFlags[i] + highlightFlags[i] + colorByFlags[i];
|
||||||
flags[i] +=
|
|
||||||
pointDilationData[i] === pointDilationLabel ? flagHighlight : 0;
|
|
||||||
}
|
|
||||||
if (colorByData) {
|
|
||||||
flags[i] += Number.isFinite(colorByData[i]) ? 0 : flagNaN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user