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

如何在Python中绘制含0时长任务的甘特图(Plotly/Matplotlib)

解决甘特图中0时长任务不显示的问题

Plotly 简便方案:给0时长任务添加微小时间增量

由于Plotly的timeline无法识别起止时间完全相同的任务,最简单的处理方式是给这类任务的结束时间加一个极小的时间差(比如1秒),让图表能渲染出一个极短的条形,同时不影响数据逻辑:

import pandas as pd
import plotly.express as px

df = pd.DataFrame([
    dict(Task="1", Start='2023-03-15', End='2023-03-15'),
    dict(Task="2", Start='2023-03-03', End='2023-03-10'),
    dict(Task="3", Start='2023-03-10', End='2023-03-15'),
])

# 转换为datetime类型
df['Start'] = pd.to_datetime(df['Start'])
df['End'] = pd.to_datetime(df['End'])

# 给0时长任务的结束时间加1秒
mask = df['Start'] == df['End']
df.loc[mask, 'End'] += pd.Timedelta(seconds=1)

fig = px.timeline(df, x_start="Start", x_end="End", y="Task")
fig.update_yaxes(autorange="reversed")
# 自定义hover模板,隐藏那1秒的增量
fig.update_traces(hovertemplate='Task: %{y}<br>Date: %{x_start}')

fig.show()

Plotly 进阶方案:用散点标记0时长任务

如果希望明确将0时长任务显示为点而非短条形,可以分开处理两类任务,用散点图标记0时长任务:

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

df = pd.DataFrame([
    dict(Task="1", Start='2023-03-15', End='2023-03-15'),
    dict(Task="2", Start='2023-03-03', End='2023-03-10'),
    dict(Task="3", Start='2023-03-10', End='2023-03-15'),
])

df['Start'] = pd.to_datetime(df['Start'])
df['End'] = pd.to_datetime(df['End'])

# 先绘制有时长的任务
fig = px.timeline(df[df['Start'] != df['End']], x_start="Start", x_end="End", y="Task")
fig.update_yaxes(autorange="reversed")

# 为0时长任务添加散点标记
zero_tasks = df[df['Start'] == df['End']]
for _, row in zero_tasks.iterrows():
    fig.add_trace(go.Scatter(
        x=[row['Start']],
        y=[row['Task']],
        mode='markers',
        marker=dict(size=10, color=fig.data[0].marker.color),
        hovertemplate='Task: %{y}<br>Date: %{x}'
    ))

fig.show()

Matplotlib 方案

如果使用Matplotlib,可以直接结合水平条形图和散点图分别处理正常任务和0时长任务:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

df = pd.DataFrame([
    dict(Task="1", Start='2023-03-15', End='2023-03-15'),
    dict(Task="2", Start='2023-03-03', End='2023-03-10'),
    dict(Task="3", Start='2023-03-10', End='2023-03-15'),
])

df['Start'] = pd.to_datetime(df['Start'])
df['End'] = pd.to_datetime(df['End'])

# 定义任务的y轴位置
task_list = df['Task'].unique()
y_positions = [task_list.index(task) for task in df['Task']]

fig, ax = plt.subplots(figsize=(10, 4))

# 绘制有时长的任务
non_zero_tasks = df[df['Start'] != df['End']]
ax.barh(
    y=[task_list.index(t) for t in non_zero_tasks['Task']],
    width=(non_zero_tasks['End'] - non_zero_tasks['Start']).dt.days,
    left=non_zero_tasks['Start'],
    height=0.5,
    color='skyblue'
)

# 绘制0时长任务的散点
zero_tasks = df[df['Start'] == df['End']]
ax.scatter(
    x=zero_tasks['Start'],
    y=[task_list.index(t) for t in zero_tasks['Task']],
    color='darkblue',
    s=100,
    zorder=5  # 确保点在条形图上方
)

# 设置x轴日期格式
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.xticks(rotation=45)

# 设置y轴标签
ax.set_yticks(y_positions)
ax.set_yticklabels(df['Task'])

plt.tight_layout()
plt.show()

内容的提问来源于stack exchange,提问作者lunamaria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 09:23:19