Plotly : 두 개의 수직선 사이에 채우기 색상을 설정하는 방법은 무엇입니까?

Aug 20 2020

matplotlib를 사용하면 fill_between()다음 예제와 같이 두 개의 수직선 사이의 영역을 "사소하게"채울 수 있습니다 .

https://matplotlib.org/3.2.1/gallery/lines_bars_and_markers/fill_between_demo.html#selectively-marking-horizontal-regions-across-the-whole-axes

matplotlib를 사용하여 필요한 것을 만들 수 있습니다.

우리는 두 개의 신호를 가지고 있습니다. 저는 롤링 / 움직이는 Pearson과 Spearman의 상관 관계를 계산하고 있습니다. 상관 관계가 -0.5 미만이거나 0.5 이상이면 기간을 음영 처리하고 싶습니다 (Pearson의 경우 파란색, Spearman의 경우 주황색). 또한 모든 플롯에서 주말을 회색으로 어둡게합니다.

그러나 Plotly를 사용하여 동일한 작업을 수행하기가 어렵습니다. 그리고 두 개의 수평선 사이에서 수행하는 방법을 아는 것도 도움이 될 것입니다.

여러 플롯의 시각화 속도를 높이기 위해 Plotly 및 Dash를 사용하고 있습니다. 사용자는보다 "동적 유형"을 요구했습니다. 그러나 나는 GUI 전문가가 아니며 초기 결과를 제공해야하지만 이것에 시간을 할애 할 수 없습니다.

BTW, 나는 과거에 Bokeh를 시도했지만 기억할 수없는 이유로 포기했습니다. 주요 개발 도구 인 Python 또는 R에서 사용할 수 있으므로 Plotly가 좋아 보입니다.

감사,

카를로스

답변

4 DerekO Aug 20 2020 at 04:35

matplotlib의 fill_between()방법 과 동일한 내장 Plotly 방법이 있다고 생각하지 않습니다 . 그러나 모양을 그릴 수 있으므로 가능한 해결 방법은 회색 사각형을 그리고 layer="below"신호가 계속 표시되도록 매개 변수를 설정하는 것 입니다. 축 범위 밖에있는 직사각형의 좌표를 설정하여 직사각형이 플롯의 가장자리까지 확장되도록 할 수도 있습니다.

비슷한 방식으로 직사각형을 그리고 축 범위를 설정하여 수평선 사이의 영역을 채울 수 있습니다.

import numpy as np
import plotly.graph_objects as go

x = np.arange(0, 4 * np.pi, 0.01)
y = np.sin(x)

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=x,
    y=y
))

# hard-code the axes
fig.update_xaxes(range=[0, 4 * np.pi])
fig.update_yaxes(range=[-1.2, 1.2])

# specify the corners of the rectangles
fig.update_layout(
    shapes=[
    dict(
        type="rect",
        xref="x",
        yref="y",
        x0="4",
        y0="-1.3",
        x1="5",
        y1="1.3",
        fillcolor="lightgray",
        opacity=0.4,
        line_width=0,
        layer="below"
    ),
    dict(
        type="rect",
        xref="x",
        yref="y",
        x0="9",
        y0="-1.3",
        x1="10",
        y1="1.3",
        fillcolor="lightgray",
        opacity=0.4,
        line_width=0,
        layer="below"
    ),
    ]
)

fig.show()

4 vestland Aug 20 2020 at 05:53

데이터 샘플을 제공하지 않았으므로 사용자 지정 함수를 사용하여 여러 범주에 대해 정의 된 시작 및 중지 날짜가있는 여러 셰이프를 추가 할 수있는 방법을 보여주기 위해 종합 시계열을 사용하겠습니다. bgLevel


그 사이에 채워진 두 개의 수직선은 매우 빠르게 직사각형으로 바뀝니다. 그리고 직사각형은 fig.add_shape. 아래 예는 특정 기준으로 지정된 기간의 시작 및 중지 날짜를 찾는 방법을 보여줍니다. 귀하의 경우 이러한 기준은 변수의 값이 특정 수준보다 높거나 낮은 지 여부입니다.

트레이스 대신 모양을 사용하면를 사용 fig.add_trace()하여 플롯 레이어와 관련된 위치를 정의 할 수 있습니다 layer='below'. 그리고 모양 윤곽선은 line=dict(color="rgba(0,0,0,0)).

그림 1 : 랜덤 데이터가있는 시계열 그림 :

플롯 2 : 다음과 같은 경우 배경이 불투명 회색으로 설정됩니다 A > 100.

플롯 2 : 배경도 다음과 같은 경우 불투명 한 빨간색으로 설정됩니다.D < 60

완전한 코드 :

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
nperiods = 200
np.random.seed(123)
df = pd.DataFrame(np.random.randint(-10, 12, size=(nperiods, 4)),
                  columns=list('ABCD'))
datelist = pd.date_range(datetime.datetime(2020, 1, 1).strftime('%Y-%m-%d'),periods=nperiods).tolist()
df['dates'] = datelist 
df = df.set_index(['dates'])
df.index = pd.to_datetime(df.index)
df.iloc[0] = 0
df = df.cumsum().reset_index()

# function to set background color for a
# specified variable and a specified level



# plotly setup
fig = px.line(df, x='dates', 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)')

def bgLevels(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())['dates'].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 = bgLevels(fig = fig, variable = 'A', level = 100, mode = 'above',
               fillcolor = 'rgba(100,100,100,0.2)', layer = 'below')

fig = bgLevels(fig = fig, variable = 'D', level = -60, mode = 'below',
               fillcolor = 'rgba(255,0,0,0.2)', layer = 'below')

fig.show()