mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-05 22:48:11 +08:00
create dimension for arbitrary gene
This commit is contained in:
+27
-25
@@ -19,12 +19,9 @@ import * as globals from "../../globals";
|
|||||||
obsAnnotations: _.get(state.controls.world, "obsAnnotations", null)
|
obsAnnotations: _.get(state.controls.world, "obsAnnotations", null)
|
||||||
}))
|
}))
|
||||||
class HistogramBrush extends React.Component {
|
class HistogramBrush extends React.Component {
|
||||||
calcHistogramCache = memoize((obsAnnotations, metadataField, ranges) => {
|
calcHistogramCache = memoize((obsAnnotations, field, ranges) => {
|
||||||
// recalculate expensive stuff
|
// recalculate expensive stuff
|
||||||
const allValuesForContinuousFieldAsArray = _.map(
|
const allValuesForContinuousFieldAsArray = _.map(obsAnnotations, field);
|
||||||
obsAnnotations,
|
|
||||||
metadataField
|
|
||||||
);
|
|
||||||
const histogramCache = {};
|
const histogramCache = {};
|
||||||
|
|
||||||
histogramCache.x = d3
|
histogramCache.x = d3
|
||||||
@@ -61,17 +58,17 @@ class HistogramBrush extends React.Component {
|
|||||||
|
|
||||||
onBrush(selection, x) {
|
onBrush(selection, x) {
|
||||||
return () => {
|
return () => {
|
||||||
const { dispatch, metadataField } = this.props;
|
const { dispatch, field } = this.props;
|
||||||
if (d3.event.selection) {
|
if (d3.event.selection) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "continuous metadata histogram brush",
|
type: "continuous metadata histogram brush",
|
||||||
selection: metadataField,
|
selection: field,
|
||||||
range: [x(d3.event.selection[0]), x(d3.event.selection[1])]
|
range: [x(d3.event.selection[0]), x(d3.event.selection[1])]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "continuous metadata histogram brush",
|
type: "continuous metadata histogram brush",
|
||||||
selection: metadataField,
|
selection: field,
|
||||||
range: null
|
range: null
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -79,10 +76,10 @@ class HistogramBrush extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawHistogram(svgRef) {
|
drawHistogram(svgRef) {
|
||||||
const { obsAnnotations, metadataField, ranges } = this.props;
|
const { obsAnnotations, field, ranges } = this.props;
|
||||||
const histogramCache = this.calcHistogramCache(
|
const histogramCache = this.calcHistogramCache(
|
||||||
obsAnnotations,
|
obsAnnotations,
|
||||||
metadataField,
|
field,
|
||||||
ranges
|
ranges
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -109,11 +106,7 @@ class HistogramBrush extends React.Component {
|
|||||||
.select(svgRef)
|
.select(svgRef)
|
||||||
.append("g")
|
.append("g")
|
||||||
.attr("class", "brush")
|
.attr("class", "brush")
|
||||||
.call(
|
.call(d3.brushX().on("end", this.onBrush(field, x.invert).bind(this)));
|
||||||
d3
|
|
||||||
.brushX()
|
|
||||||
.on("end", this.onBrush(metadataField, x.invert).bind(this))
|
|
||||||
);
|
|
||||||
|
|
||||||
const xAxis = d3
|
const xAxis = d3
|
||||||
.select(svgRef)
|
.select(svgRef)
|
||||||
@@ -127,30 +120,40 @@ class HistogramBrush extends React.Component {
|
|||||||
.attr("fill", "#000")
|
.attr("fill", "#000")
|
||||||
.attr("text-anchor", "end")
|
.attr("text-anchor", "end")
|
||||||
.attr("font-weight", "bold")
|
.attr("font-weight", "bold")
|
||||||
.text(metadataField);
|
.text(field);
|
||||||
|
|
||||||
|
d3.select(svgRef)
|
||||||
|
.selectAll(".axis--x text")
|
||||||
|
.style("fill", "rgb(80,80,80)");
|
||||||
|
d3.select(svgRef)
|
||||||
|
.selectAll(".axis--x path")
|
||||||
|
.style("stroke", "rgb(230,230,230)");
|
||||||
|
d3.select(svgRef)
|
||||||
|
.selectAll(".axis--x line")
|
||||||
|
.style("stroke", "rgb(230,230,230)");
|
||||||
|
|
||||||
this.setState({ brush, xAxis });
|
this.setState({ brush, xAxis });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleColorAction() {
|
handleColorAction() {
|
||||||
const { dispatch, metadataField, initializeRanges } = this.props;
|
const { dispatch, field, initializeRanges } = this.props;
|
||||||
dispatch({
|
dispatch({
|
||||||
type: "color by continuous metadata",
|
type: "color by continuous metadata",
|
||||||
colorAccessor: metadataField,
|
colorAccessor: field,
|
||||||
rangeMaxForColorAccessor: initializeRanges[metadataField].range.max
|
rangeMaxForColorAccessor: initializeRanges[field].range.max
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { metadataField, ranges, colorAccessor } = this.props;
|
const { field, ranges, colorAccessor } = this.props;
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginTop: 10,
|
marginTop: 10,
|
||||||
position: "flex"
|
position: "flex"
|
||||||
}}
|
}}
|
||||||
id={`histogram_${metadataField}`}
|
id={`histogram_${field}`}
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
width={this.width}
|
width={this.width}
|
||||||
@@ -168,11 +171,10 @@ class HistogramBrush extends React.Component {
|
|||||||
style={{
|
style={{
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
// padding: this.props.colorAccessor === this.props.metadataField ? 3 : "auto",
|
// padding: this.props.colorAccessor === this.props.field ? 3 : "auto",
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
color:
|
color: colorAccessor === field ? globals.brightBlue : "black",
|
||||||
colorAccessor === metadataField ? globals.brightBlue : "black",
|
// backgroundColor: this.props.colorAccessor === this.props.field ? globals.brightBlue : "inherit",
|
||||||
// backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit",
|
|
||||||
position: "relative",
|
position: "relative",
|
||||||
top: -29,
|
top: -29,
|
||||||
cursor: "pointer"
|
cursor: "pointer"
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import * as globals from "../../globals";
|
||||||
|
import _ from "lodash";
|
||||||
|
import * as constants from "./constants";
|
||||||
|
|
||||||
|
export const calcHistogram = (ranges, allValuesForContinuousFieldAsArray) => {
|
||||||
|
const histogramData = {};
|
||||||
|
|
||||||
|
histogramData.x = d3
|
||||||
|
.scaleLinear()
|
||||||
|
.domain([ranges.min, ranges.max])
|
||||||
|
.range([0, constants.width]);
|
||||||
|
|
||||||
|
histogramData.y = d3
|
||||||
|
.scaleLinear()
|
||||||
|
.range([constants.height - constants.marginBottom, 0]);
|
||||||
|
// .range([height - margin.bottom, margin.top]);
|
||||||
|
|
||||||
|
histogramData.bins = d3
|
||||||
|
.histogram()
|
||||||
|
.domain(histogramData.x.domain())
|
||||||
|
.thresholds(40)(allValuesForContinuousFieldAsArray);
|
||||||
|
|
||||||
|
histogramData.numValues = allValuesForContinuousFieldAsArray.length;
|
||||||
|
|
||||||
|
console.log(histogramData);
|
||||||
|
return histogramData;
|
||||||
|
};
|
||||||
@@ -5,15 +5,12 @@ import React from "react";
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import HistogramBrush from "./histogramBrush";
|
import HistogramBrush from "../brushableHistogram/";
|
||||||
|
|
||||||
@connect(state => {
|
@connect(state => {
|
||||||
const metadata = _.get(state.controls.world, "obsAnnotations", null);
|
|
||||||
const ranges = _.get(state.controls.world, "summary.obs", null);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ranges,
|
ranges: _.get(state.controls.world, "summary.obs", null),
|
||||||
metadata,
|
metadata: _.get(state.controls.world, "obsAnnotations", null),
|
||||||
colorAccessor: state.controls.colorAccessor,
|
colorAccessor: state.controls.colorAccessor,
|
||||||
colorScale: state.controls.colorScale,
|
colorScale: state.controls.colorScale,
|
||||||
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
|
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
|
||||||
@@ -29,16 +26,18 @@ class Continuous extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleColorAction(key) {
|
handleColorAction(key) {
|
||||||
const { dispatch, ranges } = this.props;
|
return () => {
|
||||||
dispatch({
|
const { dispatch, ranges } = this.props;
|
||||||
type: "color by continuous metadata",
|
dispatch({
|
||||||
colorAccessor: key,
|
type: "color by continuous metadata",
|
||||||
rangeMaxForColorAccessor: ranges[key].range.max
|
colorAccessor: key,
|
||||||
});
|
rangeMaxForColorAccessor: ranges[key].range.max
|
||||||
|
});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { ranges } = this.props;
|
const { ranges, obsAnnotations } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -48,8 +47,10 @@ class Continuous extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<HistogramBrush
|
<HistogramBrush
|
||||||
key={key}
|
key={key}
|
||||||
metadataField={key}
|
field={key}
|
||||||
|
fieldValues={obsAnnotations}
|
||||||
ranges={value.range}
|
ranges={value.range}
|
||||||
|
handleColorAction={this.handleColorAction(key).bind(this)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ class Graph extends React.Component {
|
|||||||
if (!this.renderCache.sizes) {
|
if (!this.renderCache.sizes) {
|
||||||
this.renderCache.sizes = new Float32Array(cellCount);
|
this.renderCache.sizes = new Float32Array(cellCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
crossfilter.fillByIsFiltered(this.renderCache.sizes, 4, 0.2);
|
crossfilter.fillByIsFiltered(this.renderCache.sizes, 4, 0.2);
|
||||||
sizeBuffer({ data: this.renderCache.sizes, dimension: 1 });
|
sizeBuffer({ data: this.renderCache.sizes, dimension: 1 });
|
||||||
|
|
||||||
|
|||||||
Vendored
+21
-13
@@ -35,6 +35,7 @@ const Controls = (
|
|||||||
categoricalAsBooleansMap: null,
|
categoricalAsBooleansMap: null,
|
||||||
crossfilter: null,
|
crossfilter: null,
|
||||||
dimensionMap: null,
|
dimensionMap: null,
|
||||||
|
dimensionMapVar: {},
|
||||||
|
|
||||||
colorAccessor: null,
|
colorAccessor: null,
|
||||||
colorScale: null,
|
colorScale: null,
|
||||||
@@ -115,9 +116,16 @@ const Controls = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
case "expression load success": {
|
case "expression load success": {
|
||||||
const { world, universe } = state;
|
const {
|
||||||
|
world,
|
||||||
|
universe,
|
||||||
|
crossfilter,
|
||||||
|
dimensionMap,
|
||||||
|
dimensionMapVar
|
||||||
|
} = state;
|
||||||
let universeVarDataCache = universe.varDataCache;
|
let universeVarDataCache = universe.varDataCache;
|
||||||
let worldVarDataCache = world.varDataCache;
|
let worldVarDataCache = world.varDataCache;
|
||||||
|
let _dimensionMapVar = dimensionMapVar;
|
||||||
_.forEach(action.expressionData, (val, key) => {
|
_.forEach(action.expressionData, (val, key) => {
|
||||||
universeVarDataCache = kvCache.set(universeVarDataCache, key, val);
|
universeVarDataCache = kvCache.set(universeVarDataCache, key, val);
|
||||||
if (kvCache.get(worldVarDataCache, key) === undefined) {
|
if (kvCache.get(worldVarDataCache, key) === undefined) {
|
||||||
@@ -128,8 +136,20 @@ const Controls = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_.forEach(action.expressionData, (val, key) => {
|
||||||
|
console.log("got one ", key);
|
||||||
|
dimensionMap[key] = World.createVarDimensionsMap(
|
||||||
|
world,
|
||||||
|
worldVarDataCache,
|
||||||
|
crossfilter,
|
||||||
|
key
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
dimensionMapVar,
|
||||||
universe: {
|
universe: {
|
||||||
...universe,
|
...universe,
|
||||||
varDataCache: universeVarDataCache
|
varDataCache: universeVarDataCache
|
||||||
@@ -152,18 +172,6 @@ const Controls = (
|
|||||||
/*******************************
|
/*******************************
|
||||||
User Events
|
User Events
|
||||||
*******************************/
|
*******************************/
|
||||||
case "parallel coordinates axes have been drawn": {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
axesHaveBeenDrawn: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case "continuous selection using parallel coords brushing": {
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
continuousSelection: action.data
|
|
||||||
};
|
|
||||||
}
|
|
||||||
case "graph brush selection change": {
|
case "graph brush selection change": {
|
||||||
state.dimensionMap.x.filterRange([
|
state.dimensionMap.x.filterRange([
|
||||||
action.brushCoords.northwest[0],
|
action.brushCoords.northwest[0],
|
||||||
|
|||||||
Reference in New Issue
Block a user