Code Monkey home page Code Monkey logo

d3-format's Introduction

D3: Data-Driven Documents

D3 (or D3.js) is a free, open-source JavaScript library for visualizing data. Its low-level approach built on web standards offers unparalleled flexibility in authoring dynamic, data-driven graphics. For more than a decade D3 has powered groundbreaking and award-winning visualizations, become a foundational building block of higher-level chart libraries, and fostered a vibrant community of data practitioners around the world.

Resources

d3-format's People

Contributors

ashamandi avatar benib avatar davinov avatar dependabot[bot] avatar dkrat7 avatar fil avatar freejoe76 avatar gavinsykes avatar haf avatar hh2k avatar joaopalmeiro avatar mbostock avatar rahulpowar avatar roveo avatar severo avatar stof avatar vasturiano avatar victornoel avatar zakjan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

d3-format's Issues

Add SI-like currency format directive?

When I execute the following:

[5,10,15,20].map(v => format('$.1s')(v * 1E9))

it returns:

["$5G", "$10G", "$20G", "$20G"]

However, to me it would make more sense if the combination of SI and currency would not result in G for giga, but B for billion, preferably localized.

Is support for this planned? Thanks.

External access to locale definitions?

Prior to wide-scale ES6 adoption, the locale definitions are not externally available. For example, they are not included in the built ES5 files. Only the pre-specified default locale is included. It would be helpful to be able to access the locale definitions for convenient specification and switching. (Note that this applies to d3-time-format as well.)

We recently updated datalib to support runtime locale switching (in particular, this was requested by Wikipedia folks for their Vega graph support), but this requires passing in a full JSON blob of locale settings. To make these settings accessible, one options for us is to build out a separate repo that contains a registry of locale definitions (i.e., one that can be included as a project dependency). However, that would simply replicate the work you've done here, and so seems both inelegant and prone to inconsistency due to code drift.

Any plans / thoughts in this regard? One option might be to include the locales in the build (though bloating the file size). Another might be a parallel build that exports just the locale definitions, perhaps as a single JSON file keyed by locale id.

Use minus sign instead of hyphen-minus by default?

Hi there,

I really like how your library supports a lot of locales for formatting numbers.

I was wondering if there was a way to use the correct minus sign (instead of the hyphen character) for negative numbers? If not, I’d like to suggest this as an enhancement.

A bit of background: A hyphen is usually shorter than a minus and is aligned with the lowercase letters of a font (as it is used to break words across lines). A minus sign is longer (in most cases it’ll have the width of the plus sign) and is vertically aligned slightly higher (it is aligned with the figures, which in most fonts used in websites have the height of uppercase numbers). See the attached image for a comparison of plus, minus and hyphen character.

210px-plus_minus_hyphen-minus svg

Cheers and keep up the good work 🎉

option to remove trailing zeros for "s" type prefix

Currently if I do d3.format("0.3s")(myString) it will add trailing zeros, however in the case when working with population-based data, it adds trailing zeroes for data involving whole numbers (for example, 9 -> 9.00)

Decimal rounding down on 5 instead of up

When rounding to one decimal place, 17.45 should round to 17.5 but is instead rounding to 17.4.

> d3.format('.1f')(17.450)
"17.4"
> d3.format('.1f')(17.451)
"17.5"

Use N/A instead of NaN by default?

I'm writing an application that displays something before the data is here. The data is lots of numbers and sometimes they're not there yet (waiting for network latency), so undefined is passed to be displayed. Transformed to a number, it yields NaN.
As it turns out, few humans understand what NaN means and why this text would show up in a screen (even worse with text-transform: uppercase both in English and French for different reasons).

As a consequence, I believe an empty string would be a better formatting of NaN or undefined than "NaN" is.

Happy to send a PR if there is agreement here.
What do you think?

Adding a parse method

Like in d3-time-format, adding a parse method to the number formatters could be useful to get a number back when the representation is not a valid argument to construct numbers

var format = d3.formatPrefix(",.0", 1e-6);
format(0.00042); // "420µ"
format.parse("420µ"); // 0.00042

Bower installable?

It's not registered on Bower, and if you point it to the repository, it doesn't pull the built version. (only worked with absolute link to package)

