Plotly-Dash,Python,加载csv文件并使用plotly-Dash板绘制结果进行比较

mspsb9vt  于 2023-05-02  发布在  Python
关注(0)|答案(1)|浏览(148)

这更有可能是第一次使用Dash Board与Plotly一起使用,没有清楚的了解代码是如何工作的,问题来自哪里。如果您给予我一些建议,我将不胜感激。我试图通过使用上传按钮和下拉栏导入两个CSV文件应该显示所有变量名称,一旦我选择多个变量名称从下拉栏,然后他们应该在x-y图绘制。
代码可以导入两个不同的csv文件并在下拉栏中显示变量,但绘图不起作用。我认为代码不能正确地将值传递到plotly函数。你能检查一下代码吗?问题的根源在哪里?谢谢。

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
import base64
import io
import plotly.express as px
import dash_table

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
# Initialize the app
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# Define the layout
app.layout = html.Div([
    html.H1('CSV File Comparison Dashboard'),
    html.Div([
        html.H2('File A'),
        dcc.Upload(
            id='upload-data-A',
            children=html.Div([
                'Drag and Drop or ',
                html.A('Select Files')
            ]),
            style={
                'width': '50%',
                'height': '60px',
                'lineHeight': '60px',
                'borderWidth': '1px',
                'borderStyle': 'dashed',
                'borderRadius': '5px',
                'textAlign': 'center',
                'margin': '10px'
            },
            multiple=False
        ),
        html.Div(id='file-name_A'),
        dcc.Dropdown(
            id='variable-dropdown-A',
            options=[],
            value=[],
            multi=True
        ),
        dcc.Graph(
            id='graph-A'
        )
    ], style={'width': '49%', 'display': 'inline-block', 'vertical-align': 'top'}),
    html.Div([
        html.H2('File B'),
        dcc.Upload(
            id='upload-data-B',
            children=html.Div([
                'Drag and Drop or ',
                html.A('Select Files')
            ]),
            style={
                'width': '50%',
                'height': '60px',
                'lineHeight': '60px',
                'borderWidth': '1px',
                'borderStyle': 'dashed',
                'borderRadius': '5px',
                'textAlign': 'center',
                'margin': '10px'
            },
            multiple=False
        ),
        html.Div(id='file-name_B'),
        dcc.Dropdown(
            id='variable-dropdown-B',
            options=[],
            value=[],
            multi=True
        ),
        dcc.Graph(
            id='graph-B'
        )
    ], style={'width': '49%', 'display': 'inline-block', 'vertical-align': 'top'})
])

# Define the callback for updating the variable dropdown menus
@app.callback([Output('variable-dropdown-A', 'options'), Output('variable-dropdown-A', 'value')],
              [Input('upload-data-A', 'contents')],
              prevent_initial_call=True)

def update_dropdowns_A(list_of_contents_A):
    # Initialize empty options for each dropdown
    options_A = []

    # Check if a csv file has been uploaded for file A
    if list_of_contents_A:
        # Read the csv file
        content_type, content_string = list_of_contents_A.split(',')
        decoded = base64.b64decode(content_string)
        df_A = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
        

        # Add the column names to the options for file A
        options_A = [{"label": col, "value": col} for col in df_A.columns]
        return options_A, df_A.columns[0]
    else:
        # Return the options for both dropdowns
        return [], None

@app.callback([Output('variable-dropdown-B', 'options'), Output('variable-dropdown-B', 'value')],
              [Input('upload-data-B', 'contents')],
              prevent_initial_call=True)

def update_dropdowns_B(list_of_contents_B):
    # Initialize empty options for each dropdown

    options_B = []

    # Check if a csv file has been uploaded for file B
    if list_of_contents_B:
        # Read the csv file
        content_type, content_string = list_of_contents_B.split(',')
        decoded = base64.b64decode(content_string)
        df_B = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
        

        # Add the column names to the options for file A
        options_B = [{"label": col, "value": col} for col in df_B.columns]
        return options_B, df_B.columns[0]
    else:
        # Return the options for both dropdowns
        return [], None



# Define the callback for updating the graphs
@app.callback([Output('graph-A', 'figure'), Output('graph-B', 'figure')],
              [Input('variable-dropdown-A', 'value'), Input('variable-dropdown-B', 'value')],
              [State('upload-data-A', 'contents'), State('upload-data-B', 'contents')],
              prevent_initial_call=True)
