D3 Value Formatters

See the Value Formatters Intro for more information on getting started with valueFormatter.

Formatting Numbers with d3-format

Dash AG Grid includes the d3-format library, so you have access to all d3-format functions to use with valueFormatter.

The basic syntax for the d3 function is: d3.format(specifier)(value)

For example:

d3.format(".0%")(0.123);  # rounded percentage, "12%"
d3.format("($.2f")(-3.5); # localized fixed-point currency, "(£3.50)"
d3.format("+20")(42);     # space-filled and signed, "                 +42"
d3.format(".^20")(42);    # dot-filled and centered, ".........42........."
d3.format(".2s")(42e6);   # SI-prefix with two significant digits, "42M"
d3.format("#x")(48879);   # prefixed lowercase hexadecimal, "0xbeef"
d3.format(",.2r")(4223);  # grouped thousands with two significant digits, "4,200"

For more options, see d3-format examples

If this looks familiar to you, it’s because this JavaScript library is based on Python!

So d3.format(".0%")(0.123) is like "{:.0%}".format(0.123) in Python. The specifiers are based on the Python’s Format Specification.

In dash-ag-grid, use the d3.format function in the column definitions like this:

# example valueFormatter for currency
columnDefs = [
    {
        "valueFormatter": {"function": "d3.format('($,.2f')(params.value)"},
    },
]

Example: Number formatting

Here is a simple example of formatting numbers with d3.format function:
- The “Quantity” column has commas for the thousands seperators and is rounded to 1 decimal place.
- The “Balance” column is currency with negative numbers in ( )
- The “Rate” column is percentage, rounded to 1 decimal place.

import dash_ag_grid as dag
from dash import Dash, html, dcc

app = Dash(__name__)

rowData = [
    dict(account='A', quantity=522.31, balance=522.31, rate=0.139),
    dict(account='B', quantity=1607.9, balance=1607.9, rate=0.104444),
    dict(account='C', quantity=-228.41, balance=-228.41, rate=0.19999),
]


columnDefs = [
    {"field": "account"},
    {
        "field": "quantity",
        "valueFormatter": {"function": "d3.format(',.1f')(params.value)"},
    },
    {
        "field": "balance",
        "valueFormatter": {"function": "d3.format('($,.2f')(params.value)"},
    },
    {
        "field": "rate",
        "valueFormatter": {"function": "d3.format(',.1%')(params.value)"},
    },

]

defaultColDef = {
    "type": ["rightAligned"],
    "resizable": True,
    "editable": True,
}

app.layout = html.Div(
    [
        dcc.Markdown(
            "This demonstrates some basic number formatting with d3-format."
        ),
        dag.AgGrid(
            id="number-formatting-grid-example",
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            defaultColDef=defaultColDef,
            dashGridOptions={"singleClickEdit": True},
        ),
    ],
    style={"margin": 20},
)


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

This demonstrates some basic number formatting with d3-format.

import dash_ag_grid as dag
from dash import Dash, html, dcc
import plotly.express as px

df = px.data.gapminder()

app = Dash(__name__)

columnDefs = [
    {"headerName": "Country", "field": "country"},
    {"headerName": "Continent", "field": "continent"},
    {"headerName": "Year", "field": "year"},
    {
        "headerName": "Life Expectancy",
        "field": "lifeExp",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('.1f')(params.value)"},
    },
    {
        "headerName": "Population",
        "field": "pop",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format(',.0f')(params.value)"},
    },
    {
        "headerName": "GDP per Capita",
        "field": "gdpPercap",
        "type": "rightAligned",
        "valueFormatter": {"function": "d3.format('$,.1f')(params.value)"},
    },
]

