1

I have the following code to plot a gantt chart in plotly:

import datetime
import pandas
import plotly.express as px

task_list = [{
    'Task': 'T-3', 'y': 0, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-350', 'y': 1, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 2, 25), 'Status': 'Backlog'}, {
    'Task': 'RD-6687', 'y': 2, 'Start': datetime.date(2022, 3, 18),
    'Finish': datetime.date(2022, 4, 8), 'Status': 'Selected'}, {
    'Task': 'RD-6643', 'y': 3, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-337', 'y': 4, 'Start': datetime.date(2022, 5, 21),
    'Finish': datetime.date(2022, 5, 23), 'Status': 'Backlog'}, {
    'Task': 'SNP-352', 'y': 5, 'Start': datetime.date(2022, 2, 26),
    'Finish': datetime.date(2022, 2, 28), 'Status': 'Clarification'}, {
    'Task': 'SNP-239', 'y': 6, 'Start': datetime.date(2022, 5, 24),
    'Finish': datetime.date(2022, 5, 25), 'Status': 'Selected'}]

df = pandas.DataFrame(task_list)

fig = px.timeline(df, x_start="Start", x_end="Finish", y="y",
                  # color="Status",
                  )

fig.show()

This gives me a gantt chart as expected: gantt chart without color

However, if I now include the line that is commented out in the code above, i.e. color the bars in the gantt chart according to their status, it messes up the height of the different bars:

gantt chart with colors

So the colors are shown as expected but it seems the height of the different bars is now not limited by the neighboring bar but only by the neighboring bar with the same color. How can I add the colors to the gantt chart but keep the height of the bars as it is without colors?

2 Answers 2

2
  • using color creates a trace for each Status, hence change in heights
  • have put Status into hover_data
  • built colormap and then updated trace to use value of Status to lookup color
import datetime
import pandas
import plotly.express as px
import numpy as np

# fmt: off
task_list = [{
    'Task': 'T-3', 'y': 0, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-350', 'y': 1, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 2, 25), 'Status': 'Backlog'}, {
    'Task': 'RD-6687', 'y': 2, 'Start': datetime.date(2022, 3, 18),
    'Finish': datetime.date(2022, 4, 8), 'Status': 'Selected'}, {
    'Task': 'RD-6643', 'y': 3, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-337', 'y': 4, 'Start': datetime.date(2022, 5, 21),
    'Finish': datetime.date(2022, 5, 23), 'Status': 'Backlog'}, {
    'Task': 'SNP-352', 'y': 5, 'Start': datetime.date(2022, 2, 26),
    'Finish': datetime.date(2022, 2, 28), 'Status': 'Clarification'}, {
    'Task': 'SNP-239', 'y': 6, 'Start': datetime.date(2022, 5, 24),
    'Finish': datetime.date(2022, 5, 25), 'Status': 'Selected'}]
# fmt: on
df = pandas.DataFrame(task_list)

# put status into figure as well as customdata
fig = px.timeline(
    df,
    x_start="Start",
    x_end="Finish",
    y="y",
    # color="Status",
    hover_data=["Status"],
)

# build a colormap for status 
colormap = {s:c for s,c in zip(df["Status"].unique(), px.colors.qualitative.Plotly)}
# use status in customdata to map color
fig.update_traces(marker_color=[colormap[s[0]] for s in fig.data[0].customdata])

enter image description here

2
  • This is really nice, thank you very much. Would you by any chance know how I could still add the legend?
    – Thomas
    Commented Feb 25, 2022 at 6:58
  • given the approach legend is not really usable here. a legend shows awn entry for each trace, in this case there is only one trace. a legend could be created by synthesising a trace for each status that is only there as visual cue, not an interactive component to control visibility Commented Feb 25, 2022 at 7:56
1

I've found the answer, but spent more when 2 hours and I found this accidentally.

# Format for your call/bar/trace
# Set/align bar HEIGHT to one. Prevent to make some of bar bigger or lower. 
fig.update_traces( width=0.6 )

Absolutely unpredictable place for these settings. I'm shocked.

Before

After

Full code:

import datetime
import pandas
import plotly.express as px

task_list = [{
    'Task': 'T-3', 'y': 0, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-350', 'y': 1, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 2, 25), 'Status': 'Backlog'}, {
    'Task': 'RD-6687', 'y': 2, 'Start': datetime.date(2022, 3, 18),
    'Finish': datetime.date(2022, 4, 8), 'Status': 'Selected'}, {
    'Task': 'RD-6643', 'y': 3, 'Start': datetime.date(2022, 2, 24),
    'Finish': datetime.date(2022, 3, 17), 'Status': 'Scheduled'}, {
    'Task': 'SNP-337', 'y': 4, 'Start': datetime.date(2022, 5, 21),
    'Finish': datetime.date(2022, 5, 23), 'Status': 'Backlog'}, {
    'Task': 'SNP-352', 'y': 5, 'Start': datetime.date(2022, 2, 26),
    'Finish': datetime.date(2022, 2, 28), 'Status': 'Clarification'}, {
    'Task': 'SNP-239', 'y': 6, 'Start': datetime.date(2022, 5, 24),
    'Finish': datetime.date(2022, 5, 25), 'Status': 'Selected'}]

df = pandas.DataFrame(task_list)

fig = px.timeline(df, x_start="Start", x_end="Finish", y="y",
                   color="Status",
                  )
# Set/align bar HEIGHT to one. Prevent to make some of bar bigger or lower. 
fig.update_traces( width=0.6 )

fig.show()

Not the answer you're looking for? Browse other questions tagged or ask your own question.