Skip to content

Commit

Permalink
Merge branch 'add-si-prefix-format' of https://github.com/pjjw/d3 int…
Browse files Browse the repository at this point in the history
…o si-format
  • Loading branch information
mbostock committed Oct 11, 2011
2 parents 50ecefd + 8914a38 commit fe83f16
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 10 deletions.
65 changes: 60 additions & 5 deletions d3.js
Expand Up @@ -473,7 +473,9 @@ d3.format = function(specifier) {
precision = match[8],
type = match[9],
percentage = false,
integer = false;
integer = false,
trim_decimal_zero = false,
si = false;

if (precision) precision = precision.substring(1);

Expand All @@ -487,19 +489,30 @@ d3.format = function(specifier) {
case "%": percentage = true; type = "f"; break;
case "p": percentage = true; type = "r"; break;
case "d": integer = true; precision = "0"; break;
case "s": si = true; trim_decimal_zero = true;
type = "r"; precision = "3"; break;
}

type = d3_format_types[type] || d3_format_typeDefault;

return function(value) {
var number = percentage ? value * 100 : +value,
negative = (number < 0) && (number = -number) ? "\u2212" : sign;
exponent = si ? d3_format_getExponent(number) : 0,
scale = si ? Math.pow(10, -exponent) : 1,
si_prefixes = ['y','z','a','f','p','n','μ','m','','k','M','G','T','P','E','Z','Y'],
suffix = percentage ? '%' : si ? (Math.abs(exponent) < 27) ? si_prefixes[(exponent + 24) / 3] : "e" + exponent : '';

// Return the empty string for floats formatted as ints.
if (integer && (number % 1)) return "";

// Convert the input value to the desired precision.
value = type(number, precision);
value = type(number * scale, precision);

// if using SI prefix notation, scale and trim insignificant zeros
if (trim_decimal_zero) {
value = (new Number(value)).toPrecision();
}

// If the fill character is 0, the sign and group is applied after the fill.
if (zfill) {
Expand All @@ -516,7 +529,8 @@ d3.format = function(specifier) {
var length = value.length;
if (length < width) value = new Array(width - length + 1).join(fill) + value;
}
if (percentage) value += "%";
value += suffix;


return value;
};
Expand All @@ -532,8 +546,49 @@ var d3_format_types = {
r: function(x, p) {
var n = x ? 1 + Math.floor(1e-15 + Math.log(x) / Math.LN10) : 1;
return d3.round(x, p - n).toFixed(Math.max(0, Math.min(20, p - n)));
}
};
// },
// s: function(x, p) {
// // copied from gnuplot and modified
// // find exponent and significand
// var l10 = Math.log(x) / Math.LN10,
// exponent = Math.floor(l10),
// mantissa = l10 - exponent,
// significand = Math.pow(10, mantissa);
// // round exponent to integer multiple of 3
// var pr = exponent % 3;
// if (pr < 0) exponent -= 3;
// significand *= Math.pow(10, (3 + pr) % 3); // if 1 or -2, 10. if -1 or 2, 100.
// exponent -= pr;
// // decimal significand fixup
// var tolerance = 1e-2;
// if (significand + tolerance >= 1e3) {
// significand /= 1e3;
// exponent += 3;
// }
// var metric_suffix = (Math.abs(exponent) <= 24) ? si_prefixes[(exponent + 24) / 3] : "e" + exponent;
// // floating point joy
// var sig_round = new Number(d3.format(".3r")(significand));
// return sig_round.toPrecision() + metric_suffix;
}
};

function d3_format_getExponent(value) {
if (value == 0) return 0;
var l10 = Math.log(value) / Math.LN10,
exponent = Math.floor(l10),
mantissa = l10 - exponent;
significand = Math.pow(10, mantissa),
em = exponent % 3;
if (em < 0) exponent -= 3;
exponent -= em;
// equivalent to mantissa += (mod + em) % mod;
significand *= Math.pow(10, (3 + em) % 3);
// if rounding the sig up would bring it above 1e3, adjust the exponent
var tolerance = .5 + 1e-15;
if (significand + tolerance >= 1e3) exponent += 3;
// equivalent to if (Math.pow(10, mantissa) + tolerance >= 1e3) exponent += mod;
return exponent;
}

