mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-07 21:08:11 +08:00
embedding to tsx
This commit is contained in:
@@ -1,155 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { useAsync } from "react-async";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
ButtonGroup,
|
|
||||||
H4,
|
|
||||||
Popover,
|
|
||||||
Position,
|
|
||||||
Radio,
|
|
||||||
RadioGroup,
|
|
||||||
Tooltip,
|
|
||||||
} from "@blueprintjs/core";
|
|
||||||
import * as globals from "../../globals";
|
|
||||||
import actions from "../../actions";
|
|
||||||
import { getDiscreteCellEmbeddingRowIndex } from "../../util/stateManager/viewStackHelpers";
|
|
||||||
|
|
||||||
@connect((state) => {
|
|
||||||
return {
|
|
||||||
layoutChoice: state.layoutChoice, // TODO: really should clean up naming, s/layout/embedding/g
|
|
||||||
schema: state.annoMatrix?.schema,
|
|
||||||
crossfilter: state.obsCrossfilter,
|
|
||||||
dotplot: state.layoutChoice.dotplot,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
class Embedding extends React.PureComponent {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
handleLayoutChoiceChange = (e) => {
|
|
||||||
const { dispatch } = this.props;
|
|
||||||
dispatch(actions.layoutChoiceAction(e.currentTarget.value));
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { layoutChoice, schema, crossfilter, dotplot } = this.props;
|
|
||||||
const { annoMatrix } = crossfilter;
|
|
||||||
return (
|
|
||||||
<ButtonGroup
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
left: 8,
|
|
||||||
bottom: 8,
|
|
||||||
zIndex: 9999,
|
|
||||||
display: dotplot ? "none" : "inherit",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Popover
|
|
||||||
target={
|
|
||||||
<Tooltip
|
|
||||||
content="Select embedding for visualization"
|
|
||||||
position="top"
|
|
||||||
hoverOpenDelay={globals.tooltipHoverOpenDelay}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="button"
|
|
||||||
data-testid="layout-choice"
|
|
||||||
icon="heatmap"
|
|
||||||
// minimal
|
|
||||||
id="embedding"
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{layoutChoice?.current}: {crossfilter.countSelected()} out of{" "}
|
|
||||||
{crossfilter.size()} cells
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
// minimal /* removes arrow */
|
|
||||||
position={Position.TOP_LEFT}
|
|
||||||
content={
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "flex-start",
|
|
||||||
alignItems: "flex-start",
|
|
||||||
flexDirection: "column",
|
|
||||||
padding: 10,
|
|
||||||
width: 400,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<H4>Embedding Choice</H4>
|
|
||||||
<p style={{ fontStyle: "italic" }}>
|
|
||||||
There are {schema?.dataframe?.nObs} cells in the entire dataset.
|
|
||||||
</p>
|
|
||||||
<EmbeddingChoices
|
|
||||||
onChange={this.handleLayoutChoiceChange}
|
|
||||||
annoMatrix={annoMatrix}
|
|
||||||
layoutChoice={layoutChoice}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</ButtonGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Embedding;
|
|
||||||
|
|
||||||
const loadAllEmbeddingCounts = async ({ annoMatrix, available }) => {
|
|
||||||
const embeddings = await Promise.all(
|
|
||||||
available.map((name) => annoMatrix.base().fetch("emb", name))
|
|
||||||
);
|
|
||||||
return available.map((name, idx) => ({
|
|
||||||
embeddingName: name,
|
|
||||||
embedding: embeddings[idx],
|
|
||||||
discreteCellIndex: getDiscreteCellEmbeddingRowIndex(embeddings[idx]),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const EmbeddingChoices = ({ onChange, annoMatrix, layoutChoice }) => {
|
|
||||||
const { available } = layoutChoice;
|
|
||||||
const { data, error, isPending } = useAsync({
|
|
||||||
promiseFn: loadAllEmbeddingCounts,
|
|
||||||
annoMatrix,
|
|
||||||
available,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
/* log, as this is unexpected */
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
if (error || isPending) {
|
|
||||||
/* still loading, or errored out - just omit counts (TODO: spinner?) */
|
|
||||||
return (
|
|
||||||
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
|
||||||
{layoutChoice.available.map((name) => (
|
|
||||||
<Radio label={`${name}`} value={name} key={name} />
|
|
||||||
))}
|
|
||||||
</RadioGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (data) {
|
|
||||||
return (
|
|
||||||
<RadioGroup onChange={onChange} selectedValue={layoutChoice.current}>
|
|
||||||
{data.map((summary) => {
|
|
||||||
const { discreteCellIndex, embeddingName } = summary;
|
|
||||||
const sizeHint = `${discreteCellIndex.size()} cells`;
|
|
||||||
return (
|
|
||||||
<Radio
|
|
||||||
label={`${embeddingName}: ${sizeHint}`}
|
|
||||||
value={embeddingName}
|
|
||||||
key={embeddingName}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</RadioGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
@@ -26,6 +26,7 @@ type EmbeddingState = any;
|
|||||||
schema: (state as any).annoMatrix?.schema,
|
schema: (state as any).annoMatrix?.schema,
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any --- FIXME: disabled temporarily on migrate to TS.
|
||||||
crossfilter: (state as any).obsCrossfilter,
|
crossfilter: (state as any).obsCrossfilter,
|
||||||
|
dotplot: (state as any).layoutChoice.dotplot,
|
||||||
}))
|
}))
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types --- FIXME: disabled temporarily on migrate to TS.
|
// eslint-disable-next-line @typescript-eslint/ban-types --- FIXME: disabled temporarily on migrate to TS.
|
||||||
class Embedding extends React.PureComponent<{}, EmbeddingState> {
|
class Embedding extends React.PureComponent<{}, EmbeddingState> {
|
||||||
@@ -45,13 +46,13 @@ class Embedding extends React.PureComponent<{}, EmbeddingState> {
|
|||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types --- FIXME: disabled temporarily on migrate to TS.
|
||||||
render() {
|
render() {
|
||||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'layoutChoice' does not exist on type 'Re... Remove this comment to see the full error message
|
// @ts-expect-error ts-migrate(2339) FIXME: Property 'layoutChoice' does not exist on type 'Re... Remove this comment to see the full error message
|
||||||
const { layoutChoice, schema, crossfilter } = this.props;
|
const { layoutChoice, schema, crossfilter, dotplot } = this.props;
|
||||||
const { annoMatrix } = crossfilter;
|
const { annoMatrix } = crossfilter;
|
||||||
return (
|
return (
|
||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
display: "inherit",
|
display: dotplot ? "none" : "inherit",
|
||||||
left: 8,
|
left: 8,
|
||||||
bottom: 8,
|
bottom: 8,
|
||||||
zIndex: 9999,
|
zIndex: 9999,
|
||||||
|
|||||||
Reference in New Issue
Block a user