app.layout = html.Div(
    [
        dcc.Markdown("""Examples of the Plolty "Gapminder" dataset both with and without number formatting"""),
        dag.AgGrid(
            id="with-without-example-1",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
        ),
        dcc.Markdown("Gapminder dataset without formatting", style={"marginTop": 40}),
        dag.AgGrid(
            id="with-without-example-2",
            columnDefs=[{"field": i} for i in df.columns if i not in ["iso_alpha", "iso_num"]],
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
        ),
    ],
    style={"margin": 20},
)

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

Examples of the Plolty “Gapminder” dataset both with and without number formatting

Gapminder dataset without formatting

Example: d3.format specifiers

Here are examples of formatting numbers with some of the specifiers available in the d3.format function.

import dash_ag_grid as dag
from dash import Dash, html, dcc


app = Dash(__name__)


columnDefs = [
    {"headerName": "Description", "field": "description", "minWidth": 300},
    {
        "headerName": "d3.format",
        "field": "format",
        "minWidth": 300,
        "cellRenderer": "markdown",
    },
    {"headerName": "Specifier", "field": "specifier", "minWidth": 100},
    {"headerName": "Value", "field": "value", "minWidth": 125},
    {
        "headerName": "Formatted Value",
        "field": "formatted",
        "valueFormatter": {"function": "d3.format(params.data.specifier)(params.value)"},
        "minWidth": 150,
    },
]

rowData = [
    {
        "description": "fixed decimal",
        "format": "`d3.format('.1f')(0.1234)`",
        "specifier": ".1f",
        "value": 0.1234,
        "formatted": 0.1234,
        "notes": "",
    },
    {
        "description": "fixed decimal",
        "format": "`d3.format('.2f')(0.1234)`",
        "specifier": ".2f",
        "value": 0.1234,
        "formatted": 0.1234,
        "notes": "",
    },
    {
        "description": "rounded percentage",
        "format": "`d3.format('.0%')(0.1234)`",
        "specifier": ".0%",
        "value": 0.1234,
        "formatted": 0.1234,
        "notes": "",
    },
    {
        "description": "rounded percentage",
        "format": "`d3.format('.1%')(0.1234)`",
        "specifier": ".1%",
        "value": 0.1234,
        "formatted": 0.1234,
        "notes": "",
    },
    {
        "description": "localized fixed-point currency",
        "format": "`d3.format('$,.2f')(1000.1234)`",
        "specifier": "$,.2f",
        "value": 1000.1234,
        "formatted": 1000.1234,
        "notes": "",
    },
    {
        "description": "localized fixed-point currency",
        "format": "`d3.format('$,.2f')(-1000.1234)`",
        "specifier": "$,.2f",
        "value": -1000.1234,
        "formatted": -1000.1234,
        "notes": "",
    },
    {
        "description": "localized fixed-point currency",
        "format": "`d3.format('($,.2f')(-1000.1234)`",
        "specifier": "($,.2f",
        "value": -1000.1234,
        "formatted": -1000.1234,
        "notes": "",
    },
    {
        "description": "signed",
        "format": "`d3.format('+')(12)`",
        "specifier": "+",
        "value": 12,
        "formatted": 12,
        "notes": "",
    },
    {
        "description": "dot filled and centered",
        "format": "`d3.format('.^20')(12)`",
        "specifier": ".^20",
        "value": 12,
        "formatted": 12,
        "notes": "",
    },
    {
        "description": "SI-prefix with two significant digits",
        "format": "`d3.format('.2s')(421e6)`",
        "specifier": ".2s",
        "value": 42e6,
        "formatted": 42e6,
        "notes": "",
    },
    {
        "description": "grouped thousands with two significant digits",
        "format": "`d3.format(',.2r')(4223)`",
        "specifier": ",.2r",
        "value": 4223,
        "formatted": 4223,
        "notes": "",
    },
]

app.layout = html.Div(
    [
        dcc.Markdown("Number formatting example"),
        dag.AgGrid(
            id="format-specifiers-example",
            style={"height": "500px", "width": "100%"},
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
        ),
    ],
    style={"margin": 20},
)

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

Number formatting example

Locales

