'float' object not iterable, dcc.Upload in Dash

Question:

This is a strange error, and one that has been asked before here but unfortunately went unanswered.

I have taken the code from the Dash official documentation here, which allows the user to upload a csv or xls file and view it as a datatable in the dash web app. I’ve copied and pasted the code below:

import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output, State
from dash import dcc, html, dash_table

import pandas as pd

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '100%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'center',
            'margin': '10px'
        },
        # Allow multiple files to be uploaded
        multiple=True
    ),
    html.Div(id='output-data-upload'),
])

def parse_contents(contents, filename, date):
    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:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),

        dash_table.DataTable(
            df.to_dict('records'),
            [{'name': i, 'id': i} for i in df.columns]
        ),

        html.Hr(),  # horizontal line

        # For debugging, display the raw contents provided by the web browser
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])

@app.callback(Output('output-data-upload', 'children'),
              Input('upload-data', 'contents'),
              State('upload-data', 'filename'),
              State('upload-data', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
    if list_of_contents is not None:
        children = [
            parse_contents(c, n, d) for c, n, d in
            zip(list_of_contents, list_of_names, list_of_dates)]
        return children

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

The above code works flawlessly, as one would expect from code taken from the official documentation. Below is my code, which works perfectly except for the feature taken from the above documentation. I didn’t change the code at all.

import pandas as pd
import numpy as np
import plotly.express as px
import dash
from dash import html, Dash, dcc, dash_table
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import dash_split_pane
import base64
import io
import datetime
from pandas.tseries.offsets import BDay
import plotly.graph_objects as go

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]

app = Dash(__name__, external_stylesheets=external_stylesheets)

columnNames = ["Blood Lactate", "Velocity (km/h)", "Stage Finish Time (MM:SS)"]
df = pd.DataFrame(columns=columnNames)
df.rename_axis("Stage", inplace=True, axis=0)
columnIds = ["bloodLactate", "velocity", "stageFinishTime"]

# ------------------------------------------------------------------------

input_types = ['number', 'number', 'text']

row1 = html.Div(
    [
        dbc.Row([
            dbc.Col([
                html.Div([
                    html.P("Blood Lactate:", style={"margin-left":20}),
                    dcc.Input(
                            id="bloodLactateId",
                            type="number",
                            placeholder="insert Blood Lactate",
                            minLength=0, maxLength=50,          
                            autoComplete='on',
                            disabled=False,                    
                            readOnly=False,                               
                            required=False,                     
                            size=20,   
                            style={"margin-right":20}
                            )
                        ], style=
                         {
                            "display":"flex", 
                            "justify-content":"space-between", 
                            "align-items":"baseline", 
                            "margin-top":20
                            }
            )
                ])
            
        ])

    ] 
                    )

row2 = html.Div(
    [
        dbc.Row([
            dbc.Col([
    html.Div([
        html.P("Velocity (km/h):", style={"margin-left":20}),
        dcc.Input(
            id="velocityId",
            type="number",
            placeholder="insert Velocity",
            minLength=0, maxLength=50,          
            autoComplete='on',
            disabled=False,                     
            readOnly=False,                     
            required=False,                     
            size="20",   
            style={"margin-right":20}
        )
    ], style={
        "display":"flex", 
        "justify-content":"space-between", 
        "align-items":"baseline"})
]),
            
        ])

    ]
                    )

row3 = html.Div(
    [
        dbc.Row([
            dbc.Col([
                html.Div([
                    html.P("Stage Finish Time (MM:SS):", 
                           style={"margin-left":20}),
                    dcc.Input(
            id="stageFinishTimeId",
            type="text",
            placeholder="insert (MM:SS)",
            minLength=0, maxLength=50,          
            autoComplete='on',
            disabled=False,                     
            readOnly=False,                    
            required=False,                     
            size="20",
            style={"margin-right":20}
        ) 
    ], style={"display":"flex", 
              "justify-content":"space-between", 
              "align-items":"baseline"})
                ]),
            
        ])

    ]
                    )

row4 = html.Div(
        dbc.Row(
            html.Button('Add Row', 
                        id='add_row',n_clicks=0), 
            style={"text-align":"center"}
         )
        
    )

row5 = html.Div([
        dcc.Upload(
            id="upload-data", children=html.Div([
                'Drag and Drop COSMED file or ', html.A('Select Files')
                ] ),
            style={
                'width':'80%', 
                "lineHeight":"60px", 
                'borderWidth':'1px', 
                'borderStyle':'dashed', 
                'borderRadius':'5px', 
                'text-align':'center', 
                'margin-left':'auto',
                'margin-right':'auto',
                'margin-top':40,
                }
            ) 

], style={"align-content":'center'})

table = html.Div([
dbc.Row([    
        dbc.Col([html.H5('Results',
                         className='text-center', 
                         style={"margin-left":20}),
        dash_table.DataTable(
                id='table-container_3',
                data=[],
                columns=[{"name":i_3,"id":i_3,'type':'numeric'} for i_3 in df.columns],
                style_table={'overflow':'scroll','height':600},
                style_cell={'textAlign':'center'},
                row_deletable=True,
                editable=True),


                ],width={'size':12,"offset":0,'order':1})
            ]),  html.Div(id='output-data-upload')
 ])







pane1 = html.Div([
    row1,
    html.Br(),
    row2,
    html.Br(),
    row3,
    html.Br(),
    row4,
    html.Br(),
    row5
    ])

pane2 = html.Div(
    table
    )



app.layout = dash_split_pane.DashSplitPane(
    children=[pane1, pane2],
    id="splitter",
    split="vertical",
    size=500
    )

#copy pasted code from docs ======================================================

def parse_contents(contents, filename, date):
    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:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),

        dash_table.DataTable(
            df.to_dict('records'),
            [{'name': i, 'id': i} for i in df.columns]
        ),

        html.Hr(),  # horizontal line

        # For debugging, display the raw contents provided by the web browser
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])

