✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🐇 Announcing Dash VTK for 3d simulation graphics. Check out the March webinar.

How do you update a dataframe in plotly?

I’d like to show a dataframe that only loads after pressing a ‘submit’ button.
At the moment my app is waiting for the dataframe from the beginning:

Here’s app.py

import dash_daq as daq
import plotly.graph_objects as go
import dash_core_components as dcc
import dash_html_components as html
import datetime as dt
import dash_table

from . import utils
from .server import app, server

from .callbacks import (search)

def article_search():
    return html.Div(
        [
            # Value we searc in the text
            html.Div(dcc.Input(id='input-box', type='text', value = 'Bank')),
            # Dropdown
            html.Div([
                dcc.Dropdown(
                    id='demo-dropdown',
                    options=[
                        {'label': 'truco1', 'value': 'truco1'},
                        {'label': 'truco2', 'value': 'truco2'}
                    ],
                    value='truco1'
                ),
                html.Div(id='dd-output-container')
            ]),
            # Date picker, to be change to a range selector
            html.Div([
                dcc.DatePickerRange(
                    id='my-date-picker-range',
                    min_date_allowed=dt.datetime(1995, 8, 5),
                    max_date_allowed=dt.datetime.today(),
                    initial_visible_month=dt.datetime(2017, 8, 5),
                    end_date=dt.datetime.today()
                ),
                html.Div(id='output-container-date-picker-range')
            ]),
            # Submit button
            html.Button(children = 'Submit', id='submit-button',),
            # articles
            html.Div(id='output-container-button',
                     children='Enter a value and press submit'),
            html.Div(
                id='articles',
                children='Matching articles',
            ),
            html.Div(id='computed-table')
            )
        ]
    )


app.layout = html.Div(
    [
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),
        # Header
        header(),
        dcc.Tabs(
            [
                dcc.Tab(
                    label='Search article',
                    value='search',
                    children=article_search()
                )
            ]
        )
    ]
)

And here’s callback, search.py:

from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import datetime as dt
import pandas as pd
import plotly.graph_objects as go
import pickle

from ..server import app

PAGE_SIZE = 10

@app.callback(
    Output('computed-table', 'children'),
    [Input('submit-button', 'n_clicks'),
    Input('my-date-picker-range', 'start_date'),
    Input('my-date-picker-range', 'end_date'),
    Input('demo-dropdown', 'value')], 
    [State('input-box', 'value')])
def update_search(n_clicks, start_date, end_date, selection, word):
    f = pickle.load(open("dashboard/data-mm/truc.p", "rb"))
    articles = []
    print(type(start_date))
    start_date = dt.datetime.fromisoformat(start_date)
    end_date = dt.datetime.fromisoformat(end_date)

    for article in f:
        if word in article['headline']:
            if article['date'] is not None and article['date'] > start_date and article['date'] <end_date:
                articles.append(article)

    df = pd.DataFrame(articles)
    grouped = df.groupby(['date']).count()

    max_rows = 100
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in df.columns])] +

        # Body
        [html.Tr([
            html.Td(df.iloc[i][col]) for col in df.columns
        ]) for i in range(min(len(df), max_rows))]
    )

And it returns me:

introducir la descripción de la imagen aquí.

The error message is

An object was provided as children instead of a component, string, or number (or list of those). Check the children property that looks
something like: {}

But I would like to use a dash_table.DataTable, it seems to be more interactive. I inspired myself from this community post. However, when I try to do it with, in search.py :

return html.Div([
    dash_table.DataTable(
        id='table',
        columns=[{"name": i, "id": i} for i in df.columns],
        data=df.head().to_dict("rows"),
        style_cell={'width': '300px',
        'height': '60px',
        'textAlign': 'left'})
    ])

