通过下拉列表上传CSV文件后访问列

时间:2019-02-04 17:16:21

标签: plotly plotly-dash

我有一个破折号应用程序,我尝试在其中上传任意csv,然后通过下拉菜单访问所述数据文件的列。我有两个下拉菜单。访问列之后,我想计算两者之间的相关性并绘制它们。但是,我一直试图找出如何访问下拉列表中的上传数据列。我有一个工作的Shiny应用程序可以执行此操作,但是我正在尝试使用Dash复制它。我对Dash真的很陌生,所以这可能是一个简单的修复。我的代码在下面!

import os
import io
import json
import dash
import base64
import plotly
import datetime
import operator
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dte
from dash.dependencies import Input, Output, State

app = dash.Dash()
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True

app.layout = html.Div([

    html.H5("Upload Files"),
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '15%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'left',
            'margin': '10px'
        },
        multiple=False),

    html.Div([
        html.H5("First Column"),
        dcc.Dropdown(
            id = 'y-dropdown',
            options = [],
        )
    ]),

    html.Div([
        html.H5("Second Column"),
        dcc.Dropdown(
            id = 'x-dropdown',
            options = [],
        )
    ]),    

    html.Br(),
    html.Button(
        id = 'propagate-button',
        n_clicks = 0,
        children = 'Propagate Table Data'
    ),

    html.Br(),
    html.H5("Updated Table"),
    html.Div(
        dte.DataTable(rows = [{}], id = 'table')
    ),

    html.Div(
    dcc.Graph(
        id = 'graph'
        )
    )
])

## Functions 
# File upload function
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:
        print(e)
        return None

    return df

## Callbacks 
# Table creation
@app.callback(Output('table', '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.css.append_css({
    "external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})

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

1 个答案:

答案 0 :(得分:0)

我认为您无法创建具有多个输出的单个回调,因此您需要为每个下拉列表和表格创建一个单独的回调。请参考下面的代码。

import os
import io
import json
import dash
import base64
import plotly
import datetime
import operator
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import dash_core_components as dcc
import dash_html_components as html
import dash_table_experiments as dte
from dash.dependencies import Input, Output, State

app = dash.Dash()
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True
app.layout = html.Div([

    html.H5("Upload Files"),
    dcc.Upload(
        id='upload-data',
        children=html.Div([
            'Drag and Drop or ',
            html.A('Select Files')
        ]),
        style={
            'width': '15%',
            'height': '60px',
            'lineHeight': '60px',
            'borderWidth': '1px',
            'borderStyle': 'dashed',
            'borderRadius': '5px',
            'textAlign': 'left',
            'margin': '10px'
        },
        multiple=False),

    html.Div([
        html.H5("First Column"),
        dcc.Dropdown(
            id = 'y-dropdown',
            options = [],
        )
    ]),

    html.Div([
        html.H5("Second Column"),
        dcc.Dropdown(
            id = 'x-dropdown',
            options = [],
        )
    ]),    

    html.Br(),
    html.Button(
        id = 'propagate-button',
        n_clicks = 0,
        children = 'Propagate Table Data'
    ),

    html.Br(),
    html.H5("Updated Table"),
    html.Div(
        dte.DataTable(rows = [{}], id = 'table')
    ),

    html.Div(
    dcc.Graph(
        id = 'graph'
        )
    )
])

## Functions 
# File upload function
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:
        print(e)
        return None
    return df

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

# update y-dropdown
@app.callback(Output('y-dropdown', 'options'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def update_y_dropdown(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        columns = df.columns.values.tolist()
        if df is not None:
            return [ {'label': x, 'value': x} for x in columns ]
        else:
            return []
    else:
        return []

# update x-dropdown
@app.callback(Output('x-dropdown', 'options'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def update_x_dropdown(contents, filename):
    if contents is not None:
        df = parse_contents(contents, filename)
        columns = df.columns.values.tolist()
        if df is not None:
            return [ {'label': x, 'value': x} for x in columns ]
        else:
            return []
    else:
        return []

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