def update_graphs(variables_A, variables_B, contents_A, contents_B):
    
    if not variables_A or not variables_B:
        return {}, {}
    # # Initialize empty dataframes for each file
    df_A = pd.DataFrame()
    df_B = pd.DataFrame()

    # # Check if a csv file has been uploaded for file A
    # if contents_A is not None:
    #     # Read the csv file
    #     content_type, content_string = contents_A.split(',')
    #     decoded = base64.b64decode(content_string)
    #     df_A = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
    
    # # Check if a csv file has been uploaded for file B
    # if contents_B is not None:
    #     # Read the csv file
    #     content_type, content_string = contents_B.split(',')
    #     decoded = base64.b64decode(content_string)
    #     df_B = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
    
    # Initialize empty figures for each graph
    fig_A = go.Figure()
    fig_B = go.Figure()

    # Check if any variables have been selected for file A

    for var in variables_A:
        fig_A.add_trace(go.Scatter(
            x=df_A['time'],
            y=df_A[var],
            mode='lines',
            name=var
        ))

    fig_A.update_layout(title='Time Series Plot',
                      xaxis_title='Time',
                      yaxis_title='Value')

    # Check if any variables have been selected for file B

    for var in variables_B:
        fig_B.add_trace(go.Scatter(
            x=df_B['time'],
            y=df_B[var],
            mode='lines',
            name=var
        ))

    fig_B.update_layout(title='Time Series Plot',
                      xaxis_title='Time',
                      yaxis_title='Value')

    # Return the figures for both graphs
    return fig_A, fig_B

# Update file name
@app.callback(Output('file-name_A', 'children'),
              [Input('upload-data-A', 'filename')])
def update_file_name(filename):
    if filename is not None:
        return html.P(f'File loaded: {filename}')
    else:
        return html.P('No file loaded')
    
@app.callback(Output('file-name_B', 'children'),
              [Input('upload-data-B', 'filename')])
def update_file_name(filename):
    if filename is not None:
        return html.P(f'File loaded: {filename}')
    else:
        return html.P('No file loaded')

# Run the app
if __name__ == '__main__':
    app.run_server(debug=True, port = 8000)

关于这个问题的解释和进一步的评论,如果我需要使用子图函数扩展图的数量,该怎么做。

8wigbo56

8wigbo561#

关于你的代码,我们可以讨论很多事情,但我只关注你的问题,我做了这些修改。

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
import base64
import io
import plotly.express as px
import dash_table

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
# Initialize the app
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# Define the layout
app.layout = html.Div(
    [
        dcc.Store(id="a"),
        dcc.Store(id="b"),
        html.H1("CSV File Comparison Dashboard"),
        html.Div(
            [
                html.H2("File A"),
                dcc.Upload(
                    id="upload-data-A",
                    children=html.Div(["Drag and Drop or ", html.A("Select Files")]),
                    style={
                        "width": "50%",
                        "height": "60px",
                        "lineHeight": "60px",
                        "borderWidth": "1px",
                        "borderStyle": "dashed",
                        "borderRadius": "5px",
                        "textAlign": "center",
                        "margin": "10px",
                    },
                    multiple=False,
                ),
                html.Div(id="file-name_A"),
                dcc.Dropdown(
                    id="variable-dropdown-A", options=[], value=[], multi=True
                ),
                dcc.Graph(id="graph-A"),
            ],
            style={"width": "49%", "display": "inline-block", "vertical-align": "top"},
        ),
        html.Div(
            [
                html.H2("File B"),
                dcc.Upload(
                    id="upload-data-B",
                    children=html.Div(["Drag and Drop or ", html.A("Select Files")]),
                    style={
                        "width": "50%",
                        "height": "60px",
                        "lineHeight": "60px",
                        "borderWidth": "1px",
                        "borderStyle": "dashed",
                        "borderRadius": "5px",
                        "textAlign": "center",
                        "margin": "10px",
                    },
                    multiple=False,
                ),
                html.Div(id="file-name_B"),
                dcc.Dropdown(
                    id="variable-dropdown-B", options=[], value=[], multi=True
                ),
                dcc.Graph(id="graph-B"),
            ],
            style={"width": "49%", "display": "inline-block", "vertical-align": "top"},
        ),
    ]
)

