Note: Dash.NET is currently considered experimental. If your organization is interested in sponsoring Dash.NET, please get in touch.

DataTable - Number Formatting

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

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

Use Format.init() to access specifier and locale directly, and use Format.helper() to access the helper functions.

See d3-format for additional syntax details.

Using FormatTemplate

The FormatTemplate provides the following predefined templates:

  • Money
  • Percentage
open Dash.NET.Giraffe
open Dash.NET.DashTable

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

let columns = [|
    DataTable.Column.init("Account", "account")
    DataTable.Column.init("Balance", "balance", columnType = DataTable.ColumnType.Numeric, format=money)
    DataTable.Column.init("Rate", "rate", columnType = DataTable.ColumnType.Numeric, format=percentage)
|]

let data = [
    box {| account = "A"; balance = 522.3199; rate = 0.139 |}
    box {| account = "B"; balance = 1607.999; rate = 0.1044 |}
    box {| account = "C"; balance = (-228.4199); rate = 0.199 |}
]

let layout =
    DataTable.dataTable "datatable" [
        DataTable.Attr.columns columns
        DataTable.Attr.data data
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
Account
Balance
Rate
A
$522.31
13.90%
B
$1,607.90
10.44%
C
−$228.41
19.90%

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.

open Dash.NET.Giraffe
open Dash.NET.DashTable

let columns = [|
    DataTable.Column.init("No groups", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper())
    DataTable.Column.init("Groups of 3", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper().group(true))
    DataTable.Column.init("Groups of 4", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(group=Group.Yes, groups=[ 4u ]))
    DataTable.Column.init("Groups of 2,3,2", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(group=Group.Yes).groups([ 2u; 3u; 2u ]))
|]

let values = [ 123; 123; 1234; 12345; 123456789 ]

let layout =
    DataTable.dataTable "datatable" [
        DataTable.Attr.columns columns
        DataTable.Attr.data (values |> List.map (fun v -> box {| a = v |}))
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
No groups
Groups of 3
Groups of 4
Groups of 2,3,2
123
123
123
1,23
123
123
123
1,23
1234
1,234
1234
12,34
12345
12,345
1,2345
123,45
123456789
123,456,789
1,2345,6789
12,34,567,89

Align and Fill

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

open Dash.NET.Giraffe
open Dash.NET.DashTable

let columns = [|
    DataTable.Column.init("No fill", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init())
    DataTable.Column.init("Align left (10)", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper().align(Left).fill('-').paddingWidth(10u))
    DataTable.Column.init("Align right (8)", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(align=Right, fill='-', paddingWidth=8u))
    DataTable.Column.init("Align center (6)", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init(specifier="-^6"))
|]

let values = [ 123; 123; 1234; 12345; 123456789 ]

let layout =
    DataTable.dataTable "datatable" [
        DataTable.Attr.columns columns
        DataTable.Attr.data (values |> List.map (fun v -> box {| a = v |}))
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
No fill
Align left (10)
Align right (8)
Align center (6)
123
123-------
-----123
-123--
123
123-------
-----123
-123--
1234
1234------
----1234
-1234-
12345
12345-----
---12345
12345-
123456789
123456789-
123456789
123456789

Padding and Padding Width

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

open Dash.NET.Giraffe
open Dash.NET.DashTable

let columns = [|
    DataTable.Column.init("No padding", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init())
    DataTable.Column.init("Padding 12", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(padding=Padding.Yes, paddingWidth=12u))
    DataTable.Column.init("Padding 9", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(padding=Padding.Yes).paddingWidth(9u))
    DataTable.Column.init("Padding 6", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init(specifier="06"))
|]

let values = [ 123; 123; 1234; 12345; 123456789 ]

let layout =
    DataTable.dataTable "datatable" [
        DataTable.Attr.columns columns
        DataTable.Attr.data (values |> List.map (fun v -> box {| a = v |}))
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
No padding
Padding 12
Padding 9
Padding 6
123
000000000123
000000123
000123
123
000000000123
000000123
000123
1234
000000001234
000001234
001234
12345
000000012345
000012345
012345
123456789
000123456789
123456789
123456789

Precision and Scheme

open Dash.NET.Giraffe
open Dash.NET.DashTable
open Dash.NET.Html

let columns = [
    [|
        DataTable.Column.init("No precision", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init())
        DataTable.Column.init("Default", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u))
        DataTable.Column.init("Fixed", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Fixed))
        DataTable.Column.init("Decimal", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Decimal))
        DataTable.Column.init("Integer", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=DecimalInteger))
        DataTable.Column.init("Decimal/Exponent", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=DecimalOrExponent))
        DataTable.Column.init("Decimal SI", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=DecimalSiPrefix))
        DataTable.Column.init("Exponent", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Exponent))
    |]
    [|
        DataTable.Column.init("Percentage", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Percentage))
        DataTable.Column.init("Rounded Percentage", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=PercentageRounded))
        DataTable.Column.init("Binary", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Scheme.Binary))
        DataTable.Column.init("Octal", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Scheme.Octal))
        DataTable.Column.init("hex", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=LowerCaseHex))
        DataTable.Column.init("HEX", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=UpperCaseHex))
        DataTable.Column.init("Unicode", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=2u, scheme=Unicode))
    |]
    [|
        DataTable.Column.init("4 decimals", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=4u, scheme=Fixed))
        DataTable.Column.init("4 decimals / trimmed", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(precision=4u, scheme=Fixed, trim=Trim.Yes))
        DataTable.Column.init("Custom 4 decimals / trimmed", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier=".4~f"))
    |]
]