Is this just not implemented yet or is it intentional because it's not ready?

D3-format version 3 working broken in version 4

var value = 124.256
d3.format(',.f') was returning the actual value on
format(value) =124.256

but in version 4 same function is broken

d3.min.js:2 Uncaught Error: invalid format: ,.f
at new Xe (d3.min.js:2)
at He (d3.min.js:2)
at Object.n [as format] (d3.min.js:2)
at Object.locale.decimalFormat (com01.fwk:165)

Custom bundle via rollup is broken

I'm trying to generate a custom bundle of D3 v4 using rollup:

https://github.com/Turbo87/rollup-d3-issue

Running npm run build (or rollup -c) will produce a bundled file at dist/d3.js which looks fine on first glance. It includes the following function call:

defaultLocale({
  decimal: ".",
  thousands: ",",
  grouping: [3],
  currency: ["$", ""]
});

but the defaultLocale() function is not defined anywhere in the bundle even though it's in the original code (at https://github.com/d3/d3-format/blob/v1.0.2/src/defaultLocale.js).

Note that if I add export { formatDefaultLocale } from 'd3-format'; to the d3.js file we can work around this issue. This is not a good long-term solution though.

Cross-posted this as rollup/rollup#970

Add option to use JS Intl.NumberFormat

Hello,

If possible add option to use the Intl.NumberFormat instead of the current format.

Currently for the charts I use the d3-format and for the rest of the application I use the Intl.NumberFormat

If is possible to create an option to set the default locale I want to use to format the numbers with the Intl API.

d3.formatDefaultLocaleIntl('en-GB'); // if empty use the browser locale

P.S. also for the https://github.com/d3/d3-time-format to do the same would be great.

Thanks

RequireJS

I want to load this module only, with RequireJS, does not work. The d3 object is invalid unless i receive the variable as "d3", but this not is a total solution because: What happen if i want load more individually modules?. This is my code:
define(['d3_format'], function(d3_format){ console.log(d3) });
And the message is:
d3 is not defined

formatPrefixAuto#prefixExponent used as a global

I am transpiling this package wirh ClojureScript, and faced a peculiar behaviour when using the SI prefix formatter (s type). The prefix always rendered as undefined, e.g. 1undefined, 100undefined, 42undefined, etc. This was caused by the fact that prefixExponent on line 84 was invariably undefined. The issue appears to be that formatPrefixAuto.js on line 10 expects prefixExponent to be in (global) scope. The transpilier however copies the value in an attempt to alias the name, here's the transpiled code:

goog.provide("module$usr$src$node_modules$d3_format$src$formatPrefixAuto");
goog.require("module$usr$src$node_modules$d3_format$src$formatDecimal");
var prefixExponent$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto;
var $jscompDefaultExport$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto = function(x, p) {
  /*snip*/
    var i = exponent - (prefixExponent$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto = /*snip*/)
  /*snip*/
};
module$usr$src$node_modules$d3_format$src$formatPrefixAuto.prefixExponent = prefixExponent$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto;
module$usr$src$node_modules$d3_format$src$formatPrefixAuto.default = $jscompDefaultExport$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto;

...and prefixExponent$$module$usr$src$node_modules$d3_format$src$formatPrefixAuto is never referenced again. I don't know if this is still an issue with Closure advanced optimisations (maybe it is, maybe it isn't).

I think that it's fair to say that formatPrefixAuto.js is trying to expose its internals and it hasn't ended well in my case.

I can think of a couple of alternatives to fix the problem, both feel like hacks to me:

Box prefixExponent

Instead of exposing prefixExponent as a primitive that is passed by value, wrap it in an object:

export var internals;

export default function(x, p) {
  /*snip*/
  var i = exponent - (internals.prefixExponent = /*snip*/) + 1
  /*snip*/
}

Perhaps the intention was to attach it to the exported function? I.e.

export default function formatPrefixAuto(x, p) {
  /*snip*/
  var i = exponent - (formatPrefixAuto.prefixExponent = /*snip*/) + 1
  /*snip*/
}

Add to API

Instead of using some sneaky backdoor, go through a window at the front:

