I have two different Dataframes containing various columns : start & end date, Duration ...
I would like to plot the data into Timelines(Gantt charts) using plotly express. I know how to use subplots however I want them on the same graphic not figure.
'''
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()
'''
The solution with graph_objs is correct however the one using express didn't
EDIT : Sample of my two dataframes :
Solution using Graph objs :
The solution I tried was to concatenate the two dataframes & create a new column to differentiate each data, I get the following figure using plotly express timeline when you hover over each bar you see all the information needed :
You have the right idea: to reproduce the figure you made with plotly graph_objects using plotly express, we need to create new columns for your two DataFrames to hold information that you'll need to pass to the px.timeline
method. Then we can concatenate the two DataFrames and pass the one combined DataFrame to px.timeline.
We can create a column called legend_entry
to hold the string that you want to be displayed in the legend, and pass this to the color
parameter of px.timeline. However since the color parameter is also used to assign colors to the bars, and each legend_entry you have will be unique, each bar will be a different color — we can override this by passing an explicit array of colors to be assigned to each bar to the parameter color_discrete_sequence
. To do this, we can create an additional column called color
that we will populate with 'black'
or 'blue'
depending on towing or hook-up tasks.
Since the topmost and bottommost bars will be right up against the edge of the plot, we can add some padding by expanding the range of the y-axis by however many hours you like. I chose 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()