DataTable - Number Formatting

DataTable offers extensive number formatting and localization possibilities with the columns nested prop format and
table-wide localization prop locale_format.

Most formatting and localization for columns can be done through the dash_table.FormatTemplate
and dash_table.Format Python helpers but it’s also possible to use the d3-format
specifier and locale directly.

See d3-format for additional syntax details.

Using FormatTemplate

The FormatTemplate provides the following predefined templates:

from dash import Dash
from dash.dash_table import DataTable, FormatTemplate

app = Dash(__name__)

money = FormatTemplate.money(2)
percentage = FormatTemplate.percentage(2)

columns = [
    dict(id='account', name='Account'),
    dict(id='balance', name='Balance', type='numeric', format=money),
    dict(id='rate', name='Rate', type='numeric', format=percentage)
]

data = [
    dict(account='A', balance=522.31, rate=0.139),
    dict(account='B', balance=1607.9, rate=0.1044),
    dict(account='C', balance=-228.41, rate=0.199),
]

app.layout = DataTable(
    columns=columns,
    data=data
)

if __name__ == '__main__':
    app.run(debug=True)

Using Format Helper

Group

Grouping is defined with the format nested props group and groups.
group takes values True or Group.yes to toggle digit grouping.
groups takes a list of numbers used to define the digits grouping pattern.
If the number has more digits than what’s defined in groups, it cycles through the
list again until it runs out of numbers to group.

from dash import Dash
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Group

app = Dash(__name__)

columns = [
    dict(id='a', name='No groups', type='numeric', format=Format()),
    dict(id='a', name='Groups of 3', type='numeric', format=Format().group(True)),
    dict(id='a', name='Groups of 4', type='numeric', format=Format(group=True, groups=[4])),
    dict(id='a', name='Groups of 2,3,2', type='numeric', format=Format(group=Group.yes).groups([2, 3, 2]))
]

values = [123, 123, 1234, 12345, 123456789]

app.layout = DataTable(
    columns=columns,
    data=[dict(a=value) for value in values]
)

if __name__ == '__main__':
    app.run(debug=True)

Align and Fill

Alignment and filling is defined with the format nested props align, fill, and padding_width.
The align helper takes values left, right, and center.
fill is single character that will be used for filling.
padding_width is the minimum length of the filled string.
If the formatted number requires more space than padding_width allows for, it will do so.

from dash import Dash
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Align

app = Dash(__name__)

columns = [
    dict(id='a', name='No fill', type='numeric', format=Format()),
    dict(id='a', name='Align left (10)', type='numeric', format=Format().align(Align.left).fill('-').padding_width(10)),
    dict(id='a', name='Align right (8)', type='numeric', format=Format(align=Align.right, fill='-', padding_width=8)),
    dict(id='a', name='Align center (6)', type='numeric', format=dict(specifier='-^6'))
]

values = [123, 123, 1234, 12345, 123456789]

app.layout = DataTable(
    columns=columns,
    data=[dict(a=value) for value in values]
)

if __name__ == '__main__':
    app.run(debug=True)

Padding and Padding Width

Padding and padding width is defined with the format nested props padding and padding_width and they behave similarly
to fill and padding_width, but do not allow alignment.

from dash import Dash
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Padding

app = Dash(__name__)

columns = [
    dict(id='a', name='No padding', type='numeric', format=Format()),
    dict(id='a', name='Padding 12', type='numeric', format=Format(padding=True, padding_width=12)),
    dict(id='a', name='Padding 9', type='numeric', format=Format(padding=Padding.yes).padding_width(9)),
    dict(id='a', name='Padding 6', type='numeric', format=dict(specifier='06'))
]

values = [123, 123, 1234, 12345, 123456789]

app.layout = DataTable(columns=columns, data=[dict(a=value) for value in values])

if __name__ == '__main__':
    app.run(debug=True)

Precision and Scheme

from dash import Dash
from dash.html import Br, Div
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Scheme, Trim

app = Dash(__name__)

