4

我正在使用 plotly express 时间线在此示例之后生成甘特图:https ://medium.com/dev-genius/gantt-charts-in-python-with-plotly-e7213f932f1e

它会自动将 x 轴设置为使用日期,但我实际上只想使用整数(即 Project Kick-Off +1、Project Kick-Off +6 等)。

有没有办法让时间线图不使用 xaxis 的日期?

如果我尝试使用整数,它会将它们视为毫秒。

4

4 回答 4

8

答案:

是的,有可能!只需将整数作为开始和结束“日期”,计算它们之间的差异 ( delta),然后对您的 进行以下更改fig

fig.layout.xaxis.type = 'linear'
fig.data[0].x = df.delta.tolist()

阴谋

在此处输入图像描述

细节:

实际上有一种方法可以实现这一点,尽管文档指出:

px.timeline 函数默认将 X 轴设置为 type=date,因此可以像任何时间序列图一样进行配置。

因此,其中的所有其他功能px.timeline()似乎都围绕着这一事实。但是,如果您只是忽略这一点并使用整数作为Startand的值Finish,那么您可以调整一些属性以获得您想要的。您只需要计算每个Start和之间的差异Stop。例如像这样:

df = pd.DataFrame([
    dict(Task="Job A", Start=1, Finish=4),
    dict(Task="Job B", Start=2, Finish=6),
    dict(Task="Job C", Start=3, Finish=10)
])
df['delta'] = df['Finish'] - df['Start']

然后进一步调整:

fig.layout.xaxis.type = 'linear'
fig.data[0].x = df.delta.tolist()

完整代码:

import plotly.express as px
import pandas as pd

df = pd.DataFrame([
    dict(Task="Job A", Start=1, Finish=4),
    dict(Task="Job B", Start=2, Finish=6),
    dict(Task="Job C", Start=3, Finish=10)
])
df['delta'] = df['Finish'] - df['Start']

fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task")
fig.update_yaxes(autorange="reversed") 

fig.layout.xaxis.type = 'linear'
fig.data[0].x = df.delta.tolist()
f = fig.full_figure_for_development(warn=False)
fig.show()
于 2021-02-06T17:20:06.813 回答
4

当我们必须指定时,我认为这比上面的解决方案简单得多color

for d in fig.data:
  filt = df['color'] == d.name
  d.x = df[filt]['Delta'].tolist()
于 2021-08-19T05:10:36.037 回答
2

我尝试了此处列出的其他答案,但如果我指定color. 如果我尝试,数据fig.data有多个Bar对象,我认为它不包含分配所有增量所需的数据。但是,我确实发现我可以对plotly 代码进行monkeypatch以不将其转换为时间对象,并且我得到了正确的结果:

import plotly.express as px
import pandas as pd

def my_process_dataframe_timeline(args):
    """
    Massage input for bar traces for px.timeline()
    """
    print("my method")
    args["is_timeline"] = True
    if args["x_start"] is None or args["x_end"] is None:
        raise ValueError("Both x_start and x_end are required")

    x_start = args["data_frame"][args["x_start"]]
    x_end = args["data_frame"][args["x_end"]]

    # note that we are not adding any columns to the data frame here, so no risk of overwrite
    args["data_frame"][args["x_end"]] = (x_end - x_start)
    args["x"] = args["x_end"]
    del args["x_end"]
    args["base"] = args["x_start"]
    del args["x_start"]
    return args
px._core.process_dataframe_timeline = my_process_dataframe_timeline

df = pd.DataFrame([
    dict(Task="Job A", Start=1, Finish=4, color="1"),
    dict(Task="Job B", Start=2, Finish=6, color="2"),
    dict(Task="Job C", Start=3, Finish=10, color="1")
])
df['delta'] = df['Finish'] - df['Start']

fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="color")
fig.update_yaxes(autorange="reversed") 

fig.layout.xaxis.type = 'linear'
fig.show()

显然不希望这样做......获得正式支持会很好。

于 2021-04-09T20:27:09.270 回答
0

为了说明 JounghooLee 的答案是如何工作的,我想添加这个例子

import plotly.express as px
import pandas as pd

df = pd.DataFrame([
    dict(Task="Job A", Start=1, Finish=10),
    dict(Task="Job B", Start=3, Finish=6),
    dict(Task="Job C", Start=3, Finish=10)
])

df['delta'] = df['Finish'] - df['Start']

fig = px.timeline(df, x_start="Start", x_end="Finish", y="Task", color="Task")


print(fig.data[0].x)
print(fig.data[1].x)
print(fig.data[2].x)

a = [True, False, False]
b = [False, True, False]
c = [False, False, True]

aSeries = pd.Series(a)
bSeries = pd.Series(b)
cSeries = pd.Series(c)

fig.layout.xaxis.type = 'linear'

# the dataFrame df is filtered by the pandas series, to add the specific delta to each of the bars
fig.data[0].x = df[aSeries]['delta'].tolist()
fig.data[1].x = df[bSeries]['delta'].tolist()
fig.data[2].x = df[cSeries]['delta'].tolist()

print(fig.data[0].x)
print(fig.data[1].x)
print(fig.data[2].x)


fig.show()

给出以下prints输出:

[0.]
[0.]
[0.]
(9,)
(3,)
(7,)

并且fig.data包含三个栏

在此处输入图像描述

如果没有color分配,它就不起作用,因为 thenfig.data只包含 1 条

在此处输入图像描述

print(fig.data[0].x)回报_

[0. 0. 0.]

在这种情况下。

另请参阅此 https://stackoverflow.com/a/71141827/7447940

于 2022-02-16T11:58:32.163 回答