1

plotly plotly.express.timeline 很棒,但创造了它自己的形象。似乎我需要将此视觉效果嵌入到 FigureWidget 中,以使其与 Jupyter Notebook 中的布局搭配得很好。所以我试图使用 px.timeline() 所基于的 plotly.graph_objects.Bar() 重新创建绘图。

不幸的是,我不知道如何做到这一点。似乎条形的值被添加到不用作绝对位置的“基本”向量(作为相对值)中。Plotly 似乎不理解 datetime.timedelta() 对象。打印时间线()图形版本将值显示为浮点值数组,不清楚它们是如何计算的。我试过简单地复制它们,但这最终会导致认为 x 轴不是日期时间轴。

任何线索都将受到欢迎。如何使用 Box() 绘制适当的图形,或者如何在笔记本中嵌入/动画/布局 px.timeline() 图形。

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime

# the data:
df = pd.DataFrame([
    dict(Task="one", Start=datetime(2009,1,1), Finish=datetime(2009,4,28)),
    dict(Task="two", Start=datetime(2009,5,5), Finish=datetime(2009,7,15)),
    dict(Task="three", Start=datetime(2009,7,20), Finish=datetime(2009,9,30))
])

# working plotly express figure:
pxfig = px.timeline(df, x_start="Start", x_end="Finish", y="Task")
pxfig.show() # looks great

# Broken bar figure:
plainfig = go.Figure()
plainfig.add_bar(base=df['Start'],
#                 x=pxfig.data[0].x,  # this breaks the axis as they are not of type datetime.
#                 x=df['Finish']-df['Start'], # this doesn't produce the right plot
                 x=df['Finish'], # these appear to be relative to base, not absolute
                 y=df['Task'], orientation='h')

plainfig.show()

# looking at the two shows interesting differences in the way the x data is stored
print(pxfig)
print(plainfig)

时间线图 箱形图

Figure({
    'data': [{'alignmentgroup': 'True',
          'base': array([datetime.datetime(2009, 1, 1, 0, 0),
                         datetime.datetime(2009, 5, 5, 0, 0),
                         datetime.datetime(2009, 7, 20, 0, 0)], dtype=object),
          'x': array([1.01088e+10, 6.13440e+09, 6.22080e+09]),
          'xaxis': 'x',
          'y': array(['one', 'two', 'three'], dtype=object),
          'yaxis': 'y'}],
    'layout': {'barmode': 'overlay',
           'legend': {'tracegroupgap': 0},
           'margin': {'t': 60},
           'template': '...',
           'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'type': 'date'},
           'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'Task'}}}
})
Figure({
    'data': [{'base': array([datetime.datetime(2009, 1, 1, 0, 0),
                         datetime.datetime(2009, 5, 5, 0, 0),
                         datetime.datetime(2009, 7, 20, 0, 0)], dtype=object),
          'orientation': 'h',
          'type': 'bar',
          'x': array([datetime.datetime(2009, 4, 28, 0, 0),
                      datetime.datetime(2009, 7, 15, 0, 0),
                      datetime.datetime(2009, 9, 30, 0, 0)], dtype=object),
          'y': array(['one', 'two', 'three'], dtype=object)}],
    'layout': {'template': '...'}
})
4

1 回答 1

0

I can't answer how to embed the timeline in a FigureWidget, but I think I have the answer to your original problem of getting the timeline to play nicely with the jupyter notebook layout. I'm guessing you want to be able to update the timeline interactively?

I have gotten around this problem by embedding the figure produced by px.timeline in an output widget. Then whenever I need the figure to be updated (from a button callback, for example) I just clear the output in the output widget, create a new timeline figure and display that new figure. It's not the most elegant way of doing things but it gets the job done.

import ipywidgets as widgets
from IPython.display import display, clear_output
import pandas as pd
import plotly.express as px
from datetime import datetime

output = widgets.Output()

df = pd.DataFrame([
    dict(Task="one", Start=datetime(2009,1,1), Finish=datetime(2009,4,28)),
    dict(Task="two", Start=datetime(2009,5,5), Finish=datetime(2009,7,15)),
    dict(Task="three", Start=datetime(2009,7,20), Finish=datetime(2009,9,30))
])

updated_df = pd.DataFrame([
    dict(Task="one", Start=datetime(2009,1,1), Finish=datetime(2009,4,28)),
    dict(Task="two", Start=datetime(2009,5,5), Finish=datetime(2009,7,15)),
    dict(Task="three", Start=datetime(2009,7,20), Finish=datetime(2009,9,30)),
    dict(Task="four", Start=datetime(2009,10,5), Finish=datetime(2009,10,10))
])

# display the original timeline figure
pxfig = px.timeline(df, x_start="Start", x_end="Finish", y="Task")
with output:
    display(pxfig)

# create a button which when pressed will update the timeline figure
button = widgets.Button(description='update figure')
def on_click(button):
    with output:
        clear_output()
        new_pxfig = px.timeline(updated_df, x_start="Start", x_end="Finish", y="Task")
        display(new_pxfig)
button.on_click(on_click)

display(button)
于 2021-03-25T10:00:57.480 回答