Files
cellxgene/client/src/components/geneExpression/geneSet.js
T
Severiano Badajoz a4050f10e1 feat(geneset): save diff exp result as geneset (#2216)
* update package lock

* allow falsey vals

* remove old diff exp handling

* save diff exp results as geneset

* delete test

* check for undefined or null

* use global geneset description for diffexp

* remove diffexp special code, no longer showing adjpval + logfoldchange

* remove differential map to state

* remove clear from FSM, since we no longer support those actions

* restore controlHelpers test with todo
2021-05-25 10:51:31 -07:00

183 lines
5.2 KiB
JavaScript

import React from "react";
import { connect } from "react-redux";
import { FaChevronRight, FaChevronDown } from "react-icons/fa";
import actions from "../../actions";
import Gene from "./gene";
import { memoize } from "../../util/dataframe/util";
import Truncate from "../util/truncate";
import * as globals from "../../globals";
import GenesetMenus from "./menus/genesetMenus";
import EditGenesetNameDialogue from "./menus/editGenesetNameDialogue";
import HistogramBrush from "../brushableHistogram";
@connect((state, ownProps) => {
return {
world: state.world,
userDefinedGenes: state.controls.userDefinedGenes,
userDefinedGenesLoading: state.controls.userDefinedGenesLoading,
isColorAccessor: state.colors.colorAccessor === ownProps.setName,
};
})
class GeneSet extends React.Component {
_memoGenesToUpper = memoize(this._genesToUpper, (arr) => arr);
constructor(props) {
super(props);
this.state = {
isOpen: false,
};
}
_genesToUpper = (listGenes) => {
// Has to be a Map to preserve index
const upperGenes = new Map();
for (let i = 0, { length } = listGenes; i < length; i += 1) {
upperGenes.set(listGenes[i].toUpperCase(), i);
}
return upperGenes;
};
fetchGenes = () => {
const { world, dispatch, setGenes } = this.props;
const varIndexName = world.schema.annotations.var.index;
const worldGenes = world.varAnnotations.col(varIndexName).asArray();
const upperGenes = this._genesToUpper(setGenes);
const upperWorldGenes = this._memoGenesToUpper(worldGenes);
dispatch({ type: "bulk user defined gene start" });
Promise.all(
[...upperGenes.keys()].map((upperGene) => {
const indexOfGene = upperWorldGenes.get(upperGene);
return dispatch(
actions.requestUserDefinedGene(worldGenes[indexOfGene])
);
})
).then(
() => dispatch({ type: "bulk user defined gene complete" }),
() => dispatch({ type: "bulk user defined gene error" })
);
return undefined;
};
onGenesetMenuClick = () => {
const { isOpen } = this.state;
this.setState({ isOpen: !isOpen });
};
onColorChangeClick = () => {
// const { dispatch, setName } = this.props;
// dispatch({
// type: "color by gene set",
// colorAccessor: setName,
// });
};
renderGenes() {
const { setName, setGenes, setGenesWithDescriptions } = this.props;
return setGenes.map((gene) => {
const { geneDescription } = setGenesWithDescriptions.get(gene);
return (
<Gene
key={gene}
gene={gene}
geneDescription={geneDescription}
geneset={setName}
/>
);
});
}
render() {
const { setName, setGenes, genesetDescription } = this.props;
const { isOpen } = this.state;
const genesetNameLengthVisible = 150; /* this magic number determines how much of a long geneset name we see */
const genesetIsEmpty = setGenes.length === 0;
return (
<div style={{ marginBottom: 3 }}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "baseline",
}}
>
<span
role="menuitem"
tabIndex="0"
data-testclass="geneset-expand"
data-testid={`${setName}:geneset-expand`}
onKeyPress={
/* TODO(colinmegill): #2101: click handler on span */ () => {}
}
style={{
cursor: "pointer",
userSelect: "none",
}}
onClick={this.onGenesetMenuClick}
>
<Truncate
tooltipAddendum={
genesetDescription ? `: ${genesetDescription}` : ""
}
>
<span
style={{
maxWidth: globals.leftSidebarWidth - genesetNameLengthVisible,
}}
data-testid={`${setName}:geneset-label`}
>
{setName}
</span>
</Truncate>
{isOpen ? (
<FaChevronDown
data-testclass="geneset-expand-is-expanded"
style={{ fontSize: 10, marginLeft: 5 }}
/>
) : (
<FaChevronRight
data-testclass="geneset-expand-is-not-expanded"
style={{ fontSize: 10, marginLeft: 5 }}
/>
)}
</span>
<div>
<GenesetMenus isOpen={isOpen} genesetsEditable geneset={setName} />
</div>
</div>
<div style={{ marginLeft: 15, marginTop: 5, marginRight: 0 }}>
{isOpen && genesetIsEmpty && (
<p style={{ fontStyle: "italic", color: "lightgrey" }}>
No genes to display
</p>
)}
</div>
{isOpen && !genesetIsEmpty && setGenes.length > 0 && (
<HistogramBrush
isGeneSetSummary
field={setName}
setGenes={setGenes}
/>
)}
{isOpen && !genesetIsEmpty && this.renderGenes()}
<EditGenesetNameDialogue
parentGeneset={setName}
parentGenesetDescription={genesetDescription}
/>
</div>
);
}
}
export default GeneSet;