如何在plotly中将时间线图与散点图结合起来

问题描述 投票:0回答:1

我有一个数据框

df
,其中包含随时间变化的值(过程数据)。我有一个数据框
ef
,其中包含具有开始时间和结束时间的事件(警报)。我想以一种美观的方式将它们组合在一个图中。

"""
df==
+---------------------+------------+------------+------------+
|                     |   processA |   processB |   processC |
|---------------------+------------+------------+------------|
| 2020-01-01 00:00:00 |    101.764 |   20.0079  |   0.978738 |
| 2020-01-01 00:01:00 |    102.241 |   93.3779  |  -0.977278 |
| 2020-01-01 00:02:00 |    100.95  |   -7.56786 |  -0.103219 |
| 2020-01-01 00:03:00 |    100.411 |    7.20218 |   1.45427  |
| 2020-01-01 00:04:00 |    100.761 |    6.08375 |   0.443863 |
+---------------------+------------+------------+------------+

ef==
+----+-----------------------------------------+---------------------+---------------------+----------+
|    | alm                                     | Start               | Finish              | almid    |
|----+-----------------------------------------+---------------------+---------------------+----------|
|  0 | alarm A something something has alarmed | 2020-01-01 00:00:30 | 2020-01-01 00:01:30 | alm_id A |
|  1 | alarm B something else happened         | 2020-01-01 00:01:30 | 2020-01-01 00:02:30 | alm_id B |
|  2 | alarm A something something has alarmed | 2020-01-01 00:02:00 | 2020-01-01 00:09:30 | alm_id A |
+----+-----------------------------------------+---------------------+---------------------+----------+
"""

我从plotly的文档中收集到的内容,

.create_gantt()
已被弃用。推荐的方法是
.timeline()
。我还没有弄清楚如何在
.timeline()
图中自定义任何内容,到目前为止我所拥有的是:

直接关注的问题是:如何自定义条形的位置和宽度。 y 轴上的警报(红色)刻度占用了大量空间,如何更优雅地传达信息。
一个更大的问题是我是否采取了错误的方法?有没有更好的方法(新的图表类型,不同图表的组合)来做到这一点?

PS. 起点:

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import numpy as np
import plotly.io as pio
pio.renderers.default = "browser"

np.random.seed(0)
rowcounts = 10
df = pd.DataFrame(
    index = pd.date_range(start=pd.Timestamp('2020-01-01'), freq = 'min', periods=rowcounts, ),
    data = np.random.randn(rowcounts, 3), columns=['process'+ x for x in list('ABC')],
)
df.processA += 100
df.processB *= 50

idx = pd.date_range(start=pd.Timestamp('2020-01-01'), freq = '30S', periods=rowcounts*2, )
ef = pd.DataFrame([
    dict(alm="alarm A something something has alarmed", Start=idx[1], Finish=idx[3], almid="alm_id A"),
    dict(alm="alarm B something else happened", Start=idx[3], Finish=idx[5], almid="alm_id B"),
    dict(alm="alarm A something something has alarmed", Start=idx[4], Finish=idx[-1], almid="alm_id A")
])

"""
df==
+---------------------+------------+------------+------------+
|                     |   processA |   processB |   processC |
|---------------------+------------+------------+------------|
| 2020-01-01 00:00:00 |    101.764 |   20.0079  |   0.978738 |
| 2020-01-01 00:01:00 |    102.241 |   93.3779  |  -0.977278 |
| 2020-01-01 00:02:00 |    100.95  |   -7.56786 |  -0.103219 |
| 2020-01-01 00:03:00 |    100.411 |    7.20218 |   1.45427  |
| 2020-01-01 00:04:00 |    100.761 |    6.08375 |   0.443863 |
+---------------------+------------+------------+------------+

ef==
+----+-----------------------------------------+---------------------+---------------------+----------+
|    | alm                                     | Start               | Finish              | almid    |
|----+-----------------------------------------+---------------------+---------------------+----------|
|  0 | alarm A something something has alarmed | 2020-01-01 00:00:30 | 2020-01-01 00:01:30 | alm_id A |
|  1 | alarm B something else happened         | 2020-01-01 00:01:30 | 2020-01-01 00:02:30 | alm_id B |
|  2 | alarm A something something has alarmed | 2020-01-01 00:02:00 | 2020-01-01 00:09:30 | alm_id A |
+----+-----------------------------------------+---------------------+---------------------+----------+
"""

