Skip to content

Commit a18b3f3

Browse files
committed
Merge branch 'fix-mean-string' into 3.4.13
2 parents 84e242f + eaed66d commit a18b3f3

12 files changed

Lines changed: 100 additions & 25 deletions

File tree

d3.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,17 @@
8888
return s;
8989
};
9090
function d3_number(x) {
91-
return x != null && !isNaN(x);
91+
return x === null ? NaN : +x;
92+
}
93+
function d3_numeric(x) {
94+
return !isNaN(x);
9295
}
9396
d3.mean = function(array, f) {
9497
var s = 0, n = array.length, a, i = -1, j = n;
9598
if (arguments.length === 1) {
96-
while (++i < n) if (d3_number(a = array[i])) s += a; else --j;
99+
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
97100
} else {
98-
while (++i < n) if (d3_number(a = f.call(array, array[i], i))) s += a; else --j;
101+
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
99102
}
100103
return j ? s / j : undefined;
101104
};
@@ -104,9 +107,13 @@
104107
return e ? v + e * (values[h] - v) : v;
105108
};
106109
d3.median = function(array, f) {
107-
if (arguments.length > 1) array = array.map(f);
108-
array = array.filter(d3_number);
109-
return array.length ? d3.quantile(array.sort(d3_ascending), .5) : undefined;
110+
var array1 = [], n = array.length, a, i = -1;
111+
if (arguments.length === 1) {
112+
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) array1.push(a);
113+
} else {
114+
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) array1.push(a);
115+
}
116+
return array1.length ? d3.quantile(array1.sort(d3_ascending), .5) : undefined;
110117
};
111118
function d3_bisector(compare) {
112119
return {
@@ -2122,7 +2129,7 @@
21222129
return t.reverse().join(locale_thousands);
21232130
} : d3_identity;
21242131
return function(specifier) {
2125-
var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false;
2132+
var match = d3_format_re.exec(specifier), fill = match[1] || " ", align = match[2] || ">", sign = match[3] || "-", symbol = match[4] || "", zfill = match[5], width = +match[6], comma = match[7], precision = match[8], type = match[9], scale = 1, prefix = "", suffix = "", integer = false;
21262133
if (precision) precision = +precision.substring(1);
21272134
if (zfill || fill === "0" && align === "=") {
21282135
zfill = fill = "0";
@@ -2174,7 +2181,7 @@
21742181
return function(value) {
21752182
var fullSuffix = suffix;
21762183
if (integer && value % 1) return "";
2177-
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
2184+
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign;
21782185
if (scale < 0) {
21792186
var unit = d3.formatPrefix(value, precision);
21802187
value = unit.scale(value);
@@ -7676,7 +7683,7 @@
76767683
}
76777684
scale.domain = function(x) {
76787685
if (!arguments.length) return domain;
7679-
domain = x.filter(d3_number).sort(d3_ascending);
7686+
domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending);
76807687
return rescale();
76817688
};
76827689
scale.range = function(x) {

d3.min.js

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/arrays/mean.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ d3.mean = function(array, f) {
77
i = -1,
88
j = n;
99
if (arguments.length === 1) {
10-
while (++i < n) if (d3_number(a = array[i])) s += a; else --j;
10+
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j;
1111
} else {
12-
while (++i < n) if (d3_number(a = f.call(array, array[i], i))) s += a; else --j;
12+
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j;
1313
}
1414
return j ? s / j : undefined;
1515
};

src/arrays/median.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,16 @@ import "ascending";
33
import "quantile";
44

55
d3.median = function(array, f) {
6-
if (arguments.length > 1) array = array.map(f);
7-
array = array.filter(d3_number);
8-
return array.length ? d3.quantile(array.sort(d3_ascending), .5) : undefined;
6+
var array1 = [],
7+
n = array.length,
8+
a,
9+
i = -1;
10+
11+
if (arguments.length === 1) {
12+
while (++i < n) if (d3_numeric(a = d3_number(array[i]))) array1.push(a);
13+
} else {
14+
while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) array1.push(a);
15+
}
16+
17+
return array1.length ? d3.quantile(array1.sort(d3_ascending), .5) : undefined;
918
};

src/locale/number-format.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function d3_locale_numberFormat(locale) {
2525
var match = d3_format_re.exec(specifier),
2626
fill = match[1] || " ",
2727
align = match[2] || ">",
28-
sign = match[3] || "",
28+
sign = match[3] || "-",
2929
symbol = match[4] || "",
3030
zfill = match[5],
3131
width = +match[6],
@@ -80,7 +80,7 @@ function d3_locale_numberFormat(locale) {
8080
if (integer && (value % 1)) return "";
8181

8282
// Convert negative to positive, and record the sign prefix.
83-
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign;
83+
var negative = value < 0 || value === 0 && 1 / value < 0 ? (value = -value, "-") : sign === "-" ? "" : sign;
8484

8585
// Apply the scale, computing it from the value's exponent for si format.
8686
// Preserve the existing suffix, if any, such as the currency symbol.

src/math/number.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
function d3_number(x) {
2-
return x != null && !isNaN(x);
2+
return x === null ? NaN : +x;
3+
}
4+
5+
function d3_numeric(x) {
6+
return !isNaN(x);
37
}

src/scale/quantile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function d3_scale_quantile(domain, range) {
2525

2626
scale.domain = function(x) {
2727
if (!arguments.length) return domain;
28-
domain = x.filter(d3_number).sort(d3_ascending);
28+
domain = x.map(d3_number).filter(d3_numeric).sort(d3_ascending);
2929
return rescale();
3030
};
3131

test/arrays/mean-test.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var vows = require("vows"),
22
load = require("../load"),
3-
assert = require("../assert");
3+
assert = require("../assert"),
4+
OneTimeNumber = require("./one-time-number");
45

56
var suite = vows.describe("d3.mean");
67

@@ -28,6 +29,17 @@ suite.addBatch({
2829
"applies the optional accessor function": function(mean) {
2930
assert.equal(mean([[1, 2, 3, 4, 5], [2, 4, 6, 8, 10]], function(d) { return mean(d); }), 4.5);
3031
assert.equal(mean([1, 2, 3, 4, 5], function(d, i) { return i; }), 2);
32+
},
33+
"coerces values to numbers": function(mean) {
34+
assert.equal(mean(["1"]), 1);
35+
assert.equal(mean(["5", "1", "2", "3", "4"]), 3);
36+
assert.equal(mean(["20", "3"]), 11.5);
37+
assert.equal(mean(["3", "20"]), 11.5);
38+
},
39+
"coerces values exactly once": function(mean) {
40+
var array = [1, new OneTimeNumber(3)];
41+
assert.equal(mean(array), 2);
42+
assert.equal(mean(array), 1);
3143
}
3244
}
3345
});

test/arrays/median-test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var vows = require("vows"),
22
load = require("../load"),
3-
assert = require("../assert");
3+
assert = require("../assert"),
4+
OneTimeNumber = require("./one-time-number");
45

56
var suite = vows.describe("d3.median");
67

@@ -32,6 +33,19 @@ suite.addBatch({
3233
"applies the optional accessor function": function(median) {
3334
assert.equal(median([[1, 2, 3, 4, 5], [2, 4, 6, 8, 10]], function(d) { return median(d); }), 4.5);
3435
assert.equal(median([1, 2, 3, 4, 5], function(d, i) { return i; }), 2);
36+
},
37+
"coerces strings to numbers": function(median) {
38+
assert.equal(median(["1"]), 1);
39+
assert.equal(median(["5", "1", "2", "3", "4"]), 3);
40+
assert.equal(median(["20", "3"]), 11.5);
41+
assert.equal(median(["3", "20"]), 11.5);
42+
assert.equal(median(["2", "3", "20"]), 3);
43+
assert.equal(median(["20", "3", "2"]), 3);
44+
},
45+
"coerces values exactly once": function(median) {
46+
var array = [1, new OneTimeNumber(3)];
47+
assert.equal(median(array), 2);
48+
assert.equal(median(array), 1);
3549
}
3650
}
3751
});

test/arrays/one-time-number.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = OneTimeNumber;
2+
3+
function OneTimeNumber(value) {
4+
this.value = value;
5+
}
6+
7+
OneTimeNumber.prototype.valueOf = function() {
8+
var v = this.value;
9+
this.value = NaN;
10+
return v;
11+
};

0 commit comments

Comments
 (0)