plotlybar-chartgantt-chart

Plotly timeline plot multiple tasks per resource


I have a dataset in the form of a dataframe structured as follows

Job Task Machine Start End color
A Do X 1 0 5 blue
A Do Y 2 6 14 blue
B Do Q 3 0 8 green
B Do Z 3 9 12 green
B Do X 1 14 17 green
C Do Y 1 6 9 red

I want to plot these on an interactive timeline using Plotly (e.g. px.timeline), similar to included image below, also known as Gantt-chart. Per machine (y-axis), I want to a colored bar representing a task assigned to that machine, similar to its duration. For my example data, it means that for machine 1, there are three bars colored (0-5, 6-9, 14-17). The tasks should be colored according to a defined job color, as included in the color column. Ideally, in hovering over the bar, it shows Job - Task, Start - end.

example plot

I use the following;

Plotly 5.18.0
Python 3.9
Pandas 2.1.2

Is there a way to do this?

I played around with Plotly, but only managed to get the jobs on the y-axis (https://plotly.com/python/gantt/). I used https://plotly.com/python/figure-factories/ since the px.timeline does not appear to accept integer values for start and end times.


Solution

  • In px.timeline, colors cannot be specified, so we can simply use a horizontal bar graph. To draw a horizontal bar chart with a specified color, specify a stacked bar chart in a loop process with the contents conditionally extracted from the data frame by Job. The base is specified because it is always necessary to set the starting position. Text display can only be selected inside and outside, so we add it to the center of the bar chart using string annotations

    import plotly.graph_objects as go
    
    fig = go.Figure()
    
    for j in df['Job'].unique():
        dfj = df.query('Job == @j')
        for row in dfj.itertuples():
            print(row)
            before_base = row.Start
            fig.add_trace(go.Bar(
                base=[row.Start],
                x0=[row.Start],
                x=[row.End- before_base],
                y=[row.Job],
                y0=[row.Job],
                hovertemplate='Start: '+str(row.Start)+'<br>'+
                'End: %{x}<br>'+row.Task+'<extra></extra>',
                orientation='h',
                #text=row.Task,
                marker_color=row.color,
                width=0.9,
                showlegend=False,
            ))
            fig.add_annotation(
                x=(row.Start+row.End)/2,
                y=row.Job,
                text=row.Task,
                font=dict(color='white'),
                showarrow=False,
            )
            fig.update_layout(barmode='stack')
        
    fig.update_yaxes(autorange="reversed")
    fig.update_layout(height=400)
    fig.show()  
    

    enter image description here