Question: Similar to qtTree, I would like to have a drill down on a column of a datatable. I guess this is better illustrated with an example. Assume we have a dataframe with three columns: Country, City, Population like: Country City Population USA New-York 19MM China Shanghai 26MM China Beijing 20MM USA Los Angeles 12MM France Paris 11MM  Is there a way to present this data ideally in a dash-plotly datatable as follows: Country City Population +USA 31MM /----> New-York 19MM /----> Los Angeles 12MM +China 46MM /----> Shanghai 26MM /----> Beijing 20MM +France 11MM /----> Paris 11MM  The grouping Country/City would be expandle (or maybe hidden/shown upon click on the row -?-). At the country level, the population would be the sum of its constituents and the City level, the population would be the one from that city. The library dash_treeview_antd allows for treeview representation but I don't know how to include the population column for instance. Maybe there is a simpler way by doing the groupby in pandas first and then having a callback to hide/show the currentrow selection/clicked? Edit: I have been playing around with .groupby in pandas and the 'active_cell' Dash DataTable property in the callback. def defineDF(): df = pd.DataFrame({'Country': ['USA', 'China', 'China', 'USA', 'France'], 'City': ['New-York', 'Shanghai', 'Beijing', 'Los Angeles', 'Paris'], 'Population': [19, 26, 20, 12, 11], 'Other': [5, 3, 4, 11, 43]}) df.sort_values(by=['Country', 'City'], inplace=True) return df def baseDF(): df = pd.DataFrame({'Country': ['USA', 'China', 'China', 'USA', 'France'], 'City': ['New-York', 'Shanghai', 'Beijing', 'Los Angeles', 'Paris'], 'Population': [19, 26, 20, 12, 11], 'Other': [5, 3, 4, 11, 43]}) df.sort_values(by=['Country', 'City'], inplace=True) f = {'Population': 'sum', 'Other': 'sum'} cols = ['Country'] return df.groupby(cols).agg(f).reset_index() startDF = baseDF() app.layout = html.Div([ html.Div(html.H6("Country/City population"), style={"text-align":"center"}), html.Hr(), dash_table.DataTable( id='table', columns=[{'name': i, 'id': i} for i in startDF.columns], data = startDF.to_dict('records'), selected_rows=[], filter_action='native', ) ]) @app.callback([ Output('table', 'data'), Output('table', 'columns') ], [ Input('table', 'active_cell') ], [ State('table', 'data'), State('table', 'columns') ], ) def updateGrouping(active_cell, power_position, power_position_cols): if active_cell is None: returndf = baseDF() elif active_cell['column'] == 0: returndf = defineDF() else: returndf = baseDF() cols = [{'name': i, 'id': i} for i in returndf.columns] return [returndf.to_dict('records'), cols]  I am getting there. At start I only display the country column; it would be nice to have the column City there too but with empty values. Then once the user clicks on a country, only show the Cities for that country (and the corresponding Population/Other columns while the rest of the table is unchanged). I am not using current_df nor current_df_cols in the callback yet, but I suspect they might become handy. Maybe I can filter the country column based on active cell?

Answer: Dynamic Python Dash app data_table with row-based dropdowns triggering callbacks This is a little tricky, but hopefully the following example might help achieve what you are attempting. The main drawback is probably the requirement for hard-coding the dropdown_conditional parameter (although, you probably wouldn't want to have more columns for a user to interact with then would be prohibitive to hard-code!). So, I think this should provide you with the general functional gist sufficient for you to further customize it as needed. import pandas as pd from collections import OrderedDict from dash import Dash, Input, Output, State, dcc, html, callback from dash.exceptions import PreventUpdate from dash import dash_table start_df = pd.DataFrame( OrderedDict([("Country", ["USA", "China", "France"])]) ) start_df["City"] = "" start_df["Population"] = [31, 46, 11] population_df = pd.DataFrame( OrderedDict( [ ("Country", ["USA", "China", "China", "USA", "France"]), ( "City", ["New-York", "Shanghai", "Beijing", "Los Angeles", "Paris",], ), ("Population", [19, 26, 20, 12, 11]), ] ) ) app = Dash(__name__) app.layout = html.Div( [ html.Div( html.H1("Country/City population"), style={"text-align": "center"} ), html.Hr(), dash_table.DataTable( id="table", columns=[ {"id": "Country", "name": "Country",}, {"id": "City", "name": "City", "presentation": "dropdown",}, {"id": "Population", "name": "Population (Total [M])"}, ], data=start_df.to_dict("records"), editable=True, dropdown_conditional=[ { "if": { "column_id": "City", # skip-id-check "filter_query": '{Country} eq "China"', }, "options": [ {"label": i, "value": i} for i in population_df[ population_df.Country == "China" ].City.values ], }, { "if": { "column_id": "City", # skip-id-check "filter_query": '{Country} eq "USA"', }, "options": [ {"label": i, "value": i} for i in population_df[ population_df.Country == "USA" ].City.values ], }, { "if": { "column_id": "City", # skip-id-check "filter_query": '{Country} eq "France"', }, "options": [ {"label": i, "value": i} for i in population_df[ population_df.Country == "France" ].City.values ], }, ], style_cell={ "fontSize": "0.8rem", "whiteSpace": "normal", "padding": "3px", "textOverflow": "ellipsis", "textAlign": "center", "maxWidth": "300px", }, style_header={ "fontWeight": "500", "fontSize": "0.8rem", "cursor": "pointer", }, ), html.Div(id="table_container"), ] ) @callback( Output("table", "data"), Input("table", "data_timestamp"), State("table", "data"), ) def update_table(timestamp, rows): print(timestamp) for row in rows: country = row["Country"] city = row["City"] if city == "" or city is None: print(country) population = start_df.set_index("Country").loc[country][ "Population" ] print(population) row["Population"] = population elif city in population_df[["City"]].values: print(city) population = population_df.set_index("City").loc[city][ "Population" ] print(population) row["Population"] = population return rows if __name__ == "__main__": print(start_df) app.run(debug=True)  gives the following app reactivity:  The print() functions were used/are included for debugging purposes. E.g., providing this to stdout in the terminal when running app: Dash is running on http://127.0.0.1:8050/ * Serving Flask app "app" (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on Country City Population 0 USA 31 1 China 46 2 France 11 None USA 31 China 46 France 11 1690628030839 New-York 19 China 46 France 11 1690628033725 Los Angeles 12 China 46 France 11 1690628035972 USA 31 China 46 France 11 1690628038742 USA 31 Shanghai 26 France 11 1690628041373 USA 31 Shanghai 26 Paris 11 1690628043825 Los Angeles 12 Shanghai 26 Paris 11 1690628046159 Los Angeles 12 China 46 Paris 11 1690628047975 Los Angeles 12 China 46 France 11 1690628050125 USA 31 China 46 France 11  where you can see every interaction with the data table in the app in browser triggers first a printing of the timestamp recorded for that interaction, and then the changes which become rendered in the data_table triggered by the dropdown components in the "City" column.