Reputation: 225
Is it possible to add a gantt plot to a fig created with make_subplots that contains go.Scatter time series plots. I have set shared_xaxes=true and fixedrange=True for the y-axis in the subplot, so the go.Scatter plots are linked and zoom in and out together on the x-axis.
My goal, at a minimum, is to line the x-axis of the go.Scatter plots up with the x-axis of the gantt plot. Currently I have added the subplot and the gantt plot, created by px.timeline, to an HTML page as two separate figures and they don't quite line up. Ideally I would like the x-axis of the gantt plot to be linked to the go.Scatter plots so they zoom in and out together.
Building off of Rob's answer and in response to Derek's comment, here is an example of what I am trying to do with sub plots.
import plotly.express as px
import pandas as pd
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=2, cols=1, subplot_titles = ('Scatter1', 'Scatter2'), shared_xaxes=True)
df = pd.DataFrame(
[
dict(Task="Job A", Start="2009-01-01", Finish="2009-02-28", Resource="Alex"),
dict(Task="Job B", Start="2009-03-05", Finish="2009-04-15", Resource="Alex"),
dict(Task="Job C", Start="2009-02-20", Finish="2009-05-30", Resource="Max"),
]
)
df["Start"] = pd.to_datetime(df["Start"])
df["Finish"] = pd.to_datetime(df["Finish"])
fig2 = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Resource")
#fig2.update_yaxes(autorange="reversed")
df2 = pd.DataFrame(
{
"Date": pd.date_range(
df.loc[:, ["Start", "Finish"]].values.min(),
df.loc[:, ["Start", "Finish"]].values.max(),
freq="W-MON",
)
}
).pipe(lambda d: d.assign(Value=np.random.randint(1, 20, len(d))))
df3 = pd.DataFrame(
{
"Date": pd.date_range(
df.loc[:, ["Start", "Finish"]].values.min(),
df.loc[:, ["Start", "Finish"]].values.max(),
freq="W-MON",
)
}
).pipe(lambda d: d.assign(Value=np.random.randint(1, 20, len(d))))
trace1 = go.Scatter(x=df2.Date, y=df2.Value)
trace2 = go.Scatter(x=df3.Date, y=df3.Value)
fig.add_trace(trace1, row=1, col=1)
fig.add_trace(trace2, row=2, col=1)
fig.update_yaxes(fixedrange=True)
fig.update_layout(xaxis1_showticklabels=True, xaxis2_showticklabels=True)
fig.show()
fig2.show()
Which yields three plots. The two scatter plots in the subplot are aligned, the third gantt plot isn't.
Ideally, I would like to add the gantt plot to the subplot with another add_trace command specifying col3, row1. I have been unable to do that successfully so far. If I can't add the gantt plot to the subplot, I would like to align the x-axis' so they are the same width and the dates align vertically.
If I add the gantt plot to the subplot like this
fig.add_trace(fig2.data[0], row=3, col=1)
The plot is displayed incorrectly, as shown below.
I believe that add_trace is not correctly interpreting the base and x fields of the fig2.data shown below. Instead of adding the units in the x field to the dates in base, it is plotting them as numerical.
(Bar({
'alignmentgroup': 'True',
'base': array([datetime.datetime(2009, 1, 1, 0, 0),
datetime.datetime(2009, 3, 5, 0, 0)], dtype=object),
'hovertemplate': 'Resource=Alex<br>Start=%{base}<br>Finish=%{x}<br>Task=%{y}<extra></extra>',
'legendgroup': 'Alex',
'marker': {'color': '#636efa'},
'name': 'Alex',
'offsetgroup': 'Alex',
'orientation': 'h',
'showlegend': True,
'textposition': 'auto',
'x': array([5.0112e+09, 3.5424e+09]),
'xaxis': 'x',
'y': array(['Job A', 'Job B'], dtype=object),
'yaxis': 'y'
})
Upvotes: 1
Views: 2060
Reputation: 225
The way to do this is to pass the gantt figure to make_subplots as a parameter.
import plotly.express as px
import pandas as pd
import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go
df = pd.DataFrame(
[
dict(Task="Job A", Start="2009-01-01", Finish="2009-02-28", Resource="Alex"),
dict(Task="Job B", Start="2009-03-05", Finish="2009-04-15", Resource="Alex"),
dict(Task="Job C", Start="2009-02-20", Finish="2009-05-30", Resource="Max"),
]
)
df["Start"] = pd.to_datetime(df["Start"])
df["Finish"] = pd.to_datetime(df["Finish"])
fig2 = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Resource")
df2 = pd.DataFrame(
{
"Date": pd.date_range(
df.loc[:, ["Start", "Finish"]].values.min(),
df.loc[:, ["Start", "Finish"]].values.max(),
freq="W-MON",
)
}
).pipe(lambda d: d.assign(Value=np.random.randint(1, 20, len(d))))
df3 = pd.DataFrame(
{
"Date": pd.date_range(
df.loc[:, ["Start", "Finish"]].values.min(),
df.loc[:, ["Start", "Finish"]].values.max(),
freq="W-MON",
)
}
).pipe(lambda d: d.assign(Value=np.random.randint(1, 20, len(d))))
trace1 = go.Scatter(x=df2.Date, y=df2.Value)
trace2 = go.Scatter(x=df3.Date, y=df3.Value)
fig = make_subplots(rows=3, cols=1, figure=fig2, shared_xaxes=True)
fig.add_trace(trace1, row=2, col=1)
fig.add_trace(trace2, row=3, col=1)
fig.update_layout(xaxis1_showticklabels=True, xaxis2_showticklabels=True, xaxis3_showticklabels=True)
fig.show()
Upvotes: 0
Reputation: 31226
import plotly.express as px
import pandas as pd
import numpy as np
df = pd.DataFrame(
[
dict(Task="Job A", Start="2009-01-01", Finish="2009-02-28", Resource="Alex"),
dict(Task="Job B", Start="2009-03-05", Finish="2009-04-15", Resource="Alex"),
dict(Task="Job C", Start="2009-02-20", Finish="2009-05-30", Resource="Max"),
]
)
df["Start"] = pd.to_datetime(df["Start"])
df["Finish"] = pd.to_datetime(df["Finish"])
fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Resource")
fig.update_yaxes(autorange="reversed")
df2 = pd.DataFrame(
{
"Date": pd.date_range(
df.loc[:, ["Start", "Finish"]].values.min(),
df.loc[:, ["Start", "Finish"]].values.max(),
freq="W-MON",
)
}
).pipe(lambda d: d.assign(Value=np.random.randint(1, 20, len(d))))
fig.add_traces(
px.scatter(df2, x="Date", y="Value").update_traces(yaxis="y2").data
).update_layout(
yaxis2={"overlaying": "y", "side": "right"}, xaxis={"domain": [0, 0.98]}
)
Upvotes: 1