Conditional formatting is provided through the style_data_conditional
property. The if
keyword provides a set of conditional formatting
statements and the rest of the keywords are camelCased CSS properties.
The if
syntax supports several operators, row_index
, column_id
,
filter_query
, column_type
, column_editable
, and state
.
filter_query
is the most flexible option when dealing with data.
Here is an example of all operators:
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[
Dict("name" => "Date", "id" => "Date", "type" => "datetime", "editable" => false),
Dict("name" => "Delivery", "id" => "Delivery", "type" => "datetime"),
Dict("name" => "Region", "id" => "Region", "type" => "text"),
Dict("name" => "Temperature", "id" => "Temperature", "type" => "numeric"),
Dict("name" => "Humidity", "id" => "Humidity", "type" => "numeric"),
Dict("name" => "Pressure", "id" => "Pressure", "type" => "any"),
],
editable=true,
style_data_conditional=[
Dict(
"if" => Dict(
"column_id" => "Region",
),
"backgroundColor" => "dodgerblue",
"color" => "white"
),
Dict(
"if" => Dict(
"filter_query" => "{Humidity} > 19 && {Humidity} < 41",
"column_id" => "Humidity"
),
"backgroundColor" => "tomato",
"color" => "white"
),
Dict(
"if" => Dict(
"column_id" => "Pressure",
# since using .format, escape { with {{
"filter_query" => "{Pressure} = $(maximum(df[!,"Pressure"]))"
),
"backgroundColor" => "#85144b",
"color" => "white"
),
Dict(
"if" => Dict(
"row_index" => 5, # number | "odd" | "even"
"column_id" => "Region"
),
"backgroundColor" => "hotpink",
"color" => "white"
),
Dict(
"if" => Dict(
"filter_query" => "{id} = 4", # matching rows of a hidden column with the id, `id`
"column_id" => "Region"
),
"backgroundColor" => "RebeccaPurple"
),
Dict(
"if" => Dict(
"filter_query" => "{Delivery} > {Date}", # comparing columns to each other
"column_id" => "Delivery"
),
"backgroundColor" => "#3D9970"
),
Dict(
"if" => Dict(
"column_editable" => false # True | False
),
"backgroundColor" => "rgb(240, 240, 240)",
"cursor" => "not-allowed"
),
Dict(
"if" => Dict(
"column_type" => "text" # "text" | "any" | "datetime" | "numeric"
),
"textAlign" => "left"
),
Dict(
"if" => Dict(
"state" => "active" # "active" | "selected"
),
"backgroundColor" => "rgba(0, 116, 217, 0.3)",
"border" => "1px solid rgb(0, 116, 217)"
)
],
)
run_server(app, "0.0.0.0", debug=true)
Notes:
- filter_query
supports different operators depending on the data type
of the column:
=
, >
, >=
, <
, <=
, and contains
are supported bynumeric
, text
, datetime
, and any
)contains
, the right-hand-side needs to be a string,{Date} contains "01"
will work but {Date} contains 1
will not.datestartswith
is supported by datetime
is nil
is supported by all data typesis blank
is supported by all data types
A column’s default data type is any
column_type
refers to the data type of the column (numeric
, text
, datetime
, and any
)column_editable
can be equal to True
or False
(new in Dash 1.12.0)state
can be equal to 'active'
or 'selected'
(new in Dash 1.12.0). Use this to changerow_index
is absolute - if you filter or sort your table,column_id
, row_index
, and header_index
can be equal to a scalar'column_id': ['Region', 'Pressure']
DataTable
filtering & conditional formattingif
blocks.'filter_query': '{Delivery} > {Date}'
: Filter queries can compare columnsid
is a special hidden column that can be used as an alternativerow_index
for highlighting data by index. Since each row has aid
, the conditional formatting associated with this id
RebeccaPurple
, hotpink
, DodgerBlue
… These arered
, blue
, green
as they look very outdated. For other color.format
, we escape {
with \{{
and }
with \}}
.column_id
. To highlight a particular cell, include column_id
.style_cell_conditional
(all cells, including headers),style_header_conditional
(header cells),style_filter_conditional
(filter input boxes)style_data_conditional
via a callback whenever derived_virtual_data
changes.Instead of highlighting the background cell, you can change the color
of the text, bold the text, add underlines, or style it using any
other CSS property.
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{Humidity} > 19 && {Humidity} < 41",
"column_id" => "Humidity"
),
"color" => "tomato",
"fontWeight" => "bold"
),
Dict(
"if" => Dict(
"filter_query" => "{Pressure} > 19",
"column_id" => "Pressure"
),
"textDecoration" => "underline"
)
]
)
run_server(app, "0.0.0.0", debug=true)
You can copy and paste emoji unicode characters directly into your code.
We recommend copying values from emojipedia, e.g.
https://emojipedia.org/star/.
New unicode emoji characters are released every year and may not be
available in the character sets of your audience’s machines.
The appearance of these icons differs on most operating systems.
This example has not been ported to Julia yet - showing the Python version instead.
Visit the old docs site for Julia at: https://community.plotly.com/c/dash/julia/20
from dash import Dash, dash_table
import pandas as pd
from collections import OrderedDict
data = OrderedDict(
[
("Date", ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"]),
("Region", ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"]),
("Temperature", [1, -20, 3.512, 4, 10423, -441.2]),
("Humidity", [10, 20, 30, 40, 50, 60]),
("Pressure", [2, 10924, 3912, -10, 3591.2, 15]),
]
)
df = pd.DataFrame(data)
df['Rating'] = df['Humidity'].apply(lambda x:
'⭐⭐⭐' if x > 30 else (
'⭐⭐' if x > 20 else (
'⭐' if x > 10 else ''
)))
df['Growth'] = df['Temperature'].apply(lambda x: '↗️' if x > 0 else '↘️')
df['Status'] = df['Temperature'].apply(lambda x: '🔥' if x > 0 else '🚒')
app = Dash()
app.layout = dash_table.DataTable(
data=df.to_dict('records'),
columns=[
{"name": i, "id": i} for i in df.columns
],
)
if __name__ == '__main__':
app.run(debug=True)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{Pressure} = $(maximum(df[!,"Pressure"]))",
"column_id" => "Pressure"
),
"backgroundColor" => "#FF4136",
"color" => "white"
),
]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{Temperature} = $(minimum(df[!,"Temperature"]))"
),
"backgroundColor" => "#FF4136",
"color" => "white"
),
]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using DataStructures
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=vcat(
[
Dict(
"if" => Dict(
"filter_query" => "{Temperature} = $i",
"column_id" => "Temperature",
),
"backgroundColor" => "#0074D9",
"color" => "white"
)
for i in nlargest(3,df[!,"Temperature"])
],
[
Dict(
"if" => Dict(
"filter_query" => "{Pressure} = $i",
"column_id" => "Pressure",
),
"backgroundColor" => "#7FDBFF",
"color" => "white"
)
for i in nsmallest(3, df[!,"Pressure"])
]
)
)
run_server(app, "0.0.0.0", debug=true)
using Base: Number
using CSV: eltype
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
df[!,"id"] = 1:size(df)[1]
app = dash()
function highlight_max_row(df)
df1 = select(df, Not(:id))
nm = names(df1)
new_nm = String[]
for (idx, ec) in enumerate(eachcol(df1))
if (eltype(ec) <: Number)
push!(new_nm,nm[idx])
end
end
df_numeric_columns = df[!,new_nm]
locs = let x = Symbol[]
map(eachrow(df_numeric_columns)) do rw
push!(x, argmax(rw))
end
x
end
return [
Dict(
"if" => Dict(
"filter_query" => "{id} = $idx",
"column_id" => col
),
"backgroundColor" => "#3D9970",
"color" => "white"
)
for (idx,col) in enumerate(locs)
]
end
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=highlight_max_row(df)
)
run_server(app, "0.0.0.0", debug=true)
using Base: Number
using CSV: eltype
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
df[!,"id"] = 1:size(df)[1]
app = dash()
function style_row_by_top_values(df, nlg=2)
df1 = select(df, Not(:id))
nm = names(df1)
new_nm = String[]
for (idx, ec) in enumerate(eachcol(df1))
if (eltype(ec) <: Number)
push!(new_nm,nm[idx])
end
end
df_numeric_columns = df[!,new_nm]
styles = Dict[]
for i in 1:nrow(df_numeric_columns)
row_loc = sortperm(Array(df_numeric_columns[i, new_nm]), rev=true)
for j in 1:nlg
val = Dict(
"if" => Dict(
"filter_query" => "{id} = $i",
"column_id" => new_nm[row_loc[j]]
),
"backgroundColor" => "#39CCCC",
"color" => "white"
)
push!(styles,val)
end
end
return styles
end
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c != "id"],
style_data_conditional=style_row_by_top_values(df)
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
df[!,"id"] = 1:nrow(df)
app = dash()
function style_table_by_max_value(df)
df1 = select(df, Not(:id))
nm = names(df1)
new_nm = names(df1,Number)
df_numeric_columns = df[!,new_nm]
df_numeric_columns_mat = Array(df_numeric_columns)
max_val, max_idx = findmax(df_numeric_columns_mat, dims=2)
max_across_table = maximum(max_val)
styles = Dict[]
for (idx,col) in enumerate(max_val)
if col == max_across_table
push!(styles,
Dict(
"if" => Dict(
"filter_query" => "{id} = $idx",
"column_id" => new_nm[idx]
),
"backgroundColor" => "#39CCCC",
"color" => "white"
)
)
end
end
return styles
end
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c != "id"],
style_data_conditional=style_table_by_max_value(df)
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{2018} >= 5 && {2018} < 10",
"column_id" => "2018"
),
"backgroundColor" => "#B10DC9",
"color" => "white"
)
]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{$col} >= 5 && {$col} < 10",
"column_id" => col
),
"backgroundColor" => "#B10DC9",
"color" => "white"
) for col in names(df)
]
)
run_server(app, "0.0.0.0", debug=true)
Let’s break down \{{\{col}}}
. We want the final expression to look something like
{2017} > 5 & {2017} < 10
where 2017 is the name of the column.
Since we’re using .format()
, we need to escape the brackets,
so {2017}
would be {{2017}}
. Then, we need to replace 2017
with {col}
for the find-and-replace, so becomes\{{\{col}}}
.format(col=col)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
nm = names(df)
new_nm = names(df,Number)
df_numeric_columns = df[!,new_nm]
val_quant = [quantile(Array(df_numeric_columns[!,n]), 0.9) for n in names(df_numeric_columns)]
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{$(new_nm[idx])} >= $value",
"column_id" => new_nm[idx]
),
"backgroundColor" => "#B10DC9",
"color" => "white"
) for (idx, value) in enumerate(val_quant)
]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using Statistics
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
nm = names(df)
new_nm = names(df,Number)
df_numeric_columns = df[!,new_nm]
val_quant = [quantile(Array(df_numeric_columns[!,n]), 0.1) for n in names(df_numeric_columns)]
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{$(new_nm[idx])} <= $value",
"column_id" => new_nm[idx]
),
"backgroundColor" => "#B10DC9",
"color" => "white"
) for (idx, value) in enumerate(val_quant)
]
)
run_server(app, "0.0.0.0", debug=true)
Here, the highlighting is done per column.
using Dash
using Statistics
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
nm = names(df)
new_nm = names(df,Number)
df_numeric_columns = df[!,new_nm]
val_quant_5 = [quantile(Array(df_numeric_columns[!,n]), 0.5) for n in names(df_numeric_columns)]
val_quant_1 = [quantile(Array(df_numeric_columns[!,n]), 0.1) for n in names(df_numeric_columns)]
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=vcat(
[
Dict(
"if" => Dict(
"filter_query" => "{$(new_nm[col])} > $value",
"column_id" => new_nm[col]
),
"backgroundColor" => "#3D9970",
"color" => "white"
) for (col, value) in enumerate(val_quant_1)
],
[
Dict(
"if" => Dict(
"filter_query" => "{$(new_nm[col])} <= $value",
"column_id" => new_nm[col]
),
"backgroundColor" => "#FF4136",
"color" => "white"
) for (col, value) in enumerate(val_quant_5)
]
)
)
run_server(app, "0.0.0.0", debug=true)
Here, the highlighting is done per table.
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
nm = names(df)
new_nm = names(df,Number)
df_numeric_columns = df[!,new_nm]
df_mean = mean([mean(df[!,n]) for n in names(df, Number)])
app.layout = dash_datatable(
data = map(eachrow(df)) do r
Dict(names(r) .=> values(r))
end,
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df) if c!= "id"],
style_data_conditional=vcat(
[
Dict(
"if" => Dict(
"filter_query" => "{$col} > $df_mean",
"column_id" => col
),
"backgroundColor" => "#3D9970",
"color" => "white"
) for col in names(df)
],
[
Dict(
"if" => Dict(
"filter_query" => "{$col} <= $df_mean",
"column_id" => col
),
"backgroundColor" => "#FF4136",
"color" => "white"
) for col in names(df)
]
)
)
run_server(app, "0.0.0.0", debug=true)
Three filter queries help with empty or blank values:
- {my_column} is nil
will match None
values
- {my_column} is blank
will match None
values and empty strings
- {my_column} = ""
will match empty strings
using Dash
using DataFrames
data_with_none = [
Dict("Firm" => "Acme", "2017" => "", "2018" => 5, "2019" => 10, "2020" => 4),
Dict("Firm" => "Olive", "2017" => nothing, "2018" => 3, "2019" => 13, "2020" => 3),
Dict("Firm" => "Barnwood", "2017" => NaN, "2018" => 7, "2019" => 3, "2020" => 6),
Dict("Firm" => "Henrietta", "2017" => 14, "2018" => 1, "2019" => 13, "2020" => 1),
]
df = vcat(DataFrame.(data_with_none)...)
df2 = ifelse.(ismissing.(df) .| (df .∈ Ref(["nothing", "None"])), missing, df)
app = dash()
app.layout = html_div([
html_pre(string(df)),
dash_datatable(
data=Dict.(pairs.(eachrow(df2))),
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=(
[
Dict(
"if" => Dict(
"filter_query" => "{$col} is blank",
"column_id" => col
),
"backgroundColor" => "tomato",
"color" => "white"
) for col in names(df)
]
)
)
])
run_server(app, "0.0.0.0", debug=true)
Firm 2017 2018 2019 2020 0 Acme 5 10 4 1 Olive None 3 13 3 2 Barnwood NaN 7 3 6 3 Henrietta 14 1 13 1
NaN
or None
ValuesThis example has not been ported to Julia yet - showing the Python version instead.
Visit the old docs site for Julia at: https://community.plotly.com/c/dash/julia/20
from dash import Dash, dash_table, html
import pandas as pd
import numpy as np
from dash.dash_table.Format import Format
data_with_none = [
{'Firm': 'Acme', '2017': '', '2018': 5, '2019': 10, '2020': 4},
{'Firm': 'Olive', '2017': None, '2018': 3, '2019': 13, '2020': 3},
{'Firm': 'Barnwood', '2017': np.NaN, '2018': 7, '2019': 3, '2020': 6},
{'Firm': 'Henrietta', '2017': 14, '2018': 1, '2019': 13, '2020': 1},
]
df = pd.DataFrame(data_with_none)
app = Dash()
app.layout = html.Div([
html.Pre(repr(df)),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[
{
'name': i,
'id': i,
'type': 'numeric',
'format': Format(
nully='N/A'
)
} for i in df.columns
],
editable=True
)
])
if __name__ == '__main__':
app.run(debug=True)
Firm 2017 2018 2019 2020 0 Acme 5 10 4 1 Olive None 3 13 3 2 Barnwood NaN 7 3 6 3 Henrietta 14 1 13 1
Limitations:
- Format(nully=)
does not yet match for empty strings, only
None
values. See plotly/dash-table#763
for updates.
- 'type': 'numeric'
needs to be set, see plotly/dash-table#762
for updates.
An alternative method would be to fill in e.g. “N/A” in the data before rendering:
using Dash
using CSV, DataFrames
data_with_none = [
Dict("Firm" => "Acme", "2017" => "", "2018" => 5, "2019" => 10, "2020" => 4),
Dict("Firm" => "Olive", "2017" => nothing, "2018" => 3, "2019" => 13, "2020" => 3),
Dict("Firm" => "Barnwood", "2017" => NaN, "2018" => 7, "2019" => 3, "2020" => 6),
Dict("Firm" => "Henrietta", "2017" => 14, "2018" => 1, "2019" => 13, "2020" => 1),
]
df = vcat(DataFrame.(data_with_none)...)
df[!,"2017"] = replace(df[!,"2017"], NaN => "N/A")
df[!,"2017"] = replace(df[!,"2017"], missing => "N/A")
app = dash()
app.layout = html_div([
html_pre(string(df)),
dash_datatable(
data=Dict.(pairs.(eachrow(df))),
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=(
[
Dict(
"if" => Dict(
"filter_query" => "{$col} = $(string("N/A"))",
"column_id" => col
),
"backgroundColor" => "tomato",
"color" => "white"
) for col in names(df)
]
)
)
])
run_server(app, "0.0.0.0", debug=true)
Firm 2017 2018 2019 2020 0 Acme N/A 5 10 4 1 Olive N/A 3 13 3 2 Barnwood N/A 7 3 6 3 Henrietta 14 1 13 1
Limitation: If your table is editable, then if a user deletes the
contents of a cell, “N/A” will no longer be displayed.
This is unlike the example with Format
where the DataTable
will
automatically display N/A
for any empty cells, even after editing.
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{Region} contains $("New")"
),
"backgroundColor" => "#0074D9",
"color" => "white"
)
]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data = Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[
Dict(
"if" => Dict(
"filter_query" => "{Region} = $("London")"
),
"backgroundColor" => "#0074D9",
"color" => "white"
)
]
)
run_server(app, "0.0.0.0", debug=true)
This recipe shades cells with style_data_conditional
and creates a
legend with HTML components. You’ll need to pip install colorlover
to get the colorscales.
using Dash
using DataFrames, Colors
wide_data = [
Dict("Firm" => "Acme", "2017" => 13, "2018" => 5, "2019" => 10, "2020" => 4),
Dict("Firm" => "Olive", "2017" => 3, "2018" => 3, "2019" => 13, "2020" => 3),
Dict("Firm" => "Barnwood", "2017" => 6, "2018" => 7, "2019" => 3, "2020" => 6),
Dict("Firm" => "Henrietta", "2017" => -3, "2018" => -10, "2019" => -5, "2020" => -6),
]
df = vcat(DataFrame.(wide_data)...)
app = dash()
function discrete_background_color_bins(df; n_bins=5, columns="all")
bounds = [(i-1) * (1.0 / n_bins) for i in 1:n_bins+1]
nme = names(df, Number)
if columns == "all"
df_numeric_columns = df[!,nme]
else
df_numeric_columns = df[!,columns]
end
df_max = maximum(Array(df_numeric_columns))
df_min = minimum(Array(df_numeric_columns))
ranges = [
((df_max - df_min) * i) + df_min
for i in bounds
]
styles = Dict[]
legend = Component[]
for i in 1:length(bounds)-1
min_bound = ranges[i]
max_bound = ranges[i+1]
backgroundColor = string("#",lowercase(hex.(colormap("Blues",n_bins))[i]))
color = i > (length(bounds) / 2.) ? "white" : "inherit"
for column in names(df_numeric_columns)
chk = i < (length(bounds) - 1) ? " && {$column} < $max_bound" : ""
push!(styles, Dict(
"if" => Dict(
"filter_query" => string("{$column} >= $min_bound", chk),
"column_id"=> column
),
"backgroundColor" => backgroundColor,
"color"=> color
)
)
end
push!(legend,
html_div(style=Dict("display"=> "inline-block", "width"=> "60px"), children=[
html_div(
style=Dict(
"backgroundColor"=> backgroundColor,
"borderLeft"=> "1px rgb(50, 50, 50) solid",
"height"=> "10px"
)
),
html_small(round(min_bound, digits=2), style=Dict("paddingLeft"=> "2px"))
])
)
end
return (styles, html_div(legend, style=Dict("padding"=> "5px 0 5px 0")))
end
(styles, legend) = discrete_background_color_bins(df, n_bins=5, columns=["2018"])
app.layout = html_div([
html_div(children=[legend], style=Dict("float" => "right")),
dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=styles
),
])
run_server(app, "0.0.0.0", debug=true)
using Dash
using CSV, DataFrames, Colors
wide_data = [
Dict("Firm" => "Acme", "2017" => 13, "2018" => 5, "2019" => 10, "2020" => 4),
Dict("Firm" => "Olive", "2017" => 3, "2018" => 3, "2019" => 13, "2020" => 3),
Dict("Firm" => "Barnwood", "2017" => 6, "2018" => 7, "2019" => 3, "2020" => 6),
Dict("Firm" => "Henrietta", "2017" => -3, "2018" => -10, "2019" => -5, "2020" => -6),
]
df = vcat(DataFrame.(wide_data)...)
app = dash()
function discrete_background_color_bins(df; n_bins=5, columns="all")
bounds = [(i-1) * (1.0 / n_bins) for i in 1:n_bins+1]
nme = names(df, Number)
if columns == "all"
df_numeric_columns = df[!,nme]
else
df_numeric_columns = df[!,columns]
end
df_max = maximum(Array(df_numeric_columns))
df_min = minimum(Array(df_numeric_columns))
ranges = [
((df_max - df_min) * i) + df_min
for i in bounds
]
styles = Dict[]
legend = Component[]
for i in 1:length(bounds)-1
min_bound = ranges[i]
max_bound = ranges[i+1]
backgroundColor = string("#",lowercase(hex.(colormap("Blues",n_bins))[i]))
color = i > (length(bounds) / 2.) ? "white" : "inherit"
for column in nme
chk = i < (length(bounds) - 1) ? " && {$column} < $max_bound" : ""
push!(styles, Dict(
"if" => Dict(
"filter_query" => string("{$column} >= $min_bound", chk),
"column_id"=> column
),
"backgroundColor" => backgroundColor,
"color"=> color
)
)
end
push!(legend,
html_div(style=Dict("display"=> "inline-block", "width"=> "60px"), children=[
html_div(
style=Dict(
"backgroundColor"=> backgroundColor,
"borderLeft"=> "1px rgb(50, 50, 50) solid",
"height"=> "10px"
)
),
html_small(round(min_bound, digits=2), style=Dict("paddingLeft"=> "2px"))
])
)
end
return (styles, html_div(legend, style=Dict("padding"=> "5px 0 5px 0")))
end
(styles, legend) = discrete_background_color_bins(df)
app.layout = html_div([
html_div(children=[legend], style=Dict("float" => "right")),
dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=styles
),
])
run_server(app, "0.0.0.0", debug=true)
These recipes display a creative use of background linear-gradient
colors to display horizontal bar charts within the table.
Your mileage may vary! Feel free to modify these recipes for your own
use.
using Dash
using CSV, DataFrames, Colors
df_gapminder = CSV.read(download("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv"), DataFrame)
df = df_gapminder[1:500,:]
app = dash()
function data_bars(df, column)
n_bins = 100
bounds = [(i-1) * (1.0 / n_bins) for i in 1:n_bins+1]
df_max = maximum(Array(df[!,column]))
df_min = minimum(Array(df[!,column]))
ranges = [
((df_max - df_min) * i) + df_min
for i in bounds
]
styles = Dict[]
for i in 1:length(bounds)-1
min_bound = ranges[i]
max_bound = ranges[i+1]
max_bound_percentage = bounds[i+1] * 100
chk = i < (length(bounds) - 1) ? " && {$column} < $max_bound" : ""
push!(styles, Dict(
"if" => Dict(
"filter_query" => string("{$column} >= $min_bound", chk),
"column_id" => column
),
"background" => (
"""
linear-gradient(90deg,
#0074D9 0%,
#0074D9 $(max_bound_percentage)%,
white $(max_bound_percentage)%,
white 100%)
"""
),
"paddingBottom" => 2,
"paddingTop" => 2
)
)
end
return styles
end
app.layout = dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=vcat(
data_bars(df, "lifeExp"),data_bars(df, "gdpPercap")
),
style_cell=Dict(
"width" => "100px",
"minWidth" => "100px",
"maxWidth" => "100px",
"overflow" => "hidden",
"textOverflow" => "ellipsis",
),
page_size=20
)
run_server(app, "0.0.0.0", debug=true)
Display the data bars without text by creating a new column and making
the text transparent.
using Dash
using CSV, DataFrames, Colors
df_gapminder = CSV.read(download("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv"), DataFrame)
df = df_gapminder[1:500,:]
app = dash()
function data_bars(df, column)
n_bins = 100
bounds = [(i-1) * (1.0 / n_bins) for i in 1:n_bins+1]
df_max = maximum(Array(df[!,column]))
df_min = minimum(Array(df[!,column]))
ranges = [
((df_max - df_min) * i) + df_min
for i in bounds
]
styles = Dict[]
for i in 1:length(bounds)-1
min_bound = ranges[i]
max_bound = ranges[i+1]
max_bound_percentage = bounds[i+1] * 100
chk = i < (length(bounds) - 1) ? " && {$column} < $max_bound" : ""
push!(styles, Dict(
"if" => Dict(
"filter_query" => string("{$column} >= $min_bound", chk),
"column_id" => column
),
"background" => (
"""
linear-gradient(90deg,
#0074D9 0%,
#0074D9 $(max_bound_percentage)%,
white $(max_bound_percentage)%,
white 100%)
"""
),
"paddingBottom" => 2,
"paddingTop" => 2
)
)
end
return styles
end
df[!,"gdpPercap relative values"] = df[!,"gdpPercap"]
app.layout = dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional= vcat(
data_bars(df, "gdpPercap relative values"),
[Dict(
"if" => Dict("column_id" => "gdpPercap relative values"),
"color" => "transparent"
)]
),
style_cell=Dict(
"width" => "100px",
"minWidth" => "100px",
"maxWidth" => "100px",
"overflow" => "hidden",
"textOverflow" => "ellipsis",
),
page_size=20
)
run_server(app, "0.0.0.0", debug=true)
The data_bars_diverging
function splits up the data into two quadrants
by the midpoint.
Alternative representations of data bars may split up the data by
positive and negative numbers or by the average values.
Your mileage may vary! Feel free to modify the data_bars_diverging
function to your own visualization needs. If you create something new,
please share your work on the Dash Community Forum.
using Dash
using CSV, DataFrames
df_gapminder = CSV.read(download("https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv"), DataFrame)
df = df_gapminder[1:500,:]
app = dash()
app.layout = dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[Dict(
"if" => Dict("filter_query" => "{Date} datestartswith $(string("2015-10"))"),
"backgroundColor" => "#85144b",
"color" => "white"
)]
)
run_server(app, "0.0.0.0", debug=true)
using Dash
using OrderedCollections, DataFrames
data = OrderedDict(
"Date" => ["2015-01-01", "2015-10-24", "2016-05-10", "2017-01-10", "2018-05-10", "2018-08-15"],
"Region" => ["Montreal", "Toronto", "New York City", "Miami", "San Francisco", "London"],
"Temperature" => [1, -20, 3.512, 4, 10423, -441.2],
"Humidity" => [10, 20, 30, 40, 50, 60],
"Pressure" => [2, 10924, 3912, -10, 3591.2, 15],
)
df = DataFrame(data)
app = dash()
app.layout = dash_datatable(
data=Dict.(pairs.(eachrow(df))),
sort_action="native",
columns=[Dict("name" =>c, "id" => c) for c in names(df)],
style_data_conditional=[Dict(
"if" => Dict("filter_query" => "{Date} datestartswith $(string("2015-10"))"),
"backgroundColor" => "#85144b",
"color" => "white"
)]
)
run_server(app, "0.0.0.0", debug=true)