Plotly:如何使用日期时间索引在中心绘制一条线的范围?

Plotly: How to plot a range with a line in the center using a datetime index?

我想绘制一条围绕它的范围的线,就像这张照片一样:

我发布了一个原始问题,但没有指定索引是日期时间索引。我以为这不重要,但我错了

有一个用数字索引覆盖它的答案:

和此处的文档:

https://plotly.com/python/continuous-error-bars/

但是日期时间索引的问题没有涉及。

这里是一些测试数据:

timestamp      price   min  mean   max  
1596267946298  100.0   100  100.5  101
1596267946299  101.0   100  100.5  101
1596267946300  102.0   98   99.5   102
1596267948301  99.0    98   99.5   102
1596267948302  98.0    98   99.5   102
1596267949303  99.0    98   995.   102

我希望带从最小值到最大值覆盖,平均值绘制在中心。

另一种选择是从上面发布的问题 () 的第一个答案中获取代码,并将数据生成更改为:

index = pd.date_range('1/1/2000', periods=25, freq='T')
df = pd.DataFrame(dict(A=np.random.uniform(low=-1, high=2, size=25).tolist(),
                       B=np.random.uniform(low=-4, high=3, size=25).tolist(),
                       C=np.random.uniform(low=-1, high=3, size=25).tolist()),
                  index=index)

这将以相同的方式工作,但会创建一个日期时间索引。

中的设置相比,问题在于 x+x[::-1] 不能很好地处理日期时间索引。但是如果你设置 x=df.index in:

# add line and shaded area for each series and standards deviation
for i, col in enumerate(df):
    new_col = next(line_color)
    # x = list(df.index.values+1)
    x = df.index

然后将x+x[::-1]替换为x=x.append(x[::-1]):

# standard deviation area
fig.add_traces(go.Scatter(
                            #x+x[::-1],
                            x=x.append(x[::-1]),

那么事情应该会很顺利。

剧情:

完整代码:

# imports
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np

# sample data in a pandas dataframe
np.random.seed(1)
df=pd.DataFrame(dict(A=np.random.uniform(low=-1, high=2, size=25).tolist(),
                    B=np.random.uniform(low=-4, high=3, size=25).tolist(),
                    C=np.random.uniform(low=-1, high=3, size=25).tolist(),
                    ))
df = df.cumsum()

# set daterange as index
df['dates'] = pd.date_range('2020', freq='D', periods=len(df))
df.set_index('dates', inplace=True)

# ---

# define colors as a list 
colors = px.colors.qualitative.Plotly

# convert plotly hex colors to rgba to enable transparency adjustments
def hex_rgba(hex, transparency):
    col_hex = hex.lstrip('#')
    col_rgb = list(int(col_hex[i:i+2], 16) for i in (0, 2, 4))
    col_rgb.extend([transparency])
    areacol = tuple(col_rgb)
    return areacol

rgba = [hex_rgba(c, transparency=0.2) for c in colors]
colCycle = ['rgba'+str(elem) for elem in rgba]

# Make sure the colors run in cycles if there are more lines than colors
def next_col(cols):
    while True:
        for col in cols:
            yield col
line_color=next_col(cols=colCycle)

# plotly  figure
fig = go.Figure()

# add line and shaded area for each series and standards deviation
for i, col in enumerate(df):
    new_col = next(line_color)
    x = df.index
    y1 = df[col]
    y1_upper = [(y + np.std(df[col])) for y in df[col]]
    y1_lower = [(y - np.std(df[col])) for y in df[col]]
    y1_lower = y1_lower[::-1]

    # standard deviation area
    fig.add_traces(go.Scatter(
                                #x+x[::-1],
                                x=x.append(x[::-1]),
                                y=y1_upper+y1_lower,
                                fill='tozerox',
                                fillcolor=new_col,
                                line=dict(color='rgba(255,255,255,0)'),
                                showlegend=False,
                                name=col))

    # line trace
    fig.add_traces(go.Scatter(x=df.index,
                              y=y1,
                              line=dict(color=new_col, width=2.5),
                              mode='lines',
                              name=col)
                                )
fig.update_layout(xaxis=dict(range=[df.index[1],df.index[-1]]))
fig.show()