Locales adapt the behavior of d3-format to various languages and places. The definition may include the following properties:

Note that the thousands property is a misnomer, as the grouping definition allows groups other than thousands.

The default locale for d3.format is U.S. English, which sets:

{
  "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["$", ""]
}

To render currency numbers in French, you could override these default marks by specifying instead a locale such as:

{
  "decimal": ",",
  "thousands": " ",
  "grouping": [3],
  "currency": ["", "€"],
  "nan": "",
}

The decimal separator becomes a comma, thousands are separated by a space, and the default currency mark, the euro symbol, appears after the number.
This example includes changing the default for not-a-number from NaN to ""

Locales are not loaded by default - you can find them here. Their definition can be fed to d3.formatLocale:

locale_en_GB = """
    """d3.formatLocale({
 "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["£", ""]
})"""
    """

Then in can be used in the valueFormatter like this:

"valueFormatter": {"function": f"{locale_en_GB}.format('$,.2f')(params.value)"},

Example Formatting with locale

In this example, each column is formatted with the specifier '$,.2f' The locale determines how the numbers will be displayed.
Note that we also set a custom NaN value in the “France” column. In stead of displaying “NaN” it will be blank

import dash_ag_grid as dag
from dash import Dash, html, dcc
import pandas as pd
import numpy as np

app = Dash(__name__)

df = pd.DataFrame(
    np.random.uniform(-10000, 10000, size=(15, 4)),
    columns=["Default", "France", "Japan", "UK"],
)

# find locals at <a href="https://cdn.jsdelivr.net/npm/d3-format@1/locale/">https://cdn.jsdelivr.net/npm/d3-format@1/locale/</a>

# "nan" is the not-a-number value (defaults `"NaN"`).  Here we change it to ""
locale_fr_FR = """d3.formatLocale({
  "decimal": ",",
  "thousands": "\u00a0",
  "grouping": [3],
  "currency": ["", "\u00a0€"],
  "percent": "\u202f%",
  "nan": ""
})"""


locale_ja_JP = """d3.formatLocale({
  "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["", "円"]
})"""


locale_en_GB = """d3.formatLocale({
  "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["£", ""]
})"""


columnDefs = [
    {
        "field": "Default",
        "valueFormatter": {"function": "d3.format('$,.2f')(params.value)"},
    },
    {
        "field": "France",
        "valueFormatter": {"function": f"{locale_fr_FR}.format('$,.2f')(params.value)"},
    },
    {
        "field": "Japan",
        "valueFormatter": {"function": f"{locale_ja_JP}.format('$,.2f')(params.value)"},
    },
    {
        "field": "UK",
        "valueFormatter": {"function": f"{locale_en_GB}.format('$,.2f')(params.value)"},
    },
]

defaultColDef = {
    "type": ["numberColumn", "rightAligned"],
    "resizable": True,
    "editable": True,
}

app.layout = html.Div(
    [
        dcc.Markdown(
            "This grid demonstrates formatting numbers for different locales using d3-format with a specifier of `'$,.2f'`."
        ),
        dag.AgGrid(
            id="locale-grid-example",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            columnSize="sizeToFit",
            defaultColDef=defaultColDef,
        ),
    ],
    style={"margin": 20},
)


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

This grid demonstrates formatting numbers for different locales using d3-format with a specifier of '$,.2f'.

Editable example

In this table try changing the specifier and the values.

import dash_ag_grid as dag
from dash import Dash, html, dcc

app = Dash(__name__)


rowData = [
    {"specifier": "$,.2f", "Default": 1000, "France": 1000, "Japan": 1000, "UK": 1000},
]


# find locals at <a href="https://cdn.jsdelivr.net/npm/d3-format@1/locale/">https://cdn.jsdelivr.net/npm/d3-format@1/locale/</a>
locale_fr_FR = """d3.formatLocale({
  "decimal": ",",
  "thousands": "\u00a0",
  "grouping": [3],
  "currency": ["", "\u00a0€"],
  "percent": "\u202f%"
})"""


