Black Lives Matter. Please consider donating to Black Girls Code today.

Bugs when generating table

I have found what I’m pretty sure is a bug, since I can perform the exact action multiple times and get different results.

I have generated multiple tabs. The first Tab gets the data. The data is then stored in a hidden variable.

The second tab displays a launch button. When the button is pressed the titles of the numerical columns of the data frame that was uploaded should appear as a checklist. This however sometimes does not happen. Maybe every 1 in 5 times (sometimes 4 out of 5 times) fails to do anything and all buttons (apart from on Tab1) become unresponsive. No error message is given and repeatedly clicking launch gives “POST /_dash-update-component HTTP/1.1” 200 -"

Next if Tab 2 is launched but no Data is selected Tab 3 will become unresponsive. However if data in Tab 2 is then selected Tab 3 will immediately display the columns (signifying that the launch button on Tab 3 did properly record what happened)

I have used the code from https://dash.plot.ly/getting-started to generate the table in Tab 2.

If however the table in Tab 2 is removed:

Column data is generated correctly everytime and Tab 3 will generate Data when nothing is selected in Tab 2.

The code I’m using is as follows (apologies for the length):

import dash_html_components as html
import dash_core_components as dcc
import dash

import dash_table_experiments as dte
from dash.dependencies import Input, Output, State

import pandas as pd
import numpy as np

import json
import datetime
import operator
import os

import base64
import io

COLORS = [
    {
    },
]

def cell_style():
    style = {
    }
    return style

def generate_table(dataframe):
    rows = []
    for i in range(len(dataframe)):
        row = []
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            style = cell_style()
            row.append(html.Td(value, style=style))
        rows.append(html.Tr(row))

    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        rows)


def Sumation_Data(Data_Frame,Data_Name_List):
    """
    Numberor can be set to the value in the dataframe you want to look at
    """

    matrix_ad = [
        ["Name","Mean", "Standard deviation", "Sample size"],
    ]

    return pd.DataFrame(matrix_ad,columns = matrix_ad.pop(0))


tab_style = {
}
selected_style = {
}
container_style = {
}


app = dash.Dash()

app.css.append_css({
    "external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
}),

TAB1 = [
    html.Div(id='inter_df', style={'display': 'none'}),
    html.Div([html.H5("Upload Files"),
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
        },
        multiple=False),
    html.Br(),
    html.H5("Table"),
    html.Div(dte.DataTable(rows=[{}], id='Table of Data')),]),
]

TAB2 = [
    html.Div([
        html.Button(
            id='Make_Graph1',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.Checklist(
                    id = "Column_Names1",
                    values=[]
                ),
            ],
        ),
        html.Hr(),
        html.Div(id='Sumation_Data'),
    ]),
]

TAB3 = [
    html.Div([
        html.Button(
            id='Make_Graph2',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.RadioItems(
                    id = "Column_Names2",
                    value=""
                ),
            ],
        ),
    ]),
]


app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div(
    children = [
        dcc.Tabs(
            style=container_style,
            value='tab-1',
            vertical = False,
            children=[
                dcc.Tab(
                    children = TAB1,
                    label="Tab1",
                    value='tab-1',
                    style=tab_style,
                    selected_style=selected_style,
                ),
                dcc.Tab(
                    children = TAB2,
                    label="Tab2",
                    value='tab-2',
                    style=tab_style,
                    selected_style=selected_style
                ),
                dcc.Tab(
                    children = TAB3,
                    label="Tab3",
                    value='tab-3',
                    style=tab_style,
                    selected_style=selected_style
                ),
            ]
        )
    ],
)

def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))

    except Exception as e:
        return None

    return df


