如何绘制按类别分组的两列平均值分组条形图?
解决方案:实现同类别条形同色的分组均值条形图
针对你的需求——让每个类别(Column1)对应的两个均值条形(Column2、Column3)颜色一致,且不同类别颜色唯一,下面提供两种可行方案:
方案1:用Matplotlib手动绘制(精准控制颜色)
这种方式直接基于聚合后的均值数据绘图,能完全掌控每个条形的颜色:
import matplotlib.pyplot as plt import pandas as pd # 加载并预处理数据 data = [ ['Bananas', 1, 5], ['Apple', 4, 2], ['Bananas', 2, 5], ['Oranges', 3, 6], ['Apple', 4, 2], ['Apple', 2, 5], ['Oranges', 1, 2], ['Apple', 5, 5], ['Oranges', 6, 1] ] df = pd.DataFrame(data, columns=['Column1', 'Column2', 'Column3']) df[['Column2', 'Column3']] = df[['Column2', 'Column3']].astype(float) # 计算每个类别下的均值 mean_df = df.groupby('Column1')[['Column2', 'Column3']].mean().reset_index() # 为每个类别分配唯一颜色(可自行替换为你喜欢的色值) category_colors = { 'Bananas': '#f7931e', 'Apple': '#5ac8fa', 'Oranges': '#8bc34a' } bar_width = 0.35 categories = mean_df['Column1'] x_pos = range(len(categories)) plt.figure(figsize=(10, 6)) # 绘制Column2的条形,颜色对应所属类别 bars_col2 = plt.bar([x - bar_width/2 for x in x_pos], mean_df['Column2'], width=bar_width, color=[category_colors[cat] for cat in categories]) # 绘制Column3的条形,颜色与同类别Column2一致 bars_col3 = plt.bar([x + bar_width/2 for x in x_pos], mean_df['Column3'], width=bar_width, color=[category_colors[cat] for cat in categories]) # 添加数值标签 for bar in bars_col2: plt.text(bar.get_x() + bar.get_width()/2, bar.get_height(), f'{bar.get_height():.2f}', ha='center', va='bottom', fontsize=12) for bar in bars_col3: plt.text(bar.get_x() + bar.get_width()/2, bar.get_height(), f'{bar.get_height():.2f}', ha='center', va='bottom', fontsize=12) # 调整坐标轴与标题 plt.xticks(x_pos, categories, fontsize=14) plt.yticks(fontsize=12) plt.xlabel('类别', fontsize=14) plt.ylabel('平均值', fontsize=14) plt.title('各类别Column2/Column3平均值分组条形图', fontsize=16) # 添加图例(可选,用于区分两列数据) plt.legend([bars_col2[0], bars_col3[0]], ['Column2', 'Column3'], fontsize=12) plt.tight_layout() plt.show()
方案2:基于你现有的Seaborn+Melt代码修改
如果你想继续使用已有的数据融合(melt)逻辑,只需为每个数据行匹配对应类别的颜色即可:
import seaborn as sns import matplotlib.pyplot as plt import pandas as pd data = [ ['Bananas', 1, 5], ['Apple', 4, 2], ['Bananas', 2, 5], ['Oranges', 3, 6], ['Apple', 4, 2], ['Apple', 2, 5], ['Oranges', 1, 2], ['Apple', 5, 5], ['Oranges', 6, 1] ] df = pd.DataFrame(data, columns=['Column1', 'Column2', 'Column3']) df[['Column2', 'Column3']] = df[['Column2', 'Column3']].astype(float) # 数据融合 dfm = df.melt(id_vars=["Column1"], var_name="Test1", value_name="Test2") # 定义类别颜色映射 category_colors = { 'Bananas': '#f7931e', 'Apple': '#5ac8fa', 'Oranges': '#8bc34a' } # 为每一行分配对应类别的颜色 color_list = [category_colors[row['Column1']] for _, row in dfm.iterrows()] plt.figure(figsize=(10, 6)) p = sns.barplot(data=dfm, x="Column1", y="Test2", hue="Test1", palette=color_list, errorbar=('ci', False)) # 隐藏默认图例(若不需要区分Column2/Column3) plt.legend([], [], frameon=False) # 添加数值标签 for container in p.containers: plt.bar_label(container, fmt='%.2f', label_type='edge', padding=1, fontsize=12) # 调整样式 plt.xticks(fontsize=14) plt.yticks(fontsize=12) plt.xlabel('类别', fontsize=14) plt.ylabel('平均值', fontsize=14) plt.title('各类别Column2/Column3平均值分组条形图', fontsize=16) plt.tight_layout() plt.show()
关键说明
你之前的代码无法实现需求的原因是:Seaborn默认会为hue参数(即你的Test1,对应Column2和Column3)的不同取值分配颜色,而非按Column1的类别分配。通过上述两种方式,我们将颜色映射绑定到Column1的类别,从而实现同一类别下的两个条形颜色一致,不同类别颜色唯一的效果。
内容的提问来源于stack exchange,提问作者amthompson23
相关产品推荐
相关产品推荐