export default function(x, p, window) {
  window = window || {};
  /*snip*/
  var i = exponent - (window.prefixExponent = /*snip*/) + 1
  /*snip*/
}

(Okay, so the naming is a little cheeky, but you get the idea!)

Or accept an optional callback:

export default function(x, p, cb) {
  var prefixExponent;
  /*snip*/
  var i = exponent - (prefixExponent = /*snip*/) + 1
  /*snip*/
  cb && cb(prefixExponent);
  /*snip*/
}

Then locale.js would need to do something like this:

var window = {};
value = formatType(Math.abs(value), precision, window);
valueSuffix = (type === "s" ? prefixes[8 + window.prefixExponent / 3] : "") + /*snip*/ "";

or

var prefixExponent;
value = formatType(Math.abs(value), precision, x => prefixExponent = x);
valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + /*snip*/ "";

Indian Number System format

In India, the number system is formatted like this

1 (One)
10 (Ten)
100 (Hundred)
1,000 (Thousand)
10,000 (Ten Thousand)
1,00,000 (One Lakh)
10,00,000 (Ten Lakhs)
1,00,00,000 (One Crore)
10,00,00,000 (Ten Crores)
1,00,00,00,000 (Hundred Crores)
10,00,00,00,000 (Thousand Crores)
1,00,00,00,00,000 (Ten Thousand Crores)
10,00,00,00,00,000 (One Lakh Crore)

and it goes on.

The grouping is 2 except at the beginning. Thousand is written as 1,000 and not as 10,00

Names are not important but I couldn't figure out grouping variable in the pull request I submitted for en-IN locale #2816

It was mentioned that the array will be cycled through so I can't put [2,3] How do we solve this?

Copied from d3/d3#2817 by @rohithdaka.

Feature idea for time formatter

On numerous occasions I've needed a formatter to change seconds into hh:mm:ss format, and googling indicates wider interest in a formatter to handle something similar. A few examples:

10 seconds: 0:10
100 seconds: 1:40
100.5 seconds: 1:40.5
100.5 seconds with 6 zero fills and rounding to zero decimals: 00:01:41

I this something that would fall within the scope of d3-format? While something similar can be accomplished with d3-time-format, I feel that this is more applicable to d3-format, as the underlying variable in this case is seconds, not a Date. If so I would be happy to write up a PR for the feature.

SI-prefix changes data value

I have the following input data:
ticks = [-20, -15, -10, -5, 0, 5, 10, 15, 20]

I use a format: formatTickLabel = format(".1s") applied to text:

lg.selectAll("text")
      .data(ticks)
      .enter()
      .append("text")
      .text(x => formatTickLabel(x));

Expected
I expect the ticks labels to be: -20 -15 -10 etc.

Actual
What I see is : -20 -20 -10 5 0 5 10 20 20.

Percent type (% / p) without multiplying by 100

I can't really control what data is coming in so I'm getting floats like this e.g.: 34.21 to represent 34.21%. Except using the percentage hoverformats multiply that number by 100, outputting: 3421%

Is there a way to bypass that multiplication?

default Arabic Locales Format are missing at d3-format

Hello, This is Ayah Shamandi, bidi developer -Globalization team at IBM Egypt, we are responsible for adding globalization and bidi featuers at open source technologies which IBM products used.

and we noticed that D3.format supports different locales except Arabic ones, so I opened this isssue to request adding the missing ones.

and here is the list of locales I am going to add:

  • Arabic(Algeria) - Arabic (Bahrain) - Arabic (Chad)
  • Arabic (Comoros), - Arabic (Djibouti), - Arabic (Egypt),
  • Arabic (Eritea), - Arabic (Iraq), - Arabic (Israel),
  • Arabic (Jordan), - Arabic(Kuwait), - Arabic (Lebanon),
  • Arabic (Libya) , - Arabic(Mauritania), - Arabic (Morocco),
  • Arabic (Oman), - Arabic (Palestinian Territories),
  • Arabic(Qatar), - Arabic (Saudi Arabia), - Arabic ( Somalia),
  • Arabic (South Sudan), - Arabic (Sudan), - Arabic (Syria),
  • Arabic (Tunisia), - Arabic(United Arab Emirates),
  • Arabic (Western Sahara), - Arabic (World), - Arabic (Yemen).