# Define the callback for updating the variable dropdown menus
@app.callback(
    [
        Output("variable-dropdown-A", "options"),
        Output("variable-dropdown-A", "value"),
        Output("a", "data"),
    ],
    [Input("upload-data-A", "contents")],
    prevent_initial_call=True,
)
def update_dropdowns_A(list_of_contents_A):
    # Check if a csv file has been uploaded for file A
    if list_of_contents_A:
        # Read the csv file
        content_type, content_string = list_of_contents_A.split(",")
        decoded = base64.b64decode(content_string)
        df_A = pd.read_csv(io.StringIO(decoded.decode("utf-8")))
        print(df_A.head())

        # Add the column names to the options for file A
        options_A = [{"label": col, "value": col} for col in df_A.columns]
        return options_A, df_A.columns, df_A.to_json(orient="records")
    else:
        # Return the options for both dropdowns
        return [], None

@app.callback(
    [
        Output("variable-dropdown-B", "options"),
        Output("variable-dropdown-B", "value"),
        Output("b", "data"),
    ],
    [Input("upload-data-B", "contents")],
    prevent_initial_call=True,
)
def update_dropdowns_B(list_of_contents_B):
    # Check if a csv file has been uploaded for file B
    if list_of_contents_B:
        # Read the csv file
        content_type, content_string = list_of_contents_B.split(",")
        decoded = base64.b64decode(content_string)
        df_B = pd.read_csv(io.StringIO(decoded.decode("utf-8")))
        print(df_B.head())

        # Add the column names to the options for file A
        options_B = [{"label": col, "value": col} for col in df_B.columns]
        return options_B, df_B.columns, df_B.to_json(orient="records")
    else:
        # Return the options for both dropdowns
        return [], None

# Define the callback for updating the graphs
@app.callback(
    [Output("graph-A", "figure"), Output("graph-B", "figure")],
    [Input("variable-dropdown-A", "value"), Input("variable-dropdown-B", "value")],
    [State("a", "data"), State("b", "data")],
    prevent_initial_call=True,
)
def update_graphs(variables_A, variables_B, contents_A, contents_B):
    if not variables_A or not variables_B:
        return {}, {}
    df_A = pd.read_json(contents_A, orient="records")
    df_B = pd.read_json(contents_B, orient="records")
    # Initialize empty figures for each graph
    fig_A = go.Figure()
    fig_B = go.Figure()
    # Check if any variables have been selected for file A
    for var in variables_A:
        fig_A.add_trace(go.Scatter(x=df_A["time"], y=df_A[var], mode="lines", name=var))
    fig_A.update_layout(
        title="Time Series Plot", xaxis_title="Time", yaxis_title="Value"
    )
    # Check if any variables have been selected for file B
    for var in variables_B:
        fig_B.add_trace(go.Scatter(x=df_B["time"], y=df_B[var], mode="lines", name=var))
    fig_B.update_layout(
        title="Time Series Plot", xaxis_title="Time", yaxis_title="Value"
    )

    # Return the figures for both graphs
    return fig_A, fig_B

# Update file name
@app.callback(Output("file-name_A", "children"), [Input("upload-data-A", "filename")])
def update_file_name(filename):
    if filename is not None:
        return html.P(f"File loaded: {filename}")
    else:
        return html.P("No file loaded")

@app.callback(Output("file-name_B", "children"), [Input("upload-data-B", "filename")])
def update_file_name(filename):
    if filename is not None:
        return html.P(f"File loaded: {filename}")
    else:
        return html.P("No file loaded")

# Run the app
if __name__ == "__main__":
    app.run_server(debug=True, port=8000)

你遇到的主要问题是,当你处理csv文件时,Dash不会将数据存储到本地内存。这意味着当您的update_dropdowns_x完成时,相应的df_Adf_B将被删除。当您的update_graphs被触发时,没有数据可供它使用。我添加了两个dcc.Store对象,用于在回调之间持久化csv中的数据。你会注意到我没有传递dataframe,因为html要求数据在text/json中。这就是使用df_A.to_json(orient="records")作为输出的原因。然后用黑色处理代码以纠正轻微的格式错误。我还将下拉列表设置为自动包含所有频道,但您可以将[0]添加回返回,以获得原始应用程序的状态。这是一个截图。因为你没有张贴一个csv文件的例子,我只是做了一些事情。

相关问题