You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在日期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可识别的浮点数值格式。

解决方法

  1. 导入matplotlib.dates模块,使用date2num()函数将pd.Timestamp转换为对应的浮点数值
  2. 计算时间段宽度:用结束日期的数值减去开始日期的数值
  3. 调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 15:50:21