Don’t format -0 with a sign.

If the input value is exactly -0, or if when rounded according to the format’s precision is equivalent to -0, we should treat it as exactly 0 rather than -0.

This is necessary because tick values can be slightly off due to floating point precision, so a value that is intended to be exactly 0 may instead be something like -1.7763568394002506e-16. I can’t seem to reproduce this in 4.0’s d3-scale, but it’s definitely the case in 3.x:

var y = d3.scale.linear().domain([1.575008840033951, -0.7414613146919857]);
y.ticks(10);

Returns:

[
  -0.6000000000000001,
  -0.4000000000000001,
  -0.2000000000000001,
  -8.881784197001253e-17,
  0.1999999999999999,
  0.3999999999999999,
  0.5999999999999999,
  0.7999999999999999,
  1,
  1.2,
  1.4
]

Related d3/d3@4946a8c.

How can I rebuild d3-format after any change?

Just a Question?

I have created a PR #38 to push the new Arabic locales based on issue #36 and created test files to test them but I need to rebuild d3-format locally before pushing the test files to make sure that everything is fine but I do not know how ? the READMe file does not illustrate how to re-generate d3.format file after making any change.

Export FormatSpecifier constructor?

Is there any chance of having the ability to format with an object rather than string, e.g.:
format({ precision: 2, type: 'f' })(1.234);

Rather than:
format(".2f")(1.234);

I think it would be nice to allow being that explicit.

I also have a use case for it where I want to convert from other types of format strings into d3-format style. It's easier to convert from "other" to the specifier object, rather than the extra step of making that object a string as well.

I can see it being possible directly in the format function, or if the FormatSpecifier class was exported and had a constructor that accepts either an object or string:
const specifier = new FormatSpecifier({ precision: 2, type: 'f'}).toString();
format(specifier)(1.2345);

formatPrefix / precisionPrefix

formatPrefix should take a reference value and then compute the prefix based on what the s format type would normally do. For example, if the value is 1e-6, it uses µ.

We also need a precisionPrefix function that takes a step and value and returns the appropriate precision to use with formatPrefix. For example, if step is 1e-7 and value is 1e-6, then the returned precision should be 1. The assumption is that value is the same value that is passed to formatPrefix and determines the units, and then step is scaled appropriately before calling precisionFixed.

var p = precisionPrefix(1e-7, 1e-6),
    f = formatPrefix("." + p, 1e-6);
f(1e-7); // 0.1µ
f(2e-7); // 0.2µ
f(1e-6); // 1.0µ

Instead of today’s API, which requires you to (a) specify a prefix explicitly and (b) rescale the step before calling precisionFixed:

var p = precisionFixed(1e-7 / 1e-6),
    f = formatPrefix("." + p, "µ");
f(1e-7); // 0.1µ
f(2e-7); // 0.2µ
f(1e-6); // 1.0µ

Also, this should be more accurate, since we can do the scaling in integer space, effectively:

var p = precisionFixed(1e-7) - 6,
    f = formatPrefix("." + p, "µ");
f(1e-7); // 0.1µ
f(2e-7); // 0.2µ
f(1e-6); // 1.0µ

Alternatively, we could provide an API for returning a suggested prefix based on a given value, and another API (or the same API) for returning a scale factor / exponent for that suggested prefix. But I think the above is probably better?

Binary prefixes

When visualising information, it would be quite useful to have the option of not just SI prefixes but also IEC binary prefixes, i.e. 1024 == Ki, 1048675 == Mi, etc.

Adding Numeric shaping feature

Hello, Since d3.format supports number formating, so it will be nice if it supports numeric shaping feature too.

Arabic and many other languages (Thai and Bengali) have classical shapes for digits “National Digits” that are different from the conventional Western Digits (European).
National digits have the same semantic meaning as the European digits, and the numbers they form are read from left to right (most significant digit on the left). The difference is only a difference in glyphs.
European Digits 0 1 2 3 4 5 6 7 8 9
Arabic-Indic Digits ٠ ١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩
From the Arabic user's point of view, Arabic-Indic numerals are the basic numerals used in almost all forms of documents such as most of government documents (IDs, birth certificates, driver's licenses, passports and household bills), bank statements, newspapers, calendars, road signs and menus.

