Specify histogram thresholds in fixed-length array (#1086)

* Specify histogram thresholds in fixed-length array

Fixes https://github.com/chanzuckerberg/cellxgene/issues/1082

For background, see the following:
* https://github.com/d3/d3-array/issues/46
* https://stackoverflow.com/questions/15880058/d3-js-ticks-function-giving-more-elements-than-needed

* Oops, off by one!
This commit is contained in:
Matt Weiden
2020-01-06 11:13:02 -08:00
committed by GitHub
parent b172ff7f15
commit 4c1ecf9e52
3 changed files with 21 additions and 2 deletions

View File

@@ -1,4 +1,4 @@
import { range, rangeFill } from "../../src/util/range";
import { range, rangeFill, linspace } from "../../src/util/range";
describe("range", () => {
test("no defaults", () => {
@@ -40,3 +40,11 @@ describe("rangefill", () => {
);
});
});
describe("linspace", () => {
test("linspace(arr, start, step)", () => {
expect(linspace(0.0, 2.0, 5)).toMatchObject(
[0.0, 0.5, 1.0, 1.5, 2.0]
);
});
});

View File

@@ -12,6 +12,7 @@ import * as d3 from "d3";
import memoize from "memoize-one";
import * as globals from "../../globals";
import actions from "../../actions";
import { linspace } from "../../util/range";
import { makeContinuousDimensionName } from "../../util/nameCreators";
@connect((state, ownProps) => {
@@ -53,15 +54,20 @@ class HistogramBrush extends React.PureComponent {
const values = col.asArray();
const summary = col.summarize();
const { min: domainMin, max: domainMax } = summary;
const numBins = 40;
histogramCache.x = d3
.scaleLinear()
.domain([domainMin, domainMax])
.range([this.marginLeft, this.marginLeft + this.width]);
const [xStart, xStop] = histogramCache.x.domain();
const histThresholds = linspace(xStart, xStop, numBins + 1);
histogramCache.bins = d3
.histogram()
.domain(histogramCache.x.domain())
.thresholds(40)(values);
.thresholds(histThresholds)(values);
const yMax = histogramCache.bins
.map(b => b.length)

View File

@@ -43,3 +43,8 @@ export function range(start, stop, step) {
const len = Math.max(Math.ceil((stop - start) / step), 0);
return _doFill(new Array(len), start, step, len);
}
export function linspace(start, stop, nsteps) {
const delta = (stop - start) / (nsteps - 1).toFixed();
return range(0, nsteps, 1).map(i => start + i * delta);
}