Plotly: จะกำหนดสีเติมระหว่างเส้นแนวตั้งสองเส้นได้อย่างไร?
การใช้ 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 ฉันสามารถทำสิ่งที่ต้องการได้:

เรามีสัญญาณสองแบบและฉันกำลังคำนวณความสัมพันธ์ของเพียร์สันและสเปียร์แมนที่กำลังเคลื่อนที่ / เคลื่อนที่ เมื่อความสัมพันธ์ต่ำกว่า -0.5 หรือสูงกว่า 0.5 ฉันต้องการแรเงาช่วงเวลา (สีน้ำเงินสำหรับ Pearson และสีส้มสำหรับ Spearman's) ฉันยังทำให้วันหยุดสุดสัปดาห์มืดลงด้วยสีเทาในทุกแปลง
อย่างไรก็ตามฉันพบช่วงเวลาที่ยากลำบากในการทำแบบเดียวกันโดยใช้ Plotly และจะเป็นประโยชน์เช่นกันหากทราบวิธีทำระหว่างเส้นแนวนอนสองเส้น
โปรดทราบว่าฉันใช้ Plotly และ Dash เพื่อเร่งการแสดงภาพของหลาย ๆ แปลง ผู้ใช้ถามถึง "ประเภทไดนามิก" มากขึ้น อย่างไรก็ตามฉันไม่ใช่คน GUI และไม่สามารถใช้เวลากับเรื่องนี้ได้แม้ว่าฉันต้องการให้อาหารพวกเขาด้วยผลลัพธ์เบื้องต้นก็ตาม
BTW ที่ผ่านมาฉันลอง Bokeh และยอมแพ้ด้วยเหตุผลบางอย่างที่ฉันจำไม่ได้ ค่อนข้างดูดีเพราะฉันสามารถใช้ได้ทั้งจาก Python หรือ R ซึ่งเป็นเครื่องมือพัฒนาหลักของฉัน
ขอบคุณ
คาร์ลอส
คำตอบ
ฉันไม่คิดว่าจะมีวิธี Plotly ในตัวที่เทียบเท่ากับfill_between()
วิธีของ matplotlib อย่างไรก็ตามคุณสามารถวาดรูปทรงได้ดังนั้นวิธีแก้ปัญหาที่เป็นไปได้คือการวาดสี่เหลี่ยมผืนผ้าสีเทาและตั้งค่าพารามิเตอร์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()

คุณไม่ได้ให้ตัวอย่างข้อมูลดังนั้นฉันจะใช้อนุกรมเวลาแบบสังเคราะห์เพื่อแสดงให้คุณเห็นว่าคุณสามารถเพิ่มรูปทรงจำนวนหนึ่งพร้อมวันที่เริ่มต้นและวันหยุดที่กำหนดไว้สำหรับหมวดหมู่ต่างๆโดยใช้ฟังก์ชันที่กำหนดเองได้อย่างไร bgLevel
เส้นแนวตั้งสองเส้นที่มีช่องว่างระหว่างกันจะเปลี่ยนเป็นสี่เหลี่ยมผืนผ้าอย่างรวดเร็ว fig.add_shape
และสี่เหลี่ยมสามารถเพิ่มเป็นรูปร่างโดยใช้ ตัวอย่างด้านล่างจะแสดงวิธีค้นหาวันที่เริ่มต้นและวันหยุดสำหรับช่วงเวลาที่กำหนดโดย critera บางรายการ ในกรณีของคุณเกณฑ์เหล่านี้คือค่าของตัวแปรสูงหรือต่ำกว่าระดับหนึ่งหรือไม่
การใช้รูปทรงแทนร่องรอยด้วยจะช่วยให้คุณกำหนดตำแหน่งที่เกี่ยวกับพล็อตโดยใช้ชั้น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()