Options for Arabic Numeric Shaping
There are 3 options which should be taken into consideration when implementing national numeric shaping support in any framework/technology. These options are:
• None: No shaping is performed, and the value appears as it is in the data source.
• National: Digit shapes are determined from the user’s language.
• Contextual: Digit shapes are determined from the preceding characters in the buffer. European digits follow strong Latin character and Arabic-Indic digits follow strong Arabic character. When there is no preceding strong characters, the base text direction attribute determines the digit shaping. (Arabic-Indic digits in RTL context and European digits in LTR context).

image
image

### Problem Statement
Most of the available frameworks/technologies lack the contextual shaping option of national digits. Contextual digit shaping is a very important feature as the Arabic users don’t expect to see Arabic-Indic numerals or European numerals only when they have mixed English and Arabic data.
For example, if a document has many paragraphs/charts some in Arabic and others in English, in the Arabic paragraphs/charts Arabic users expect to see national or Arabic-Indic numerals, and in the English ones Arabic users expect to see European numerals.
Since the mixed English and Arabic data cases are very common in Arabic region, the same case with numerals is very common too.

Text Formatting (Feature suggestion)

Version 4 looks very exciting!
Sorry if I'm being presumptuous but do you think it might be useful to include text values? Then you can use the the justification, padding and minimum width on mixed types.

Also, would it be possible to include decimal place alignment in the alignment symbols?

percentage format issue

it seems we could only get ".1%" format correctly and we could not get more decimal digits format for percentage such as ".11%" or ".1111%" format.

$("#testValue").append( ".11% 1234.56789:" + "<p>" + d3.format(".11%")(1234.56789) + "</p>");//123456.78900000000%
$("#testValue").append( ".1% 1234.56789:" + "<p>" + d3.format(".1%")(1234.56789) + "</p>");//123456.8%
$("#testValue").append( ".1111% 987.654321:" + "<p>" + d3.format(".1111%")(987.654321) + "</p>");//98765.43210000000544823706%
$("#testValue").append( ".1% 987.654321:" + "<p>" + d3.format(".1%")(987.654321) + "</p>");//98765.4%
$("#testValue").append( ".11% 987.654321 with round:" + "<p>" + d3.format(".11%")(d3.round(987.654321,4)) + "</p>");//98765.43000000001%
$("#testValue").append( ".11% 987.654321 with round:" + "<p>" + d3.round(987.654321,4) + "</p>");//987.6543

Ordinal number support

I like this project a lot but I forced to use Numeral-js which has ordinal numbers support like 1st, 2nd etc.

Is there plan to support it? I can send a PR so we could discuss implementation.

feature request: format for PPM

Consider a value recorded as "14 PPM defects" i.e. "14 defective parts per million".

The underlying value is 0.000014. D3 currently shows this on the axis as "14u" (the micro symbol).
When the axis title is "ppm defects", this actually implies "14 micro parts per million".
It would be helpful if it could display as "14 ppm" instead.

In other words, I'm proposing an additional "type" format, perhaps "u", which acts in the same way as "p", but multiplies by 1000000 and has a "ppm" sign.

Thanks very much :-)

Inconsistent rounding of significant digits

Background

  • Common rounding rules say simply that you round up if the digit is 5 or above.
  • Scientific rounding rules are a little more complex. These rules are defined in ASTM E29 sections 6.4.1 through 6.4.4.

While I wouldn't expect d3-format to support scientific rounding rules, I would expect that it would apply a consistent set of rules. I know that this is a difficult problem to solve, partly due to the binary representation of floating point numbers.

Test Cases

All of these examples use the format function returned by

d3.format('.3r')

All of the x.45500 cases return the common rounding result:

Input Output Common Scientific
1.45500 1.46 1.46✔️ 1.45
2.45500 2.46 2.46✔️ 2.45
3.45500 3.46 3.46✔️ 3.45
4.45500 4.46 4.46✔️ 4.45
5.45500 5.46 5.46✔️ 5.45
6.45500 6.46 6.46✔️ 6.45
7.45500 7.46 7.46✔️ 7.45
8.45500 8.46 8.46✔️ 8.45
9.45500 9.46 9.46✔️ 9.45

