【问题标题】:Accessing Columns after uploading a csv file via drop-downs通过下拉列表上传 csv 文件后访问列
【发布时间】:2019-02-04 17:16:21
【问题描述】:

我有一个 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)

【问题讨论】:

    标签: plotly plotly-dash


    【解决方案1】:

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

    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)
    

    【讨论】:

    • propagate-button 在这里从来没有被使用过,我们甚至需要它吗?我可以使用列名填充下拉列表。但是,当通过下拉列表选择一列时,不会发生其他任何事情,表格根本不会更新。
    猜你喜欢
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    相关资源
    最近更新 更多