Python中移除Matplotlib柱状图白色间隙的方法咨询
解决Matplotlib柱状图白色间隙问题
问题描述
使用以下代码绘制主次坐标轴并反转Y轴时,生成的蓝色柱状图存在白色间隙,仅部分数据集能正常显示无间隙的柱状图,需要确保所有数据集生成的柱状图都能完整填充无空隙。
原代码如下:
#1 Import Library import matplotlib.pyplot as plt %matplotlib import numpy as np import pandas as pd #2 IMPORT DATA sfData=pd.read_excel('data/streamflow validation.xlsx',sheet_name='Sheet1') #3 Define Data x = sfData['Year'] y1 = sfData['Observed'] y2 = sfData['Simulated'] y3 = sfData['Areal Rainfall'] # Or we can use loc for defining the data x = list(sfData.iloc[:, 0]) y1 = list(sfData.iloc[:, 1]) y2 = list(sfData.iloc[:, 2]) y3 = list(sfData.iloc[:, 3]) #4 Plot Graph fig, ax1 = plt.subplots(figsize=(12,10)) # increase space below subplot fig.subplots_adjust(bottom=0.3) # Twin Axes # Secondary axes ax2 = ax1.twinx() ax2.bar(x, y3, width=15, bottom=0, align='center', color = 'b', data=sfData) ax2.set_ylabel(('Areal Rainfall(mm)'), fontdict={'fontsize': 12}) # invert y axis ax2.invert_yaxis() # Primary axes ax1.plot(x, y1, color = 'r', linestyle='dashed', linewidth=3, markersize=12) ax1.plot(x, y2, color = 'k', linestyle='dashed', linewidth=3, markersize=12) #5 Define Labels ax1.set_xlabel(('Years'), fontdict={'fontsize': 14}) ax1.set_ylabel(('Flow (m3/s)'), fontdict={'fontsize': 14}) #7 Set limit ax1.set_ylim(0, 45) ax2.set_ylim(800, 0) ax1.set_xticklabels(('Jan 2003', 'Jan 2004', 'Jan 2005', 'Jan 2006', 'Jan 2007', 'Jan 2008', 'Jan 2009' ), fontdict={'fontsize': 13}) for tick in ax1.get_xticklabels(): tick.set_rotation(90) #8 set title ax1.set_title('Stream Flow Validation 1991', color = 'g') #7 Display legend legend = fig.legend() ax1.legend(['Observed', 'Simulated'], loc='upper left', ncol=2, bbox_to_anchor=(-.01, 1.09)) ax2.legend(['Areal Rainfall'], loc='upper right', ncol=1, bbox_to_anchor=(1.01, 1.09)) #8 Saving the graph fig.savefig('output/figure1.png') fig.savefig('output/figure1.jpg')
问题原因
- 固定宽度不匹配x轴间隔:原代码中
width=15是固定值,若x轴数据(如年份)的实际间隔为1,过宽的设置会导致柱子重叠或间隙;若间隔大于1,宽度不足则出现空隙。 - 对齐方式导致空隙:
align='center'会让柱子以x轴刻度为中心,若宽度小于刻度间隔,就会出现左右空隙。 - 手动设置标签错位:硬编码
xticklabels可能与实际x轴数据不匹配,间接导致视觉上的间隙。
解决方案
修改关键代码点
- 动态设置柱状图宽度:根据x轴数据的实际间隔计算宽度,确保填满每个刻度区间。
- 调整对齐方式:将
align='center'改为align='edge',让柱子从刻度边缘开始填充。 - 匹配x轴刻度与数据:自动生成对应x数据的标签,避免手动硬编码导致的错位。
修改后的完整代码
#1 Import Library import matplotlib.pyplot as plt %matplotlib import numpy as np import pandas as pd #2 IMPORT DATA sfData=pd.read_excel('data/streamflow validation.xlsx',sheet_name='Sheet1') #3 Define Data x = sfData['Year'] y1 = sfData['Observed'] y2 = sfData['Simulated'] y3 = sfData['Areal Rainfall'] # Or we can use loc for defining the data x = list(sfData.iloc[:, 0]) y1 = list(sfData.iloc[:, 1]) y2 = list(sfData.iloc[:, 2]) y3 = list(sfData.iloc[:, 3]) #4 Plot Graph fig, ax1 = plt.subplots(figsize=(12,10)) # increase space below subplot fig.subplots_adjust(bottom=0.3) # Twin Axes # Secondary axes ax2 = ax1.twinx() # 关键修改:根据x轴间隔动态设置宽度,对齐方式改为edge x_interval = x[1] - x[0] if len(x) > 1 else 1 ax2.bar(x, y3, width=x_interval, bottom=0, align='edge', color='b', data=sfData) ax2.set_ylabel('Areal Rainfall(mm)', fontdict={'fontsize': 12}) # invert y axis ax2.invert_yaxis() # Primary axes ax1.plot(x, y1, color='r', linestyle='dashed', linewidth=3, markersize=12) ax1.plot(x, y2, color='k', linestyle='dashed', linewidth=3, markersize=12) #5 Define Labels ax1.set_xlabel('Years', fontdict={'fontsize': 14}) ax1.set_ylabel('Flow (m3/s)', fontdict={'fontsize': 14}) #7 Set limit ax1.set_ylim(0, 45) ax2.set_ylim(800, 0) # 修改:自动生成对应x数据的标签,避免错位 xtick_labels = [f'Jan {year}' for year in x] ax1.set_xticks(x) ax1.set_xticklabels(xtick_labels, fontdict={'fontsize': 13}) for tick in ax1.get_xticklabels(): tick.set_rotation(90) #8 set title ax1.set_title('Stream Flow Validation 1991', color='g') #7 Display legend # 移除冗余的fig.legend(),避免重复图例 ax1.legend(['Observed', 'Simulated'], loc='upper left', ncol=2, bbox_to_anchor=(-.01, 1.09)) ax2.legend(['Areal Rainfall'], loc='upper right', ncol=1, bbox_to_anchor=(1.01, 1.09)) #8 Saving the graph # 添加bbox_inches='tight'防止图例被截断 fig.savefig('output/figure1.png', bbox_inches='tight') fig.savefig('output/figure1.jpg', bbox_inches='tight')
额外说明
- 如果x轴是日期类型,建议将
x转换为datetime格式,Matplotlib会自动处理刻度和宽度,进一步避免间隙问题。 - 若需要柱子完全贴合无任何空隙,可将宽度设置为略大于x轴间隔(如
x_interval * 1.01),但需注意避免柱子重叠。
内容的提问来源于stack exchange,提问作者kiwi_kimchi
相关产品推荐
相关产品推荐

