See the Value Formatters Intro for more information on getting started with valueFormatter
.
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)"},
},
]
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
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 adapt the behavior of d3-format to various languages and places. The definition may include the following properties:
decimal
- the decimal point (e.g., “.”).thousands
- the group separator (e.g., ","
).grouping
- the array of group sizes (e.g., [3]
), cycled as needed.currency
- the currency prefix and suffix (e.g., ["$", ""]
).numerals
- optional; an array of ten strings to replace the numerals 0-9
.percent
- optional; the percent sign (defaults to "%"
).minus
- optional; the minus sign (defaults to "−"
).nan
- optional; the not-a-number value (defaults "NaN"
).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)"},
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'
.
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!
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:
[01,31]
.[ 1,31]
; equivalent to %_d
.[000000, 999999]
.[00,99]
.[00,23]
.[01,12]
.[001,366]
.[01,12]
.[00,59]
.[000, 999]
.[1,4]
.[00,61]
.[1,7]
.[00,53]
.[01, 53]
.[0,6]
.[00,53]
.%-m/%-d/%Y.*
%-I:%M:%S %p.*
[00,99]
.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)
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.