function d3_format_typeDefault(x) {
return x + "";
Expand Down
4 changes: 2 additions & 2 deletions d3.min.js

Large diffs are not rendered by default.

61 changes: 58 additions & 3 deletions src/core/format.js
Expand Up @@ -9,7 +9,9 @@ d3.format = function(specifier) {
precision = match[8],
type = match[9],
percentage = false,
integer = false;
integer = false,
trim_decimal_zero = false,
si = false;

if (precision) precision = precision.substring(1);

Expand All @@ -23,19 +25,30 @@ d3.format = function(specifier) {
case "%": percentage = true; type = "f"; break;
case "p": percentage = true; type = "r"; break;
case "d": integer = true; precision = "0"; break;
case "s": si = true; trim_decimal_zero = true;
type = "r"; precision = "3"; break;
}

type = d3_format_types[type] || d3_format_typeDefault;

return function(value) {
var number = percentage ? value * 100 : +value,
negative = (number < 0) && (number = -number) ? "\u2212" : sign;
exponent = si ? d3_format_getExponent(number) : 0,
scale = si ? Math.pow(10, -exponent) : 1,
si_prefixes = ['y','z','a','f','p','n','μ','m','','k','M','G','T','P','E','Z','Y'],
suffix = percentage ? '%' : si ? (Math.abs(exponent) < 27) ? si_prefixes[(exponent + 24) / 3] : "e" + exponent : '';

// Return the empty string for floats formatted as ints.
if (integer && (number % 1)) return "";

// Convert the input value to the desired precision.
value = type(number, precision);
value = type(number * scale, precision);

// if using SI prefix notation, scale and trim insignificant zeros
if (trim_decimal_zero) {
value = (new Number(value)).toPrecision();
}

// If the fill character is 0, the sign and group is applied after the fill.
if (zfill) {
Expand All @@ -52,7 +65,8 @@ d3.format = function(specifier) {
var length = value.length;
if (length < width) value = new Array(width - length + 1).join(fill) + value;
}
if (percentage) value += "%";
value += suffix;


return value;
};
Expand All @@ -68,9 +82,50 @@ var d3_format_types = {
r: function(x, p) {
var n = x ? 1 + Math.floor(1e-15 + Math.log(x) / Math.LN10) : 1;
return d3.round(x, p - n).toFixed(Math.max(0, Math.min(20, p - n)));
// },
// s: function(x, p) {
// // copied from gnuplot and modified
// // find exponent and significand
// var l10 = Math.log(x) / Math.LN10,
// exponent = Math.floor(l10),
// mantissa = l10 - exponent,
// significand = Math.pow(10, mantissa);
// // round exponent to integer multiple of 3
// var pr = exponent % 3;
// if (pr < 0) exponent -= 3;
// significand *= Math.pow(10, (3 + pr) % 3); // if 1 or -2, 10. if -1 or 2, 100.
// exponent -= pr;
// // decimal significand fixup
// var tolerance = 1e-2;
// if (significand + tolerance >= 1e3) {
// significand /= 1e3;
// exponent += 3;
// }
// var metric_suffix = (Math.abs(exponent) <= 24) ? si_prefixes[(exponent + 24) / 3] : "e" + exponent;
// // floating point joy
// var sig_round = new Number(d3.format(".3r")(significand));
// return sig_round.toPrecision() + metric_suffix;
}
};

function d3_format_getExponent(value) {
if (value == 0) return 0;
var l10 = Math.log(value) / Math.LN10,
exponent = Math.floor(l10),
mantissa = l10 - exponent;
significand = Math.pow(10, mantissa),
em = exponent % 3;
if (em < 0) exponent -= 3;
exponent -= em;
// equivalent to mantissa += (mod + em) % mod;
significand *= Math.pow(10, (3 + em) % 3);
// if rounding the sig up would bring it above 1e3, adjust the exponent
var tolerance = .5 + 1e-15;
if (significand + tolerance >= 1e3) exponent += 3;
// equivalent to if (Math.pow(10, mantissa) + tolerance >= 1e3) exponent += mod;
return exponent;
}

function d3_format_typeDefault(x) {
return x + "";
}
Expand Down
12 changes: 12 additions & 0 deletions test/core/format-test.js
Expand Up @@ -70,6 +70,18 @@ suite.addBatch({
assert.strictEqual(f(-4200000), "−4.2e+6");
assert.strictEqual(f(-42000000), "−4.2e+7");
},
"can output SI prefix notation": function(format) {
var f = format("s");
assert.strictEqual(f(1), "1");
assert.strictEqual(f(100), "100");
assert.strictEqual(f(999.5), "1k");
assert.strictEqual(f(1000), "1k");
assert.strictEqual(f(1500.5), "1.5k");
assert.strictEqual(f(145500000), "146M");
assert.strictEqual(f(145999999.999999347), "146M");
assert.strictEqual(f(1e26), "100Y");
assert.strictEqual(f(.000001), "1μ");
},
"can output a percentage": function(format) {
var f = format("%");
assert.strictEqual(f(0), "0%");
Expand Down

0 comments on commit fe83f16

Please sign in to comment.