Begin integrating blueprint (#359)

* toast test

* modify webpack build to allow for global CSS; use CSS modules to scope component styling

* remove heatmap

* add label to index resets

* swapping out buttons for blueprint

* adding constants to globals

* swapping out blueprint buttons

* title position, sidebar improvements

* sidebar styles

* adding toasts for validation errors

* zebra section trial

* integrating blueprint, switching buttons over, breaking out scatter

* clean up console
This commit is contained in:
Colin Megill
2018-10-22 15:46:37 -04:00
committed by GitHub
parent 0c271bc815
commit df671192be
34 changed files with 717 additions and 737 deletions
@@ -0,0 +1,46 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import { Button } from "@blueprintjs/core";
import { connect } from "react-redux";
import * as globals from "../../globals";
@connect()
class CellSetButton extends React.Component {
set() {
const {
differential,
crossfilter,
dispatch,
eitherCellSetOneOrTwo
} = this.props;
const set = _.map(crossfilter.allFiltered(), "name");
if (!differential.diffExp) {
/* diffexp needs to be cleared before we store a new set */
dispatch({
type: `store current cell selection as differential set ${eitherCellSetOneOrTwo}`,
data: set
});
}
}
render() {
const { differential, eitherCellSetOneOrTwo } = this.props;
const cellListName = `celllist${eitherCellSetOneOrTwo}`;
return (
<span style={{ marginRight: 10 }}>
<Button type="button" onClick={this.set.bind(this)}>
{eitherCellSetOneOrTwo}
{": "}
{differential[cellListName]
? `${differential[cellListName].length} cells`
: "0 cells"}
</Button>
</span>
);
}
}
export default CellSetButton;
@@ -0,0 +1,79 @@
// jshint esversion: 6
import React from "react";
import _ from "lodash";
import { Button } from "@blueprintjs/core";
import { connect } from "react-redux";
import * as globals from "../../globals";
import actions from "../../actions";
import CellSetButton from "./cellSetButtons";
@connect(state => ({
differential: state.differential,
world: state.controls.world,
crossfilter: state.controls.crossfilter,
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
}))
class Expression extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
computeDiffExp() {
const { dispatch, differential } = this.props;
if (differential.celllist1 && differential.celllist2) {
dispatch(
actions.requestDifferentialExpression(
differential.celllist1,
differential.celllist2
)
);
}
}
clearDifferentialExpression() {
const { dispatch, differential } = this.props;
dispatch({
type: "clear differential expression",
diffExp: differential.diffExp
});
}
render() {
const { differential } = this.props;
if (!differential) {
return null;
}
const haveBothCellSets =
!!differential.celllist1 && !!differential.celllist2;
return (
<div style={{ marginRight: 10, marginBottom: 10 }}>
<CellSetButton {...this.props} eitherCellSetOneOrTwo={1} />
<CellSetButton {...this.props} eitherCellSetOneOrTwo={2} />
{!differential.diffExp ? (
<Button
style={{ marginTop: 10 }}
disabled={!haveBothCellSets}
intent="primary"
type="button"
onClick={this.computeDiffExp.bind(this)}
>
Compute Differential Expression
</Button>
) : null}
{differential.diffExp ? (
<Button
type="button"
style={{ marginTop: 10 }}
intent="warning"
onClick={this.clearDifferentialExpression.bind(this)}
>
Clear Differential Expression
</Button>
) : null}
</div>
);
}
}
export default Expression;
+91 -76
View File
@@ -5,10 +5,11 @@ import React from "react";
import _ from "lodash";
import * as d3 from "d3";
import { connect } from "react-redux";
import { FaPlusCircle } from "react-icons/fa";
import HistogramBrush from "../brushableHistogram";
import * as globals from "../../globals";
import actions from "../../actions";
import { ErrorToastTopCenter } from "../framework/toasters";
import ExpressionButtons from "./expressionButtons";
@connect(state => {
const metadata = _.get(state.controls.world, "obsAnnotations", null);
@@ -45,13 +46,18 @@ class GeneExpression extends React.Component {
const { gene } = this.state;
if (userDefinedGenes.indexOf(gene) !== -1) {
console.log("That gene already exists");
ErrorToastTopCenter.show({
message: "That gene already exists"
});
} else if (userDefinedGenes.length > 15) {
console.log(
"That's too many genes, you can have at most 15 user defined genes"
);
ErrorToastTopCenter.show({
message:
"That's too many genes, you can have at most 15 user defined genes"
});
} else if (!_.find(world.varAnnotations, { name: gene })) {
console.log("That doesn't appear to be a valid gene name.");
ErrorToastTopCenter.show({
message: "That doesn't appear to be a valid gene name."
});
} else {
dispatch(actions.requestUserDefinedGene(gene));
dispatch({
@@ -68,79 +74,88 @@ class GeneExpression extends React.Component {
return (
<div>
<input
onKeyDown={this.keyPress.bind(this)}
onChange={e => {
this.setState({ gene: e.target.value });
}}
type="text"
value={gene}
/>
<button
type="button"
<div
style={{
border: "none",
background: "none",
cursor: "pointer",
outline: "none",
marginTop: 20,
padding: 0
padding: globals.leftSidebarSectionPadding,
marginTop: 30
}}
onClick={this.handleClick.bind(this)}
>
<FaPlusCircle
style={{
display: "inline-block",
marginLeft: 7,
position: "relative",
top: 5,
color: globals.brightBlue,
fontSize: 22
}}
/>{" "}
add gene{" "}
</button>
{world && userDefinedGenes.length > 0 ? (
<p>User defined genes</p>
) : null}
{world && userDefinedGenes.length > 0
? _.map(userDefinedGenes, geneName => {
const values = world.varDataCache[geneName];
if (!values) {
return null;
}
return (
<HistogramBrush
key={geneName}
field={geneName}
ranges={d3.extent(values)}
isUserDefined
/>
);
})
: null}
{differential.diffExp ? <p> Differentially Expressed Genes </p> : null}
{differential.diffExp
? _.map(differential.diffExp, value => {
const annotations = world.varAnnotations[value[0]];
const { name } = annotations;
const values = world.varDataCache[name];
if (!values) {
return null;
}
return (
<HistogramBrush
key={name}
field={name}
ranges={d3.extent(values)}
isDiffExp
diffExp_avgDiff={value[1]}
diffExp_set1AvgExp={value[4]}
diffExp_set2AvgExp={value[5]}
/>
);
})
: null}
<p style={globals.leftSidebarSectionHeading}>Custom genes</p>
<div style={{ marginTop: 11 }} className="bp3-control-group">
<div className="bp3-input-group">
<span className="bp3-icon bp3-icon-symbol-cross" />
<input
onKeyDown={this.keyPress.bind(this)}
onChange={e => {
this.setState({ gene: e.target.value });
}}
value={gene}
type="text"
className="bp3-input"
placeholder="Add a custom gene"
style={{ paddingRight: 94 }}
/>
</div>
<button
type="button"
className="bp3-button bp3-intent-primary"
onClick={this.handleClick.bind(this)}
>
Add
</button>
</div>
{world && userDefinedGenes.length > 0
? _.map(userDefinedGenes, geneName => {
const values = world.varDataCache[geneName];
if (!values) {
return null;
}
return (
<HistogramBrush
key={geneName}
field={geneName}
ranges={d3.extent(values)}
isUserDefined
/>
);
})
: null}
</div>
<div
style={{
padding: globals.leftSidebarSectionPadding
}}
>
<p
style={Object.assign({}, globals.leftSidebarSectionHeading, {
marginTop: 40
})}
>
Differentially Expressed Genes
</p>
<ExpressionButtons />
{differential.diffExp
? _.map(differential.diffExp, value => {
const annotations = world.varAnnotations[value[0]];
const { name } = annotations;
const values = world.varDataCache[name];
if (!values) {
return null;
}
return (
<HistogramBrush
key={name}
field={name}
ranges={d3.extent(values)}
isDiffExp
avgDiff={value[1]}
set1AvgExp={value[4]}
set2AvgExp={value[5]}
/>
);
})
: null}
</div>
</div>
);
}