为了账号安全,请及时绑定邮箱和手机立即绑定

Plotly:如何使用 For 循环突出显示具有矩形形状的 Pandas 时间序列中的某些时期?

Plotly:如何使用 For 循环突出显示具有矩形形状的 Pandas 时间序列中的某些时期?

九州编程 2023-10-06 19:30:36
我试图在 Plotly 中突出显示时间段。我似乎最好的方法是使用 Shapes,就像这样,但在现实世界中,您不想像示例 url 中那样手动添加每个形状。我认为 for 循环是最好的解决方案,但欢迎其他(计算量较小的)建议。我的脚本如下所示:np.random.seed(12345)rows = 20x = pd.Series(np.random.randn(rows),index=pd.date_range('1/1/2020', periods=rows)).cumsum()df = pd.DataFrame({"index": x})# add column showing what to shadedf["signal"] = df['index'] < 5# plot index and highlight periods with Rectangle Shapes in Plotlyfig = px.line(df, x=df.index, y="index")for row in df.iterrows():    if df['signal'] == False:        ply_shapes['shape_' + str(i)]=go.layout.Shape(type="rect",                                                            x0=df.dato[i-1],                                                            y0=0,                                                            x1=df.dato[i],                                                            y1=2000,                                                            opacity=0.5,                                                            layer="below"                                                        )lst_shapes=list(ply_shapes.values())fig.update_layout(shapes=lst_shapes)fig.show()但这返回:ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
查看完整描述

1 回答

?
临摹微笑

TA贡献1982条经验 获得超2个赞

您的代码片段无法工作的原因有多种。

1. iterrows()返回一个迭代器,其中包含每行的索引和每行中的数据作为seres。要使用它,您必须替换

for row in df.iterrows():
    if df['signal'] == False:

与(例如):

for row in df.iterrows():
    if row[1]['signal'] == True:

引发您的错误是因为您分配了一系列withTrue, False不是if df['signal'] == False:if row[1]['signal'将做的那样分配单个值。

但仅仅解决这个问题并不能帮助你。至少不在您的代码片段的范围内,因为:

2. dato您的示例数据框中不存在。

类似的问题之前已经被问过并回答过。但由于对于听起来非常不同的问题,解决方案是相似的,因此我决定也为您的用例制定一个自定义解决方案。


在这两种情况下,最好的方法在很大程度上取决于您如何在时间序列中识别和分配突出显示的时间段。以下示例将使用随机数据并根据阈值识别要突出显示的时间段。就像你的问题一样。

我的建议将归结为一个函数,highLights()该函数将一个绘图图、一个 pandas 系列和一个阈值作为输入,以及一些其他细节(看看文档字符串)。

highLights()具有一些示例输入的函数:

fig = highLights(fig = fig, variable = 'signal', level = 5, mode = 'above',
               fillcolor = 'rgba(200,0,200,0.2)', layer = 'below')

阴谋

https://img1.sycdn.imooc.com//651ff0220001fd1307880381.jpg

完整代码:

# imports

import numpy as np

import pandas as pd

import plotly.graph_objects as go

import plotly.express as px

import datetime


pd.set_option('display.max_rows', None)


# data sample

cols = ['signal']

nperiods = 200

np.random.seed(123)

df = pd.DataFrame(np.random.randint(-10, 12, size=(nperiods, len(cols))),

                  columns=cols)

datelist = pd.date_range(datetime.datetime(2020, 1, 1).strftime('%Y-%m-%d'),periods=nperiods).tolist()

df['dato'] = datelist 

df = df.set_index(['dato'])

df.index = pd.to_datetime(df.index)

df.iloc[0] = 0

df = df.cumsum().reset_index()


# plotly setup

fig = px.line(df, x='dato', y=df.columns[1:])

fig.update_xaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,255,0.1)')

fig.update_yaxes(showgrid=True, gridwidth=1, gridcolor='rgba(0,0,255,0.1)')



# function to set background color for a

# specified variable and a specified level

def highLights(fig, variable, level, mode, fillcolor, layer):

    """

    Set a specified color as background for given

    levels of a specified variable using a shape.

    

    Keyword arguments:

    ==================

    fig -- plotly figure

    variable -- column name in a pandas dataframe

    level -- int or float

    mode -- set threshold above or below

    fillcolor -- any color type that plotly can handle

    layer -- position of shape in plotly fiugre, like "below"

    

    """

    

    if mode == 'above':

        m = df[variable].gt(level)

    

    if mode == 'below':

        m = df[variable].lt(level)

        

    df1 = df[m].groupby((~m).cumsum())['dato'].agg(['first','last'])


    for index, row in df1.iterrows():

        #print(row['first'], row['last'])

        fig.add_shape(type="rect",

                        xref="x",

                        yref="paper",

                        x0=row['first'],

                        y0=0,

                        x1=row['last'],

                        y1=1,

                        line=dict(color="rgba(0,0,0,0)",width=3,),

                        fillcolor=fillcolor,

                        layer=layer) 

    return(fig)


fig = highLights(fig = fig, variable = 'signal', level = 5, mode = 'above',

               fillcolor = 'rgba(200,0,200,0.2)', layer = 'below')


fig.update_layout(template = 'plotly_dark')


fig.show()



查看完整回答
反对 回复 2023-10-06
  • 1 回答
  • 0 关注
  • 86 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信