let data =
    [ 123.1; 123.12; 1234.123; 12345.12 ]
    |> List.map (fun v -> box {| a = v |})

let layout =
    Html.div [
        Attr.children (
            columns
            |> List.mapi (fun i columns ->
                Html.div [
                    Attr.children [
                        DataTable.dataTable (sprintf "datatable_%i" i) [
                            DataTable.Attr.columns columns
                            DataTable.Attr.data data
                        ]
                        Html.br []
                    ]
                ]
            )
        )
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
No precision
Default
Fixed
Decimal
Integer
Decimal/Exponent
Decimal SI
Exponent
123.1
1.2e+2
123.10
120
123
1.2e+2
120
1.23e+2
123.12
1.2e+2
123.12
120
123
1.2e+2
120
1.23e+2
1234.123
1.2e+3
1234.12
1200
1234
1.2e+3
1.2k
1.23e+3
12345.12
1.2e+4
12345.12
12000
12345
1.2e+4
12k
1.23e+4

Percentage
Rounded Percentage
Binary
Octal
hex
HEX
Unicode
12310.00%
12000%
1111011
173
7b
7B
123.1
12312.00%
12000%
1111011
173
7b
7B
123.12
123412.30%
120000%
10011010010
2322
4d2
4D2
1234.123
1234512.00%
1200000%
11000000111001
30071
3039
3039
12345.12

4 decimals
4 decimals / trimmed
Custom 4 decimals / trimmed
123.1000
123.1
123.1
123.1200
123.12
123.12
1234.1230
1234.123
1234.123
12345.1200
12345.12
12345.12

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)

open Dash.NET.Giraffe
open Dash.NET.DashTable

let columns = [|
    DataTable.Column.init("Default", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init())
    DataTable.Column.init("Negative", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(sign=Negative))
    DataTable.Column.init("Positive", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(sign=Positive))
    DataTable.Column.init("Parentheses", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper().sign(Parantheses))
    DataTable.Column.init("Percentage/Parentheses", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.helper(scheme=Percentage, precision=2u, sign=Parantheses))
    DataTable.Column.init("Custom", "a", columnType=DataTable.ColumnType.Numeric,
                    format=Format.init(specifier="("))
|]

let values = [
    123.1; 123.12; 1234.123; 12345.12;
    -123.1; -123.12; -1234.123; -12345.12
]

let layout =
    DataTable.dataTable "datatable" [
        DataTable.Attr.columns columns
        DataTable.Attr.data (values |> List.map (fun v -> box {| a = v |}))
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
Default
Negative
Positive
Parentheses
Percentage/Parentheses
123.1
123.1
+123.1
123.1
12310.00%
123.1
123.12
123.12
+123.12
123.12
12312.00%
123.12
1234.123
1234.123
+1234.123
1234.123
123412.30%
1234.123
12345.12
12345.12
+12345.12
12345.12
1234512.00%
12345.12
−123.1
−123.1
−123.1
(123.1)
(12310.00%)
(123.1)
−123.12
−123.12
−123.12
(123.12)
(12312.00%)
(123.12)
−1234.123
−1234.123
−1234.123
(1234.123)
(123412.30%)
(1234.123)
−12345.12
−12345.12
−12345.12
(12345.12)
(1234512.00%)
(12345.12)

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.

open Dash.NET.Giraffe
open Dash.NET.DashTable
open Dash.NET.Html

let columns = [
    [|
        DataTable.Column.init("Default", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init())
        DataTable.Column.init("No Symbol", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Symbol.No))
        DataTable.Column.init("$ Symbol", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper().symbol(Symbol.Yes))
        DataTable.Column.init("@ Symbol / Locale prefix", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper().symbol(Symbol.Yes).symbolPrefix("@"))
        DataTable.Column.init("@ Symbol / Locale prefix+suffix", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper().symbol(Symbol.Yes).symbolPrefix("@").symbolSuffix("*"))
    |]
    [|
        DataTable.Column.init("Binary", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Binary))
        DataTable.Column.init("Octal", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Octal))
        DataTable.Column.init("Hex", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Hex))
        DataTable.Column.init("Custom", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(locale=DataTable.Locale.init(symbol=["@"; "*"]), specifier="$"))
    |]
]

let data =
    [ 123.1; 123.12; 1234.123; 12345.12 ]
    |> List.map (fun v -> box {| a = v |})

