Matplotlib时间序列柱状图:柱子重叠与时间范围异常修复
时间序列柱状图重叠与时间范围异常修复方案
问题背景
拥有某一日期9:00至13:00的时间序列数据,End_Datetime字段为datetime64[ns]类型,VOLUME字段为float64类型。使用Matplotlib绘制柱状图时出现两个问题:
- 柱子相互重叠
- 图表显示的时间范围远超出9:00-13:00窗口
但绘制折线图时无异常,需在不使用Seaborn的前提下完成修复。
数据示例
{'End_Datetime': {0: Timestamp('2024-02-29 09:14:59.999000'), 1: Timestamp('2024-02-29 09:29:59.999000'), 2: Timestamp('2024-02-29 09:44:59.999000'), 3: Timestamp('2024-02-29 09:59:59.999000'), 4: Timestamp('2024-02-29 10:14:59.999000'), 5: Timestamp('2024-02-29 10:29:59.999000'), 6: Timestamp('2024-02-29 10:44:59.999000'), 7: Timestamp('2024-02-29 10:59:59.999000'), 8: Timestamp('2024-02-29 11:14:59.999000'), 9: Timestamp('2024-02-29 11:29:59.999000'), 10: Timestamp('2024-02-29 11:44:59.999000'), 11: Timestamp('2024-02-29 11:59:59.999000'), 12: Timestamp('2024-02-29 12:14:59.999000'), 13: Timestamp('2024-02-29 12:29:59.999000'), 14: Timestamp('2024-02-29 12:44:59.999000'), 15: Timestamp('2024-02-29 12:59:59.999000'), 16: Timestamp('2024-02-29 13:14:59.999000'), 17: Timestamp('2024-02-29 13:29:59.999000'), 18: Timestamp('2024-02-29 13:44:59.999000')}, 'VOLUME': {0: 45000.0, 1: 142000.0, 2: 55000.0, 3: 39000.0, 4: 66000.0, 5: 32000.0, 6: 28000.0, 7: 30000.0, 8: 21000.0, 9: 18000.0, 10: 61000.0, 11: 154000.0, 12: 33000.0, 13: 24000.0, 14: 13000.0, 15: 12000.0, 16: 339000.0, 17: 31000.0, 18: 281000.0}}
原使用代码
import matplotlib.pyplot as plt import matplotlib.dates as mdates import pandas as pd fig, ax = plt.subplots(nrows=1, ncols = 1,dpi=600, figsize=(12,9)) ax.bar(x=df['End_Datetime'], height = df['VOLUME'].values, color = 'blue', label = '15 mins Bin Volume', edgecolor = 'white', alpha=0.5) ax.set_ylabel('Volume') ax.legend(fontsize=6, title_fontsize=8, loc='upper left') ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) fig.tight_layout() fig.show()
问题原因
Matplotlib的bar函数默认宽度为0.8,当x轴为datetime类型时,该宽度会被解析为天。你的数据间隔为15分钟(即1/96天),0.8天的宽度远大于数据间隔,直接导致柱子重叠;同时自动缩放的x轴会包含柱子的全部宽度,因此显示范围超出预期的9:00-13:00。
修复方案
修改思路
- 设置匹配数据间隔的柱子宽度:将宽度设置为略小于数据间隔的天数,避免柱子重叠。
- 手动限定x轴时间范围:明确设置x轴的起止时间,锁定到目标窗口。
修改后的代码
import matplotlib.pyplot as plt import matplotlib.dates as mdates import pandas as pd fig, ax = plt.subplots(nrows=1, ncols=1, dpi=600, figsize=(12,9)) # 计算15分钟间隔的0.8倍作为柱子宽度(单位:天) bar_width = 15/(24*60)*0.8 ax.bar(x=df['End_Datetime'], height=df['VOLUME'].values, width=bar_width, color='blue', label='15 mins Bin Volume', edgecolor='white', alpha=0.5) ax.set_ylabel('Volume') ax.legend(fontsize=6, title_fontsize=8, loc='upper left') ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M')) # 设置x轴范围为9:00到13:00 x_start = pd.Timestamp('2024-02-29 09:00:00') x_end = pd.Timestamp('2024-02-29 13:00:00') ax.set_xlim(x_start, x_end) # 添加小时刻度,优化x轴显示 ax.xaxis.set_major_locator(mdates.HourLocator(interval=1)) fig.tight_layout() fig.show()
额外优化
如果数据间隔不固定,可以通过计算相邻时间差的最小值动态设置柱子宽度:
# 计算最小时间间隔(单位:天) min_diff = df['End_Datetime'].diff().min().total_seconds()/(24*3600) # 设置为最小间隔的0.8倍 bar_width = min_diff * 0.8
内容的提问来源于stack exchange,提问作者user1769197
相关产品推荐
相关产品推荐