locale_ja_JP = """d3.formatLocale({
 "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["", "円"]

})"""


locale_en_GB = """d3.formatLocale({
 "decimal": ".",
  "thousands": ",",
  "grouping": [3],
  "currency": ["£", ""]
})"""


columnDefs = [
    {"field": "specifier", "headerName": "d3 specifier"},
    {
        "field": "Default",
        "valueFormatter": {"function": "d3.format(params.data.specifier)(params.value)"},
    },
    {
        "field": "France",
        "valueFormatter": {"function": f"{locale_fr_FR}.format(params.data.specifier)(params.value)"},
    },
    {
        "field": "Japan",
        "valueFormatter": {"function": f"{locale_ja_JP}.format(params.data.specifier)(params.value)"},
    },
    {
        "field": "UK",
        "valueFormatter": {"function": f"{locale_en_GB}.format(params.data.specifier)(params.value)"},
    },
]

defaultColDef = {
    "type": ["numberColumn", "rightAligned"],
    "resizable": True,
    "editable": True,
}

app.layout = html.Div(
    [
        dcc.Markdown(
            "This editable grid demonstrates formatting numbers for different locales using d3-format.  Try changing the specifier and/or the values!"
        ),
        dag.AgGrid(
            id="editable-grid-number-formatting",
            columnDefs=columnDefs,
            rowData=rowData,
            columnSize="sizeToFit",
            defaultColDef=defaultColDef,
            dashGridOptions={"singleClickEdit": True},
        ),
    ],
    style={"margin": 20},
)


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

This editable grid demonstrates formatting numbers for different locales using d3-format. Try changing the specifier and/or the values!

Formatting Dates and Times with d3-time-format

Dash AG Grid includes the d3-time-format library, so you have access to all d3-time-format functions to use with valueFormatter

The basic syntax for formatting a date object is:

formatted_date_string = d3.timeFormat(specifier)(date object)

d3.timeFormat() is like strftime() in Python.

Note that even if your datetime data is an object on the server, when it’s sent to the grid in the browser it’s converted to a string.
In order to convert the string back to a date on the client, use a parser:

date_obj= d3.timeParse(specifier)(date string)

d3.timeParse() is like strptime() in Python

When the date is converted to a JavaScript date object, then the AG Grid date filter agDateColumnFilter will work out
of the box, and no additional date filter comparator functions are required.

Here are the specifiers:

from dash import Dash, dcc, html
import dash_ag_grid as dag
import datetime

rowData = [
    {"date": "2023-01-01"},
    {"date": "2023-02-11"},
    {"date": "2023-06-10"},
    {"date": "2023-11-04"},
    {"date": "2023-12-03"},
]

# function to create a date object from  a date string "YYYY-MM-DD"
date_obj = "d3.timeParse('%Y-%m-%d')(params.data.date)"


columnDefs = [
    {
        "headerName": "Date String",
        "field": "date",
        "filter": False,
    },
    {
        "headerName": "MM/DD/YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%m/%d/%Y')({date_obj})"},
    },
    {
        "headerName": "Mon DD, YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%b %d, %Y')({date_obj})"},
    },
    {
        "headerName": "day, Mon DD, YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%a %b %d, %Y')({date_obj})"},
    },
    {
        "headerName": "Month d, YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%B %e, %Y')({date_obj})"},
    },
    {
        "headerName": "MM-DD-YY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%m-%d-%y')({date_obj})"},
    },
]

defaultColDef = {
    "filter": "agDateColumnFilter",
    "filterParams": {
        "buttons": ["clear", "apply"],
    },
    "sortable": True,
}


app = Dash(__name__)

app.layout = html.Div(
    [
        dcc.Markdown("Date formatting example."),
        dag.AgGrid(id="date-times-example-1",columnDefs=columnDefs, rowData=rowData, defaultColDef=defaultColDef),
    ],
    style={"margin": 20},
)


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