The x.55500 cases return a mix of common and scientific rounding results:

Input Output Common Scientific
1.55500 1.55 1.56 1.55✔️
2.55500 2.56 2.56✔️ 2.55
3.55500 3.56 3.56✔️ 3.55
4.55500 4.55 4.56 4.55✔️
5.55500 5.55 5.56 5.55✔️
6.55500 6.55 6.56 6.55✔️
7.55500 7.55 7.56 7.55✔️
8.55500 8.55 8.56 8.55✔️
9.55500 9.55 9.56 9.55✔️

All of the x.55501 cases return the correct result, which is the same for common and scientific rounding methods:

Input Output Common Scientific
1.55501 1.56 1.56✔️ 1.56✔️
2.55501 2.56 2.56✔️ 2.56✔️
3.55501 3.56 3.56✔️ 3.56✔️
4.55501 4.56 4.56✔️ 4.56✔️
5.55501 5.56 5.56✔️ 5.56✔️
6.55501 6.56 6.56✔️ 6.56✔️
7.55501 7.56 7.56✔️ 7.56✔️
8.55501 8.56 8.56✔️ 8.56✔️
9.55501 9.56 9.56✔️ 9.56✔️

Support CLDR JSON

Just ran across #21 trying to solve the same problem (no existing support for indian number formatting).

I've just used the google closure i18n lib to implement the en-IN locale for everything except my d3 axis so I've already got access to CLDR data in my app and would like to continue using what I already have if possible. This would be a relatively common case as CLDR is part of unicode and the JSON packages are consumed by several existing JS i18n "engines", e.g.:

Any particular reason why d3 has defined its own locale JSON format (other than historical reasons) instead of using the Unicode CLDR system?

From what I can see:

