You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Plotly Dash上传CSV生成动态柱状图问题求助

解决Plotly Dash动态生成柱状图的问题

嘿,我明白你现在的困扰——硬编码的柱状图数据没法适配不同的CSV文件,完全没法发挥上传功能的灵活性对吧?别担心,咱们通过数据预处理+动态生成Bar Trace的方式,就能让图表完全跟着你上传的CSV动态调整。

核心思路

结合你的示例数据结构(按Make和Dimension分组的Score数据),我们需要:

  1. 确保数值列(比如Score)是正确的数值类型(你的示例里Score是字符串,得转成float)
  2. 根据数据的分组维度(比如Dimension的唯一值)动态生成每个Bar trace
  3. 从DataFrame中自动提取对应trace的x轴(Make)和y轴(对应Dimension的Score)数据

修改后的完整代码

我已经把你的代码做了针对性修改,重点标注了改动部分:

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 plotly.graph_objects as go
import dash_table
import pandas as pd

app = dash.Dash()

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'
        },
        multiple=True
    ),
    html.Div(id='output-data-upload'),
])

def parse_contents(contents, filename, date):
    content_type, content_string = contents.split(',')
    decoded = base64.b64decode(content_string)
    try:
        if 'csv' in filename:
            df = pd.read_csv(
                io.StringIO(decoded.decode('utf-8')))
        elif 'xls' in filename:
            df = pd.read_excel(io.BytesIO(decoded))
        
        # ---------------------- 新增:数据预处理 ----------------------
        # 将Score列转为数值类型(避免字符串无法计算)
        if 'Score' in df.columns:
            df['Score'] = pd.to_numeric(df['Score'], errors='coerce')
        # 移除无效行(如果Score转换失败)
        df = df.dropna(subset=['Score'])
        # -----------------------------------------------------------

    except Exception as e:
        print(e)
        return html.Div([
            'There was an error processing this file.'
        ])

    # ---------------------- 动态生成Bar Traces ----------------------
    # 确定分组维度(这里用Dimension作为每个Bar的名称,你可以根据需求调整)
    if 'Make' in df.columns and 'Dimension' in df.columns and 'Score' in df.columns:
        # 获取所有唯一的Dimension值
        dimensions = df['Dimension'].unique()
        # 初始化trace列表
        bar_traces = []
        # 遍历每个Dimension,生成对应的Bar trace
        for dim in dimensions:
            # 筛选当前Dimension的数据
            dim_data = df[df['Dimension'] == dim]
            # 生成Bar trace
            bar_traces.append(go.Bar(
                name=dim,
                x=dim_data['Make'],
                y=dim_data['Score'],
                text=dim_data['Score'].round(1),  # 保留1位小数显示
                textposition='auto'
            ))
        # 生成图表Figure
        fig = go.Figure(data=bar_traces)
        # 添加图表布局(可选,让图表更美观)
        fig.update_layout(
            barmode='group',  # 分组柱状图
            title='Score by Make and Dimension',
            xaxis_title='Car Make',
            yaxis_title='Score'
        )
    else:
        # 如果缺少必要列,返回提示
        fig = go.Figure()
        fig.update_layout(title='Uploaded data does not contain required columns (Make, Dimension, Score)')
    # ---------------------------------------------------------------

    return html.Div([
        html.H5(filename),
        html.H6(datetime.datetime.fromtimestamp(date)),
        dash_table.DataTable(
            data=df.to_dict('records'),
            columns=[{'name': i, 'id': i} for i in df.columns]
        ),
        html.Hr(),
        # 替换原来硬编码的dcc.Graph为动态生成的fig
        dcc.Graph(figure=fig),
        html.Hr(),
        html.Div('Raw Content'),
        html.Pre(contents[0:200] + '...', style={
            'whiteSpace': 'pre-wrap',
            'wordBreak': 'break-all'
        })
    ])

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

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

关键改动说明

  1. 数据预处理:新增了将Score列转为数值类型的代码,避免字符串导致的计算错误,同时移除转换失败的无效行。
  2. 动态Trace生成:
    • 先检查数据是否包含必要的列(Make、Dimension、Score)
    • 遍历Dimension的所有唯一值,为每个值生成一个go.Bar trace,自动从DataFrame中提取对应的x(Make)和y(Score)数据
    • 支持任意数量的Dimension值,不管上传的CSV里有多少个维度,都会自动生成对应的柱状图
  3. 优化图表布局:添加了分组柱状图模式、标题和轴标签,让图表更易读

测试你的示例数据

把你提供的示例DataFrame导出为CSV文件上传后,会自动生成三个分组的柱状图,每个分组对应Speed、MPG、Styling三个维度,x轴是Ford、BMW、Mercedes,y轴是对应的Score值,完全不需要硬编码任何数据~

内容的提问来源于stack exchange,提问作者equanimity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:52:45