Date formatting example.

from dash import Dash, dcc, html
import dash_ag_grid as dag
from datetime import datetime

rowData = [
    {"date": datetime(2023, 1, 1, 1, 0, 0)},
    {"date": datetime(2023, 1, 2, 2, 0, 0)},
    {"date": datetime(2023, 1, 3, 3, 0, 0)},
    {"date": datetime(2023, 1, 4, 18, 0, 0)},
    {"date": datetime(2023, 1, 5, 22, 0, 0)},
]

# function to create a date object from  a date string "YYYY-MM-DD"
date_obj = "d3.timeParse('%Y-%m-%dT%H:%M:%S')(params.data.date)"

# if the time is in utc:
# date_obj = "d3.utcParse('%Y-%m-%dT%H:%M:%S')(params.data.date)"


columnDefs = [
    {
        "headerName": "Datetime string",
        "field": "date",
        "filter": False,
    },
    {
        "headerName": "MM/DD/YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%m/%d/%Y')({date_obj})"},
    },
    {
        "headerName": "Mon DD, YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%b %d, %Y')({date_obj})"},
    },
    {
        "headerName": "day, Mon DD, YYYY",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {"function": f"d3.timeFormat('%a %b %d, %Y')({date_obj})"},
    },
    {
        "headerName": "yyyy-mm-dd HH:MM:SS tt",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {
            "function": f"d3.timeFormat('%Y-%m-%d %I:%M:%S %p')({date_obj})"
        },
    },
    {
        "headerName": "yyyy-mm-dd hh:mm:ss",
        "valueGetter": {"function": date_obj},
        "valueFormatter": {
            "function": f"d3.timeFormat('%Y-%m-%d %H:%M:%S')({date_obj})"
        },
    },
]

defaultColDef = {
    "filter": "agDateColumnFilter",
    "filterParams": {
        "buttons": ["clear", "apply"],
    },
    "sortable": True,
}


app = Dash(__name__)

app.layout = html.Div(
    [
        dcc.Markdown("Datetime formatting example.  Note - The date filter will not work with datetime.  Time must be zero (i.e. 2023-01-01T00:00:00)"),
        dag.AgGrid(id="date-times-example-2", columnDefs=columnDefs, rowData=rowData, defaultColDef=defaultColDef),
    ],
    style={"margin": 20},
)


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

Datetime formatting example. Note - The date filter will not work with datetime. Time must be zero (i.e. 2023-01-01T00:00:00)

Example: Formatting Dates for the Date Filter

In the data for this example, the date is formatted as a string “yyyy-mm-dd”. In order for the date filter to work,
it must be converted to a date object. We use:

 "valueGetter": {"function": "d3.timeParse('%Y-%m-%d')(params.data.date)"}

To display in the grid, we format it like the date filter “mm/dd/yyyy”

"valueFormatter": {"function": "d3.timeFormat('%m/%d/%Y')(params.value)"},
from dash import Dash, html, dcc
import dash_ag_grid as dag
import plotly.express as px

df = px.data.stocks()

app = Dash(__name__)

columnDefs = [
    {
        "field": "date",
        "filter": "agDateColumnFilter",
        "valueGetter": {"function": "d3.timeParse('%Y-%m-%d')(params.data.date)"},
        "valueFormatter": {"function": "d3.timeFormat('%m/%d/%Y')(params.value)"},
        "floatingFilter": True,
    }
] + [{"field": i} for i in df.columns if i != "date"]

defaultColDef = {"sortable": True}

app.layout = html.Div(
    [
        dcc.Markdown("Date formatting example."),
        dag.AgGrid(
            id="date-formatting-example",
            columnDefs=columnDefs,
            rowData=df.to_dict("records"),
            defaultColDef=defaultColDef,
        ),
    ],
    style={"margin": 20},
)


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

Date formatting example.