// jshint esversion: 6 /* rc slider https://www.npmjs.com/package/rc-slider */ import React from "react"; import _ from "lodash"; import fuzzysort from "fuzzysort"; import { connect } from "react-redux"; import { MenuItem, Button, FormGroup, InputGroup, ControlGroup } from "@blueprintjs/core"; import { Suggest } from "@blueprintjs/select"; import HistogramBrush from "../brushableHistogram"; import * as globals from "../../globals"; import actions from "../../actions"; import { postUserErrorToast, keepAroundErrorToast } from "../framework/toasters"; import ExpressionButtons from "./expressionButtons"; import finiteExtent from "../../util/finiteExtent"; const renderGene = (fuzzySortResult, { handleClick, modifiers, query }) => { if (!modifiers.matchesPredicate) { return null; } /* the fuzzysort wraps the object with other properties, like a score */ const gene = fuzzySortResult.obj; const text = gene.name; return ( { /* this fires when user clicks a menu item */ handleClick(g); }} text={text} /> ); }; const filterGenes = (query, genes) => { /* fires on load, once, and then for each character typed into the input */ return fuzzysort.go(query, genes, { key: "name", limit: 5, threshold: -10000 // don't return bad results }); }; @connect(state => { const metadata = _.get(state.controls.world, "obsAnnotations", null); const ranges = _.get(state.controls.world, "summary.obs", null); const initializeRanges = _.get(state.controls.world, "summary.obs"); return { ranges, metadata, initializeRanges, userDefinedGenes: state.controls.userDefinedGenes, userDefinedGenesLoading: state.controls.userDefinedGenesLoading, world: state.controls.world, colorAccessor: state.controls.colorAccessor, allGeneNames: state.controls.allGeneNames, differential: state.differential }; }) class GeneExpression extends React.Component { constructor(props) { super(props); this.state = { bulkAdd: "", tab: "autosuggest" }; } handleClick(g) { const { world, dispatch, userDefinedGenes } = this.props; const gene = g.target; if (userDefinedGenes.indexOf(gene) !== -1) { postUserErrorToast("That gene already exists"); } else if (userDefinedGenes.length > 15) { postUserErrorToast( "That's too many genes, you can have at most 15 user defined genes" ); } else if (!_.find(world.varAnnotations, { name: gene })) { postUserErrorToast("That doesn't appear to be a valid gene name."); } else { dispatch(actions.requestUserDefinedGene(gene)); dispatch({ type: "user defined gene", data: gene }); } } handleBulkAddClick() { const { world, dispatch, userDefinedGenes } = this.props; const { bulkAdd } = this.state; /* test: Apod,,, Cd74,, ,,, Foo, Bar-2,, */ if (bulkAdd !== "") { const genes = _.pull(_.uniq(bulkAdd.split(/[ ,]+/)), ""); genes.forEach(gene => { if (userDefinedGenes.indexOf(gene) !== -1) { keepAroundErrorToast("That gene already exists"); } else if (!_.find(world.varAnnotations, { name: gene })) { keepAroundErrorToast( `${gene} doesn't appear to be a valid gene name.` ); } else { dispatch(actions.requestUserDefinedGene(gene)); dispatch({ type: "user defined gene", data: gene }); } }); } this.setState({ bulkAdd: "" }); } render() { const { world, userDefinedGenes, userDefinedGenesLoading, differential } = this.props; const { tab, bulkAdd } = this.state; return (

Selected Genes

{tab === "autosuggest" ? ( true : () => false } noResults={} onItemSelect={g => { /* this happens on 'enter' */ this.handleClick(g); }} inputValueRenderer={g => { return ""; }} itemListPredicate={filterGenes} itemRenderer={renderGene.bind(this)} items={ world && world.varAnnotations ? world.varAnnotations : [{ name: "No genes" }] } popoverProps={{ minimal: true }} /> ) : null} {tab === "bulkadd" ? (
{ e.preventDefault(); this.handleBulkAddClick(); }} > { this.setState({ bulkAdd: e.target.value }); }} id="text-input-bulk-add" placeholder="Apod, Cd74, ..." value={bulkAdd} />
) : null} {world && userDefinedGenes.length > 0 ? _.map(userDefinedGenes, (geneName, index) => { const values = world.varDataCache[geneName]; if (!values) { return null; } return ( ); }) : null}

Differentially Expressed Genes

{differential.diffExp ? _.map(differential.diffExp, (value, index) => { const annotations = world.varAnnotations[value[0]]; const { name } = annotations; const values = world.varDataCache[name]; if (!values) { return null; } return ( ); }) : null}
); } } export default GeneExpression;