Format numbers for human consumption with extensive localization support and Python-style format specification syntax
npx @tessl/cli install tessl/npm-d3-format@3.1.0d3-format is a comprehensive JavaScript library for formatting numbers for human consumption, modeled after Python 3's format specification mini-language. It provides sophisticated number formatting capabilities including fixed-point notation, scientific notation, percentage formatting, currency formatting, localization support, and SI prefix formatting.
npm install d3-formatimport { format, formatPrefix, formatLocale, formatDefaultLocale, formatSpecifier, FormatSpecifier, precisionFixed, precisionPrefix, precisionRound } from "d3-format";For CommonJS:
const { format, formatPrefix, formatLocale, formatDefaultLocale, formatSpecifier, FormatSpecifier, precisionFixed, precisionPrefix, precisionRound } = require("d3-format");import { format, formatPrefix } from "d3-format";
// Create formatters using format specification strings
const percentage = format(".0%"); // percentage with no decimal places
const currency = format("$,.2f"); // currency with thousands separator
const scientific = format(".2e"); // scientific notation
const rounded = format(".3r"); // rounded to 3 significant digits
const siPrefix = format(".2s"); // SI prefix notation
// Format numbers
console.log(percentage(0.123)); // "12%"
console.log(currency(1234.56)); // "$1,234.56"
console.log(scientific(12345)); // "1.23e+4"
console.log(rounded(1234.56789)); // "1,230"
console.log(siPrefix(42e6)); // "42M"
// Format with consistent SI prefix
const prefixFormatter = formatPrefix(",.0", 1e-6);
console.log(prefixFormatter(0.00042)); // "420µ"
console.log(prefixFormatter(0.0042)); // "4,200µ"d3-format is built around several key components:
[fill]align][sign][symbol][0][width][,][.precision][~][type])Core formatting functionality that converts numbers to formatted strings based on format specifications.
/**
* Creates a number formatter function using the default locale
* @param specifier - Format specification string
* @returns Function that formats numbers to strings
*/
function format(specifier: string): (value: number) => string;
/**
* Creates a prefix formatter with consistent SI scaling
* @param specifier - Format specification string
* @param value - Reference value for determining SI prefix
* @returns Function that formats numbers with consistent prefix
*/
function formatPrefix(specifier: string, value: number): (value: number) => string;Format Specification Syntax:
[fill][align][sign][symbol][0][width][,][.precision][~][type]
< (left), > (right, default), ^ (center), = (sign-aware)- (default), + (always), ( (parentheses for negative), (space)$ (currency), # (prefix for binary/octal/hex).n decimal places or significant digitsFormat Types:
e - Scientific notation (1.23e+4)f - Fixed-point notation (1234.56)g - General format (decimal or scientific)r - Rounded decimal notations - SI-prefix notation (42M, 1.5k)% - Percentage (multiply by 100)p - Percentage with significant digitsb - Binary integero - Octal integerd - Decimal integerx - Lowercase hexadecimalX - Uppercase hexadecimalc - Character datan - Shorthand for ,g~gInternationalization system for number formatting with regional conventions.
/**
* Creates a locale object for custom formatting rules
* @param definition - Locale definition with decimal, thousands, grouping, currency, etc.
* @returns Locale object with format and formatPrefix methods
*/
function formatLocale(definition: LocaleDefinition): Locale;
/**
* Sets the default locale and updates global format/formatPrefix functions
* @param definition - Locale definition object
* @returns Locale object
*/
function formatDefaultLocale(definition: LocaleDefinition): Locale;
interface LocaleDefinition {
/** Decimal point character (e.g., ".") */
decimal: string;
/** Group separator character (e.g., ",") */
thousands: string;
/** Array of group sizes (e.g., [3] for thousands) */
grouping: number[];
/** Currency prefix and suffix (e.g., ["$", ""]) */
currency: [string, string];
/** Optional: array of 10 strings to replace numerals 0-9 */
numerals?: string[];
/** Optional: percent symbol (default "%") */
percent?: string;
/** Optional: minus sign (default "−") */
minus?: string;
/** Optional: not-a-number representation (default "NaN") */
nan?: string;
}
interface Locale {
/** Creates formatter using this locale's rules */
format(specifier: string): (value: number) => string;
/** Creates prefix formatter using this locale's rules */
formatPrefix(specifier: string, value: number): (value: number) => string;
}Tools for parsing and constructing format specification strings.
/**
* Parses a format specifier string into its components
* @param specifier - Format specification string
* @returns FormatSpecifier object with exposed fields
* @throws Error for invalid format specifiers
*/
function formatSpecifier(specifier: string): FormatSpecifier;
/**
* Creates a format specifier object from properties
* @param specifier - Object with format specification properties
*/
class FormatSpecifier {
constructor(specifier: {
fill?: string;
align?: string;
sign?: string;
symbol?: string;
zero?: boolean;
width?: number;
comma?: boolean;
precision?: number;
trim?: boolean;
type?: string;
});
/** Fill character for padding (default " ") */
fill: string;
/** Alignment: "<", ">", "^", "=" (default ">") */
align: string;
/** Sign: "-", "+", "(", " " (default "-") */
sign: string;
/** Symbol: "", "$", "#" (default "") */
symbol: string;
/** Zero-padding enabled (default false) */
zero: boolean;
/** Minimum field width (default undefined) */
width: number | undefined;
/** Comma grouping enabled (default false) */
comma: boolean;
/** Precision value (default undefined) */
precision: number | undefined;
/** Trim trailing zeros (default false) */
trim: boolean;
/** Format type: "e", "f", "g", etc. (default "") */
type: string;
/** Reconstructs the format specifier string */
toString(): string;
}Helper functions for calculating appropriate precision based on data characteristics.
/**
* Calculates decimal precision for fixed-point notation
* @param step - Minimum absolute difference between values
* @returns Number of decimal places needed
*/
function precisionFixed(step: number): number;
/**
* Calculates precision for SI-prefix formatting
* @param step - Minimum absolute difference between values
* @param value - Reference value for determining SI prefix
* @returns Number of decimal places needed
*/
function precisionPrefix(step: number, value: number): number;
/**
* Calculates precision for significant digit formatting
* @param step - Minimum absolute difference between values
* @param max - Largest absolute value to be formatted
* @returns Number of significant digits needed
*/
function precisionRound(step: number, max: number): number;import { format } from "d3-format";
// Custom alignment and padding
const rightPadded = format(">20"); // Right-aligned, min width 20
const leftPadded = format("<20"); // Left-aligned, min width 20
const centered = format("^20"); // Centered, min width 20
const zeroPadded = format("020"); // Zero-padded, width 20
console.log(rightPadded(42)); // " 42"
console.log(leftPadded(42)); // "42 "
console.log(centered(42)); // " 42 "
console.log(zeroPadded(42)); // "00000000000000000042"
// Sign control
const alwaysSign = format("+"); // Always show sign
const parentheses = format("("); // Parentheses for negative
const spaceSign = format(" "); // Space for positive
console.log(alwaysSign(42)); // "+42"
console.log(alwaysSign(-42)); // "-42"
console.log(parentheses(-42)); // "(42)"
console.log(spaceSign(42)); // " 42"
// Hexadecimal with prefix
const hex = format("#x"); // Prefixed lowercase hex
const HEX = format("#X"); // Prefixed uppercase hex
console.log(hex(255)); // "0xff"
console.log(HEX(255)); // "0XFF"import { formatLocale, formatDefaultLocale } from "d3-format";
// Create custom locale
const frenchLocale = formatLocale({
decimal: ",",
thousands: " ",
grouping: [3],
currency: ["", " €"],
percent: " %"
});
const frFormat = frenchLocale.format("$,.2f");
console.log(frFormat(1234.56)); // "1 234,56 €"
// Set as default locale
formatDefaultLocale({
decimal: ",",
thousands: ".",
grouping: [3],
currency: ["R$ ", ""]
});
// Global format now uses new locale
const globalFormat = format("$,.2f");
console.log(globalFormat(1234.56)); // "R$ 1.234,56"import { format, precisionFixed, precisionPrefix, precisionRound } from "d3-format";
// Calculate appropriate precision for fixed-point formatting
const data = [1.0, 1.5, 2.0];
const step = 0.5;
const fixedPrecision = precisionFixed(step);
const fixedFormat = format(`.${fixedPrecision}f`);
data.forEach(d => console.log(fixedFormat(d)));
// "1.0", "1.5", "2.0"
// Calculate precision for SI-prefix formatting
const values = [1.1e6, 1.2e6, 1.3e6];
const prefixStep = 1e5;
const prefixPrecision = precisionPrefix(prefixStep, 1.3e6);
const prefixFormat = formatPrefix(`.${prefixPrecision}`, 1.3e6);
values.forEach(v => console.log(prefixFormat(v)));
// "1.1M", "1.2M", "1.3M"
// Calculate precision for significant digit formatting
const roundStep = 0.01;
const maxValue = 1.01;
const roundPrecision = precisionRound(roundStep, maxValue);
const roundFormat = format(`.${roundPrecision}r`);
[0.99, 1.0, 1.01].forEach(v => console.log(roundFormat(v)));
// "0.990", "1.00", "1.01"import { formatSpecifier, FormatSpecifier, format } from "d3-format";
// Parse existing specifier
const spec = formatSpecifier("$,.2f");
console.log(spec.symbol); // "$"
console.log(spec.comma); // true
console.log(spec.precision); // 2
console.log(spec.type); // "f"
// Modify and create new format
spec.precision = 0;
const newFormat = format(spec.toString());
console.log(newFormat(1234.56)); // "$1,235"
// Create specifier from scratch
const customSpec = new FormatSpecifier({
align: "^",
width: 10,
type: "s",
precision: 1
});
const customFormat = format(customSpec.toString());
console.log(customFormat(42000)); // " 42k "The library supports full SI prefix notation with the following prefixes:
| Prefix | Symbol | Factor | Name |
|---|---|---|---|
| y | y | 10⁻²⁴ | yocto |
| z | z | 10⁻²¹ | zepto |
| a | a | 10⁻¹⁸ | atto |
| f | f | 10⁻¹⁵ | femto |
| p | p | 10⁻¹² | pico |
| n | n | 10⁻⁹ | nano |
| µ | µ | 10⁻⁶ | micro |
| m | m | 10⁻³ | milli |
| 10⁰ | |||
| k | k | 10³ | kilo |
| M | M | 10⁶ | mega |
| G | G | 10⁹ | giga |
| T | T | 10¹² | tera |
| P | P | 10¹⁵ | peta |
| E | E | 10¹⁸ | exa |
| Z | Z | 10²¹ | zetta |
| Y | Y | 10²⁴ | yotta |
formatSpecifier() throws an Error for invalid format specification strings"g" with precision 12 and trim enablednan property (default "NaN")