# callback table creation
@app.callback(Output('Table of Data', 'rows'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def update_output(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        if df is not None:
            return df.to_dict('records')
        else:
            return [{}]
    else:
        return [{}]

@app.callback(
    dash.dependencies.Output('Sumation_Data', 'children'),
                  [Input("inter_df","children"),
                   Input("Make_Graph1", "n_clicks"),
                   Input("Column_Names1","values")])
def Make_Histograms_Graph(af,Click,Column):
    if Click < 1:
        return []
    else:
        if Column == []:
            return [{}]
        else:
            df = pd.read_json(af, orient='split')
            if not df.empty:
                a = Sumation_Data(df,Column)
                return generate_table(a)
            else:
                return [{}]


#Columns========================================================================

@app.callback(
    dash.dependencies.Output("Column_Names1", 'options'),
                  [Input("inter_df","children"),
                   Input("Make_Graph1", "n_clicks")])
def Make_Column_Options1_1(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.read_json(af, orient='split')
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

@app.callback(
    dash.dependencies.Output("Column_Names2", 'options'),
                  [Input("inter_df","children"),
                   Input("Make_Graph2", "n_clicks")])
def Make_Column_Options2(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.read_json(af, orient='split')
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

@app.callback(
    dash.dependencies.Output('inter_df', "children"),
                    [Input('Table of Data', 'rows')])
def Transform_Data(Data):
    inter = pd.DataFrame.from_dict(Data)
    return inter.to_json(date_format='iso', orient='split')


app.scripts.config.serve_locally = True


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

Many thanks

After some fiddling about I have been able to reproduce the error but without Tabs and without a hidden value, meaning that it seems even more likely that the html.Table is what is causing an issue (code works fine when html.Table is removed).

import dash_html_components as html
import dash_core_components as dcc
import dash

import dash_table_experiments as dte
from dash.dependencies import Input, Output, State

import pandas as pd
import numpy as np

import json
import datetime
import operator
import os

import base64
import io

def generate_table(dataframe):
    rows = []
    for i in range(len(dataframe)):
        row = []
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            row.append(html.Td(value, style=style))
        rows.append(html.Tr(row))

    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        rows)

def Sumation_Data(Data_Frame,Data_Name_List):
    matrix_ad = [
        ["Name","Mean", "Standard deviation", "Sample size"],
    ]
    return pd.DataFrame(matrix_ad,columns = matrix_ad.pop(0))

app = dash.Dash()

app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div([
        html.Div([html.H5("Upload Files"),
        dcc.Upload(
            id='upload-data',
            children=html.Div([
                'Drag and Drop or ',
                html.A('Select Files')
            ]),
            style={
            },
            multiple=False),
        html.Br(),
        html.H5("Table"),
        html.Div(dte.DataTable(rows=[{}], id='Table of Data')),]),
        html.Button(
            id='Make_Graph1',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.Checklist(
                    id = "Column_Names1",
                    values=[]
                ),
            ],
        ),
        html.Hr(),
        html.Div(id='Sumation_Data'),
        html.Button(
            id='Make_Graph2',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.RadioItems(
                    id = "Column_Names2",
                    value=""
                ),
            ],
        ),
    ]
)

def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))

    except Exception as e:
        return None

    return df


