I'm using d3.format("s") with d3.svg.axis.tickFormat to nicely format the tick labels with SI units (from the International System of Units). It works beautifully for the most part, except for certain values that run into a rounding error and return a ton of decimal places (1400, for example, as 1400 * 0.001 = 1.4000000000000001).
To get around this I can specify a precision, such as d3.format(".2s") but this forces 2 significant digits in cases where 1 would be better. For example, if I have ticks [5000, 10000, 15000] I would now see [5.0k, 10k, 15k]. Originally when I didn't specify precision at all I got [5k, 10k, 15k].
I'm wondering if it's possible to specify a maximum precision such that it will only get applied when the number of significant digits exceeds the number specified? So 5000 would be 5k and not 5.0k.
While 1400 * .001 is 1.4000000000000001, 1400 / 1000 is 1.4; multiplying an integer by a negative power of ten (such as .001) may introduce rounding error, but it appears that dividing an integer by a power of ten (such as 1000) does not. Or at least, it's less likely? I've implemented a tentative fix in the fix-si-format-rounding branch. It's strictly backwards-incompatible, but since the d3.formatPrefix
function is undocumented, I think it'd be safe to include in the next patch release.
Edit: This fix was released in version 2.9.2.
You can do this by placing an if/else statement in an anonymous function where you would output the text string. Within that if/else you can satisfy any condition that you want and create a function that parses your value. Here is an example:
var w = 30, h = 300;
var data = [
{'point':1, 'value':100.005},
{'point':2, 'value':20.010},
{'point':3, 'value':1000},
{'point':4, 'value':5000.099},
{'point':5, 'value':6000.934},
{'point':6, 'value':9000.888},
{'point':7, 'value':500.22},
{'point':8, 'value':5.123},
{'point':9, 'value':50.022},
{'point':10, 'value':7000.999}
];
var chart = d3.select("body").append("svg")
.attr('class', 'chart')
.attr("width", w * data.length - 1)
.attr("height", h);
chart.selectAll('text')
.data(data)
.enter().append('text')
.attr('x', function(d, i) { return x(i); })
.attr('y', function(d) { return h - y(d.value); })
.attr('dx', '0.75em')
.attr('dy', '-0.3em')
.attr('text-anchor', 'start')
.text(function(d) {
if(d.value > 5000) {
// Define your formatting function to return SI units
var si = d3.format('s');
return String(si(d.value));
} else {
// Otherwise round to the nearest integer
return String(d3.round(d.value, 0));
}
});
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With