如何在Plotly/Streamlit中按行展示fname对应的饼图数据?
针对你的DataFrame交互式仪表盘实现方案
一、单个Fname选中时的饼图最优实现
用Plotly Dash做交互式绑定是适配仪表盘需求的最佳方案,核心逻辑是通过选择器触发饼图数据源的实时过滤:
1. 数据预处理
先将宽表转换为饼图所需的长格式:
import pandas as pd import plotly.express as px import dash from dash import dcc, html, Input, Output # 构造你的目标DataFrame df = pd.DataFrame({ 'fname': ['A', 'B', 'C'], 'col1': [2, 1, 6], 'col2': [3, 2, 6], 'col3': [3, 3, 3], 'sum': [10, 12, 13] }) # 转长表:把col1/col2/col3转为「类别-数值」的键值对结构 long_df = df.melt(id_vars='fname', value_vars=['col1', 'col2', 'col3'], var_name='column', value_name='value')
2. 交互式仪表盘代码
通过下拉选择器绑定饼图,选中单个fname时自动生成对应行的列数据饼图:
app = dash.Dash(__name__) app.layout = html.Div([ html.H3("Fname列数据分布饼图"), # 下拉选择器,包含「全选」选项 dcc.Dropdown( id='fname-picker', options=[ {'label': '全部Fname', 'value': 'all'}, *[{'label': name, 'value': name} for name in df['fname'].unique()] ], value='all', clearable=False ), dcc.Graph(id='pie-output') ]) @app.callback( Output('pie-output', 'figure'), Input('fname-picker', 'value') ) def update_chart(selected): if selected != 'all': # 过滤选中fname的数据,生成饼图 filtered_data = long_df[long_df['fname'] == selected] fig = px.pie(filtered_data, values='value', names='column', title=f"{selected}的各列数值占比", hole=0.3) # 可选甜甜圈样式,提升可读性 return fig # 全选逻辑见下方方案
二、全选Fname时的展示方案(3种实用选项)
全选时不推荐使用sunburst(易造成视觉混乱),推荐以下3种清晰的展示方式:
1. 堆叠条形图(对比各Fname的列数值)
适合直观对比每个fname下各列的数值大小:
# 替换update_chart函数中的全选分支 fig = px.bar(df, x='fname', y=['col1', 'col2', 'col3'], barmode='stack', title='所有Fname的列数值堆叠对比') return fig
2. 分组子饼图(保持比例展示)
每个fname对应一个独立饼图,并排展示各列占比:
# 替换全选分支,需导入子图模块 from plotly.subplots import make_subplots import plotly.graph_objects as go fig = make_subplots(rows=1, cols=3, specs=[[{'type':'domain'}]*3]) for idx, name in enumerate(df['fname'].unique()): data = long_df[long_df['fname'] == name] fig.add_trace(go.Pie(labels=data['column'], values=data['value'], name=name), 1, idx+1) fig.update_layout( title_text='所有Fname的列数值占比', annotations=[dict(text='A', x=0.12, y=0.5, showarrow=False), dict(text='B', x=0.5, y=0.5, showarrow=False), dict(text='C', x=0.88, y=0.5, showarrow=False)] ) return fig
3. 均值聚合饼图(展示整体趋势)
计算所有行col1-col3的均值,展示整体比例分布:
# 替换全选分支 mean_data = df[['col1', 'col2', 'col3']].mean().reset_index() mean_data.columns = ['column', 'value'] fig = px.pie(mean_data, values='value', names='column', title='所有Fname的列均值占比', hole=0.3) return fig
三、修正你的Sunburst代码
你之前的sunburst效果混乱是因为层级顺序错误,应把fname作为最外层分类,调整后结构清晰:
# 先转长表 sunburst_data = df.melt(id_vars='fname', value_vars=['col1', 'col2', 'col3'], var_name='column', value_name='value') # 正确层级:fname -> column fig = px.sunburst(sunburst_data, values='value', path=['fname', 'column'], title='各Fname的列数值层级分布') fig.show()
内容的提问来源于stack exchange,提问作者RustyShackleford
相关产品推荐
相关产品推荐