And, in app.py, replace the Div with the id: with html.Div(id=‘computed-table’)`, does not show the table and sends me back:

Objects are not valid as a React child (found: object with keys {/Finance/Banking}). If you meant to render a collection of children, use an array instead.
    in div (created by t)
    in t (created by t)
    in td (created by t)
    in t (created by t)
    in tr (created by t)
    in tbody (created by t)
    in table (created by t)
    in div (created by t)
    in div (created by t)
    in div (created by t)
    in div (created by t)
    in div (created by t)
    in t (created by t)
    in t (created by t)
    in t (created by t)
    in Suspense (created by t)
    in t (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in div (created by u)
    in u (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in div (created by u)
    in u (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in div (created by u)
    in u (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in ui (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in div (created by t)
    in div (created by t)
    in t (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by TreeContainer)
    in div (created by u)
    in u (created by CheckedComponent)
    in CheckedComponent (created by TreeContainer)
    in UnconnectedComponentErrorBoundary (created by Connect(UnconnectedComponentErrorBoundary))
    in Connect(UnconnectedComponentErrorBoundary) (created by TreeContainer)
    in TreeContainer (created by Connect(TreeContainer))
    in Connect(TreeContainer) (created by UnconnectedContainer)
    in div (created by UnconnectedGlobalErrorContainer)
    in div (created by GlobalErrorOverlay)
    in div (created by GlobalErrorOverlay)
    in GlobalErrorOverlay (created by DebugMenu)
    in div (created by DebugMenu)
    in DebugMenu (created by UnconnectedGlobalErrorContainer)
    in div (created by UnconnectedGlobalErrorContainer)
    in UnconnectedGlobalErrorContainer (created by Connect(UnconnectedGlobalErrorContainer))
    in Connect(UnconnectedGlobalErrorContainer) (created by UnconnectedContainer)
    in UnconnectedContainer (created by Connect(UnconnectedContainer))
    in Connect(UnconnectedContainer) (created by UnconnectedAppContainer)
    in UnconnectedAppContainer (created by Connect(UnconnectedAppContainer))
    in Connect(UnconnectedAppContainer) (created by AppProvider)
    in Provider (created by AppProvider)
    in AppProvider

I’m not able to run your code right now, but based on a previous experience I had - coupled with the fact that this error happens on app load, I believe your problem is assoc. with dash firing all callbacks when the app starts. Thus, I suspect if you add some error checking at the start of your update_search callback (i.e. n_clicks not None and n_clicks > 0) - also check output of dash.callback_context for additional useful information that you could use to ensure other inputs are populated - this may resolve your problem.

Thanks for your insight @flyingcujo ! A few error message I had before disappeared adding:

if n_clicks != None and n_clicks > 0:
    ...

Actually the first error message n object was provided as children instead of a component ... does not bother me much. I was looking to use a use a dash_table.DataTable and the error Objects are not valid as a React child ... tells me that I’m not doing it properly. Do you have any idea?

Nothing pops out but I could test your code this evening.

Thank you so much! Don’t mindto much about the dataframe. I’m getting out a pickle file but anything could make it

I combined your code into one file for simplicity and it runs w/o any errors. I did notice one or two bracket/parens that didn’t match so I fixed that…may want to check your code for this in the event this wasn’t caused by my copy-paste.

Also, unrelated, I notice you are using df.head() which only return the first 5 rows - I updated to pass in max_rows which I suspect may be your intent

Are you running the latest versions of Dash? Here are my version listings:

dash                      1.8.0     
dash-core-components      1.7.0     
dash-daq                  0.3.3     
dash-html-components      1.0.2     
dash-renderer             1.2.3     
dash-table                4.6.0 

Here is the combined code:

import dash_core_components as dcc
import dash_html_components as html
import datetime as dt
import dash_table
import dash
from dash.dependencies import Input, Output, State
import pandas as pd


app = dash.Dash(
    suppress_callback_exceptions = True
)


def article_search():
    return html.Div(
        [
            # Value we search in the text
            html.Div(
                [
                    dcc.Input(
                        id='input-box',
                        type='text',
                        value = 'Bank')
                ]
            ),

            # Dropdown
            html.Div(
                [
                    dcc.Dropdown(
                        id='demo-dropdown',
                        options=[
                            {'label': 'truco1', 'value': 'truco1'},
                            {'label': 'truco2', 'value': 'truco2'}
                        ],
                        value='truco1'
                    ),
                    html.Div(id='dd-output-container')
                ]
            ),

            # Date picker, to be change to a range selector
            html.Div(
                [
                    dcc.DatePickerRange(
                        id='my-date-picker-range',
                        min_date_allowed=dt.datetime(1995, 8, 5),
                        max_date_allowed=dt.datetime.today(),
                        initial_visible_month=dt.datetime(2017, 8, 5),
                        end_date=dt.datetime.today()
                    ),
                    html.Div(id='output-container-date-picker-range')
                ]
            ),

            # Submit button
            html.Button(
                children = 'Submit',
                id='submit-button'
            ),

            # articles
            html.Div(
                id='output-container-button',
                children='Enter a value and press submit'
            ),

            html.Div(
                id='articles',
                children='Matching articles',
            ),

            html.Div(
                id='computed-table'
            ),
        ]
    )


app.layout = html.Div(
    [
        # empty Div to trigger javascript file for graph resizing
        html.Div(id="output-clientside"),

        dcc.Tabs(
            [
                dcc.Tab(
                    label='Search article',
                    value='search',
                    children=article_search()
                )
            ]
        )
    ]
)

@app.callback(
    output=Output('computed-table', 'children'),
    inputs=[Input('submit-button', 'n_clicks'),
            Input('my-date-picker-range', 'start_date'),
            Input('my-date-picker-range', 'end_date'),
            Input('demo-dropdown', 'value')],
    state=[State('input-box', 'value')])
def update_search(n_clicks, start_date, end_date, selection, word):
    if not n_clicks or n_clicks < 1:
        return dash.no_update

    df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
                       'num_wings': [2, 0, 0, 0],
                       'num_specimen_seen': [10, 2, 1, 8]},
                      index=['falcon', 'dog', 'spider', 'fish'])

    max_rows = 100

    return html.Div(
        [
            dash_table.DataTable(
                id='table',
                columns=[{"name": i, "id": i} for i in df.columns],
                data=df.head(n=max_rows).to_dict("rows"),
                style_cell={'width': '300px',
                            'height': '60px',
                            'textAlign': 'left'}
            )
        ]
    )

if __name__ == '__main__':
    app.run_server(debug=True)

Also, after reading your intial problem statement ("...show a dataframe that only loads after pressing a ‘submit’ button"), I notice that your callback has multiple other inputs. As a result, changing the date or dropdown will also trigger the callback to update the table. You may want these to be State parameters. You can use dash.callback_context to help check whether or not all parameters are populated at the start of your callback.

Thanks for your help @flyingcujo I was able to run your example but not to adapt it yet. It is because of empty dictionaries in somes cells.
That might be useless but here are my libraries versions:

dash==1.7.0
dash-core-components==1.6.0
dash-daq==0.3.1
dash-html-components==1.0.2
dash-renderer==1.2.2
dash-table==4.5.1

I’m sure it his because of the dataframe now. Here is df.head(1):

                                                body  ...                                          topics_kw
0  &quot;The loan write-off program was flabberga...  ...  [Politics, The financial sector, Media, Societ...

THANK YOU! This helped solved a very painful issue for me. I used PreventUpdate and it worked like a charm