You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Plotly子图添加形状:数字信号绘制问题求助

解决Plotly子图中为指定子图添加自定义形状的问题

问题描述

需要用Plotly绘制自定义格式的数字信号:信号值为0时显示细线,值为1时显示粗线。当前实现方式是绘制水平线,在值为1的区间添加填充矩形。但使用子图绘制多个信号时,所有形状只会显示在第一个子图中,需实现为任意子图添加对应形状。

用户原始代码:

import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go

#Creating digital signals in array
y=np.zeros((2,40))

x=np.arange(0,4,.1)

y[0,:]=np.sign(np.cos(x*np.pi))
y[1,:]=np.sign(np.cos(x*1.5*np.pi))
y[y==-1]=0


dig_signals = make_subplots(rows=2,cols=1,subplot_titles=["signal 1", "signal 2"]
                            ,shared_xaxes=True,x_title="time [sec]",vertical_spacing=.2)

for k in range(2):
    
    tiempo_flancos=[] #to save the amount of state changes

    if y[k,0]==1:
        tiempo_flancos.append(x[0])
        

    for i in range(1,len(x)):
        if y[k,i]!=y[k,i-1]:
            tiempo_flancos.append(x[i])
            
    
    if y[k,-1]==1:
        tiempo_flancos.append(x[-1])
    
    dictionaries=[] #this list is needed to create shapes in plotly
    for i in range(int(len(tiempo_flancos)/2)):
        dictionaries.append(dict(x0=tiempo_flancos[i*2],y0=.75,
                                 x1=tiempo_flancos[1+i*2],y1=-.75,
                                 line_width=0,fillcolor="steelblue"))

    dig_signals.add_trace(go.Scatter(x=x,y=np.repeat(0,len(x))),row=k+1,col=1)
    dig_signals.update_layout(yaxis=dict(range[-3,3]),showlegend=False,shapes=dictionaries)
    
    dig_signals.update_traces(line_color="steelblue", line_width=2.5)
    dig_signals.update_yaxes(visible=False)


dig_signals

解决方案

问题核心是:未指定形状所属的子图坐标轴,且每次循环调用update_layout(shapes=dictionaries)会覆盖之前的形状配置。需做以下修改:

  1. 为每个形状指定子图坐标轴:Plotly子图的坐标轴以x1/y1、x2/y2命名(对应第1/2个子图),在创建形状字典时添加xref和yref属性,明确指定形状归属的子图。
  2. 累加形状而非覆盖:每次循环将新生成的形状列表追加到布局的现有形状中,避免覆盖。
  3. 正确设置子图y轴范围:使用update_yaxes指定row参数,为每个子图设置y轴范围。

修改后的完整代码:

import numpy as np
from plotly.subplots import make_subplots
import plotly.graph_objects as go

# 创建数字信号数组
y = np.zeros((2, 40))
x = np.arange(0, 4, .1)

y[0, :] = np.sign(np.cos(x * np.pi))
y[1, :] = np.sign(np.cos(x * 1.5 * np.pi))
y[y == -1] = 0

dig_signals = make_subplots(rows=2, cols=1,
                            subplot_titles=["signal 1", "signal 2"],
                            shared_xaxes=True,
                            x_title="time [sec]",
                            vertical_spacing=.2)

for k in range(2):
    tiempo_flancos = []  # 存储状态变化的时间点
    if y[k, 0] == 1:
        tiempo_flancos.append(x[0])

    for i in range(1, len(x)):
        if y[k, i] != y[k, i-1]:
            tiempo_flancos.append(x[i])

    if y[k, -1] == 1:
        tiempo_flancos.append(x[-1])

    dictionaries = []
    # 为当前子图创建形状,指定xref和yref
    for i in range(int(len(tiempo_flancos)/2)):
        dictionaries.append(dict(
            x0=tiempo_flancos[i*2],
            y0=.75,
            x1=tiempo_flancos[1+i*2],
            y1=-.75,
            line_width=0,
            fillcolor="steelblue",
            xref=f"x{k+1}",  # 指定对应子图的x轴
            yref=f"y{k+1}"   # 指定对应子图的y轴
        ))

    # 添加轨迹到对应子图
    dig_signals.add_trace(go.Scatter(x=x, y=np.repeat(0, len(x))), row=k+1, col=1)
    # 累加新形状到布局中,而非覆盖
    dig_signals.update_layout(
        showlegend=False,
        shapes=dig_signals.layout.shapes + dictionaries
    )
    # 更新当前子图的轨迹样式
    dig_signals.update_traces(
        line_color="steelblue",
        line_width=2.5,
        row=k+1, col=1
    )
    # 设置当前子图的y轴范围和可见性
    dig_signals.update_yaxes(
        range=[-3, 3],
        visible=False,
        row=k+1, col=1
    )

dig_signals.show()

关键修改说明

  • 指定形状的子图归属:通过xref=f"x{k+1}"和yref=f"y{k+1}",让每个形状绑定到对应的子图坐标轴,解决了形状只显示在第一个子图的问题。
  • 累加形状配置:shapes=dig_signals.layout.shapes + dictionaries确保每次循环添加的形状不会覆盖之前的,所有子图的形状都会被保留。
  • 精准更新子图属性:调用update_traces和update_yaxes时指定row和col参数,确保修改仅作用于当前子图,避免全局影响。

内容的提问来源于stack exchange,提问作者def user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:20:34