mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-01 17:48:12 +08:00
* revert all commits to before Typescript migration * update compat workflow to match latest deps (#2335) * update compat workflow to match latest deps * attempt to debug * attempt to debug * remove debugging code * typo * update deps to match desktop (#2340) * fix: don't run lint with `--fix` on push tests (#2273) * fix: don't run lint with `--fix` on push tests * npx Co-authored-by: maniarathi <mani.arathi@gmail.com> Co-authored-by: Madison Dunitz <madison.dunitz@chanzuckerberg.com> * rename X_approx_distribution to X_approximate_distribution (#2337) * Correctly handle non-finite numbers in heuristic determination of X distribution (#2342) * handle non-finites explicitly * improve and test edge case handling for distribution estimation * revert debugging changes * code readability * clean up type inferencing (#2332) * unit tests for 64 bit conversion * clean up type handling * type inference tests * more type inference fixes * use schema to determine user intent for data typing * stop using deprecated API * fbs type encoding test * add missing test * add more tests * correctly infer X type for CXG adaptor * lint * fix typo * ts migration * cleanup from PR review * lint * PR review changes * remove unused packages from client (#2359) * remove unused packages from client * add missing peer dep * fix: disable FE auth testing on compatibility tests (#2377) * update: release process (#2277) Co-authored-by: maniarathi <mani.arathi@gmail.com> * fix: remove spaces in param setup (#2380) * delete deploy workflow (#2396) * undo reformatting which now does not pass lint * fix snapshots which changed due to npm dep changes * add missing quoting to snapshot * another snapshot typo fix * TS Revert (2) - replay PR #2347 and #2354 (#2403) * replay edits from PR 2347 * TS Revert (3) - replay edits in PR #2327 (#2404) * replay edits in PR 2327 * TS Revert (4) - replay PR #2355 (#2405) * replay edits in PR 2355 * add additional babel config * reformat with new prettier config Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com> Co-authored-by: maniarathi <mani.arathi@gmail.com> Co-authored-by: Madison Dunitz <madison.dunitz@chanzuckerberg.com>
153 lines
4.2 KiB
JavaScript
153 lines
4.2 KiB
JavaScript
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) => ({
|
|
layoutChoice: state.layoutChoice, // TODO: really should clean up naming, s/layout/embedding/g
|
|
schema: state.annoMatrix?.schema,
|
|
crossfilter: state.obsCrossfilter,
|
|
}))
|
|
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 } = this.props;
|
|
const { annoMatrix } = crossfilter;
|
|
return (
|
|
<ButtonGroup
|
|
style={{
|
|
position: "absolute",
|
|
display: "inherit",
|
|
left: 8,
|
|
bottom: 8,
|
|
zIndex: 9999,
|
|
}}
|
|
>
|
|
<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;
|
|
};
|