Plotly绘制眼动追踪数据并添加填充色随事件变化的矩形
眼动追踪数据可视化问题解决
问题背景
我有一个眼动追踪数据集,包含四列:
t:时间戳的numpy数组x、y:凝视点的像素坐标e:取值为{0,1,2,3,4,5}的数组,标记每个样本对应的凝视事件(如注视、扫视等)
需求是绘制x、y随时间变化的曲线,并添加填充色随e值变化的矩形区域。
示例数据
import numpy as np t = np.arange(30) x = np.array([125.9529, 124.6142, 125.0569, 125.3117, 126.7498, 127.035,125.4822, 125.6249, 126.9371, 127.6047, 129.031 , 128.2419, 121.521 , 114.7071, 109.4141, 100.5057, 94.9606, 95.2231, 95.9032, 96.4991, 101.2602, 103.9582, 108.2527, 108.8801, 110.3254, 112.8205, 113.0079, 113.3547, 113.0962, 113.2508]) y = np.array([31.218 , 31.236 , 31.147 , 31.2614, 30.806 , 30.8423, 31.727, 32.2256, 32.0504, 32.7774, 34.7089, 37.0671, 46.309 , 55.9716, 62.4481, 68.0248, 75.4912, 79.0622, 81.2176, 83.191 , 83.7656, 84.6713, 83.9343, 82.4546, 81.1652, 80.7981, 80.2136, 80.7405, 80.4398, 80.0738]) e = np.array([1., 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 3., 3., 3., 3., 3., 3., 4., 4., 4., 4.])
尝试代码及报错
import plotly.graph_objects as go from plotly.subplots import make_subplots fig = make_subplots() fig.add_trace(ply.graph_objects.Line(x=t, y=x, name="X"), secondary_y=False, row=1, col=1) fig.add_trace(ply.graph_objects.Line(x=t, y=y, name="Y"), secondary_y=False, row=1, col=1) fig.add_shape(type="rect", x0=t[0], y0=0, x1=t[-1], y1=0.05 * np.max([x, y]), line=dict(color="black", width=2), fillcolor=e)
报错信息:
ValueError: Invalid value of type 'numpy.ndarray' received for the 'fillcolor' property of layout.shape
问题分析与解决
报错原因是add_shape的fillcolor仅接受单一颜色值,无法直接传入数组。要实现不同e值对应不同颜色的矩形区域,需先将e的连续相同值分组,为每组单独添加矩形。
完整代码实现
import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots # 示例数据 t = np.arange(30) x = np.array([125.9529, 124.6142, 125.0569, 125.3117, 126.7498, 127.035,125.4822, 125.6249, 126.9371, 127.6047, 129.031 , 128.2419, 121.521 , 114.7071, 109.4141, 100.5057, 94.9606, 95.2231, 95.9032, 96.4991, 101.2602, 103.9582, 108.2527, 108.8801, 110.3254, 112.8205, 113.0079, 113.3547, 113.0962, 113.2508]) y = np.array([31.218 , 31.236 , 31.147 , 31.2614, 30.806 , 30.8423, 31.727, 32.2256, 32.0504, 32.7774, 34.7089, 37.0671, 46.309 , 55.9716, 62.4481, 68.0248, 75.4912, 79.0622, 81.2176, 83.191 , 83.7656, 84.6713, 83.9343, 82.4546, 81.1652, 80.7981, 80.2136, 80.7405, 80.4398, 80.0738]) e = np.array([1., 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 2., 3., 3., 3., 3., 3., 3., 4., 4., 4., 4.]) # 定义e值对应的颜色映射 color_map = { 1: "#FF9999", 2: "#99FF99", 3: "#9999FF", 4: "#FFFF99", 0: "#FFCC99", 5: "#CC99FF" } # 找出e值变化的索引,用于分组 change_indices = np.where(np.diff(e) != 0)[0] + 1 # 分割成连续相同e值的区间 segments = np.split(t, change_indices) e_values = np.split(e, change_indices) # 创建子图 fig = make_subplots() # 添加x、y曲线 fig.add_trace(go.Scatter(x=t, y=x, name="X坐标"), row=1, col=1) fig.add_trace(go.Scatter(x=t, y=y, name="Y坐标"), row=1, col=1) # 计算矩形区域的y轴范围 y_max = 0.05 * np.max([x, y]) # 为每个区间添加矩形 for seg, ev in zip(segments, e_values): # 取当前区间的时间起止点 x0 = seg[0] x1 = seg[-1] # 取当前区间对应的e值 event_type = ev[0] # 添加矩形 fig.add_shape( type="rect", x0=x0, y0=0, x1=x1, y1=y_max, fillcolor=color_map[event_type], opacity=0.3, # 设置透明度避免遮挡曲线 line=dict(width=0) # 隐藏矩形边框 ) # 更新布局 fig.update_layout( title="眼动追踪坐标随时间变化及事件标记", xaxis_title="时间戳", yaxis_title="像素坐标", showlegend=True ) fig.show()
关键说明
- 分组连续事件:通过
np.diff找出e值变化的位置,将时间戳和事件分割成连续相同事件的区间。 - 颜色映射:为每个
e值定义对应的填充色,方便区分不同凝视事件。 - 逐个添加矩形:遍历每个事件区间,为每个区间添加独立的矩形,设置对应填充色和透明度,避免遮挡上方的坐标曲线。
- 修复原代码错误:原代码中
ply是笔误,应改为go;同时用go.Scatter替代go.Line(Plotly中推荐用Scatter绘制折线)。
内容的提问来源于stack exchange,提问作者Jon Nir
相关产品推荐
相关产品推荐

