'Dash datatable with expandable/collapsable rows
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: -
Edit2: I have been playing around with groupby in pandas and activecell 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 reste 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 (?)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|