dspractician
dspractician

Reputation: 89

How to render plotly express while using dash upload component?

I use the following code dor dcc upload component. I twisted the code that I have seen in this thread. In that thread, plot was rendered using plotly go, however, I would like to use plotly express instead of plotly go. Since px.line expects teh name of dataframe, I write it as px.line(df,...). But, in that thread, df is not defined in the if contents condition(in the answer of that thread.). As I write the df out of that condition, I encounter with the following error UnboundLocalError: local variable 'df' referenced before assignment. The code works when I upload a file. But, I would like to get rid of that error, because it i annoying to see it there. How can I handle this issue?

import base64
import datetime
import io
import plotly.graph_objs as go
import cufflinks as cf
import plotly.express as px
from dash import Dash, html, dcc, Input, Output,dash_table
import dash
from dash.dash_table.Format import Group
import pandas as pd

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

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

colors = {"graphBackground": "#F5F5F5", "background": "#ffffff", "text": "#000000"}

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,
        ),
        dcc.Graph(id="Mygraph"),
        html.Div(id="output-data-upload"),
    ]
)


@app.callback(
    Output("Mygraph", "figure"),
    [Input("upload-data", "contents"), Input("upload-data", "filename")],
)
def update_lineplot(contents, filename):
    x = []
    y = []
    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)
        #df = df.set_index(df.columns[0])
        x=df['TIME']
        y=df['VALUE2']
    #print(df)
    fig = px.line(df, x="TIME", y=["VALUE1", "VALUE2"],
                         facet_col_wrap=2,
                         facet_row_spacing=0.1,
                         facet_col_spacing=0.09)
    return fig


def parse_data(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 or TXT 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))
        elif "txt" or "tsv" in filename:
            # Assume that the user upl, delimiter = r'\s+'oaded an excel file
            df = pd.read_csv(io.StringIO(decoded.decode("utf-8")), delimiter=r"\s+|;|,")
    except Exception as e:
        print(e)
        return html.Div(["There was an error processing this file."])

    return df


@app.callback(
    Output("output-data-upload", "children"),
    [Input("upload-data", "contents"), Input("upload-data", "filename")],
)


def update_table(contents, filename):
    table = html.Div()

    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)

        table = html.Div(
            [
                html.H5(filename),
                dash_table.DataTable(
                    data=df.to_dict("rows"),
                    columns=[{"name": i, "id": i} for i in df.columns],
                ),
                html.Hr(),
                html.Div("Raw Content"),
                html.Pre(
                    contents[0:200] + "...",
                    style={"whiteSpace": "pre-wrap", "wordBreak": "break-all"},
                ),
            ]
        )

    return table


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

Upvotes: 1

Views: 182

Answers (1)

Hamzah Al-Qadasi
Hamzah Al-Qadasi

Reputation: 9826

All you should do is to define an empty dataframe before the If statement, you will get in the beginning an empty graph and then when you upload a file, you will get your graph.

@app.callback(
    Output("Mygraph", "figure"),
    [Input("upload-data", "contents"), Input("upload-data", "filename")],
)
def update_lineplot(contents, filename):
    x = []
    y = []
    df = pd.DataFrame(columns=["TIME","VALUE1", "VALUE2"])
    if contents:
        contents = contents[0]
        filename = filename[0]
        df = parse_data(contents, filename)
        #df = df.set_index(df.columns[0])
        x=df['TIME']
        y=df['VALUE2']
    #print(df)
    fig = px.line(df, x="TIME", y=["VALUE1", "VALUE2"],
                         facet_col_wrap=2,
                         facet_row_spacing=0.1,
                         facet_col_spacing=0.09)
    return fig

Output:

enter image description here

Upvotes: 2

Related Questions