columns_1 = [
    dict(id='a', name='No precision', type='numeric', format=Format()),
    dict(id='a', name='Default', type='numeric', format=Format(precision=2)),
    dict(id='a', name='Fixed', type='numeric', format=Format(precision=2, scheme=Scheme.fixed)),
    dict(id='a', name='Decimal', type='numeric', format=Format(precision=2, scheme=Scheme.decimal)),
    dict(id='a', name='Integer', type='numeric', format=Format(precision=2, scheme=Scheme.decimal_integer)),
    dict(id='a', name='Decimal/Exponent', type='numeric', format=Format(precision=2, scheme=Scheme.decimal_or_exponent)),
    dict(id='a', name='Decimal SI', type='numeric', format=Format(precision=2, scheme=Scheme.decimal_si_prefix)),
    dict(id='a', name='Exponent', type='numeric', format=Format(precision=2, scheme=Scheme.exponent)),
]

columns_2 = [
    dict(id='a', name='Percentage', type='numeric', format=Format(precision=2, scheme=Scheme.percentage)),
    dict(id='a', name='Rounded Percentage', type='numeric', format=Format(precision=2, scheme=Scheme.percentage_rounded)),
    dict(id='a', name='Binary', type='numeric', format=Format(precision=2, scheme=Scheme.binary)),
    dict(id='a', name='Octal', type='numeric', format=Format(precision=2, scheme=Scheme.octal)),
    dict(id='a', name='hex', type='numeric', format=Format(precision=2, scheme=Scheme.lower_case_hex)),
    dict(id='a', name='HEX', type='numeric', format=Format(precision=2, scheme=Scheme.upper_case_hex)),
    dict(id='a', name='Unicode', type='numeric', format=Format(precision=2, scheme=Scheme.unicode))
]

columns_3 = [
    dict(id='a', name='4 decimals', type='numeric', format=Format(precision=4, scheme=Scheme.fixed)),
    dict(id='a', name='4 decimals / trimmed', type='numeric', format=Format(precision=4, scheme=Scheme.fixed, trim=Trim.yes)),
    dict(id='a', name='Custom 4 decimals / trimmed', type='numeric', format=dict(specifier='.4~f')),
]

values = [123.1, 123.12, 1234.123, 12345.12]
data = [dict(a=value) for value in values]

app.layout = Div([
    DataTable(columns=columns_1, data=data),
    Br(),
    DataTable(columns=columns_2, data=data),
    Br(),
    DataTable(columns=columns_3, data=data)
])

if __name__ == '__main__':
    app.run(debug=True)


Sign

When to display a sign and what type of sign to display is defined with the format nested prop sign.
The Sign helper takes values negative (show sign when negative), positive (always show sign), parantheses (when negative)

from dash import Dash
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Scheme, Sign

app = Dash(__name__)

columns = [
    dict(id='a', name='Default', type='numeric', format=Format()),
    dict(id='a', name='Negative', type='numeric', format=Format(sign=Sign.negative)),
    dict(id='a', name='Positive', type='numeric', format=Format(sign=Sign.positive)),
    dict(id='a', name='Parentheses', type='numeric', format=Format().sign(Sign.parantheses)),
    dict(id='a', name='Percentage/Parentheses', type='numeric', format=Format(scheme=Scheme.percentage, precision=2, sign=Sign.parantheses)),
    dict(id='a', name='', type='numeric', format=dict(specifier='('))
]

values = [
    123.1, 123.12, 1234.123, 12345.12,
    -123.1, -123.12, -1234.123, -12345.12
]

app.layout = DataTable(columns=columns, data=[dict(a=value) for value in values])

if __name__ == '__main__':
    app.run(debug=True)

Symbol

Displaying of symbols is defined with the format nested prop symbol and the prefix/suffix symbols are defined with the locale nested prop symbol.
The Symbol helper takes values yes and no.
The locale symbol nested prop is a list of strings of length 2 of the form [prefix, suffix]. Strings in symbol can be of any length.