# callback table creation
@app.callback(Output('Table of Data', 'rows'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def update_output(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        if df is not None:
            print(df.to_dict('records'))
            return df.to_dict('records')
        else:
            return [{}]
    else:
        return [{}]

@app.callback(
    dash.dependencies.Output('Sumation_Data', 'children'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph1", "n_clicks"),
                   Input("Column_Names1","values")])
def Make_Histograms_Graph(af,Click,Column):
    if Click < 1:
        return []
    else:
        if Column == []:
            return [{}]
        else:
            df = pd.DataFrame.from_dict(af)
            if not df.empty:
                a = Sumation_Data(df,Column)
                return generate_table(a)
            else:
                return [{}]


#Columns========================================================================

@app.callback(
    dash.dependencies.Output("Column_Names1", 'options'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph1", "n_clicks")])
def Make_Column_Options1_1(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.DataFrame.from_dict(af)
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

@app.callback(
    dash.dependencies.Output("Column_Names2", 'options'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph2", "n_clicks")])
def Make_Column_Options2(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.DataFrame.from_dict(af)
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

app.scripts.config.serve_locally = True


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

After further fiddling I have found that if the CheckList is replaced with a RadioItem then everything begins to work again. Further I have removed direct interaction between the CheckList and Generate Table and the problem still persists. However without either one the other works fine.

Would it please be possible to confirm that this is indeed a bug since the inability to use CheckList and Generate Table is an issue.

My code is as follows:

import dash_html_components as html
import dash_core_components as dcc
import dash

import dash_table_experiments as dte
from dash.dependencies import Input, Output, State

import pandas as pd
import numpy as np

import json
import datetime
import operator
import os

import base64
import io

def generate_table(dataframe):
    rows = []
    for i in range(len(dataframe)):
        row = []
        for col in dataframe.columns:
            value = dataframe.iloc[i][col]
            row.append(html.Td(value))
        rows.append(html.Tr(row))

    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        rows)

def Sumation_Data():
    matrix_ad = [
        ["Name","Mean", "Standard deviation", "Sample size"],
    ]
    return pd.DataFrame(matrix_ad,columns = matrix_ad.pop(0))

app = dash.Dash()

app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div([
        html.Div([html.H5("Upload Files"),
        dcc.Upload(
            id='upload-data',
            children=html.Div([
                'Drag and Drop or ',
                html.A('Select Files')
            ]),
            multiple=False),
        html.Br(),
        html.H5("Table"),
        html.Div(dte.DataTable(rows=[{}], id='Table of Data')),]),
        html.Button(
            id='Make_Graph1',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.Checklist(
                    id = "Column_Names1",
                    values=[]
                ),
            ],
        ),
        html.Hr(),
        html.Div(id='Sumation_Data'),
        html.Button(
            id='Make_Graph2',
            n_clicks = 0,
            children='Launch'
        ),
        html.Div(html.H5("Column Data you want to Display")),
        html.Div(
            children =[
                dcc.RadioItems(
                    id = "Column_Names2",
                    value=""
                ),
            ],
        ),
    ]
)

def parse_contents(contents, filename):
    content_type, content_string = contents.split(',')

    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            # Assume that the user uploaded an excel file
            df = pd.read_excel(io.BytesIO(decoded))

    except Exception as e:
        return None

    return df


# callback table creation
@app.callback(Output('Table of Data', 'rows'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def update_output(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        if df is not None:
            print(df.to_dict('records'))
            return df.to_dict('records')
        else:
            return [{}]
    else:
        return [{}]

@app.callback(
    dash.dependencies.Output('Sumation_Data', 'children'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph1", "n_clicks"),
                   Input("Column_Names1","values")])
def Make_Histograms_Graph(af,Click,Column):
    if Click < 1:
        return []
    else:
        if Column == []:
            return [{}]
        else:
            df = pd.DataFrame.from_dict(af)
            if not df.empty:
                a = Sumation_Data()
                return generate_table(a)
            else:
                return [{}]


#Columns========================================================================

@app.callback(
    dash.dependencies.Output("Column_Names1", 'options'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph1", "n_clicks")])
def Make_Column_Options1_1(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.DataFrame.from_dict(af)
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

@app.callback(
    dash.dependencies.Output("Column_Names2", 'options'),
                  [Input('Table of Data', 'rows'),
                   Input("Make_Graph2", "n_clicks")])
def Make_Column_Options2(af,Click):
    if Click < 1:
        return []
    else:
        df = pd.DataFrame.from_dict(af)
        if not df.empty:
            return [{'label': i, 'value': i} for i in list(df.select_dtypes(['number']).columns.values)]
        else:
            return [{}]

app.scripts.config.serve_locally = True


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

It seems to be an issue with the interaction between dcc.Checklist and generate_table.

I have found the source of the problem (I think). It is in some way related to sequence in which the callbacks launch. I combined some of the callbacks and the problem seems to be completely gone.