Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to show task dependencies when creating Gantt charts using `create_gantt()`?

When making Gantt charts was to use the create_gantt() figure factory, as follows:

import plotly.figure_factory as ff

df = [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')]

fig = ff.create_gantt(df)
fig.show()

I got the following result:

Gantt charts

However, I also want to show the task dependencies that Job B depends on Job A, that is, I want to draw an arrow from Job A to Job B. How to show task dependencies in the above Gantt chart?

like image 250
Frank Sheng Avatar asked Oct 21 '25 16:10

Frank Sheng


1 Answers

As mentioned in the comments, you can draw an arrow using annotations. You can make a styled arrow similar to ones available in matplotlib by using several line segments with an arrow at the end.

For convenience, I converted all of the datetime strings to datetimes and placed them in dictionaries.

And to make the solution more generalizable, I also wrapped the annotations in a function so you can create such annotations for any two jobs. Note that the function is a bit rigid in the sense that it assumes the beginning of the second job occurs after the start of the first job.

import pandas as pd
import plotly.figure_factory as ff

jobA_dict = dict(Task="Job A", Start=pd.to_datetime('2009-01-01'), Finish=pd.to_datetime('2009-02-28'))
jobB_dict = dict(Task="Job B", Start=pd.to_datetime('2009-03-05'), Finish=pd.to_datetime('2009-04-15'))
jobC_dict = dict(Task="Job C", Start=pd.to_datetime('2009-05-01'), Finish=pd.to_datetime('2009-06-30'))

df = [jobA_dict, jobB_dict, jobC_dict]

fig = ff.create_gantt(df)

## draw an arrow from the end of the first job to the start of the second job

def draw_arrow_between_jobs(fig, first_job_dict, second_job_dict):
    ## retrieve tick text and tick vals
    job_yaxis_mapping = dict(zip(fig.layout.yaxis.ticktext,fig.layout.yaxis.tickvals))
    jobs_delta = second_job_dict['Start'] - first_job_dict['Finish']
    ## horizontal line segment
    fig.add_shape(
        x0=first_job_dict['Finish'], y0=job_yaxis_mapping[first_job_dict['Task']], 
        x1=first_job_dict['Finish'] + jobs_delta/2, y1=job_yaxis_mapping[first_job_dict['Task']],
        line=dict(color="blue", width=2)
    )
    ## vertical line segment
    fig.add_shape(
        x0=first_job_dict['Finish'] + jobs_delta/2, y0=job_yaxis_mapping[first_job_dict['Task']], 
        x1=first_job_dict['Finish'] + jobs_delta/2, y1=job_yaxis_mapping[second_job_dict['Task']],
        line=dict(color="blue", width=2)
    )
    ## horizontal line segment
    fig.add_shape(
        x0=first_job_dict['Finish'] + jobs_delta/2, y0=job_yaxis_mapping[second_job_dict['Task']], 
        x1=second_job_dict['Start'], y1=job_yaxis_mapping[second_job_dict['Task']],
        line=dict(color="blue", width=2)
    )
    ## draw an arrow
    fig.add_annotation(
        x=second_job_dict['Start'], y=job_yaxis_mapping[second_job_dict['Task']],
        xref="x",yref="y",
        showarrow=True,
        ax=-10,
        ay=0,
        arrowwidth=2,
        arrowcolor="blue",
        arrowhead=2,
    )
    return fig

Now to draw an arrow between Job A and Job B:

fig = draw_arrow_between_jobs(fig, jobA_dict, jobB_dict)

enter image description here

And you can add an additional arrow between Job B and Job C:

fig = draw_arrow_between_jobs(fig, jobB_dict, jobC_dict)

enter image description here

like image 187
Derek O Avatar answered Oct 26 '25 19:10

Derek O



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!