Gantt Chart, set legend/colorbar at the top of chart

Hi,
Iā€™m making a Gantt chart, but Iā€™m having problems with the legend/colorbar. To view the legend on the right I need to scroll down to view it.


Is there a way to fix the legend so that it is at the top rather than the bottom? Or somewhere else where you do not have to scroll down to see it?

I have look at this https://plot.ly/python/legend/ , but Iā€™m using

from plotly.offline import plot
import plotly.graph_objs as go
...
fig = ff.create_gantt(df, index_col='TaskType', group_tasks=True, show_colorbar=True, bar_width=0.4,
                          showgrid_x=True, showgrid_y=True)
fig['layout'].update(autosize=False, height=750, width=1400, margin=go.Margin(l=160, b=30))
plot(go.Figure(fig))

so I canā€™t get it to work.
Anyone who can help?

Have you tried the following setting?

fig['layout'].update(legend={'x': 1, 'y': 1})

I am not particularly familiar with the syntax, yet you may want to investigate the idea further. 'x': 1 means ā€œput the legend on the right side of the plotā€ (and 0 means ā€œon the left sideā€). 'y': 1 is the same with the vertical axis (just check if 1 means ā€œtopā€ or ā€œbottomā€).

Thanks for the answer.
I can move it to the left, but I still have to scroll down to see it.

Hi @MQ94,

