我正在使用 plotly express 时间线在此示例之后生成甘特图:https ://medium.com/dev-genius/gantt-charts-in-python-with-plotly-e7213f932f1e
它会自动将 x 轴设置为使用日期,但我实际上只想使用整数(即 Project Kick-Off +1、Project Kick-Off +6 等)。
有没有办法让时间线图不使用 xaxis 的日期?
如果我尝试使用整数,它会将它们视为毫秒。
我正在使用 plotly express 时间线在此示例之后生成甘特图:https ://medium.com/dev-genius/gantt-charts-in-python-with-plotly-e7213f932f1e
它会自动将 x 轴设置为使用日期,但我实际上只想使用整数(即 Project Kick-Off +1、Project Kick-Off +6 等)。
有没有办法让时间线图不使用 xaxis 的日期?
如果我尝试使用整数,它会将它们视为毫秒。
是的,有可能!只需将整数作为开始和结束“日期”,计算它们之间的差异 ( delta
),然后对您的 进行以下更改fig
:
fig.layout.xaxis.type = 'linear'
fig.data[0].x = df.delta.tolist()
实际上有一种方法可以实现这一点,尽管文档指出:
px.timeline 函数默认将 X 轴设置为 type=date,因此可以像任何时间序列图一样进行配置。
因此,其中的所有其他功能px.timeline()
似乎都围绕着这一事实。但是,如果您只是忽略这一点并使用整数作为Start
and的值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()
当我们必须指定时,我认为这比上面的解决方案简单得多color
for d in fig.data:
filt = df['color'] == d.name
d.x = df[filt]['Delta'].tolist()
我尝试了此处列出的其他答案,但如果我指定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()
显然不希望这样做......获得正式支持会很好。
为了说明 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.]
在这种情况下。