Skip to content

Commit 57cdbdd

Browse files
committed
Fix boundary case when filtering histogram thresholds.
Also document that thresholds outside the domain are ignored. Fixes #54.
1 parent f0bb1bf commit 57cdbdd

File tree

3 files changed

+20
-3
lines changed

3 files changed

+20
-3
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ Note that the domain accessor is invoked on the materialized array of [values](#
357357

358358
If *thresholds* is specified, sets the [threshold generator](#histogram-thresholds) to the specified function or array and returns this histogram generator. If *thresholds* is not specified, returns the current threshold generator, which by default implements [Sturges’ formula](#thresholdSturges). (Thus by default, the histogram values must be numbers!) Thresholds are defined as an array of values [*x0*, *x1*, …]. Any value less than *x0* will be placed in the first bin; any value greater than or equal to *x0* but less than *x1* will be placed in the second bin; and so on. Thus, the [generated histogram](#_histogram) will have *thresholds*.length + 1 bins. See [histogram thresholds](#histogram-thresholds) for more information.
359359

360+
Any threshold values outside the [domain](#histogram_domain) are ignored. The first *bin*.x0 is always equal to the minimum domain value, and the last *bin*.x1 is always equal to the maximum domain value.
361+
360362
If a *count* is specified instead of an array of *thresholds*, then the [domain](#histogram_domain) will be uniformly divided into approximately *count* bins; see [ticks](#ticks).
361363

362364
### Histogram Thresholds

src/histogram.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import bisect from "./bisect";
33
import constant from "./constant";
44
import extent from "./extent";
55
import identity from "./identity";
6-
import ticks from "./ticks";
6+
import range from "./range";
7+
import {tickStep} from "./ticks";
78
import sturges from "./threshold/sturges";
89

910
export default function() {
@@ -27,12 +28,15 @@ export default function() {
2728
tz = threshold(values, x0, x1);
2829

2930
// Convert number of thresholds into uniform thresholds.
30-
if (!Array.isArray(tz)) tz = ticks(x0, x1, tz);
31+
if (!Array.isArray(tz)) {
32+
tz = tickStep(x0, x1, tz);
33+
tz = range(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
34+
}
3135

3236
// Remove any thresholds outside the domain.
3337
var m = tz.length;
3438
while (tz[0] <= x0) tz.shift(), --m;
35-
while (tz[m - 1] >= x1) tz.pop(), --m;
39+
while (tz[m - 1] > x1) tz.pop(), --m;
3640

3741
var bins = new Array(m + 1),
3842
bin;

test/histogram-test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ tape("histogram.thresholds(array) sets the bin thresholds", function(test) {
9090
test.end();
9191
});
9292

93+
tape("histogram.thresholds(array) ignores thresholds outside the domain", function(test) {
94+
var h = arrays.histogram().thresholds([0, 1, 2, 3]);
95+
test.deepEqual(h([0, 1, 2, 3]), [
96+
bin([0], 0, 1),
97+
bin([1], 1, 2),
98+
bin([2], 2, 3),
99+
bin([3], 3, 3) // Note: inclusive upper bound for last bin.
100+
]);
101+
test.end();
102+
});
103+
93104
tape("histogram.thresholds(function) sets the bin thresholds accessor", function(test) {
94105
var actual,
95106
values = [0, 0, 0, 10, 30, 30],

0 commit comments

Comments
 (0)