Borders in Gantt-Charts?

Hey there,

Is there a way to surround all the bars in a Gantt-Chart with borders?
I have several activities that are colored the same as they belong to the same Resource, and if they appear together in the chart it is difficult to find the beginning and end times.

I tried updating the traces as seen in examples for regular bar charts, but without any success.
For example:

 fig.update_traces(marker=dict(
        color='rgba(58, 71, 80, 0.6)',
        line=dict(color='rgba(58, 71, 80, 1.0)', width=3)
    ))

Thank you!

Hi @thedomay, welcome to the forum! Here is a working example adapted from the documentation page on Gantt charts

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.update_traces(mode='lines', line_color='black', selector=dict(fill='toself'))
for trace in fig.data:
    trace.x += (trace.x[0],)
    trace.y += (trace.y[0],)
fig.show()

A few explanations:

  • the figure factory create_gantt creates the Gantt rectangles as Scatter traces which are filled, plus adds other other traces just for the hover (I discovered this from a print(fig), which is always a useful thing to do when you want to modify a figure). In the code you shared, adding line= did not help because the mode of the traces was set to None, hence the line properties were not used.
  • therefore you can modify each trace with update_traces by setting the mode to lines and the line_color, but you need to exclude the transparent traces otherwise they also have lines (you can try it yourself). For this I used the selector argument of update_traces.
  • if you want the lines to be closed, you also need to add the first point of each scatter trace at the end; this is what the for loop does.

Hope this helps!

3 Likes

Hey @Emmanuelle,

Thanks for the detailed explanation!

It works like a charm and the print(fig) is very helpful knowledge.

.

1 Like

This looks like a great solution but unfortunately I am having trouble to get it to work with a grouped task chart. I cannot make sense of the data fig data has saved for each trace. Can you explain how to use it in this case:

for var in X:
    if X[var].varValue==1:
        start_time=start_times[var[0],var[1],var[2]].varValue # convert seconds to hours, minutes and seconds
        end_time=completion_times[var[0],var[1],var[2]].varValue
        j_record[(var[0],var[1],var[2])]=[start_time,end_time]
        index_record.append([var[0],var[1],var[2]])
index_record.sort(key=itemgetter(2))
        

df=[]
for i in index_record:
    df.append(dict(Task='Machine %s'%(i[2]), Start=str(j_record[(i[0],i[1],i[2])][0]), Finish=str(j_record[(i[0],i[1],i[2])][1]),Resource='Job %s'%(i[0])))
    
fig = ff.create_gantt(df, index_col='Resource', show_colorbar=True, group_tasks=True, showgrid_x=True, title='Flexible_Job shop Schedule')
fig.update_traces(mode='lines', line_color='black', selector=dict(fill='toself'))
fig.update_xaxes(type='linear')
for trace in fig.data:
    print(trace)
fig

which gives me data like for example:

It results in a gantt with borders but I cannot get the border at the beginning of a block to work

Just doing

fig.update_traces(marker_line_color=‘rgb(0,48,107)’, marker_line_width=1, opacity=1)

gave me borders all around the bars for a px.timeline()

1 Like