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

如何按Hue/图例组为分组条形图添加组内百分比标注及问题修正

Fixing Per-Hue Group Percentage Annotations in Seaborn Grouped Bar Plot

I see the issue with your red bars (with_client_nmbr=False) not showing correct percentages—your current code isn't properly linking each bar to its respective hue group's total. Let's break down the problem and fix it:

What Went Wrong

In your original code, you loop through ax.containers to set group_total, but you don't actually pair each container's total with its bars. The second loop over all patches ends up using the last assigned group_total (which is df_t, the total for with_client_nmbr=True) for every bar—so even the red bars are using the blue group's total to calculate percentages.

The Fix

We need to:

  1. Calculate the total count for each hue group directly from your aggregated dataframe (cleaner than separate queries).
  2. Iterate over each container (each container represents one hue group), get that group's total, then annotate every bar in that container with the correct percentage relative to its own group's total.

Full Corrected Code

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Sample data
np.random.seed(365)
rows = 100000
data = {'Call_ID': np.random.normal(10000, 8000, size=rows).astype(int),
        'with_client_nmbr': np.random.choice([False, True], size=rows, p=[.17, .83]),
        'Type_of_Caller': np.random.choice(['Agency', 'EE', 'ER'], size=rows, p=[.06, .77, .17])}
all_call = pd.DataFrame(data)

# Aggregate data
df_agg = all_call.groupby(['Type_of_Caller','with_client_nmbr'])['Call_ID'].nunique().reset_index()

# Create grouped bar plot
ax = sns.barplot(x='Type_of_Caller', y='Call_ID', hue='with_client_nmbr', data=df_agg, palette=['orangered', 'skyblue'])

# Calculate total count for each hue group (False and True)
group_totals = df_agg.groupby('with_client_nmbr')['Call_ID'].sum().to_dict()

# Annotate each bar with percentage relative to its hue group's total
for container in ax.containers:
    # Get the hue value from the container's label (convert back to boolean if needed)
    hue_label = container.get_label()
    hue_val = eval(hue_label) if isinstance(hue_label, str) else hue_label
    current_total = group_totals[hue_val]
    
    for p in container:
        height = p.get_height()
        x_pos = p.get_x() + p.get_width() / 2
        y_pos = p.get_y() + height * 1.02  # Slightly above the bar
        ax.annotate(f'{(height / current_total):.1%}',
                    (x_pos, y_pos),
                    ha='center',
                    fontsize=9)

plt.show()

Key Improvements

  • Cleaner Total Calculation: Using df_agg.groupby('with_client_nmbr')['Call_ID'].sum() directly computes each hue group's total without redundant queries.
  • Container-Patched Pairing: By iterating over each container (hue group) first, we ensure every bar in that container uses the correct group total for percentage calculation.
  • Label Handling: Converting the container's string label back to a boolean matches the original data type in group_totals.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:17:49