From 4c1ecf9e52a463138ce3630bdcd4698a099ff234 Mon Sep 17 00:00:00 2001 From: Matt Weiden <538456+mweiden@users.noreply.github.com> Date: Mon, 6 Jan 2020 11:13:02 -0800 Subject: [PATCH] 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! --- client/__tests__/util/range.test.js | 10 +++++++++- client/src/components/brushableHistogram/index.js | 8 +++++++- client/src/util/range.js | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/client/__tests__/util/range.test.js b/client/__tests__/util/range.test.js index 0567c9eb..fac1ade3 100644 --- a/client/__tests__/util/range.test.js +++ b/client/__tests__/util/range.test.js @@ -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] + ); + }); +}); diff --git a/client/src/components/brushableHistogram/index.js b/client/src/components/brushableHistogram/index.js index fc7732fc..1b5b1a29 100644 --- a/client/src/components/brushableHistogram/index.js +++ b/client/src/components/brushableHistogram/index.js @@ -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) diff --git a/client/src/util/range.js b/client/src/util/range.js index 972a6276..01ac931b 100644 --- a/client/src/util/range.js +++ b/client/src/util/range.js @@ -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); +} \ No newline at end of file