fig = px.timeline(
    ef, x_start="Start", x_end="Finish", y="alm", color="almid",
    color_discrete_map={
        "alm_id A": 'rgba(222, 111, 222, .2)',
        "alm_id B": 'rgba(111, 222, 222, .2)',
    }
)

myfont=dict(
    color="red",
    family="monospace",
    size=14,
)
for c in df.columns:
    fig = fig.add_trace(
        go.Scatter(
            x=df.index,
            y=df[c],
            name = c,
            yaxis = 'y2',
            hovertemplate = '%{y} <extra></extra>',
        ))
    
fig = fig.update_layout(
    xaxis=dict(
        type="date",
        domain=[0.15,1],
        range = [idx[2], idx[10]],
        rangeslider=dict(
            autorange=True,
            visible=True,
        ),
    ),
    yaxis=dict(
        title="alarms",
        titlefont=myfont,
        tickfont=myfont,
    ),
    yaxis2=dict(
        title="processes",
        anchor="free",
        overlaying="y",
        side="left",
        position=0.05
    ),
)

fig = fig.update_yaxes(showline=True, linewidth=2, linecolor='black')
fig.show()
python pandas plotly plotly-dash
1个回答
0
投票

一种可能的选择是这样做:

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import numpy as np
import plotly.io as pio

np.random.seed(0)
rowcounts = 10
df = pd.DataFrame(
    index = pd.date_range(start=pd.Timestamp('2020-01-01'), freq = 'min', periods=rowcounts, ),
    data = np.random.randn(rowcounts, 3), columns=['process'+ x for x in list('ABC')],
)
df.processA += 100
df.processB *= 50

idx = pd.date_range(start=pd.Timestamp('2020-01-01'), freq = '30S', periods=rowcounts*2, )
ef = pd.DataFrame([
    dict(alm="alarm A something something has alarmed", Start=idx[1], Finish=idx[3], almid="alm_id A"),
    dict(alm="alarm B something else happened", Start=idx[3], Finish=idx[5], almid="alm_id B"),
    dict(alm="alarm A something something has alarmed", Start=idx[4], Finish=idx[-1], almid="alm_id A")
])

这是你的数据

                       processA   processB  processC
2020-01-01 00:00:00  101.764052  20.007860  0.978738
2020-01-01 00:01:00  102.240893  93.377900 -0.977278
2020-01-01 00:02:00  100.950088  -7.567860 -0.103219
2020-01-01 00:03:00  100.410599   7.202179  1.454274
2020-01-01 00:04:00  100.761038   6.083751  0.443863
2020-01-01 00:05:00  100.333674  74.703954 -0.205158
2020-01-01 00:06:00  100.313068 -42.704787 -2.552990
2020-01-01 00:07:00  100.653619  43.221810 -0.742165
2020-01-01 00:08:00  102.269755 -72.718284  0.045759
2020-01-01 00:09:00   99.812816  76.638961  1.469359

并绘制它

import plotly.graph_objects as go
import pandas as pd
import numpy as np


fig = go.Figure()

for process in df.columns:
    fig.add_trace(go.Scatter(x=df.index, y=df[process], mode='lines', name=process))

for _, alarm in ef.iterrows():
    fig.add_shape(type="rect",
                  x0=alarm['Start'], y0=0, x1=alarm['Finish'], y1=1,
                  xref='x', yref='paper',
                  fillcolor="Red", opacity=0.2, line_width=0, layer="below")

fig.update_layout(
    yaxis_title='Process Values',
    xaxis=dict(title='Time', domain=[0, 0.95]),
    legend_title='Process',
    hovermode="x unified",
    margin=dict(l=20, r=20, t=20, b=20),
    height=400, width=800,
)

fig.show()

这给出了

© www.soinside.com 2019 - 2024. All rights reserved.