Drag and drop, how to change this, to use it in my app?

hi,

I have this drang n drop , and I whant to use it in my app (so the page app can use the cvs that I drop):

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)

how can I change or what do I have to change. please help

I’ve inserted that in my code, but gives an arror:

TypeError: parse_contents() missing 3 required positional arguments: 'contents', 'filename', and 'date'

I’ve put that def at the begining of my app, but the app doesn’t run and gives typeError… what can I do to solve this?

@topotaman,

Not sure if this is what you are looking for, but you can use the Input from the data_table’s data to graph the output. I added an id to your data_table’s output as ‘myData’.

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],
            id='myData'
        ),

        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('myGraph','figure'),
    Input('myData','data'),
    prevent_initial_call=True,
    suppress_callback_exceptions=True
)
def displayData(data):

    return px.line(data, x='Time_stamp',y=['x_SoC_Batt','x_SoC_EV'])

This gives a callback error because the ‘myData’ id isnt in the initial layout.

1 Like

hi

My problem is that the app I’ve done, get’s the df.csv at the begining, and if I use that def at the begining, it gives this error (before returning a df or running)

TypeError: parse_contents() missing 3 required positional arguments: 'contents', 'filename', and 'date'

how can I solve this?

What is your app’s code, or is there anything that you can show where exactly you’re trying to insert this functionality?

Dont give the parse contents() in the callback, that belongs in the first callback. These callbacks stack because you are changing the data on the data_table when you upload a file.

I just dont know how to upload the csv, to use it with my app

I can use read_csv when reading from the directory, but don’t know how to use the dragndrop with the app (the web example only shows a table) the

dont know from where to start … my app goes well when using data from the foldier, but now idea of how to use the dragndrop

and if I cant use the parse … what do I use?

1 Like

this is my code for reading from the foldier:


nombre_del_archivo = "data.csv"

df = pd.read_csv(nombre_del_archivo)



tmp = df.select_dtypes(include=['Int64'])
df=df[tmp.columns]= tmp.astype('float64')

file_name = nombre_del_archivo

with open(file_name, "r", encoding='cp437') as csv_file:
    csv_reader = reader(csv_file)
    head = next(csv_reader)
    print("head:")
    print(", ".join(head))


    for row in csv_reader:
        (", ".join(row))


dff=df
dff=pd.DataFrame(dff)

but how do I change this for reading from a drag and drop?

Are you trying to get the data onto the server computer?

What is your end goal?

not very sure how it works in my computer … but in some days im deploying this app into a server … so for now I need to drag and drop in my computer, and after into the server (so both)

What are you wanting to do with both dataframes?

the data frame I whant to use (read it from the csv draged in) … is called for other graphs in a page of the app

lets go step by step, just tell me how to drag and drop a csv file into my app, to use it for graphs and other stuff in my app, please

I will deploy the app in pythonanywhere, so I think it will be the same as in my laptop

The code I provided will allow for you to drag and drop a file, then take the output and make a chart of the file.

You will have to change the columns that you want to graph inside the function call “displayData()”

sorry, this is a solution, but not the one I’m looking for … my app has lots of graphs and callbacks, dropdowns, ect, I need a drag and drop for the app, not one to show a figure, coz I have lots of figures already done, just need to insert the data …

Without seeing your app’s code, I do not know how specifically to design a solution for your unique case.

However, what I recommend, is that instead of hard coding your app’s data to use the df from a file, you design a function that creates all your figures and layout from the df as an argument.

def makeLayout(df):
      ### make your chart layout here
      layout = []
      layout.append(dcc.Graph(id="myChart"))
      return layout

### use your initial dff in the first load
app.layout = html.Div([ dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ])), html.Div(id='output-data-upload'), html.Div(makeLayout(dff), id='page-content')])


### once the parse data element is called from the file uploading then the layout will be redone with the new data
@app.callback(
      Output('page-content','children'),
      Input('myData', 'data')
)
def reloadLayout(data):
    return makeLayout(data)

This is as close as I can get without stuff from your actual app. This is also not complete as it doesnt actually run the app, just the bit of code as an example.

I can’t make this work … the code I pasted before (the one that reads from a csv from the foldier), is at the begining … so … I dont have a df (in your code) I have not defined it yet, and this is why, it gives this error:

IndexError: index 1 is out of bounds for axis 0 with size 0

and if not this one

TypeError: makeLayout() missing 1 required positional argument: 'df'

so … I can’t use a df at the begining that is not defined …

please help, I just need to drag and drop a csv file in the app, and extract the dataframe from that csv, at the begining. how can I make this possible? I can’t change the app coz it’s 4 thousand lines, and can’t share it, and also, doesn’t matter a lot because it’s at the begining of the script.

There must be an easy way to do this.

I just need to finish this part to finish the app … please help

You can’t have the app load with the user inputed data file, I was assuming that you were initially loading it with the dff that you had mentioned in your other response.

If not, you can drop the initial makeLayout() in the app’s layout.

0k, so first I have to have a layout, and that is done with the data I have … correct? can I upload after data in a draganddrop and and refresh the app to use that new data?