mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-22 05:08:12 +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)
|
||||
}))
|
||||
class HistogramBrush extends React.Component {
|
||||
calcHistogramCache = memoize((obsAnnotations, metadataField, ranges) => {
|
||||
calcHistogramCache = memoize((obsAnnotations, field, ranges) => {
|
||||
// recalculate expensive stuff
|
||||
const allValuesForContinuousFieldAsArray = _.map(
|
||||
obsAnnotations,
|
||||
metadataField
|
||||
);
|
||||
const allValuesForContinuousFieldAsArray = _.map(obsAnnotations, field);
|
||||
const histogramCache = {};
|
||||
|
||||
histogramCache.x = d3
|
||||
@@ -61,17 +58,17 @@ class HistogramBrush extends React.Component {
|
||||
|
||||
onBrush(selection, x) {
|
||||
return () => {
|
||||
const { dispatch, metadataField } = this.props;
|
||||
const { dispatch, field } = this.props;
|
||||
if (d3.event.selection) {
|
||||
dispatch({
|
||||
type: "continuous metadata histogram brush",
|
||||
selection: metadataField,
|
||||
selection: field,
|
||||
range: [x(d3.event.selection[0]), x(d3.event.selection[1])]
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: "continuous metadata histogram brush",
|
||||
selection: metadataField,
|
||||
selection: field,
|
||||
range: null
|
||||
});
|
||||
}
|
||||
@@ -79,10 +76,10 @@ class HistogramBrush extends React.Component {
|
||||
}
|
||||
|
||||
drawHistogram(svgRef) {
|
||||
const { obsAnnotations, metadataField, ranges } = this.props;
|
||||
const { obsAnnotations, field, ranges } = this.props;
|
||||
const histogramCache = this.calcHistogramCache(
|
||||
obsAnnotations,
|
||||
metadataField,
|
||||
field,
|
||||
ranges
|
||||
);
|
||||
|
||||
@@ -109,11 +106,7 @@ class HistogramBrush extends React.Component {
|
||||
.select(svgRef)
|
||||
.append("g")
|
||||
.attr("class", "brush")
|
||||
.call(
|
||||
d3
|
||||
.brushX()
|
||||
.on("end", this.onBrush(metadataField, x.invert).bind(this))
|
||||
);
|
||||
.call(d3.brushX().on("end", this.onBrush(field, x.invert).bind(this)));
|
||||
|
||||
const xAxis = d3
|
||||
.select(svgRef)
|
||||
@@ -127,30 +120,40 @@ class HistogramBrush extends React.Component {
|
||||
.attr("fill", "#000")
|
||||
.attr("text-anchor", "end")
|
||||
.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 });
|
||||
}
|
||||
}
|
||||
|
||||
handleColorAction() {
|
||||
const { dispatch, metadataField, initializeRanges } = this.props;
|
||||
const { dispatch, field, initializeRanges } = this.props;
|
||||
dispatch({
|
||||
type: "color by continuous metadata",
|
||||
colorAccessor: metadataField,
|
||||
rangeMaxForColorAccessor: initializeRanges[metadataField].range.max
|
||||
colorAccessor: field,
|
||||
rangeMaxForColorAccessor: initializeRanges[field].range.max
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { metadataField, ranges, colorAccessor } = this.props;
|
||||
const { field, ranges, colorAccessor } = this.props;
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
marginTop: 10,
|
||||
position: "flex"
|
||||
}}
|
||||
id={`histogram_${metadataField}`}
|
||||
id={`histogram_${field}`}
|
||||
>
|
||||
<svg
|
||||
width={this.width}
|
||||
@@ -168,11 +171,10 @@ class HistogramBrush extends React.Component {
|
||||
style={{
|
||||
fontSize: 16,
|
||||
marginLeft: 4,
|
||||
// padding: this.props.colorAccessor === this.props.metadataField ? 3 : "auto",
|
||||
// padding: this.props.colorAccessor === this.props.field ? 3 : "auto",
|
||||
borderRadius: 3,
|
||||
color:
|
||||
colorAccessor === metadataField ? globals.brightBlue : "black",
|
||||
// backgroundColor: this.props.colorAccessor === this.props.metadataField ? globals.brightBlue : "inherit",
|
||||
color: colorAccessor === field ? globals.brightBlue : "black",
|
||||
// backgroundColor: this.props.colorAccessor === this.props.field ? globals.brightBlue : "inherit",
|
||||
position: "relative",
|
||||
top: -29,
|
||||
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 { connect } from "react-redux";
|
||||
|
||||
import HistogramBrush from "./histogramBrush";
|
||||
import HistogramBrush from "../brushableHistogram/";
|
||||
|
||||
@connect(state => {
|
||||
const metadata = _.get(state.controls.world, "obsAnnotations", null);
|
||||
const ranges = _.get(state.controls.world, "summary.obs", null);
|
||||
|
||||
return {
|
||||
ranges,
|
||||
metadata,
|
||||
ranges: _.get(state.controls.world, "summary.obs", null),
|
||||
metadata: _.get(state.controls.world, "obsAnnotations", null),
|
||||
colorAccessor: state.controls.colorAccessor,
|
||||
colorScale: state.controls.colorScale,
|
||||
selectionUpdate: _.get(state.controls, "crossfilter.updateTime", null)
|
||||
@@ -29,16 +26,18 @@ class Continuous extends React.Component {
|
||||
}
|
||||
|
||||
handleColorAction(key) {
|
||||
const { dispatch, ranges } = this.props;
|
||||
dispatch({
|
||||
type: "color by continuous metadata",
|
||||
colorAccessor: key,
|
||||
rangeMaxForColorAccessor: ranges[key].range.max
|
||||
});
|
||||
return () => {
|
||||
const { dispatch, ranges } = this.props;
|
||||
dispatch({
|
||||
type: "color by continuous metadata",
|
||||
colorAccessor: key,
|
||||
rangeMaxForColorAccessor: ranges[key].range.max
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { ranges } = this.props;
|
||||
const { ranges, obsAnnotations } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -48,8 +47,10 @@ class Continuous extends React.Component {
|
||||
return (
|
||||
<HistogramBrush
|
||||
key={key}
|
||||
metadataField={key}
|
||||
field={key}
|
||||
fieldValues={obsAnnotations}
|
||||
ranges={value.range}
|
||||
handleColorAction={this.handleColorAction(key).bind(this)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -165,6 +165,7 @@ class Graph extends React.Component {
|
||||
if (!this.renderCache.sizes) {
|
||||
this.renderCache.sizes = new Float32Array(cellCount);
|
||||
}
|
||||
|
||||
crossfilter.fillByIsFiltered(this.renderCache.sizes, 4, 0.2);
|
||||
sizeBuffer({ data: this.renderCache.sizes, dimension: 1 });
|
||||
|
||||
|
||||
Vendored
+21
-13
@@ -35,6 +35,7 @@ const Controls = (
|
||||
categoricalAsBooleansMap: null,
|
||||
crossfilter: null,
|
||||
dimensionMap: null,
|
||||
dimensionMapVar: {},
|
||||
|
||||
colorAccessor: null,
|
||||
colorScale: null,
|
||||
@@ -115,9 +116,16 @@ const Controls = (
|
||||
};
|
||||
}
|
||||
case "expression load success": {
|
||||
const { world, universe } = state;
|
||||
const {
|
||||
world,
|
||||
universe,
|
||||
crossfilter,
|
||||
dimensionMap,
|
||||
dimensionMapVar
|
||||
} = state;
|
||||
let universeVarDataCache = universe.varDataCache;
|
||||
let worldVarDataCache = world.varDataCache;
|
||||
let _dimensionMapVar = dimensionMapVar;
|
||||
_.forEach(action.expressionData, (val, key) => {
|
||||
universeVarDataCache = kvCache.set(universeVarDataCache, key, val);
|
||||
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 {
|
||||
...state,
|
||||
dimensionMapVar,
|
||||
universe: {
|
||||
...universe,
|
||||
varDataCache: universeVarDataCache
|
||||
@@ -152,18 +172,6 @@ const Controls = (
|
||||
/*******************************
|
||||
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": {
|
||||
state.dimensionMap.x.filterRange([
|
||||
action.brushCoords.northwest[0],
|
||||
|
||||
Reference in New Issue
Block a user