Benefits of CLDR:

  • far more comprehensive than the d3 locale system, both in terms of quantity of locales supported and depth of support for each locale
  • robust engines for using CLDR to both format and parse numbers/dates/etc. (#20) already exist (https://rxaviers.github.io/javascript-globalization/ has a chart of what libs can do what)
  • Declarative yet doesn't have limitations present in d3 JSON format that make representing certain locales hacky by relying on implementation details of the engine to work, e.g. #21
  • No work required by d3 team to maintain or add new JSON, other than to maybe periodically run a build script (npm and bower are natively supported by unicode https://github.com/unicode-cldr/cldr-json) or copy and paste some JSON data by hand
  • d3 users could add their own locales really easily by copying it from CLDR without any prior knowledge of d3's internal systems
  • Based on standards, so people who have used it elsewhere don't need to learn something new to work with d3
  • Long term potential to go the route of globalize.js and completely strip all locale data from d3 (making d3 easier to maintain, although admittedly harder for consumers who want "batteries included")

Cons of CLDR:

  • need to write some code (engine implementation + backwards compatibility/switch), but much of this can be "borrowed" from elsewhere

Trim insignificant .00 on SI prefix format

I'm trying to get this number formatting:
1000 -> '1k'
1500 -> '1.5k'

But doing format('s') gives me instead:
1000 -> '1.00000k'
1500 -> '1.50000k'

I can try to remove the fixed precision (format('.0s')), but that will break it for the 2nd number:
1000 -> '1k'
1500 -> '2k'

That seems to be happening because the default precision is set to 6 fixed points, and the minimum is 1. So .0s really acts as .1s, if I'm reading this section correctly:
https://github.com/d3/d3-format/blob/master/src/locale.js#L46

This feature seems to be showing up in the tickFormat block too:
https://bl.ocks.org/mbostock/9764126

In the middle axis (format('.0s')), the top values show as repeated 2M and 1M due to the rounding, while ideally they would show 1.2M, 1.4M, etc.

Would be nice if there's an easy option to remove insignificant trailing 0s, regardless of the type. This option exists for type 'g' (type none), but not for SI and other modes.

Or maybe there's a way to do this currently that I didn't realise. :)

Precision error when there are 18 decimal places

d3Format.format(".18f")(1.1) gives 1.100000000000000089
d3Format.format(".18f")(1.2) gives 1.199999999999999956
d3Format.format(".18f")(1.3) gives 1.300000000000000044

... etc. which are all wrong.

This package claims to fix the problem of binary floating point yet it seems to suffer from it.

Can this problem be fixed? Or is there an alternative package that is precise for many decimal places or large numbers?

I use the bignumber.js package for precise calculations with 18 decimal places, but it would be great to be able to format the results nicely for the UI.

Should g, n and (none) format types use exponent notation based on precision?

The format types that use number.toPrecision behave reasonably for large x, switching to exponent notation when the number of output digits is greater than the specified precision. For example:

var f = format(".3n");
f(9.99); // "9.99"
f(99.9); // "99.9"
f(999); // "999"
f(9990); // "9.99e+3"
f(99900); // "9.99e+4"
f(99900); // "9.99e+5"

But, they don’t behave symmetrically for small absolute values of x, since the specification of number.toPrecision says to only use exponent when |x| is less than 1e-6:

var f = format(".3n");
f(9.99); // "9.99"
f(0.999); // "0.999"
f(0.0999); // "0.0999"
f(0.00999); // "0.00999"
f(0.000999); // "0.000999"
f(0.0000999); // "0.0000999"
f(0.00000999); // "0.00000999"
f(0.000000999); // "9.99e-7"

I wonder whether this would be better, since it avoids displaying more than precision digits:

var f = format(".3n");
f(9.99) // "9.99"
f(0.999) // "9.99e-1"
f(0.0999) // "9.99e-2"
f(0.00999) // "9.99e-3"
f(0.000999) // "9.99e-4"
f(0.0000999) // "9.99e-5"
f(0.00000999) // "9.99e-6"
f(0.000000999) // "9.99e-7"

On the other hand, this makes the shift to exponent notation dependent on the number of significant digits and not the value of x, which means that for some x1 > x2, x1 is formatted in exponent notation and x2 is formatted in decimal notation:

var f = format(".3n");
f(0.099); // "9.99e-2"
f(0.090); // "0.09"

So maybe it’s better to make the threshold dependent on the precision, but independent of the number of significant digits? Like if precision is 3, then use 1e-3. Then the current threshold 1e-6 would remain the default if the default precision of 6 is used.

var fn = format(".3n"),
    fe = format(".3e"),
    f = function(x) { return (x < 1e-3 ? fe : fn)(x); };

f(0.999); // "0.999"
f(0.0999); // "0.0999"
f(0.0900); // "0.0900"
f(0.00999); // "0.00999"
f(0.000999); // "9.990e-4"
f(0.0000999); // "9.990e-5"
f(0.00000999); // "9.990e-6"
f(0.000000999); // "9.990e-7"

Access to default locale

It could be usefull to have getter to the default locale. Something like d3.formatLocale() without args could do the job.

Why?
Because when you work on multilang graphics, it's simplier to handle a locale object, update it, and call locale.format than the global format function, and always setting the default locale of d3. For now I recreate the locale object with the format and formatPrefix functions. But it's something that the lib could do.

I can make the PR if you agree.

Adding Numeral system to locales

As D3 supports different locales, we need also to add numeral system to these locales

When users select a locale file they also expect to see numbers formated in a numeral system based on the selected locale.

for example: if we talk about users from saudi arabia, when they select ar-SA as their locale file, they expect to see arabic/ indic numerals - ٠١٢٣٤٥٦٧٨٩ - instead of European numerals - 0123456789 - .
on the other hand users from Tunisia, when selecting ar-TN, they expect to see European numerals

and to solve this problem, I suggest to

  1. Add numeral parameter at each locale.json file to define which numeral system this locale supports.

numeric1

numeric2

  1. Add the next function to locale.js file to formatNumerals
    numeric3

  2. then call it immediately before adding padding, valuePrefix @ newFormat function as follows:
    numeric4

and for now as I am interesting to support Arabic users I will add one of 2 numerals types (European or arabic/indic) at each locale. (ar-*.json)
and for the remaining locales I will define numerals as european numerals.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.