在ggplot中实现按区域分组且内部分降序的条形图需求问询
通用条形图实现方案(按Region分组、Count降序排列)
我来给你提供一个完全通用的实现方案,用Python的pandas和matplotlib就能搞定,完美符合你的所有要求——不用填充颜色区分Region,支持任意数量的Region和国家,同一Region的条形相邻且按Count降序排列,所有条形宽度一致、高度共用同一刻度。
核心思路
- 先对数据做预处理:按Region分组,每个组内的国家按Count从高到低排序,然后把所有组拼接起来,确保同一Region的国家挨在一起。
- 不用填充色区分Region的话,我们可以用条形边框颜色+分组分隔线,或者**条形填充图案(hatch)**来做视觉区分,效果同样清晰。
- 所有逻辑都是动态的,不管你加多少Region或者国家,代码都能自动适配。
完整代码示例
import pandas as pd import matplotlib.pyplot as plt # 这里可以替换成你自己的真实数据,只要结构是Site/Region/Count就行 data = pd.DataFrame({ 'Site': ['USA', 'Canada', 'Mexico', 'UK', 'France', 'Germany', 'Japan', 'China', 'South Korea'], 'Region': ['North America', 'North America', 'North America', 'Europe', 'Europe', 'Europe', 'Asia', 'Asia', 'Asia'], 'Count': [120, 90, 75, 100, 85, 95, 150, 130, 110] }) # 关键预处理:按Region分组,组内按Count降序排序,保留Region的原始顺序 sorted_data = data.groupby('Region', sort=False).apply(lambda x: x.sort_values('Count', ascending=False)).reset_index(drop=True) # 记录每个Region在排序后数据中的起始/结束位置,方便后续分组设置样式 region_boundaries = sorted_data.groupby('Region').agg( start_idx=('Site', 'idxmin'), end_idx=('Site', 'idxmax') ).reset_index() # 创建画布和轴对象 fig, ax = plt.subplots(figsize=(10, 6)) # 绘制所有条形,统一宽度 bar_width = 0.8 x_positions = range(len(sorted_data)) bars = ax.bar(x_positions, sorted_data['Count'], width=bar_width, edgecolor='black') # 方案1:用边框颜色区分Region(替代填充色) # 可以根据Region数量扩展颜色列表 region_colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] for idx, region in enumerate(region_boundaries['Region']): start = region_boundaries.loc[idx, 'start_idx'] end = region_boundaries.loc[idx, 'end_idx'] # 给当前Region的所有条形设置统一的边框颜色和粗细 for bar in bars[start:end+1]: bar.set_edgecolor(region_colors[idx % len(region_colors)]) bar.set_linewidth(2) # 添加Region之间的分隔虚线,强化分组视觉效果 for end_idx in region_boundaries['end_idx'][:-1]: ax.axvline(x_positions[end_idx] + bar_width/2 + 0.2, color='gray', linestyle='--', alpha=0.7) # 设置x轴标签为国家名称,旋转避免重叠 ax.set_xticks(x_positions) ax.set_xticklabels(sorted_data['Site'], rotation=45, ha='right') # 添加标题和轴标签 ax.set_title('Count by Country (Grouped by Region, Sorted by Count)', fontsize=12) ax.set_ylabel('Count', fontsize=10) ax.set_xlabel('Country', fontsize=10) # 在每个条形上方添加数值标签,更直观 for bar in bars: height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2., height, f'{int(height)}', ha='center', va='bottom', fontsize=9) # 调整布局,防止标签被截断 plt.tight_layout() plt.show()
替代区分方案(不用颜色)
如果你连边框颜色都不想用,还可以用**填充图案(hatch)**来区分Region,把上面的边框颜色部分替换成这段代码就行:
# 方案2:用填充图案区分Region hatch_patterns = ['///', '\\\\\\', 'xxx', '+++'] for idx, region in enumerate(region_boundaries['Region']): start = region_boundaries.loc[idx, 'start_idx'] end = region_boundaries.loc[idx, 'end_idx'] for bar in bars[start:end+1]: bar.set_hatch(hatch_patterns[idx % len(hatch_patterns)]) bar.set_edgecolor('black') # 保持边框统一黑色
通用性说明
- 不管你有多少个Region或者国家,只要你的数据包含
Site(国家)、Region(所属区域)、Count(数值)这三列,直接替换代码里的data部分就行,核心逻辑完全不用改。 - 排序、分组、样式设置都是动态计算的,自动适配数据规模。
内容的提问来源于stack exchange,提问作者David Hobbs
相关产品推荐
相关产品推荐