from dash import Dash
from dash.html import Br, Div
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Symbol

app = Dash(__name__)

columns_1 = [
    dict(id='a', name='Default', type='numeric', format=Format()),
    dict(id='a', name='No Symbol', type='numeric', format=Format(symbol=Symbol.no)),
    dict(id='a', name='$ Symbol', type='numeric', format=Format(symbol=Symbol.yes)),
    dict(id='a', name='@ Symbol / Locale prefix', type='numeric', format=Format().symbol(Symbol.yes).symbol_prefix('@')),
    dict(id='a', name='@ Symbol / Locale prefix+suffix', type='numeric', format=Format().symbol(Symbol.yes).symbol_prefix('@').symbol_suffix('*'))
]

columns_2 = [
    dict(id='a', name='Binary', type='numeric', format=Format(symbol=Symbol.binary)),
    dict(id='a', name='Octal', type='numeric', format=Format(symbol=Symbol.octal)),
    dict(id='a', name='Hex', type='numeric', format=Format(symbol=Symbol.hex)),
    dict(id='a', name='Custom', type='numeric', format=dict(locale=dict(symbol=['@', '*']), specifier='$'))
]

values = [123.1, 123.12, 1234.123, 12345.12]
data = [dict(a=value) for value in values]

app.layout = Div([
    DataTable(columns=columns_1, data=data),
    Br(),
    DataTable(columns=columns_2, data=data)
])

if __name__ == '__main__':
    app.run(debug=True)

Localization

from dash import Dash
from dash.html import Br, Div
from dash.dash_table import DataTable
from dash.dash_table.Format import Format, Group, Prefix, Scheme, Symbol

app = Dash(__name__)

columns_1 = [
    dict(id='a', name='Symbol', type='numeric', format=Format(symbol=Symbol.yes)),
    dict(id='a', name='Symbol prefix', type='numeric', format=Format(symbol=Symbol.yes, symbol_prefix='CAD$ ')),
    dict(id='a', name='Symbol suffix', type='numeric', format=Format(symbol=Symbol.yes, symbol_suffix=' $CAD')),
    dict(id='a', name='Symbol custom', type='numeric', format=dict(specifier='$', locale=dict(symbol=['@', '*'])))
]

columns_2 = [
    dict(id='a', name='Decimal', type='numeric', format=Format(decimal_delimiter=':').scheme('f').precision(2)),
    dict(id='a', name='Custom decimal', type='numeric', format=dict(specifier='.2f', locale=dict(decimal=':'))),
    dict(id='a', name='Group', type='numeric', format=Format(group_delimiter=':', group=Group.yes, groups=[2])),
    dict(id='a', name='Custom group', type='numeric', format=dict(specifier=',', locale=dict(group=':', grouping=[2])))
]

columns_3 = [
    dict(id='a', name='Custom numerals', type='numeric', format=dict(locale=dict(numerals=['0', 'AA', 'b', 'CC', '', '', '', '77', '88', '99']))),
    dict(id='a', name='Percent symbol', type='numeric', format=dict(specifier='.2%', locale=dict(percent='@'))),
    dict(id='a', name='Group 4 digits', type='numeric', format=dict(specifier=',.0f', locale=dict(separate_4digits=False))),
    dict(id='a', name='SI', type='numeric', format=Format(si_prefix=Prefix.milli).precision(0)),
    dict(id='a', name='SI+space', type='numeric', format=Format(si_prefix=Prefix.milli, symbol=Symbol.yes, symbol_suffix=' ').precision(0)),
    dict(id='a', name='Explicit SI', type='numeric', format=Format(si_prefix=10 ** -3).precision(0))
]

values = [123, 123, 1234, 12345, 123456789]
data = [dict(a=value) for value in values]

app.layout = Div([
    DataTable(columns=columns_1, data=data),
    Br(),
    DataTable(columns=columns_2, data=data),
    Br(),
    DataTable(columns=columns_3, data=data)
])

if __name__ == '__main__':
    app.run(debug=True)