What version of plotly.py are you using? I think there was a fix for this in version 3.2 (https://github.com/plotly/plotly.py/pull/1110). Could you try updating?

-Jon

I think I have version 3.3.0.

In [16]: plotly.version
Out[16]: ā€˜3.3.0rc1ā€™

Iā€™m a beginner at Python and gantt chart, just so you know. So Iā€™m not sure how to use the fixā€¦ As shown I use ā€œshow_colorbarā€ and not ā€œshowlegendā€. If I write

fig = ff.create_gantt( ā€¦ , showlegend=True)

I get the error: TypeError: create_gantt() got an unexpected keyword argument ā€˜showlegendā€™

Hi @MQ94,

The change I referenced above is something that was added to version 3.2, so as long as youā€™re using a version newer than that thereā€™s nothing extra you need to do to use it.

When I run https://plot.ly/python/gantt/#index-by-string-variable the legend displays correctly. Could you add an full code example that reproduces what youā€™re seeing?

-Jon

Hi @jmmease

So Iā€™m taking data from a json fil, but hereā€™s some of the code:

from plotly.offline import plot
import plotly.graph_objs as go
import plotly.figure_factory as ff
import pandas as pd

def createGantt(data1, data2):
    df = []
    for row in data1.itertuples():
        # Create the working hours
        workHours = row.workingHours
        df.append(dict(Task=row.shiftRef, Start='startTime',
                       Finish='endTime',
                       TaskType='WorkingHours'
                       ))
        # Create the tasks
        for elementAllocTask in row.allocatedTasks:
            df.append(dict(Task=row.shiftRef, Start='start',
                           Finish='end',
                           TaskType=elementAllocTask['taskTypeRef'],
                           Description='TaskRef: ' + elementAllocTask['taskRef']
                           ))
            # Create the transportation times
            for elementTransTime in row.transportationTimes:
                if elementAllocTask['taskRef'] == elementTransTime['fromTaskRef']:
                    df.append(dict(Task=row.shiftRef, Start='end',
                           Finish='end',
                           TaskType='TransportationTimes',
                           Description='Duration: ' + elementTransTime['travelDuration']
                           ))
    # Create the unplanned tasks
    for row in data2.itertuples():
        df.append(dict(Task=row.taskRef, Start=row.start,
                       Finish=row.end, TaskType=row.status))


    fig = ff.create_gantt(df, index_col='TaskType', group_tasks=True, show_colorbar=True, bar_width=0.4,
                          showgrid_x=True, showgrid_y=True)
    fig['layout'].update(autosize=False, height=750, width=1400, margin=go.Margin(l=160, b=30))
    plot(go.Figure(fig))

Hi @MQ94,

Could you include include a small portion of data that reproduces the problem?

Thanks!
-Jon

Hi @jmmease
Sorry, that is classified. But I think that the problem would be somewhere in the code I have already shared.

Hi @MQ94,

It doesnā€™t need to be your actual data :slightly_smiling_face: Just something that reproduces the problem. I canā€™t really diagnose what might be going on without being able to reproduce it.

-Jon

Hi @jmmease ,

I have the same issue as @MQ94, where the legend is right below and needs to scroll down to see it.

At first, I thought that maybe the issue could be how long the yaxis is, and due to a large number of unique tasks. However, sticking to the date string formats similar to the plotly example does not recreate the problem. Iā€™ve tried to do some investigation and I believe the problem could be the use of timestamps rather than date strings.

The plotly example for ff.create_gantt() uses -> Start=ā€˜2017-01-01ā€™, Finish=ā€˜2017-02-02ā€™
For my case, ā€˜Startā€™: Timestamp(ā€˜2018-07-07 00:00:00ā€™), ā€˜Finishā€™: Timestamp(ā€˜2019-01-10 00:00:00ā€™), which creates the problem. Datatype was created from pd.to_datetime

Okay sorry about my previous response. Seems like the issue is if number of Tasks is >50 rather than the time format

Hi @junh.tan,
thanks for the answer, but Iā€™m not sure how to solve it. I have made a set of the task (the length is only 11) and:

if len(task) < 40:
    fig = ff.create_gantt(df, index_col='TaskType', group_tasks=True, show_colorbar=True, bar_width=0.4,
                      showgrid_x=True, showgrid_y=True)
    fig['layout'].update(autosize=False, height=750, width=1400, margin=go.Margin(l=160, b=30))
    plot(go.Figure(fig))

but this does not solve the problemā€¦ Can you show how you have solved it?

Hi @MQ94,

To be honest I am not sure what am I doing right that you are not. But I can show you roughly what I have.

fig = ff.create_gantt(df, index_col=ā€˜Resourceā€™, show_colorbar=True, height=1200, width=900,showgrid_x=True, bar_width=0.2)

iplot(fig)

For my df, my Tasks are unique (i.e only one row per task) as compared to yours whereby your group_task=True. So this might be a reason for the difference between my result and yours. Also, iā€™m plotting in a jupyter notebook. Not sure if this affects as well.

Hi @jmmease

Here is an example of the data that produces the problem

{
  "solutionId" : null,
  "shiftSchedules" : [ {
    "employeeRef" : "PROFESSIONAL:3090",
    "shiftRef" : "195750",
    "opportunityRef" : "PROFESSIONAL:3090:2018-09-07T05:00:00Z",
    "allocatedTasks" : [ {
      "status" : "SUCCESFULLY_SCHEDULED",
      "taskRef" : "0&R148043",
      "taskTypeRef" : "RESOURCE_EVENT",
      "assignedShiftRefs" : [ "195750" ],
      "start" : "2018-09-07T05:00:00Z",
      "end" : "2018-09-07T05:30:00Z"
    }, {
      "status" : "SUCCESFULLY_SCHEDULED",
      "taskRef" : "0&580340-2018-09-07",
      "taskTypeRef" : "PLANNED_GRANT_EVENT",
      "assignedShiftRefs" : [ "195750" ],
      "start" : "2018-09-07T06:12:00Z",
      "end" : "2018-09-07T07:19:00Z"
    }, {
      "status" : "SUCCESFULLY_SCHEDULED",
      "taskRef" : "0&580339-2018-09-07",
      "taskTypeRef" : "PLANNED_GRANT_EVENT",
      "assignedShiftRefs" : [ "195750" ],
      "start" : "2018-09-07T07:22:00Z",
      "end" : "2018-09-07T08:53:00Z"
    }, {
      "status" : "SUCCESFULLY_SCHEDULED",
      "taskRef" : "0&580337-2018-09-07",
      "taskTypeRef" : "PLANNED_GRANT_EVENT",
      "assignedShiftRefs" : [ "195750" ],
      "start" : "2018-09-07T08:57:00Z",
      "end" : "2018-09-07T10:46:00Z"
    }, {
      "status" : "SUCCESFULLY_SCHEDULED",
      "taskRef" : "0&580338-2018-09-07",
      "taskTypeRef" : "PLANNED_GRANT_EVENT",
      "assignedShiftRefs" : [ "195750" ],
      "start" : "2018-09-07T10:50:00Z",
      "end" : "2018-09-07T11:59:00Z"
    } ],
    "workingHours" : {
      "startTime" : "2018-09-07T05:00:00Z",
      "endTime" : "2018-09-07T13:00:00Z"
    },
    "transportationTimes" : [ {
      "travelDuration" : "00:42",
      "fromTaskRef" : "0&R148043",
      "toTaskRef" : "0&580340-2018-09-07"
    }, {
      "travelDuration" : "00:03",
      "fromTaskRef" : "0&580340-2018-09-07",
      "toTaskRef" : "0&580339-2018-09-07"
    }, {
      "travelDuration" : "00:04",
      "fromTaskRef" : "0&580339-2018-09-07",
      "toTaskRef" : "0&580337-2018-09-07"
    }, {
      "travelDuration" : "00:04",
      "fromTaskRef" : "0&580337-2018-09-07",
      "toTaskRef" : "0&580338-2018-09-07"
    } ]
  } ],
  "plannedTasks" : [ {
    "status" : "SUCCESFULLY_SCHEDULED",
    "taskRef" : "0&R148044",
    "taskTypeRef" : "RESOURCE_EVENT",
    "assignedShiftRefs" : [ "195650" ],
    "start" : "2018-09-07T05:00:00Z",
    "end" : "2018-09-07T05:30:00Z"
  }, {
    "status" : "SUCCESFULLY_SCHEDULED",
    "taskRef" : "0&580339-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ "195750" ],
    "start" : "2018-09-07T07:22:00Z",
    "end" : "2018-09-07T08:53:00Z"
  }, {
    "status" : "SUCCESFULLY_SCHEDULED",
    "taskRef" : "0&580345-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ "195650" ],
    "start" : "2018-09-07T06:09:00Z",
    "end" : "2018-09-07T07:24:00Z"
  }, {
    "status" : "SUCCESFULLY_SCHEDULED",
    "taskRef" : "0&R148043",
    "taskTypeRef" : "RESOURCE_EVENT",
    "assignedShiftRefs" : [ "195750" ],
    "start" : "2018-09-07T05:00:00Z",
    "end" : "2018-09-07T05:30:00Z"
  } ],
  "unplannedTasks" : [ {
    "status" : "CANNOT_BE_SCHEDULED",
    "taskRef" : "0&580342-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ ],
    "start" : "2018-09-06T22:00:00Z",
    "end" : "2018-09-06T23:08:00Z"
  }, {
    "status" : "CANNOT_BE_SCHEDULED",
    "taskRef" : "0&580346-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ ],
    "start" : "2018-09-06T22:00:00Z",
    "end" : "2018-09-06T23:51:00Z"
  }, {
    "status" : "CANNOT_BE_SCHEDULED",
    "taskRef" : "0&580347-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ ],
    "start" : "2018-09-06T22:00:00Z",
    "end" : "2018-09-06T23:42:00Z"
  }, {
    "status" : "CANNOT_BE_SCHEDULED",
    "taskRef" : "0&580348-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ ],
    "start" : "2018-09-06T22:00:00Z",
    "end" : "2018-09-06T23:53:00Z"
  }, {
    "status" : "CANNOT_BE_SCHEDULED",
    "taskRef" : "0&580349-2018-09-07",
    "taskTypeRef" : "PLANNED_GRANT_EVENT",
    "assignedShiftRefs" : [ ],
    "start" : "2018-09-06T22:00:00Z",
    "end" : "2018-09-06T23:22:00Z"
  } ],
  "scenarioId" : null,
  "jobId" : -1,
  "links" : [ ]
}

Thanks for the data @MQ94, but Iā€™m not sure you to use it to create your plot. Could you add the code that uses this data to call the figure factor?
-Jon

Hi guys,

I am replying because I am facing the same issue after trying to use a Gantt Chart.

Blockquote
Hi @MQ94, What version of plotly.py are you using? I think there was a fix for this in version 3.2 (https://github.com/plotly/plotly.py/pull/1110 ). Could you try updating?
-Jon

I donā€™t consider this as a permanent solution because the solution is just to turn showlegend to False (showlegend = False).

Curious about it, I put a color background to the legend, and it shows something funny.
Could it help Plotly team to understand and fix the issue ?

It seems that every single trace provide a legend but only the last one is active.

Here is the code used :

fig = ff.create_gantt(data_2000.iloc[:5], index_col = 'Resource', show_colorbar=True, bar_width=0.2, showgrid_x=True, showgrid_y=True)
fig['layout'].update(autosize = True, margin = dict(l=100), legend=dict(bgcolor='#E2E2E2'))

Finally, a temporary solution is to set :

traceorder=ā€˜reversedā€™,

However, if the legend is longer than the chart, the scrollbar keep appearing.

Best,

Quentin.

Hi @qdumont, @junh.tan, and @MQ94,

Iā€™m happy to take a look, but I still need someone to provide the exact version of plotly.py that they are using along with a full reproducible example (including imports, data, code, etc.) of the issue.

Thanks!
-Jon

Hi @jmmease, I have the same issue as the other users, so I created a sample data that you can test.

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.figure_factory as ff
import pandas as pd



df1 = pd.DataFrame({'TaskName': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'I', 'J', 'K'],
                'StartDate1' : ['2019-03-27 00:00:00','2019-03-27 00:00:30', '2019-03-27 00:01:00', '2019-03-27 00:01:30', '2019-03-27 00:01:40',
                             '2019-03-27 00:02:30', '2019-03-27 00:03:00', '2019-03-27 00:03:30', '2019-03-27 00:04:00', '2019-03-27 00:04:30'],
                'EndDate1': ['2019-03-27 00:03:00', '2019-03-27 00:03:20', '2019-03-27 00:04:10', '2019-03-27 00:03:40', '2019-03-27 00:05:50',
                            '2019-03-27 00:06:40', '2019-03-27 00:07:10', '2019-03-27 00:08:00', '2019-03-27 00:08:20', '2019-03-27 00:08:40'],
                'StartDate2' : ['2019-03-27 00:03:00', '2019-03-27 00:03:20', '2019-03-27 00:04:10', '2019-03-27 00:03:40', '2019-03-27 00:05:50',
                            '2019-03-27 00:06:40', '2019-03-27 00:07:10', '2019-03-27 00:08:00', '2019-03-27 00:08:20', '2019-03-27 00:08:40'],
                'EndDate2': ['2019-03-27 00:04:00', '2019-03-27 00:04:20', '2019-03-27 00:05:10', '2019-03-27 00:05:40', '2019-03-27 00:06:50',
                            '2019-03-27 00:07:40', '2019-03-27 00:08:10', '2019-03-27 00:09:00', '2019-03-27 00:09:20', '2019-03-27 00:09:40']})

def gantt_fig3(df1):
    data3 = []
    for row in df1.itertuples():
        data3.append(dict(Task=str(row.TaskName), Start=str(row.StartDate1),
                      Finish=str(row.EndDate1), Resource='Resource1'))
        data3.append(dict(Task=str(row.TaskName), Start=str(row.StartDate2),
                      Finish=str(row.EndDate2), Resource='Resource2'))


    fig = ff.create_gantt(data3, index_col='Resource', title='Gantt Chart', show_colorbar = True, group_tasks = True , height=500, width=1300 )
    fig['layout'].update(legend=dict(traceorder='reversed'))
    return fig

app = dash.Dash()


app.layout = html.Div(children=[
    html.H1(children='Gantt Chart'),       
    dcc.Graph(
        id='gantt-chart',
        figure = gantt_fig3(df1))
])

if __name__ == '__main__':
    app.run_server(debug=True, port=9000)

This is the output that I get. The command ā€˜traceorder=reversedā€™ places the legend at the top. Also, because I said that ā€˜group_tasks=Trueā€™, the tasks are displayed from the top to the bottom, and not from bottom to top.
My version of plotly is 3.4.1

1 Like

Thanks @kna, thatā€™s exactly what was needed :slightly_smiling_face: Iā€™ve opened an issue at https://github.com/plotly/plotly.py/issues/1493.