如何在一张图中绘制多个时间线?

How to plot multiple timelines in one graph?

我有两个不同的数据框,其中包含不同的列:开始和结束日期、持续时间...

我想使用 plotly express 将数据绘制到时间线(甘特图)中。我知道如何使用子图,但我希望它们在同一个图形上而不是图形上。

这是我的尝试:

'''

import plotly.graph_objs as go
import plotly.express as px

fig = px.timeline(chosen_data3, x_start="Start Date", x_end="End Date", y="new" )
fig2 = px.timeline(chosen_data4, x_start="Start Date", x_end="End Date", y="new", ax = fig )
fig2.show()

#Using graph_objs :

fig = go.Figure()

for (start, end, value, value2) in zip(chosen_data3["Start Date"], chosen_data3["End Date"], 
chosen_data3["Duration [Hours]"],chosen_data3["Hs [m]"] ):
   name = f"Towing : {start} to {end}"
   fig.add_trace(go.Scatter(x=[start, end], y=[value, value],mode='lines', name = name , marker = 
   dict(color = 'rgb(0,0,0)'), hoverinfo = 'all'))    

 for (start, end, value, value2) in zip(chosen_data4["Start Date"], chosen_data4["End Date"], chosen_data4["Duration [Hours]"], chosen_data4["Hs [m]"]):
name = f"Hook-Up :{start} to {end}"
fig.add_trace(go.Scatter(x=[start, end], y=[value, value],mode='lines', name = name, marker = dict(color = 'rgb(65,105,225)'), hoverinfo = 'all')) 

fig.show()

'''

graph_objs 的解决方案是正确的,但是使用 express 的解决方案不正确

编辑: 我的两个数据框样本:

使用 Graph objs 的解决方案:

我尝试的解决方案是连接两个数据框并创建一个新列来区分每个数据,当您将鼠标悬停在每个条形图上时,我使用 plotly express 时间轴得到下图,您会看到所有需要的信息:

你的想法是正确的:要使用 plotly express 重现你用 plotly graph_objects 制作的图形,我们需要为你的两个 DataFrame 创建新的列来保存你需要传递给px.timeline 方法。然后我们可以连接两个 DataFrame 并将一个组合的 DataFrame 传递给 px.timeline.

我们可以创建一个名为legend_entry的列来保存您想要在图例中显示的字符串,并将其传递给px.timeline的color参数。然而,由于颜色参数也用于为条形分配颜色,并且每个 legend_entry 都是唯一的,每个条形将是不同的颜色——我们可以通过传递要分配的显式颜色数组来覆盖它到参数 color_discrete_sequence 的每个柱。为此,我们可以创建一个名为 color 的附加列,我们将根据牵引或连接任务使用 'black''blue' 填充该列。

由于最顶部和最底部的条形将紧靠绘图的边缘,我们可以通过将 y 轴的范围扩大任意小时数来添加一些填充。我选了10.

import numpy as np
import pandas as pd
import plotly.express as px

## recreate your data
chosen_data3 = pd.DataFrame({
    "Start Date":['1999-03-06 05:00:00','1999-03-08 22:00:00','1999-03-12 22:00:00','1999-03-22 19:00:00'],
    "End Date":['1999-03-08 00:00:00','1999-03-12 19:00:00','1999-03-21 20:00:00','1999-03-26 03:00:00'],
    "Hs [m]":[1.804182,1.461362,1.825023,1.717531]
})

chosen_data4 = pd.DataFrame({
    "Start Date":['1999-03-09 06:00:00','1999-03-20 05:00:00'],
    "End Date":['1999-03-11 18:00:00','1999-03-21 10:00:00'],
    "Hs [m]":[1.209672,1.121267]
})

chosen_data3[['Start Date','End Date']] = chosen_data3[['Start Date','End Date']].apply(pd.to_datetime)
chosen_data4[['Start Date','End Date']] = chosen_data4[['Start Date','End Date']].apply(pd.to_datetime)

chosen_data3['Duration [Hours]'] = (chosen_data3['End Date'] - chosen_data3['Start Date']) / np.timedelta64(1, 'h')
chosen_data4['Duration [Hours]'] = (chosen_data4['End Date'] - chosen_data4['Start Date']) / np.timedelta64(1, 'h')

## add a new column with a string for the legend
chosen_data3['legend_entry'] = "Towing : " + chosen_data3['Start Date'].apply(str) + " to " + chosen_data3['End Date'].apply(str) 
chosen_data4['legend_entry'] = "Hook up : " + chosen_data4['Start Date'].apply(str) + " to " + chosen_data4['End Date'].apply(str)

## add a new column to specify the color of each bar
chosen_data3['color'] = 'black'
chosen_data4['color'] = 'blue'

## we can concatenate the data into one DataFrame so that we only need to use px.timeline once
df = pd.concat([chosen_data3, chosen_data4])

## pass an explicit array to the color_discrete_sequence 
fig = px.timeline(df, x_start="Start Date", x_end="End Date", y="Duration [Hours]", 
    color="legend_entry", color_discrete_sequence=df.color.values)

## add some padding so that the bottom and topmost bars aren't flush against the edge of the figure
y_axis_range_padding = 10
fig.update_layout(
    title="Towing & Hook up tasks in function of duration", title_x=0.5, 
    legend_title_text='', yaxis_range=[df['Duration [Hours]'].min() - y_axis_range_padding, df['Duration [Hours]'].max() + y_axis_range_padding]
    )
fig.show()