Line3D 更新列表坐标后报没有 shape:无效点触发了绘制分支
Matplotlib3.11.1的Line3D接受列表坐标,遇NaN、无穷值或尺度无效点时却在绘制阶段读取.shape。3.11.2仍保留该访问;坐标可显式转为同形状数值数组。
更新三维折线时,line.set_data_3d() 接受了三个列表,直到窗口重绘或保存才报 AttributeError: 'list' object has no attribute 'shape'。如果坐标中刚出现 NaN、无穷值或不符合轴尺度的点,应检查无效坐标掩码的绘制分支。
Matplotlib 3.11.1 有这条具体路径,正式 3.11.2 也仍在相应分支直接读取首组坐标的 .shape。全是正常有限值的列表可能一直绘制成功,因此初始化时看过一张图,不能覆盖后续数据更新。
setter 接受 iterable,draw 又要求 shape
set_data_3d 检查各组坐标可迭代后,会保留传入对象。列表、元组满足这个条件,但没有 ndarray 的 .shape。绘制时一旦需要对无效点或裁切点构造广播掩码,读取 shape 就会失败。
NaN 只是一个容易遇到的条件。无穷值、对数尺度中的非正数,以及启用 axlim_clip 后位于视图外的点,也可能让相关掩码生效。不能靠把所有 NaN 改成零来处理,那会改变曲线与尺度含义。
在更新边界转为数值数组
以下示例保留一个缺失点,以说明容器转换的位置:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(projection="3d")
line, = ax.plot([0.0], [0.0], [0.0])
x = np.asarray([np.nan], dtype=float)
y = np.asarray([np.nan], dtype=float)
z = np.asarray([np.nan], dtype=float)
line.set_data_3d(x, y, z)
真实更新应先确认三组坐标是一维、长度相同且对应同一批点,再分别转换。这样绘制分支拥有 shape,NaN 仍作为缺失坐标保留,不会凭空增加一段经过零点的线。
如果使用 set_data() 加 set_3d_properties() 分步更新,也要检查最终保存的三组坐标类型。高层 ax.plot() 初始化时的转换,不会保证后续每次自定义 setter 调用都替你转换。
转换的 dtype 应符合数据本身;日期、单位对象或特殊坐标不能无条件压成 float。输入已是 ndarray 时,asarray 也可能共享它,后续若要独立保存帧数据,应另行考虑复制责任。
触发真实重绘再验收
验收应包含更新后的实际绘制与导出,覆盖有限点、缺失点和真实尺度边界。绘制调用没有异常后,还要检查曲线是否在正确位置断开、轴范围与裁切是否保留;只确认 setter 返回不足以验收。
不要直接改 _verts3d 等私有属性,也不要为取得 .shape 而把三维点压平。若异常实际来自另一个 Artist 的属性,应沿完整栈继续定位,不把所有三维图的 shape 错误都归到这个容器条件。


