Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to get localizable or customizable si codes with d3.format

Tags:

d3.js

When drawing graphs using SI codes is pretty much what we want. Our y-axis values tend to be large currency values. eg: $10,411,504,201.20

Abbreviating this, at least in a US locale, this should translate to $10.4B.

But using d3.format's 's' type for SI codes this would display as $10.4G. This might be great for some locales and good when dealing with computer-based values (eg: processor speed, memory...), but not so with currency or other non-computer types of values.

Is there a way to get locale-specific functionality similar to SI-codes that would convert billions to B instead of G, etc...?

(I realize this is mostly an SI-codes thing and not specific to D3, but since I'm using D3 this seems the most appropriate tag.)

like image 584
lostdorje Avatar asked Jun 11 '13 05:06

lostdorje


1 Answers

I prefer overriding d3.formatPrefix. Then you can just forget about replacing strings within your viz code. Simply execute the following code immediately after loading D3.js.

// Change D3's SI prefix to more business friendly units
//      K = thousands
//      M = millions
//      B = billions
//      T = trillion
//      P = quadrillion
//      E = quintillion
// small decimals are handled with e-n formatting.
var d3_formatPrefixes = ["e-24","e-21","e-18","e-15","e-12","e-9","e-6","e-3","","K","M","B","T","P","E","Z","Y"].map(d3_formatPrefix);

// Override d3's formatPrefix function
d3.formatPrefix = function(value, precision) {
    var i = 0;
    if (value) {
        if (value < 0) {
            value *= -1;
        }
        if (precision) {
            value = d3.round(value, d3_format_precision(value, precision));
        }
        i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
        i = Math.max(-24, Math.min(24, Math.floor((i - 1) / 3) * 3));
    }
    return d3_formatPrefixes[8 + i / 3];
};

function d3_formatPrefix(d, i) {
    var k = Math.pow(10, Math.abs(8 - i) * 3);
    return {
        scale: i > 8 ? function(d) { return d / k; } : function(d) { return d * k; },
        symbol: d
    };
}

function d3_format_precision(x, p) {
    return p - (x ? Math.ceil(Math.log(x) / Math.LN10) : 1);
}

After running this code, try formatting a number with SI prefix:

d3.format(".3s")(1234567890) // 1.23B

You could augment this code pretty simply to support different locales by including locale-specific d3_formatPrefixes values in an object and then select the proper one that matches a locale you need.

like image 75
nross83 Avatar answered Oct 27 '22 18:10

nross83