如何基于pandas DataFrame绘制带清晰标签的多饼图
多维度拆分饼图排版优化方案
当前代码排版混乱的核心原因是没有根据子图数量动态调整画布尺寸、没有配置行列标识、饼图标签和图例重复渲染挤占空间,以下提供两种可直接运行的整洁实现方案:
方案1:优化原有Plotly交互图实现
直接在原有代码基础上调整配置,保留交互能力,解决重叠问题:
import plotly.graph_objects as go from plotly.subplots import make_subplots # 初始化子图时直接配置行列标题、间距 fig = make_subplots( rows=len(country_codes), cols=len(pollutants), specs=[[{"type": "domain"} for _ in range(len(pollutants))] for _ in range(len(country_codes))], row_titles=[f"国家代码:{cc}" for cc in country_codes], column_titles=[f"污染物:{p}" for p in pollutants], horizontal_spacing=0.06, vertical_spacing=0.12 ) for i, cc in enumerate(country_codes, start=1): for j, p in enumerate(pollutants, start=1): df_slice = df.loc[(df.country_code == cc) & (df.pollutant == p)].sort_values('count') fig.add_trace( go.Pie( labels=df_slice['category'].astype(str), values=df_slice['count'], name=f"{cc} : {p}", textposition='inside', textinfo='percent', showlegend=(i == 1 and j == 1) # 仅第一个子图显示图例,避免重复 ), row=i, col=j ) # 全局样式适配 fig.update_traces(hole=0.4, hoverinfo="label+percent+name") fig.update_layout( height=320 * len(country_codes), # 按行数动态设置画布高度 width=380 * len(pollutants), # 按列数动态设置画布宽度 legend_title="排放类别", title_text="分国家分污染物排放类别占比", title_x=0.5 ) fig.show()
关键优化点:
- 按子图行列数动态计算画布宽高,从根源避免饼图挤压变形
- 内置行列标题,无需额外标注即可识别每个饼图对应的维度
- 标签内置仅显示百分比,完整类别信息放到hover提示和全局图例中,解决标签重叠
- 保留单份全局图例,减少冗余元素占用空间
- 调整子图间距,避免元素互相遮挡
方案2:Matplotlib+Seaborn静态图实现
如果需要导出用于报告的静态图片,该方案排版稳定性更高,代码逻辑更简单:
import matplotlib.pyplot as plt import seaborn as sns sns.set_theme(style="white") n_rows = len(country_codes) n_cols = len(pollutants) fig, axes = plt.subplots(n_rows, n_cols, figsize=(5*n_cols, 4*n_rows)) fig.suptitle("分国家分污染物排放类别占比", y=1.03, fontsize=15) # 统一类别配色,保证所有子图同类别颜色一致 all_categories = sorted(df['category'].unique()) palette = sns.color_palette("tab20", len(all_categories)) cat_color_map = dict(zip(all_categories, palette)) for i, cc in enumerate(country_codes): for j, p in enumerate(pollutants): ax = axes[i, j] if n_rows > 1 else axes[j] df_slice = df.loc[(df.country_code == cc) & (df.pollutant == p)].sort_values('count') # 绘制环形饼图 wedges, _, autotexts = ax.pie( df_slice['count'], labels=None, autopct='%1.1f%%', pctdistance=0.75, colors=[cat_color_map[cat] for cat in df_slice['category']], wedgeprops={"width": 0.4, "edgecolor": "white"} ) ax.set_title(f"{cc} | {p}", fontsize=10) plt.setp(autotexts, size=8, weight="bold") # 添加全局统一图例 handles = [plt.Rectangle((0,0),1,1, color=cat_color_map[c]) for c in all_categories] fig.legend(handles, all_categories, loc="center right", bbox_to_anchor=(1.18, 0.5), title="排放类别") plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者nnn
相关产品推荐
相关产品推荐

