Matplotlib柱状图分段阈值水平线绘制问题求助
问题需求
我需要在柱状图中创建3条阈值水平线,每条线仅延伸至对应Tenor的日期范围,到下一个Tenor时换线接续。数据包含Cash、End Date、Tenor三列。现有代码无法实现分段显示,水平线会贯穿整个图表宽度;尝试修改axhline的xmin/xmax参数但无效,同时需要在每个Tenor结束位置绘制垂直线分隔。
当前效果:水平线贯穿全图,无分段
预期效果:水平线按Tenor分段显示,Tenor结束处有垂直线分隔
现有代码
import pandas as pd import matplotlib.pyplot as plt df = {'Cash':[900e6,800e6,700e6,600e6,500e6,400e6,300e6,200e6,100e6,0], 'End Date': ['27/03/2023','28/03/2023','29/03/2023','30/03/2023','31/03/2023','01/04/2023','02/04/2023','20/09/2023','21/09/2023','21/01/2024'], 'Tenor': ['1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','6 Month','6 Month','9Month']} df = pd.DataFrame(data = df) pd.to_datetime(df['End Date']) fig, ax = plt.subplots(figsize=(10, 100)) for tenor, group in df.groupby('Tenor'): cash_out_limits = [200e6, 300e6, 500e6] # define cash out limits for each tenor last_end_date = group.iloc[-1]['End Date'] # get the last end date for each tenor start_end_date = group.iloc[0]['End Date'] print(start_end_date) # create a red hline for each cash out limit for limit in cash_out_limits: ax.axhline(limit, color='r', linestyle='--') # plot cash out vs end date as a bar chart df.plot(x='End Date', y='Cash', kind='bar', ax=ax) plt.show()
尝试过的无效代码
for limit in cash_out_limits: ax.axhline(y=limit, xmin = start_end_date, xmax = last_end_date, color='r', linestyle='--')
解决方案
问题核心是axhline的xmin/xmax需要的是坐标轴相对位置(0到1之间),而非日期字符串。另外柱状图的x轴是分类轴,每个柱子对应一个索引位置,需通过分组的索引范围确定水平线起止,同时绘制垂直线分隔Tenor。
修改后的完整代码:
import pandas as pd import matplotlib.pyplot as plt # 数据处理:正确解析日期并保留原始索引 df = { 'Cash': [900e6,800e6,700e6,600e6,500e6,400e6,300e6,200e6,100e6,0], 'End Date': ['27/03/2023','28/03/2023','29/03/2023','30/03/2023','31/03/2023','01/04/2023','02/04/2023','20/09/2023','21/09/2023','21/01/2024'], 'Tenor': ['1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','1-3 Month','6 Month','6 Month','9Month'] } df = pd.DataFrame(data=df) df['End Date'] = pd.to_datetime(df['End Date'], dayfirst=True) fig, ax = plt.subplots(figsize=(12, 6)) # 先绘制柱状图,确保x轴索引对应正确 df.plot(x='End Date', y='Cash', kind='bar', ax=ax) cash_out_limits = [200e6, 300e6, 500e6] total_bars = len(df) # 遍历每个Tenor分组,绘制分段水平线和垂直线 for tenor, group in df.groupby('Tenor'): start_idx = group.index[0] end_idx = group.index[-1] # 将柱子索引转换为axhline需要的相对坐标(0-1范围) xmin = (start_idx - 0.5) / (total_bars - 1) if total_bars > 1 else 0 xmax = (end_idx + 0.5) / (total_bars - 1) if total_bars > 1 else 1 # 绘制分段阈值水平线 for limit in cash_out_limits: ax.axhline(y=limit, xmin=xmin, xmax=xmax, color='r', linestyle='--') # 绘制Tenor分隔垂直线(最后一个分组不画) if end_idx != total_bars - 1: ax.axvline(x=end_idx + 0.5, color='gray', linestyle='-') # 优化图表显示 plt.xticks(rotation=45) plt.tight_layout() plt.show()
关键修改说明:
- 正确解析日期格式,避免索引混乱
- 利用分组的原始索引计算柱状图的x轴位置,转换为
axhline所需的相对坐标 - 垂直线绘制在分组最后一个柱子的右侧(
end_idx + 0.5位置) - 调整图表尺寸和标签角度,提升可读性
内容的提问来源于stack exchange,提问作者c_dogg
相关产品推荐
相关产品推荐