#==================================================================================

@app.callback(
Output('table-container_3', 'data'),
Output('bloodLactateId', 'value'),
Output('velocityId', 'value'),
Output('stageFinishTimeId', 'value'),
Input('add_row', 'n_clicks'),
State('table-container_3', 'data'),
State('table-container_3', 'columns'),
State('bloodLactateId', 'value'),
State('velocityId', 'value'),
State('stageFinishTimeId', 'value'))

def add_row(n_clicks, rows, columns, selectedBloodLactate, selectedVelocity,
            selectedStageFinishTime):

    if n_clicks > 0:
        rows.append({c['id']: r for c,r in zip(columns, 
                                               [selectedBloodLactate, 
                                                selectedVelocity, 
                                                selectedStageFinishTime])})

    return rows, '', '', ''






#copy pasted code ===============================================================

@app.callback(Output('output-data-upload', 'children'),
              Input('upload-data', 'contents'),
              State('upload-data', 'filename'),
              State('upload-data', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
    if list_of_contents is not None:
        children = [
            parse_contents(c, n, d) for c, n, d in
            zip(list_of_contents, list_of_names, list_of_dates)]
        return children

#=================================================================================

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

Here is a photo of what the app looks like, to get an idea.picture of my web app

When I load the app it runs as expected, I can add rows, but when I upload a csv file I get the following error:

File "C:UsersharryOneDriveDocumentscodingfypWebAppdashAppapp.py", line 255, in update_output
zip(list_of_contents, list_of_names, list_of_dates)]
TypeError: 'float' object is not iterable

It seems the problem lies in one of the lists in the update_output function. Also, I get the following notice in VSCode.

"content_type" is not accessed

This notice does not appear when I have just the code taken from the documentation in a standalone file (as seen in the image below), only when I enter the code into my code.

same code, no error

I don’t know where to start to fix this problem, and it seems like it requires a good understanding of Dash to solve. Any help is appreciated.

Asked By: haaz

||

Answers:

After long debugging, the problem is that list_of_dates is a float number which represents the last modified for the uploaded file. There is a list comprehension in the callback which iterates through this float number, which does not make sense to iterate through a number, and it eventually throws an error. To solve this problem, all you should do is to replace the callback function with the following:

def update_output(list_of_contents, list_of_names, list_of_dates):
    if list_of_contents is not None:
        children = [parse_contents(list_of_contents, list_of_names, list_of_dates)]
        return children

Inside the function parse_contents, I added the delimiter=";" to read the CSV file properly.

 if 'csv' in filename:
            # Assume that the user uploaded a CSV file
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')), delimiter=";") #<-- this line.

Finally, I reduced the size of the upper table to show the table of the CSV file.

Output

enter image description here

Answered By: Hamzah
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.