绘制甘特图:删除重复的 Y 轴标签和堆栈并行任务

时间:2021-05-28 13:56:13

标签: python plotly gantt-chart

我打算使用 python 库“Plotly”来构建甘特图。具体来说:https://plotly.com/python/gantt/#group-tasks-together

但是,每个“作业”可以有多个任务,并且这些任务可以并行运行。据我观察,Plotly 不会将并行运行的任务堆叠在一起,这使得阅读图表非常困难。这是一个示例,其中“作业 A”有两个并行运行的任务,但只有一个可见:

data = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'),
      dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')]

# Without group_tasks=True, There would be two separate "Job A" labels
fig = ff.create_gantt(data, group_tasks=True)
fig.show()

enter image description here

我想要的是“作业 A”任务都可见,但垂直堆叠,“作业 A”位于其任务占用的垂直空间的中心。像这样但没有两个“作业 A”标签的东西:

enter image description here

如果有人对我的甘特图项目有任何我应该考虑的图书馆建议,请随时分享!谢谢!

1 个答案:

答案 0 :(得分:0)

一个起点是使用 fig.add_shape 在原始 Task 下方添加一个相同的 Task 作为矩形。

为此,我们需要每个矩形的 y 坐标,但方便的是,第一个条形位于 y=0,第二个条形位于 y=1,依此类推。因此,按顺序列出的唯一任务的索引也是 y 坐标(唯一任务是 [Job A, Job B, Job C],因此作业 C 条将以 y=3 为中心)。每个条形的默认宽度为 0.8,因此如果 y0 是条形的起始 y 坐标,则 y1 应以 y0-0.4 结束。

请注意,带注释的形状不会有任何悬停模板,并且每个条的颜色与当前编写的方式相同。

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

## added additional duplicate Task to demonstrate generalizability
data = [dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job A", Start='2009-01-01', Finish='2009-02-28'),
      dict(Task="Job B", Start='2009-03-05', Finish='2009-04-15'),
      dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30'),
      dict(Task="Job C", Start='2009-02-20', Finish='2009-05-30')]

df = pd.DataFrame(data)

# Without group_tasks=True, There would be two separate "Job A" labels
# fig = ff.create_gantt(data, group_tasks=True)

## plot the non-duplicate rows
fig = px.timeline(df.loc[~df['Task'].duplicated()], x_start="Start", x_end="Finish", y="Task")

## plot the duplicate rows using rectangular shapes
for row in df.loc[df['Task'].duplicated()].itertuples():
      y_val = np.where(df.Task.unique()==row[1])[0][0]
      # print(f"found {row[1]} at index {y_val}")
      fig.add_shape(type="rect",
            xref="x", yref="y",
            x0=row[2], x1=row[3], 
            y0=y_val, y1=y_val-0.4,
            line_width=0,
            fillcolor="salmon",
)
fig.show()

enter image description here