Проблема с графикой загруженного CSV - PullRequest
0 голосов
/ 15 марта 2019

Я пытаюсь создать панель мониторинга с использованием plotly / Dash, которая позволяет пользователю загрузить файл CSV и затем отобразить результаты.Я позаимствовал примеры из документации в dash и попытался собрать пример, который строит график, но я получаю сообщение об ошибке, которое я прикрепил ниже.

Мой код прикреплен:

import base64
import datetime
import io

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import plotly.graph_objs as go

import pandas as pd

graph_name = 'Time series plot'
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

colors = {
    "graphBackground": "#212529",
    "background": "#000000",
    "text": "#ffffff"
}
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'),
    dcc.Graph(id='new-hydrograph')
])

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 html.Div([
            'There was an error processing this file.'
        ])
    if df.shape[1] == 4:

        df = df.iloc[2:]
        df.columns = ['Datetime', 'Depth (in)', 'Velocity (feet/sec)', 'Flow (MGD)']
    else:
        df.columns = ['Datetime', 'Rain (in)']

    return df


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

@app.callback(Output('new-hydrograph', 'figure'),
            [Input('upload-data', 'contents'),
            Input('upload-data', 'filename')])

def plot_graph(contents, filename):

    df = parse_contents(contents, filename)


    trace1 = go.Scatter(
        x = df.date, 
        y = df['Depth (in)'],
        mode = 'lines',
        )
    return {
        'data': [trace1],
        'layout': go.Layout(
            title = graph_name,
            plot_bgcolor = colors["graphBackground"],
            paper_bgcolor = colors["graphBackground"])
    }



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

Я получаю сообщение об ошибке:

Traceback (most recent call last):
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\_compat.py", line 33, in reraise
    raise value
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\_compat.py", line 33, in reraise
    raise value
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
h-0.39.0-py3.6.egg\dash\dash.py", line 1073, in dispatch
    response.set_data(self.callback_map[output]['callbac
  File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
h-0.39.0-py3.6.egg\dash\dash.py", line 969, in add_conte
    output_value = func(*args, **kwargs)
  File "C:\Users\hvkumar\Documents\Atlanta\pressure_data
- Copy\app_1.py", line 93, in plot_graph
    df = parse_contents(contents, filename)
  File "C:\Users\hvkumar\Documents\Atlanta\pressure_data
- Copy\app_1.py", line 50, in parse_contents
    content_type, content_string = contents.split(',')
AttributeError: 'list' object has no attribute 'split'

Вот пример CSV

PRC-01   "Average=15min"     "QualityFlag=FALSE"     "QualityValue=FALSE"
DateTime     "MP1\DFINAL"    "MP1\VFINAL"    "MP1\QFINAL"
M/d/yyyy h:mm:ss tt  "inches"    "feet/sec"  "MGD"
1/1/2015 0:00   14.9748 3.69    7.976
1/1/2015 0:15   15.0504 3.64    7.934
1/1/2015 0:30   14.7672 3.79    8.047
1/1/2015 0:45   14.9844 3.68    7.97
1/1/2015 1:00   14.8416 3.52    7.53
1/1/2015 1:15   14.7108 3.55    7.497

1 Ответ

1 голос
/ 17 марта 2019

У вашего кода было несколько проблем:

  1. Ошибка, которую вы нам сообщили, связана с использованием multiple=True в поле загрузки. Это заставляет функцию обратного вызова получать списки вместо строк в переменных contents, filename. Установка False устранит эту ошибку и позволит вам выбрать только один файл для загрузки, как я полагаю, вы собираетесь.
  2. Ваш CSV разделен табуляцией, поэтому должен включать delimiter='\t' в ваш pd.read_csv вызов.
  3. Функция обратного вызова вызывается один раз при загрузке страницы, даже если файл не выбран. В этом случае contents, filename оба равны None. Я предлагаю проверить это в начале функции обратного вызова, прежде чем пытаться проанализировать ввод.
  4. Вы использовали неправильное имя для столбца даты. Вам нужно df['Datetime'], согласно столбцам, которые вы определили в parse_contents.

Пункты 3 и 4 рассматриваются в пересмотренной функции ниже. Не забудьте позаботиться о пунктах 1 и 2.

@app.callback(Output('new-hydrograph', 'figure'),
              [Input('upload-data', 'contents'),
               Input('upload-data', 'filename')])
def plot_graph(contents, filename):
    fig = {
        'layout': go.Layout(
            title=graph_name,
            plot_bgcolor=colors["graphBackground"],
            paper_bgcolor=colors["graphBackground"])
    }

    if contents:
        df = parse_contents(contents, filename)
        trace1 = go.Scatter(
            x=df['Datetime'],
            y=df['Depth (in)'],
            mode='lines',
        )
        fig['data'] = [trace1]

    return fig
...