I don't understand the need for the expected graph requirement, but my approach is to use transparency to overlay the same task with scheduled and actual results. I took the end date of the data you presented as scheduled and added a progress date. px.timeline()
is used to create a graph of scheduled vs. actual. This chart data is reused and set as a bar chart in the graph_object
. Layout information is also reused and set.
My response was to overlay the timeline and annotate the progress rate. Make duplicate legend elements unique.
import pandas as pd
import datetime
import plotly.express as px
import plotly.graph_objects as go
df['Start_Date'] = pd.to_datetime(df['Start_Date'])
df['End_Date'] = pd.to_datetime(df['End_Date'])
df['End_Date2'] = df[['Percentage_complete', 'Start_Date','End_Date']].apply(lambda x: (x[2]-x[1])*x[0]+x[1], axis=1)
fig1 = px.timeline(df, x_start="Start_Date", x_end="End_Date", y="Task_Name", color='Team_Name', opacity=0.5)
fig2 = px.timeline(df, x_start="Start_Date", x_end="End_Date2", y="Task_Name", color='Team_Name')
fig = go.Figure()
fig.add_trace(go.Bar(fig1.data[0]))
fig.add_trace(go.Bar(fig1.data[1]))
fig.add_trace(go.Bar(fig1.data[2]))
fig.add_trace(go.Bar(fig1.data[3]))
fig.add_trace(go.Bar(fig2.data[0]))
fig.add_trace(go.Bar(fig2.data[1]))
fig.add_trace(go.Bar(fig2.data[2]))
fig.add_trace(go.Bar(fig2.data[3]))
for row in df.itertuples():
fig.add_annotation(xref='x', yref='y',
x=row.End_Date+datetime.timedelta(days=1),
y=row.Task_Name,
showarrow=False,
text='{:.0%}'.format(row.Percentage_complete)
)
names = set()
fig.for_each_trace(
lambda trace:
trace.update(showlegend=False)
if (trace.name in names) else names.add(trace.name))
fig.update_layout(fig1.layout)
fig.update_yaxes(autorange="reversed")
fig.show()
