Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotly Dash table callback

I am trying to get the dependency between a slider, user input and a table to work. I have tried outputting the data and using a callback to update it. I was advised to just create the table in a callback and just use a "Div." to define its location in the display.

other info:

  • table is created from a pandas DataFrame, using dash_table library.
  • data is in dictionary format.
  • with a the variable threshold being the value adjusted by user input (slider or input)

I would be grateful if someone could help me find out why the table is not displaying?

Here is my code:


import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
from dash.dependencies import Input, Output
import dash_table

threshold = 0.5
################################################################
###################### Table Data ##############################
################################################################

metrics_index = ["AUC", "Accuracy", "Kappa", "Sensitivity (Recall)", "Specificity", "Precision", "F1"]

algo_columns = ["Test-SVM+Naïve B", "RF"]

table_data = {"AUC": [threshold * 0.8, threshold * 0.83],
              "Accuracy": [threshold * 0.85, threshold * 0.86],
              "Kappa": [threshold * 0.66, threshold * 0.69],
              "Sensitivity (Recall)": [threshold * 0.82, threshold * 0.83],
              "Specificity": [threshold * 0.78, threshold * 0.79],
              "Precision": [threshold * 0.78, threshold * 0.79],
              "F1": [threshold * 0.81, threshold * 0.82]}

data = [i for i in table_data]
table = pd.DataFrame(columns=algo_columns, index=metrics_index, data=[table_data[i] for i in metrics_index])
# display(table)


################################################################
########################  Body  ################################
################################################################


body = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [
                        html.H2("Slider + Manual entry test"),
                        dcc.Slider(
                            id='my-slider',
                            min=0,
                            max=1,
                            step=0.01,
                            marks={"0": "0", "0.5": "0.5", "1": "1"},
                            value=threshold
                        ),
                        html.Div(id='update-table')
                    ]
                ),
                dbc.Col(
                    [
                        html.Div(
                            [
                                html.Div(
                                    dcc.Input(id='input-box', type='float', max=0, min=1, step=0.01, value=threshold)
                                    ),
                                 html.Div(id='slider-output-container')
                            ]
                        )
                    ]
                )
            ]
        )
    ]
)

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([body])


##############################################################
######################## callbacks ###########################
##############################################################

@app.callback(
    dash.dependencies.Output('slider-output-container', 'children'),
    [dash.dependencies.Input('my-slider', 'value')]
)
def update_output(value):
    threshold = float(value)
    return threshold


# call back for slider to update based on manual input
@app.callback(
    dash.dependencies.Output(component_id='my-slider', component_property='value'),
    [dash.dependencies.Input('input-box', 'value')]
)
def update_output(value):
    threshold = float(value)
    return threshold


# call back to update table

@app.callback(
    dash.dependencies.Output('update-table', 'children'),
    [dash.dependencies.Input('my-slider', 'value')]
)
def update_output(value):
    threshold = float(value)
    table_data = {"AUC": [threshold * 0.8, threshold * 0.83],
                  "Accuracy": [threshold * 0.85, threshold * 0.86],
                  "Kappa": [threshold * 0.66, threshold * 0.69],
                  "Sensitivity (Recall)": [threshold * 0.82, threshold * 0.83],
                  "Specificity": [threshold * 0.78, threshold * 0.79],
                  "Precision": [threshold * 0.78, threshold * 0.79],
                  "F1": [threshold * 0.81, threshold * 0.82]}


    return dash_table.DataTable(
                            id='update-table',
                            data= table_data.to_dict('records'),
                            columns=[{'id': x, 'name': x} for x in table.columns]
                )


if __name__ == "__main__":
    app.run_server()

like image 717
sam c Avatar asked Nov 11 '19 15:11

sam c


People also ask

How does Callback work in dash?

Whenever an input property changes, the function that the callback decorator wraps will get called automatically. Dash provides this callback function with the new value of the input property as its argument, and Dash updates the property of the output component with whatever was returned by the function.

Is @app_callback is the callback decorator?

@app_callback is the callback decorator.

Are dash callbacks parallel?

Dash is also designed to be able to run with multiple workers so that callbacks can be executed in parallel.

What is Dash_table?

Dash DataTable is an interactive table component designed for viewing, editing, and exploring large datasets. This component was written from scratch in React. js specifically for the Dash community. Its API was designed to be ergonomic and its behavior is completely customizable through its properties.


1 Answers

[screenshot of table live dynamic editing]

import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import pandas as pd

from dash.dependencies import Input, Output

threshold = 0.5
################################################################
###################### Table Data ##############################
################################################################

metrics_index = [
    "AUC",
    "Accuracy",
    "Kappa",
    "Sensitivity (Recall)",
    "Specificity",
    "Precision",
    "F1",
]

