如何在日期X轴绘图中绘制FancyBboxPatch实现甘特图效果
在Matplotlib日期轴上绘制FancyBboxPatch实现甘特图效果
需求是在带有日期X轴的Matplotlib绘图中,用FancyBboxPatch覆盖特定时间段,实现类似甘特图的效果。初始代码仅在日期位置添加了文本标注:
import matplotlib.pyplot as plt import pandas as pd data = [('2019-04-15', 'Start'), ('2019-05-01', 'Stop')] date, labels = zip(*data) frame = pd.DataFrame({'bla': labels}, index=pd.DatetimeIndex(date)) fig, ax = plt.subplots(figsize=(12.5, 2.5)) for index, row in frame.iterrows(): ax.text(index, 0.5, row['bla']) ax.set_xlim([frame.index[0], frame.index[-1]]) plt.show()
添加FancyBboxPatch时出现错误:TypeError: unsupported operand type(s) for -: 'Timestamp' and 'float',错误代码如下:
import matplotlib.pyplot as plt import pandas as pd import matplotlib.patches as mpatches data = [('2019-04-15', 'Start'), ('2019-05-01', 'Stop')] date, labels = zip(*data) frame = pd.DataFrame({'bla': labels}, index=pd.DatetimeIndex(date)) fig, ax = plt.subplots(figsize=(12.5, 2.5)) for index, row in frame.iterrows(): ax.text(index, 0.5, row['bla']) ax.set_xlim([frame.index[0], frame.index[-1]]) ax.add_patch( mpatches.FancyBboxPatch( (frame.index[0],0.5), # xy 100, # width 0.5, # heigth boxstyle=mpatches.BoxStyle("Round", pad=0.02) ) ) plt.show()
错误原因
Matplotlib的图形补丁(Patch)使用的是轴的数据坐标,当X轴为日期类型时,直接传入pd.Timestamp对象与数值进行计算会触发类型不兼容错误。需要将日期转换为Matplotlib可识别的浮点数值格式。
解决方法
- 导入
matplotlib.dates模块,使用date2num()函数将pd.Timestamp转换为对应的浮点数值 - 计算时间段宽度:用结束日期的数值减去开始日期的数值
- 调整FancyBboxPatch的位置和尺寸参数,确保使用转换后的数值坐标
修正后的完整代码
import matplotlib.pyplot as plt import pandas as pd import matplotlib.patches as mpatches import matplotlib.dates as mdates data = [('2019-04-15', 'Start'), ('2019-05-01', 'Stop')] date, labels = zip(*data) frame = pd.DataFrame({'bla': labels}, index=pd.DatetimeIndex(date)) fig, ax = plt.subplots(figsize=(12.5, 2.5)) # 添加日期文本标注 for index, row in frame.iterrows(): ax.text(index, 0.5, row['bla'], ha='center', va='center') # 转换日期为Matplotlib数值格式 start_date = frame.index[0] end_date = frame.index[1] start_num = mdates.date2num(start_date) end_num = mdates.date2num(end_date) # 计算时间段宽度 time_width = end_num - start_num # 添加FancyBboxPatch,覆盖整个时间段 ax.add_patch( mpatches.FancyBboxPatch( (start_num, 0.25), # 补丁左下角坐标(X为起始日期数值,Y为垂直位置) time_width, # 补丁宽度(时间段长度对应的数值) 0.5, # 补丁高度 boxstyle=mpatches.BoxStyle("Round", pad=0.02), facecolor='#cce5ff', # 填充色 edgecolor='#0056b3', # 边框色 alpha=0.7 # 透明度 ) ) ax.set_xlim([start_date, end_date]) # 优化日期显示格式 ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d')) plt.xticks(rotation=45) plt.tight_layout() plt.show()
内容的提问来源于stack exchange,提问作者Stücke
相关产品推荐
相关产品推荐

