Dash DataTable component offers a free-text filter under the column header.

How can I replace this filter with a drop-down filter that contains all unique values to select from?
Something that is available off-the-shelf in Excel:

or with some simple hack in DataTables JavaScript component

I know I could use drop-drop down filter outside of a DataTable that interacts with DataTable via callbacks but I want the drop-down filter to be part of DataTable column header. In this sense, I don't want to use solution from: display datatable after filtering rows from dropdown list in dash
Answer Updated: 2023
E.g., with a simple project setup like the following:
.
├── app.py
└── assets
└── custom.css
2 directories, 2 files
where assets/custom.css contains:
.dash-table-container .dash-spreadsheet-container .dash-spreadsheet-inner td, .dash-table-container .dash-spreadsheet-container .dash-spreadsheet-inner th {
text-align: center !important;
width: 20%
}
and app.py contains:
import pandas as pd
import dash
from dash import Dash, Input, Output, dcc, html, dash_table, State
# Sample filter & data
place_holder = None
df_filter = pd.DataFrame(
{
"Person": [place_holder],
"Age": [place_holder],
"Gender": [place_holder],
"Occupation": [place_holder],
}
)
df_data = pd.DataFrame(
{
"Person": ["Alice", "Brian", "Chris", "David", "Emily"],
"Age": [25, 30, 36, 25, 36],
"Gender": ["Female", "Male", "Male", "Male", "Female"],
"Occupation": ["Engineer", "Doctor", "Lawyer", "Artist", "Artist"],
}
)
app = Dash(__name__)
app.layout = html.Div(
[
html.H1("DataTable with Header Dropdowns for Filtering"),
html.H2("Filtering Table"),
html.Div(
[
dash_table.DataTable(
id="table-filter",
columns=[
{"name": i, "id": i, "presentation": "dropdown"}
for i in df_filter.columns
],
data=df_filter.to_dict("records"),
editable=True,
dropdown={
col: {
"options": [
{"label": str(i), "value": str(i)}
for i in df_data[col].unique()
],
}
for col in df_data.columns
},
)
]
),
dash_table.DataTable(
id="table-data",
columns=[{"name": i, "id": i} for i in df_data.columns],
data=df_data.to_dict("records"),
style_table={"overflowX": "scroll"},
css=[{"selector": "tr:first-child", "rule": "display: none",},],
),
html.Div(id="table-output"),
],
# NOTE The CSS margin set below and also the width set in the
# custom.css file depends on the number of columns in this example.
# Alternative &/or additional CSS (e.g., overflow) would be probably
# best for data tables with many more columns.
style={"textAlign": "center", "margin": "5%"},
)
# Callback for updating table based on dropdown selection
@app.callback(
Output("table-data", "data"),
[Input("table-filter", "data_timestamp")],
[State("table-filter", "data"), State("table-data", "data")],
)
def update_table(timestamp, filter_rows, current_data):
if timestamp is None:
raise dash.exceptions.PreventUpdate
data = df_data.copy()
cols = data.columns
for col, value in filter_rows[0].items():
if value is not None:
data = data[data.astype(str)[col] == value]
return data.to_dict("records")
app.run_server(debug=True)
results in:
Note, however, that it is currently not possible to set multi=True for dropdowns within Dash DataTables (like it is for dash.dcc.Dropdown components). If such filtering ability is required, it would probably be best to use the built-in filtering capability of Dash DataTables, or, see Option #2 below.
import dash
import pandas as pd
from dash import dash_table as dt
from dash import dcc
from dash import html
from dash.dependencies import Input
from dash.dependencies import Output
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/solar.csv")
app = dash.Dash(__name__)
states = df.State.unique().tolist()
app.layout = html.Div(
children=[
dcc.Dropdown(
id="filter_dropdown",
options=[{"label": st, "value": st} for st in states],
placeholder="-Select a State-",
multi=True,
value=df.State.values,
),
dt.DataTable(
id="table-container",
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict("records")
)
]
)
@app.callback(
Output("table-container", "data"),
Input("filter_dropdown", "value")
)
def display_table(state):
dff = df[df.State.isin(state)]
return dff.to_dict("records")
if __name__ == "__main__":
app.run_server(debug=True)

→ Select red ❌ to Clear all


One option would be to add the following CSS to a local ./assets/custom.css file:
.Select--multi .Select-value {
display: none;
}
which would result in the following behavior:

(you could add some title above the dropdown, or something, to indicate to "select a state", etc.)

Note: In this implementation case, you may likely want to additionally add the parameter
row_deletable=Trueto thedt.DataTable. However, I just tested this, and it does not automatically repopulate the dropdown with options, so, further code would need to be invented to address that, which I imagine is possible. But you get the idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With