Plotly:2本の垂直線の間に塗りつぶしの色を設定するにはどうすればよいですか?

Aug 20 2020

matplotlibを使用するfill_between()と、次の例のように、2本の垂直線の間の領域を「簡単に」埋めることができます。

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

matplotlibを使用して、必要なものを作成できます。

2つの信号があり、ローリング/移動するピアソンとスピアマンの相関を計算しています。相関が-0.5未満または0.5を超える場合は、期間に陰影を付けます(ピアソンの場合は青、スピアマンの場合はオレンジ)。また、すべてのプロットで週末を灰色で暗くします。

しかし、Plotlyを使用して同じことを達成するのに苦労しています。また、2本の水平線の間でそれを行う方法を知ることも役立ちます。

PlotlyとDashを使用して、いくつかのプロットの視覚化を高速化していることに注意してください。ユーザーはもっと「ダイナミックなタイプのもの」を求めました。ただし、私はGUIの専門家ではないため、初期の結果を提供する必要はありますが、これに時間を費やすことはできません。

ところで、私は過去にボケを試しましたが、なぜか思い出せないので諦めました。私の主な開発ツールである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


間に塗りつぶしがある2本の垂直線は、すぐに長方形に変わります。また、長方形は、を使用して形状として簡単に追加できます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()