如何修改Matplotlib分组柱状图X轴标签并优化分组间距?
问题描述
我编写了一个Python函数来生成分组柱状图,目前图表可正常运行,但X轴会针对data_list中的每个子列表重复显示1,2,3,4,5,6,7,8,9,10。我希望改为每个分组仅显示一次该标签,并且将10组柱状图彼此分隔开,使其更清晰易读。
原代码如下:
import matplotlib.pyplot as plt def plot_graph(list, title_str): x_plot = [] y_plot = [] legend_labels = ['a', 'b', 'c', 'd', 'e', 'f'] x_labels = [1,2,3,4,5,6,7,8,9,10] x_labels_text = ['red', 'blue', 'green', 'purple', 'olive', 'brown'] x_colors = ['tab:red', 'tab:blue', 'tab:green', 'tab:purple', 'tab:olive', 'tab:brown'] fig, ax = plt.subplots() ax.set_xlabel('\nFault Type', fontsize=15) ax.set_ylabel('Number of Errors (%)', fontsize=15) ax.set_title('Total Number of Errors (%)', fontsize=15) for i in range(len(list)): for j in range(len(list[i])): x_plot.append(x_labels[i]) y_plot.append(list[i][j]) ax.bar(range(len(x_plot)), y_plot, label=legend_labels, color=x_colors, width=0.5) ax.set_xticks(range(len(x_plot)), x_plot) ax.set_ylim(ymax=100) #ax.legend(['a', 'b', 'c', 'd', 'e', 'f']) patches, _ = ax.get_legend_handles_labels() labels = [*'abcdef'] ax.legend(*patches, labels, loc='best') fig.tight_layout() plt.setp(ax.get_xticklabels(), fontsize=10) plt.savefig("C:/CoolTermWin64Bit/CoolTermWin64Bit/uart_data/Gathered Data/Code Generated Data Files/" + title_str + ".pdf") data_list = [ [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60] ] plot_graph(data_list, "data grouped bar graph")
原图表效果:
解决方案
通过调整柱子位置计算、X轴刻度设置以及分组间距,可实现需求。修改后的代码如下:
import matplotlib.pyplot as plt def plot_graph(data_list, title_str): legend_labels = ['a', 'b', 'c', 'd', 'e', 'f'] x_group_labels = [1,2,3,4,5,6,7,8,9,10] # 每个分组的唯一标签 x_colors = ['tab:red', 'tab:blue', 'tab:green', 'tab:purple', 'tab:olive', 'tab:brown'] fig, ax = plt.subplots(figsize=(12, 6)) # 调整画布适配分组显示 ax.set_xlabel('\nFault Type', fontsize=15) ax.set_ylabel('Number of Errors (%)', fontsize=15) ax.set_title('Total Number of Errors (%)', fontsize=15) num_groups = len(data_list) # 分组总数:10 num_bars_per_group = len(data_list[0]) # 每组内柱子数量:6 bar_width = 0.14 # 缩小单柱宽度,预留分组间距 group_spacing = 0.2 # 分组之间的间隔 # 遍历每个分组,计算每组内柱子的X坐标 for group_idx in range(num_groups): # 当前分组的基准X位置 base_x = group_idx * (num_bars_per_group * bar_width + group_spacing) # 绘制组内每一根柱子 for bar_idx in range(num_bars_per_group): x_pos = base_x + bar_idx * bar_width # 仅在第一个分组添加图例标签,避免重复 ax.bar(x_pos, data_list[group_idx][bar_idx], width=bar_width, color=x_colors[bar_idx], label=legend_labels[bar_idx] if group_idx == 0 else "") # 设置X轴刻度:每个分组的中间位置对应一个标签 tick_positions = [i * (num_bars_per_group * bar_width + group_spacing) + (num_bars_per_group * bar_width)/2 for i in range(num_groups)] ax.set_xticks(tick_positions, x_group_labels, fontsize=10) ax.set_ylim(ymax=100) ax.legend(loc='best') fig.tight_layout() plt.savefig(f"C:/CoolTermWin64Bit/CoolTermWin64Bit/uart_data/Gathered Data/Code Generated Data Files/{title_str}.pdf") plt.show() data_list = [ [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60], [10, 20, 30, 40, 50, 60] ] plot_graph(data_list, "data grouped bar graph")
关键改动说明
- 分组位置规划:为每个分组设置独立的基准X坐标,组内柱子按宽度依次排列,通过
group_spacing实现组间分隔。 - X轴刻度优化:将刻度点放在每个分组的中间位置,仅显示一次分组标签,避免重复。
- 图例简化:仅在第一个分组生成图例标签,防止图例重复出现。
- 画布适配:调整画布宽度,配合缩小的柱子宽度,让分组显示更舒展清晰。
内容的提问来源于stack exchange,提问作者David777
相关产品推荐
相关产品推荐