algo_columns = ["Test-SVM+Naïve B", "RF"]

table_data = {
    "AUC": [threshold * 0.8, threshold * 0.83],
    "Accuracy": [threshold * 0.85, threshold * 0.86],
    "Kappa": [threshold * 0.66, threshold * 0.69],
    "Sensitivity (Recall)": [threshold * 0.82, threshold * 0.83],
    "Specificity": [threshold * 0.78, threshold * 0.79],
    "Precision": [threshold * 0.78, threshold * 0.79],
    "F1": [threshold * 0.81, threshold * 0.82],
}

data = [i for i in table_data]
table = pd.DataFrame(
    columns=algo_columns,
    index=metrics_index,
    data=[table_data[i] for i in metrics_index],
)
# display(table)


################################################################
########################  Body  ################################
################################################################


body = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [
                        html.H2("Slider + Manual entry test"),
                        dcc.Slider(
                            id="my-slider",
                            min=0,
                            max=1,
                            step=0.01,
                            marks={"0": "0", "0.5": "0.5", "1": "1"},
                            value=threshold,
                        ),
                        html.Div(id="update-table"),
                    ]
                ),
                dbc.Col(
                    [
                        html.Div(
                            [
                                html.Div(
                                    dcc.Input(
                                        id="input-box",
                                        max=0,
                                        min=1,
                                        step=0.01,
                                        value=threshold,
                                    )
                                ),
                                html.Div(id="slider-output-container"),
                            ]
                        )
                    ]
                ),
            ]
        )
    ]
)

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

app.layout = html.Div([body])


##############################################################
######################## callbacks ###########################
##############################################################


@app.callback(
    dash.dependencies.Output("slider-output-container", "children"),
    [dash.dependencies.Input("my-slider", "value")],
)
def update_output(value):
    threshold = float(value)
    return threshold


# call back for slider to update based on manual input
@app.callback(
    dash.dependencies.Output(component_id="my-slider", component_property="value"),
    [dash.dependencies.Input("input-box", "value")],
)
def update_output(value):
    threshold = float(value)
    return threshold


# call back to update table


@app.callback(
    dash.dependencies.Output("update-table", "children"),
    [dash.dependencies.Input("my-slider", "value")],
)
def update_output(value):
    threshold = float(value)
    table_data = pd.DataFrame.from_dict(
        {
            "AUC": [threshold * 0.8, threshold * 0.83],
            "Accuracy": [threshold * 0.85, threshold * 0.86],
            "Kappa": [threshold * 0.66, threshold * 0.69],
            "Sensitivity (Recall)": [threshold * 0.82, threshold * 0.83],
            "Specificity": [threshold * 0.78, threshold * 0.79],
            "Precision": [threshold * 0.78, threshold * 0.79],
            "F1": [threshold * 0.81, threshold * 0.82],
        }
    )

    return html.Div(
        [
            dash_table.DataTable(
                data=table_data.to_dict("rows"),
                columns=[{"id": x, "name": x} for x in table_data.columns],
            )
        ]
    )


if __name__ == "__main__":
    app.run_server(host="0.0.0.0", port=8050, debug=True, dev_tools_hot_reload=True)

I tried this out & seems to be working w/ slightly modified code above; the changes I had to make were:

  1. Transform dict table_data into a dataframe (this allows the .to_dict() method which is a pd.DataFrame method to work!)
    table_data = pd.DataFrame.from_dict(
        {
            "AUC": [threshold * 0.8, threshold * 0.83],
            "Accuracy": [threshold * 0.85, threshold * 0.86],
            "Kappa": [threshold * 0.66, threshold * 0.69],
            "Sensitivity (Recall)": [threshold * 0.82, threshold * 0.83],
            "Specificity": [threshold * 0.78, threshold * 0.79],
            "Precision": [threshold * 0.78, threshold * 0.79],
            "F1": [threshold * 0.81, threshold * 0.82],
        }
    )
  1. Also in update_output callback fxn:

    • A. change 'records' to 'rows' for df .to_dict method call
    • B. you had table instead of table_data for the columns param
    • C. remove the use of the id Dash param here, b/c it's already in the layout
    return html.Div(
        [
            dash_table.DataTable(
                data=table_data.to_dict("rows"),
                columns=[{"id": x, "name": x} for x in table_data.columns],
            )
        ]
    )

  1. Looks like you had max and min switched! (max zero doesn't leave a lot of possible inputs! [actually, none..]); also might be important to have put the decimals and matching precision which I add just in case.
                                html.Div(
                                    dcc.Input(
                                        id="input-box",
                                        max=1.00,
                                        min=0.00,
                                        step=0.01,
                                        value=threshold,
                                        type="number"
                                    )
                                ),
like image 183
John Collins Avatar answered Oct 10 '22 10:10

John Collins