subset embedding UI improvement (#1667)

* add user flag feature to annomatrix

* add implicit subsetting for partial embeddings

* lint

* add embedding cell counts to embedding choice menu

* layout
This commit is contained in:
Bruce Martin
2020-07-27 09:58:14 -07:00
committed by GitHub
parent c25dd33d28
commit 0a626537d5
9 changed files with 295 additions and 71 deletions
+45 -5
View File
@@ -1,5 +1,6 @@
import React from "react";
import { connect } from "react-redux";
import Async from "react-async";
import {
ButtonGroup,
Popover,
@@ -11,10 +12,11 @@ import {
} from "@blueprintjs/core";
import * as globals from "../../globals";
import actions from "../../actions";
import { getDiscreteCellEmbeddingRowIndex } from "../../util/stateManager/viewStackHelpers";
@connect((state) => {
return {
layoutChoice: state.layoutChoice,
layoutChoice: state.layoutChoice, // TODO: really should clean up naming, s/layout/embedding/g
schema: state.annoMatrix?.schema,
crossfilter: state.obsCrossfilter,
};
@@ -32,6 +34,7 @@ class Embedding extends React.PureComponent {
render() {
const { layoutChoice, schema, crossfilter } = this.props;
const { annoMatrix } = crossfilter;
return (
<ButtonGroup
style={{
@@ -61,7 +64,6 @@ class Embedding extends React.PureComponent {
>
{layoutChoice?.current}: {crossfilter.countSelected()} out of{" "}
{crossfilter.size()} cells
{/* BRUCE to extend 1559 */}
</Button>
</Tooltip>
}
@@ -87,9 +89,9 @@ class Embedding extends React.PureComponent {
selectedValue={layoutChoice.current}
>
{layoutChoice.available.map((name) => (
<Radio
label={`${name} ${schema?.dataframe?.nObs} cells`}
value={name}
<LayoutChoice
annoMatrix={annoMatrix}
layoutName={name}
key={name}
/>
))}
@@ -103,3 +105,41 @@ class Embedding extends React.PureComponent {
}
export default Embedding;
const loadEmbeddingCounts = async ({ annoMatrix, layoutName }) => {
const embedding = await annoMatrix.fetch("emb", layoutName);
const discreteCellIndex = getDiscreteCellEmbeddingRowIndex(embedding);
return { embedding, discreteCellIndex };
};
const LayoutChoice = ({ annoMatrix, layoutName }) => {
return (
<Async
promiseFn={loadEmbeddingCounts}
annoMatrix={annoMatrix}
layoutName={layoutName}
>
{({ data, error, isPending }) => {
if (error) {
/* log, as this is unexpected */
console.error(error);
}
if (error || isPending) {
/* still loading, or errored out - just omit counts (TODO: spinner?) */
return <Radio label={`${layoutName}`} value={layoutName} />;
}
if (data) {
const { embedding, discreteCellIndex } = data;
const isAllCells = discreteCellIndex.size() === embedding.length;
const sizeHint = `${discreteCellIndex.size()} ${
isAllCells ? "(all) " : ""
}cells`;
return (
<Radio label={`${layoutName}: ${sizeHint}`} value={layoutName} />
);
}
return null;
}}
</Async>
);
};
+6 -3
View File
@@ -10,6 +10,7 @@ import InformationMenu from "./infoMenu";
import Subset from "./subset";
import UndoRedoReset from "./undoRedo";
import DiffexpButtons from "./diffexpButtons";
import { getEmbSubsetView } from "../../util/stateManager/viewStackHelpers";
@connect((state) => {
const { annoMatrix } = state;
@@ -17,9 +18,11 @@ import DiffexpButtons from "./diffexpButtons";
const selectedCount = crossfilter.countSelected();
const subsetPossible =
selectedCount !== 0 && selectedCount !== crossfilter.size(); // ie, not all are selected
const subsetResetPossible =
annoMatrix.nObs !== annoMatrix.schema.dataframe.nObs;
selectedCount !== 0 && selectedCount !== crossfilter.size(); // ie, not all and not none are selected
const embSubsetView = getEmbSubsetView(annoMatrix);
const subsetResetPossible = !embSubsetView
? annoMatrix.nObs !== annoMatrix.schema.dataframe.nObs
: annoMatrix.nObs !== embSubsetView.nObs;
return {
subsetPossible,