如何使 plotply.express.timeline 个图形具有不同的高度和颜色

How to enable plotply.express.timeline graphs to have different height and colors

我正在尝试使用时间线图表在下图中显示具有不同高度的每一行(Y 轴)。代码:

import plotly.express as px
import pandas as pd

df = pd.DataFrame([dict(Task="Task1", Start='2017-01-01', Finish='2017-02-15', Phase ='Phase1', Height=0.50),
      dict(Task="Task1", Start='2017-02-15', Finish='2017-03-15', Phase ='Phase2', Height=0.50),
      dict(Task="Task2", Start='2017-01-17', Finish='2017-02-17', Phase ='Phase2', Height=0.2),
      dict(Task="Task2", Start='2017-02-18', Finish='2017-03-17', Phase ='Phase3', Height=0.20),
      dict(Task="Task3", Start='2017-03-10', Finish='2017-03-31', Phase ='Phase1', Height=1.0),
      dict(Task="Task3", Start='2017-04-01', Finish='2017-05-20', Phase ='Phase2', Height=1.0),
      dict(Task="Task3", Start='2017-05-18', Finish='2017-06-18', Phase ='Phase3', Height=1.0),
      dict(Task="Task4", Start='2017-01-14', Finish='2017-03-14', Phase ='Phase4', Height=0.4)])

colors = {'Shadow': 'rgb(237, 125, 49)','Rev Shadow': 'rgb(0, 255, 100)', 'KA': 'rgb(68, 114, 196)', 'Enablement': 'rgb(150, 150, 150)'}

fig = px.timeline(df,  y = 'Task', x_start='Start', x_end = 'Finish', color= 'Phase',
                  color_discrete_sequence=px.colors.qualitative.D3)
fig.update_layout(autosize=False, width=800, height=300)

fig.show()

Timeline chart with correct colors, but same height

请问如何 increase/decrease 每个条形的高度。请注意,一行(任务)中的所有单独的条都将具有相同的高度。 此外,我可以将 px.timeline 中的颜色参数更改为 'Task' 和 运行 下面的命令,这将按我想要的方式更改 'Heights' 。但是,这将使整行(任务)具有相同的颜色。我得到了我想要的高度,但在这种情况下不是颜色...

请提前帮助并感谢!!

fig = px.timeline(df,  y = 'Task', x_start='Start', x_end = 'Finish', color= 'Task',
                  color_discrete_sequence=px.colors.qualitative.D3)
fig.update_layout(autosize=False, width=800, height=300)

for i, d in enumerate(fig.data):
    d.width = df[df['Task']==d.name]['Height']

Timeline chart with correct height, but same color for each task

我能够在 matplotlib 中使用 broken barh,它可以满足我的需求。如果其他人有类似的问题,希望它能有所帮助。虽然不能使用 plotly express 来完成。

import pandas as pd
import matplotlib.pyplot as plt

fig, gnt = plt.subplots()

df = pd.DataFrame([dict(Task="Task1", Start='2017-01-01', Finish='2017-02-15', Phase ='Phase1', Height=0.5),
      dict(Task="Task1", Start='2017-02-15', Finish='2017-03-15', Phase ='Phase2', Height=0.5),
      dict(Task="Task2", Start='2017-01-17', Finish='2017-02-17', Phase ='Phase2', Height=0.2),
      dict(Task="Task2", Start='2017-02-18', Finish='2017-03-17', Phase ='Phase3', Height=0.2),
      dict(Task="Task3", Start='2017-03-10', Finish='2017-03-31', Phase ='Phase1', Height=0.9),
      dict(Task="Task3", Start='2017-04-01', Finish='2017-05-20', Phase ='Phase2', Height=0.9),
      dict(Task="Task3", Start='2017-05-18', Finish='2017-06-18', Phase ='Phase3', Height=0.9),
      dict(Task="Task4", Start='2017-01-14', Finish='2017-03-14', Phase ='Phase4', Height=0.4)])

df['Start']= pd.to_datetime(df['Start'])
df['Finish']= pd.to_datetime(df['Finish'])

colors = pd.DataFrame([('Phase1', 'tab:brown', 0), ('Phase2', 'tab:blue', 0), 
                       ('Phase3', 'tab:orange', 0),('Phase4', 'tab:green', 0)],
                      columns = ['Phase', 'Color', 'LegendUse'])

bar_height = pd.DataFrame([('Task1', 0.5), ('Task2', 0.2), ('Task3', 0.9), ('Task4', 0.4)],
                          columns = ['Task', 'Height'])

for i in df.index:
    if colors.loc[colors['Phase'] == df.Phase[i], 'LegendUse'].iloc[0] == 0:
        colors.loc[colors['Phase'] == df.Phase[i], 'LegendUse'] = 1
        prefix = ''
    else:
        prefix = '_'
    thisbar = float(bar_height.loc[bar_height.Task == df.Task[i]].Height)
    thisYaxis = int(bar_height.loc[bar_height.Task == df.Task[i]].index[0])
    thiscolor = colors.loc[colors['Phase'] == df.Phase[i], 'Color'].iloc[0]
    gnt.broken_barh([(df.Start[i], (df.Finish[i] - df.Start[i]))], (thisYaxis, thisbar), 
                    facecolors=(thiscolor), label = prefix+df.Phase[i])

plt.legend(loc='upper left', bbox_to_anchor=(1.01, 1))

gnt.axes.get_yaxis().set_ticks([])
gnt.set_xticklabels(pd.date_range(start="2017-01-01",end="2017-07-01",freq = 'M').strftime('%b %Y'))

fig.set_figheight(4)
fig.set_figwidth(15)
fig.show()

Graph of bar here