mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-10-07 04:58:11 +08:00
Merge pull request #55 from chanzuckerberg/bkmartinjr-perf3
performance - improve caching in histogram and graph
This commit is contained in:
@@ -36,6 +36,7 @@ class HistogramBrush extends React.Component {
|
|||||||
this.width = 300;
|
this.width = 300;
|
||||||
this.height = 100;
|
this.height = 100;
|
||||||
this.marginBottom = 20;
|
this.marginBottom = 20;
|
||||||
|
this.histogramCache = {};
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
svg: null,
|
svg: null,
|
||||||
@@ -47,6 +48,44 @@ class HistogramBrush extends React.Component {
|
|||||||
}
|
}
|
||||||
componentDidMount() {}
|
componentDidMount() {}
|
||||||
componentDidUpdate() {}
|
componentDidUpdate() {}
|
||||||
|
|
||||||
|
calcHistogramCache(nextProps) {
|
||||||
|
// recalculate expensive stuff
|
||||||
|
const allValuesForContinuousFieldAsArray = _.map(
|
||||||
|
nextProps.currentCellSelection,
|
||||||
|
nextProps.metadataField
|
||||||
|
);
|
||||||
|
|
||||||
|
this.histogramCache.x = d3
|
||||||
|
.scaleLinear()
|
||||||
|
.domain([nextProps.ranges.min, nextProps.ranges.max])
|
||||||
|
.range([0, this.width]);
|
||||||
|
|
||||||
|
this.histogramCache.y = d3
|
||||||
|
.scaleLinear()
|
||||||
|
.range([this.height - this.marginBottom, 0]);
|
||||||
|
// .range([height - margin.bottom, margin.top]);
|
||||||
|
|
||||||
|
this.histogramCache.bins = d3
|
||||||
|
.histogram()
|
||||||
|
.domain(this.histogramCache.x.domain())
|
||||||
|
.thresholds(40)(allValuesForContinuousFieldAsArray);
|
||||||
|
|
||||||
|
this.histogramCache.numValues = allValuesForContinuousFieldAsArray.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.calcHistogramCache(this.props);
|
||||||
|
}
|
||||||
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (
|
||||||
|
this.props.metadataField !== nextProps.metadataField ||
|
||||||
|
!this.histogramCache.x
|
||||||
|
) {
|
||||||
|
this.calcHistogramCache(nextProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onBrush(selection, x) {
|
onBrush(selection, x) {
|
||||||
return () => {
|
return () => {
|
||||||
if (d3.event.selection) {
|
if (d3.event.selection) {
|
||||||
@@ -65,24 +104,10 @@ class HistogramBrush extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
drawHistogram(svgRef) {
|
drawHistogram(svgRef) {
|
||||||
const allValuesForContinuousFieldAsArray = _.map(
|
const x = this.histogramCache.x;
|
||||||
this.props.currentCellSelection,
|
const y = this.histogramCache.y;
|
||||||
this.props.metadataField
|
const bins = this.histogramCache.bins;
|
||||||
);
|
const numValues = this.histogramCache.numValues;
|
||||||
|
|
||||||
var x = d3
|
|
||||||
.scaleLinear()
|
|
||||||
.domain(d3.extent(allValuesForContinuousFieldAsArray, d => +d))
|
|
||||||
.range([0, this.width]);
|
|
||||||
// .range([margin.left, width - margin.right]);
|
|
||||||
|
|
||||||
var y = d3.scaleLinear().range([this.height - this.marginBottom, 0]);
|
|
||||||
// .range([height - margin.bottom, margin.top]);
|
|
||||||
|
|
||||||
const bins = d3
|
|
||||||
.histogram()
|
|
||||||
.domain(x.domain())
|
|
||||||
.thresholds(40)(allValuesForContinuousFieldAsArray);
|
|
||||||
|
|
||||||
d3
|
d3
|
||||||
.select(svgRef)
|
.select(svgRef)
|
||||||
@@ -96,13 +121,13 @@ class HistogramBrush extends React.Component {
|
|||||||
return x(d.x0) + 1;
|
return x(d.x0) + 1;
|
||||||
})
|
})
|
||||||
.attr("y", function(d) {
|
.attr("y", function(d) {
|
||||||
return y(d.length / allValuesForContinuousFieldAsArray.length);
|
return y(d.length / numValues);
|
||||||
})
|
})
|
||||||
.attr("width", function(d) {
|
.attr("width", function(d) {
|
||||||
return Math.abs(x(d.x1) - x(d.x0) - 1);
|
return Math.abs(x(d.x1) - x(d.x0) - 1);
|
||||||
})
|
})
|
||||||
.attr("height", function(d) {
|
.attr("height", function(d) {
|
||||||
return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length);
|
return y(0) - y(d.length / numValues);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.state.brush && !this.state.axis) {
|
if (!this.state.brush && !this.state.axis) {
|
||||||
|
|||||||
@@ -113,35 +113,43 @@ class Graph extends React.Component {
|
|||||||
if (this.state.regl && nextProps.vertices) {
|
if (this.state.regl && nextProps.vertices) {
|
||||||
const vertices = nextProps.currentCellSelection;
|
const vertices = nextProps.currentCellSelection;
|
||||||
const vertexCount = vertices.length;
|
const vertexCount = vertices.length;
|
||||||
const positions = new Float32Array(2 * vertexCount);
|
|
||||||
const colors = new Float32Array(3 * vertexCount);
|
const colors = new Float32Array(3 * vertexCount);
|
||||||
const sizes = new Float32Array(vertexCount);
|
const sizes = new Float32Array(vertexCount);
|
||||||
|
|
||||||
// d3.scaleLinear().domain([0,1]).range([-1,1])
|
// Cache a scaled graph
|
||||||
const glScaleX = scaleLinear([0, 1], [-1, 1]);
|
if (!this.scaledGraphVec || this.props.graphVec !== nextProps.graphVec) {
|
||||||
// d3.scaleLinear().domain([0,1]).range([1,-1])
|
const positions = new Float32Array(2 * vertexCount);
|
||||||
const glScaleY = scaleLinear([0, 1], [1, -1]);
|
|
||||||
|
// d3.scaleLinear().domain([0,1]).range([-1,1])
|
||||||
|
const glScaleX = scaleLinear([0, 1], [-1, 1]);
|
||||||
|
// d3.scaleLinear().domain([0,1]).range([1,-1])
|
||||||
|
const glScaleY = scaleLinear([0, 1], [1, -1]);
|
||||||
|
|
||||||
|
const graphVec = nextProps.graphVec;
|
||||||
|
for (var i = 0; i < vertexCount; i++) {
|
||||||
|
const cell = vertices[i];
|
||||||
|
const cellIdx = cell.__cellIndex__;
|
||||||
|
|
||||||
|
const x = glScaleX(graphVec[2 * cellIdx]);
|
||||||
|
const y = glScaleY(graphVec[2 * cellIdx + 1]);
|
||||||
|
positions[2 * i] = x;
|
||||||
|
positions[2 * i + 1] = y;
|
||||||
|
}
|
||||||
|
this.scaledGraphVec = positions;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Construct Vectors
|
Construct Size & Color Vectors
|
||||||
*/
|
*/
|
||||||
const graphVec = nextProps.graphVec;
|
|
||||||
for (var i = 0; i < vertexCount; i++) {
|
for (var i = 0; i < vertexCount; i++) {
|
||||||
const cell = vertices[i];
|
const cell = vertices[i];
|
||||||
const cellIdx = cell.__cellIndex__;
|
|
||||||
const x = glScaleX(graphVec[2 * cellIdx]);
|
|
||||||
const y = glScaleY(graphVec[2 * cellIdx + 1]);
|
|
||||||
positions[2 * i] = x;
|
|
||||||
positions[2 * i + 1] = y;
|
|
||||||
|
|
||||||
colors.set(cell.__colorRGB__, 3 * i);
|
colors.set(cell.__colorRGB__, 3 * i);
|
||||||
|
|
||||||
sizes[i] = cell.__selected__
|
sizes[i] = cell.__selected__
|
||||||
? 4
|
? 4
|
||||||
: 0.2; /* make this a function of the number of total cells, including regraph */
|
: 0.2; /* make this a function of the number of total cells, including regraph */
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state.pointBuffer({ data: positions, dimension: 2 });
|
this.state.pointBuffer({ data: this.scaledGraphVec, dimension: 2 });
|
||||||
this.state.colorBuffer({ data: colors, dimension: 3 });
|
this.state.colorBuffer({ data: colors, dimension: 3 });
|
||||||
this.state.sizeBuffer({ data: sizes, dimension: 1 });
|
this.state.sizeBuffer({ data: sizes, dimension: 1 });
|
||||||
this.count = vertexCount;
|
this.count = vertexCount;
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ const updateCellSelectionMiddleware = store => {
|
|||||||
- metadata has cellname and index, and that's all we ever need to reference cell info
|
- metadata has cellname and index, and that's all we ever need to reference cell info
|
||||||
*/
|
*/
|
||||||
let newSelection = s.controls.currentCellSelection.slice(0);
|
let newSelection = s.controls.currentCellSelection.slice(0);
|
||||||
_.forEach(newSelection, cell => (cell.__selected__ = true));
|
// _.forEach(newSelection, cell => (cell.__selected__ = true));
|
||||||
|
for (let i = 0; i < newSelection.length; i++) {
|
||||||
|
newSelection[i].__selected__ = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
in plain language...
|
in plain language...
|
||||||
|
|||||||
Reference in New Issue
Block a user