Files
cellxgene/client/src/components/geneExpression/geneSet.js
T
e6e358ddc8 Gene sets UI, right sidebar refactor (#2097)
* prototyping

* render histos on open gene set

* prototyping

* render histos on open gene set

* factor out add genes to own component

* remove unused import

* mock reducer

* color by geneset stub

* menus and buttons

* geneset dialogue stub

* remove heatmap mock

* componetize histogram

* reenable add genes

* re-add isuserdefined

* test data

* remove have fetched

* add isExpanded state to gene, and pass to histogram

* expand button

* toggleable

* mini

* bump number of genes to 50

* don't clear diffexp on subset

* move create category to top

* render diffexp as geneset

* geneset show mean expression

* gene set reducer

* add geneset UI reducer

* wire e2e gene set loading prototype

* fix sniffing bug

* fix typo

* add gene modals

* client/src/actions/

* add autosave

* rename data-dir cli param

* add geneset, add gene, delete set

* prototype: remove csv upload placeholder

* handle delete gene from set

* prepopulate geneset with genes from modal

* add geneset: rename action

* icons, language consistency

* chevron after

* handle empty string case on genes for create geneset

* edit geneset

* fix language on create

* copy correction

* add popper2
upgrade react popper
upgrade react popper
adding popover2 package

* truncate uses tooltip2

* gene set button text typo

* remove logging

* moving server over

* remove test imports

* don't try to destructure map, use array.from

* fix add gene map datastructure error

* Revert "fix add gene map datastructure error"

This reverts commit b0eed45952.

* name --> genesetName, genes --> geneSymbols

* add gene to geneset, temporary format

* handle empty case, clear form input

* lint -- genesets wasn't passed via props

* userinfo

* move genes string to object conversion to action

* remove tmp gene description

* emptystring default for description

* remove empty string

* remove top level package json

* remove package lock as well

* remove flag for feature toggle

* remove comments in geneset

* comment cleanup

* remove comment

* revert diffexp genes to 10

* color by gene set

* disable color by gene set

* Gene menus are now inline, remove dead prototype code

* remove todo, magic number to variable

* remove jshint in rightsidebar

Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com>

* remove unused geneset validation code

* tmp format pending geneset description

* move magic number into variable

* reorganize genesetsUI reducer pending tests

* rewire edit given new action name

* add basic validation and feedback for geneset name uniqueness

* mv annoDialog

* mv label, repair paths

* Update client/src/components/brushableHistogram/header.js

Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com>

* add imports for icon in histo

* update jest snapshots given blueprint/tooltip2 usage of index -1

* ensure no empty paragraph

* intent from blueprint

* remove remainder of jshint references

* do not push undo when autosave fires

* fix autosave bugs

* remove todos

* clamp to util

* scient to util

* revert clearing diffexp

* rename value to be more specific stacked bar

* clean up logging and commetns

* remove gene entry tests pending rewrite

* tab index -1

* update jest snapshot, blueprint tooltip 2

* caret margin

* snapshot update

* ensure histogram is centered

* add geneset actions to config

* comment maybeScientific

* comment clamp

* comment ui reducer

* remove prototype code

* remove error log

* remove references to bl.ocks

* componetize parseBulkGeneString

* catch case where geneset rename same name

* genesetui reducer tests

* add geneset ui to index reducer config

Co-authored-by: bkmartinjr <bruce@chanzuckerberg.com>
Co-authored-by: Severiano Badajoz <sbadajoz@chanzuckerberg.com>
2021-03-24 16:33:26 -04:00

184 lines
5.4 KiB
JavaScript

import React from "react";
import _ from "lodash";
import { connect } from "react-redux";
import { Tooltip, Position, Switch } from "@blueprintjs/core";
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";
@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,
toggleSummaryHisto: 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,
// });
};
toggleSummaryHisto = () => {
const { toggleSummaryHisto } = this.state;
this.setState({ toggleSummaryHisto: !toggleSummaryHisto });
};
render() {
const { setName, setGenes, isDiffexp } = this.props;
const { isOpen, toggleSummaryHisto } = this.state;
const genesetNameLengthVisible = 120; /* this magic number determines how much of a long geneset name we see */
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>
<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 genesetsEditable geneset={setName} />
</div>
</div>
<div style={{ marginLeft: 15, marginTop: 5, marginRight: 0 }}>
{isOpen ? (
<Tooltip
content="Aggregate all genes in this geneset, and allow coloring by and selecting on the entire set."
position={Position.BOTTOM_RIGHT}
usePortal
hoverOpenDelay={globals.tooltipHoverOpenDelay}
modifiers={{
preventOverflow: { enabled: false },
hide: { enabled: false },
}}
>
<Switch
style={{ fontStyle: "italic" }}
checked={toggleSummaryHisto}
label="Show mean expression across entire set"
alignIndicator="left"
innerLabel="off"
innerLabelChecked="on"
onChange={this.toggleSummaryHisto}
/>
</Tooltip>
) : null}
</div>
{isOpen && !toggleSummaryHisto
? _.map(setGenes, (gene) => {
return (
<Gene
key={gene}
gene={gene}
geneset={setName}
isDiffexp={isDiffexp}
/>
);
})
: null}
</div>
);
}
}
export default GeneSet;