Reputation: 2014
I have a map and datatable component in the layout that is update by a callback. The datatable is editable and the user can add new information to the new table. Upon the click event of update table
I have two callbacks, one for updating the map and another one for datatable. What I'd like to do is run the map callback from inside of the datatable callback. Basically, I'd like to update the map based on the values of datatable.
Can I run another callback from a callback or run some lines of code inside another callback? Trying to figure out a elegant and efficient way of doing this.
layout = html.Div([
# Plot map
dcc.Graph(id="map-graph"),
# DataTable
dash_table.DataTable(
id="table",
columns=[{"id":"Type","name":"Type"},
{"id":"space","name": "space"}],
sort_action="native",
filter_action="native",
row_deletable=True
),
# Update map
dbc.Button("Update map", id="update-map", className="mr-1"),
# Update Table
dbc.Button("Update table", id="update-table", className="mr-1")
]),
# Callbacks
# Update map
@app.callback(Output("map-graph", "figure"),
[Input("update-map", "value")])
def updatemap(value):
...
do something
...
return value
# Update table
@app.callback(Output("table", "data"),
[Input("update-table", "value")])
def updatetable(value):
...
do something
...
# Run the code inside previous callback which updates the map.
return rows
Upvotes: 7
Views: 11908
Reputation: 2951
dash_table.DataTable
with a single callback in a Dash appIn the example you provide you have an HTML button component user interaction acting as the trigger event which initializes the first callback. One callback in this case can be sufficient.
E.g., a simple example using a pie chart instead of a map graph:
import pandas as pd
import plotly.express as px
import dash_bootstrap_components as dbc
from dash import dcc, html, dash_table
from dash import Dash, Input, Output, State, callback
from dash.exceptions import PreventUpdate
df = pd.DataFrame(
{
"reputation": [0, 10, 2, 25, 50, 0, 4],
"day": [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
],
}
)
pie_cmap = {
"Sunday": "red",
"Monday": "orange",
"Tuesday": "yellow",
"Wednesday": "green",
"Thursday": "blue",
"Friday": "purple",
"Saturday": "pink",
}
def plot_fig(df):
return px.pie(
df,
values="reputation",
names="day",
color="day",
color_discrete_map=pie_cmap,
)
fig = plot_fig(df)
app = Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = dbc.Container(
[
dcc.Graph(figure=fig, id="pie-graph"),
dbc.Label("Click a cell in the table to edit the table:"),
dash_table.DataTable(
df.to_dict("records"),
[{"name": i, "id": i} for i in df.columns],
id="table-1",
editable=True,
),
html.Br(),
html.Button("Update Graph", id="update-graph", n_clicks=0),
],
style={"textAlign": "center"},
)
@callback(
Output("pie-graph", "figure"),
Input("update-graph", "n_clicks"),
State("table-1", "data"),
)
def update_graphs(n_clicks, table_data):
if n_clicks < 1:
raise PreventUpdate
df_update = pd.DataFrame(table_data)
return plot_fig(df_update)
if __name__ == "__main__":
app.run(debug=True)
Nonetheless, if you did have another callback which was updating the data in the data table, that would be compatible with this example code. The graph will update based on the latest state (i.e., State
) of the data in the table following the event that triggers the callback (in this case and example above, a user clicking a button) - regardless of how it was that the data in the dash_table.DataTable
was changed/updated.
Upvotes: 0
Reputation: 11619
Check out the Dash documentation in Dash Tutorial - Part 3: Basic Callbacks in the section Dash App With Chained Callbacks
, currently about half-way down the page.
The basics of that section are that you can use any output from a callback as an input to another callback.
For example, below the first callback writes out to my-output-1
, its value
property, then the second callback uses that id and property as an input to drive the my-output-2
id's value
property.
@app.callback(
Output('my-output-1', 'value'),
Input('my-input-1', 'value'))
def set_output_1_from_input_1(input_1_value):
return input_1_value
@app.callback(
Output('my-output-2', 'value'),
Input('my-output-1', 'value'))
def set_output_2_from_output_1(output_1_value):
return some_function_doing_something(output_1_value)
Upvotes: 0