let layout =
    Html.div [
        Attr.children (
            columns
            |> List.mapi (fun i columns ->
                Html.div [
                    Attr.children [
                        DataTable.dataTable (sprintf "datatable_%i" i) [
                            DataTable.Attr.columns columns
                            DataTable.Attr.data data
                        ]
                        Html.br []
                    ]
                ]
            )
        )
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
Default
No Symbol
$ Symbol
@ Symbol / Locale prefix
@ Symbol / Locale prefix+suffix
123.1
123.1
$123.1
@123.1
@123.1*
123.12
123.12
$123.12
@123.12
@123.12*
1234.123
1234.123
$1234.123
@1234.123
@1234.123*
12345.12
12345.12
$12345.12
@12345.12
@12345.12*

Binary
Octal
Hex
Custom
0b1111011
0o173
0x7b
@123.1*
0b1111011
0o173
0x7b
@123.12*
0b10011010010
0o2322
0x4d2
@1234.123*
0b11000000111001
0o30071
0x3039
@12345.12*

Localization

open Dash.NET.Giraffe
open Dash.NET.DashTable
open Dash.NET.Html

let columns = [
    [|
        DataTable.Column.init("Symbol", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Symbol.Yes))
        DataTable.Column.init("Symbol prefix", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Symbol.Yes, symbolPrefix="CAD$ "))
        DataTable.Column.init("Symbol suffix", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(symbol=Symbol.Yes, symbolSuffix=" CAD$"))
        DataTable.Column.init("Symbol custom", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier="$", locale=DataTable.Locale.init(symbol = [ "@"; "*" ])))
    |]
    [|
        DataTable.Column.init("Decimal", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(decimalDelimiter=':').scheme("f").precision(2u))
        DataTable.Column.init("Custom decimal", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier=".2f", locale=DataTable.Locale.init(decimal=':')))
        DataTable.Column.init("Group", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(groupDelimiter=':', group=Group.Yes, groups=[2u]))
        DataTable.Column.init("Custom group", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier=",", locale=DataTable.Locale.init(group=':', grouping=[2u])))
    |]
    [|
        DataTable.Column.init("Custom numerals", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(locale=DataTable.Locale.init(numerals=["0"; "AA"; "b"; "CC"; ""; ""; ""; "77"; "88"; "99"])))
        DataTable.Column.init("Percent symbol", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier=".2%", locale=DataTable.Locale.init(percent="@")))
        DataTable.Column.init("Group 4 digits", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.init(specifier=",.0f", locale=DataTable.Locale.init(separate4digits=false)))
        DataTable.Column.init("SI", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(siPrefix=Milli).precision(0u))
        DataTable.Column.init("SI+space", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(siPrefix=Milli, symbol=Symbol.Yes, symbolSuffix=" ").precision(0u))
        DataTable.Column.init("Explicit SI", "a", columnType=DataTable.ColumnType.Numeric,
                        format=Format.helper(siPrefix=Explicit (10. ** -3.)).precision(0u))
    |]
]

let data =
    [ 123; 123; 1234; 12345; 123456789 ]
    |> List.map (fun v -> box {| a = v |})

let layout =
    Html.div [
        Attr.children (
            columns
            |> List.mapi (fun i columns ->
                Html.div [
                    Attr.children [
                        DataTable.dataTable (sprintf "datatable_%i" i) [
                            DataTable.Attr.columns columns
                            DataTable.Attr.data data
                        ]
                        Html.br []
                    ]
                ]
            )
        )
    ]

[<EntryPoint>]
let main argv =
    DashApp.initDefault()
    |> DashApp.withLayout layout
    |> DashApp.run argv (DashGiraffeConfig.initDefault "localhost")
Symbol
Symbol prefix
Symbol suffix
Symbol custom
$123
CAD$ 123
123 $CAD
@123*
$123
CAD$ 123
123 $CAD
@123*
$1234
CAD$ 1234
1234 $CAD
@1234*
$12345
CAD$ 12345
12345 $CAD
@12345*
$123456789
CAD$ 123456789
123456789 $CAD
@123456789*

Decimal
Custom decimal
Group
Custom group
123:00
123:00
1:23
1:23
123:00
123:00
1:23
1:23
1234:00
1234:00
12:34
12:34
12345:00
12345:00
1:23:45
1:23:45
123456789:00
123456789:00
1:23:45:67:89
1:23:45:67:89

Custom numerals
Percent symbol
Group 4 digits
SI
SI+space
Explicit SI
AAbCC
12300.00@
123
123000m
123000 m
123000m
AAbCC
12300.00@
123
123000m
123000 m
123000m
AAbCC
123400.00@
1234
1234000m
1234000 m
1234000m
AAbCC
1234500.00@
12,345
12345000m
12345000 m
12345000m
AAbCC778899
12345678900.00@
123,456,789
123456789000m
123456789000 m
123456789000m