将 go.Scatter 个绘图和甘特图添加到同一个 plotly 子图中

Add go.Scatter plots and gantt plot to the same plotly subplot

是否可以将甘特图添加到使用 make_subplots 创建的包含 go.Scatter 时间序列图的图中。我已经为子图中的 y 轴设置了 shared_xaxes=true 和 fixedrange=True,因此 go.Scatter 图被链接起来并在 x 轴上一起放大和缩小。

我的目标至少是将 go.Scatter 图的 x 轴与甘特图的 x 轴对齐。目前,我已将由 px.timeline 创建的子图和甘特图作为两个单独的图形添加到 HTML 页面,但它们并没有完全对齐。理想情况下,我希望将甘特图的 x 轴链接到 go.Scatter 图,以便它们一起放大和缩小。

根据 Rob 的回答和对 Derek 的评论的回应,这里是我尝试处理子图的示例。

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()

这会产生三个地块。子图中的两个散点图是对齐的,第三个甘特图不是。

理想情况下,我想使用另一个指定 col3、row1 的 add_trace 命令将甘特图添加到子图中。到目前为止,我一直无法成功地做到这一点。如果我不能将甘特图添加到子图中,我想对齐 x 轴,使它们具有相同的宽度并且日期垂直对齐。

如果我像这样将甘特图添加到子图中

fig.add_trace(fig2.data[0], row=3, col=1)

剧情显示不正确,如下图

我认为 add_trace 没有正确解释下面显示的 fig2.data 的基数和 x 字段。它不是将 x 字段中的单位添加到基础中的日期,而是将它们绘制为数字。

(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'
})
  • 你没有提供样本数据,所以模拟了。假设散点图的 y 值与甘特图的 y 值不同
  • 向图形添加 散点图 并适当配置坐标轴的简单案例
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]}
)

这样做的方法是将甘特图作为参数传递给make_subplots。

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()