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

使用pyplot绘制3D图报错ValueError:形状不匹配问题排查

3D曲面图生成报错:shape mismatch问题排查与修复

问题概述

生成模糊逻辑模型的3D曲面图时触发维度不匹配错误,报错信息显示ValueError: shape mismatch: objects cannot be broadcast to a single shape,目标是生成类似示例的3D图表,当前视图窗口可正常打开,问题出在数据维度与赋值逻辑上。

报错回溯

ValueError                                Traceback (most recent call last)
<ipython-input-79-bb38fe77253e> in <module>()
     13 fig = plt.figure()
     14 ax = fig.gca(projection='3d')
---> 15 surf = ax.plot_surface(s, v, pred_val, cmap=cm.coolwarm, linewidth=0, antialiased=False)
     16 fig.colorbar(surf, shrink=0.5, aspect=5)
     17 plt.show()

2 frames
/usr/local/lib/python3.7/dist-packages/mpl_toolkits/mplot3d/axes3d.py in plot_surface(self, X, Y, Z, norm, vmin, vmax, lightsource, *args, **kwargs)
   1502 
   1503         # TODO: Support masked arrays
-> 1504         X, Y, Z = np.broadcast_arrays(X, Y, Z)
   1505         rows, cols = Z.shape
   1506 

<__array_function__ internals> in broadcast_arrays(*args, **kwargs)

/usr/local/lib/python3.7/dist-packages/numpy/lib/stride_tricks.py in broadcast_arrays(subok, *args)
    536     args = [np.array(_m, copy=False, subok=subok) for _m in args]
    537 
-> 538     shape = _broadcast_shape(*args)
    539 
    540     if all(array.shape == shape for array in args):

/usr/local/lib/python3.7/dist-packages/numpy/lib/stride_tricks.py in _broadcast_shape(*args)
    418     # use the old-iterator because np.nditer does not handle size 0 arrays
    419     # consistently
-> 420     b = np.broadcast(*args[:32])
    421     # unfortunately, it cannot handle 32 or more arguments directly
    422     for pos in range(32, len(args), 31):

ValueError: shape mismatch: objects cannot be broadcast to a single shape

原代码

d = 0.2
i_min = 1 / d
i_max = pipe.max_slope(d=d) # float value
slope = ctrl.Antecedent(np.arange(i_min, i_max + 1, 1), 'slope')

v_min = 0
v_max = 5
velocity = ctrl.Antecedent(np.arange(v_min, v_max, 0.1), 'velocity')
diameter = ctrl.Consequent(np.arange(1, 4, 1), 'diameter')

# Populate slope with membership functions.
slope['low'] = fuzz.trapmf(slope.universe, [i_min, i_min, i_min + 20, 50])
slope['medium'] = fuzz.trapmf(slope.universe, [25, 40, 120, 150])
slope['high'] = fuzz.trapmf(slope.universe, [100, 150, i_max, i_max])

# Populate velocity with membership functions.
velocity['low'] = fuzz.trimf(velocity.universe, [v_min, v_min, 0.5 * v_max])
velocity['medium'] = fuzz.trimf(velocity.universe, [v_min, 0.5 * v_max, v_max])
velocity['high'] = fuzz.trimf(velocity.universe, [0.5 * v_max, v_max, v_max])

# Populate dimension 
diameter['reduction'] = fuzz.trimf(diameter.universe, [1, 1, 1])
diameter['optimal'] = fuzz.trimf(diameter.universe, [1, 2, 3])
diameter['increase'] = fuzz.trimf(diameter.universe, [2, 3, 3])

# Define rules
r1 = ctrl.Rule(slope['low'] & velocity['low'] | velocity['medium'], diameter['reduction'])
r2 = ctrl.Rule(slope['low'] & velocity['high'] | velocity['medium'], diameter['optimal'])
r3 = ctrl.Rule(slope['medium'] & velocity['medium'], diameter['optimal'])
r4 = ctrl.Rule(slope['high'] & velocity['high'] | slope['medium'], diameter['increase'])

# Create model
diameter_ctrl = ctrl.ControlSystem([r1, r2, r3, r4])
diameters = ctrl.ControlSystemSimulation(diameter_ctrl)

# Model using
diameters.input['slope'] = 150
diameters.input['velocity'] = 5

diameters.compute()
print(diameters.output['diameter'])


# Create 3D chart
s = np.arange(i_min, i_max + 1, 1)
v = np.arange(v_min, v_max + 0.1, 0.1)
s, v = np.meshgrid(s, v)

pred_val: np.ndarray = np.zeros(shape=(len(v), len(s)))
for i in range(len(s)):
    for j in range(len(v)):
        diameters.input['slope'] = i_min + i
        diameters.input['velocity'] = v_min + j
        diameters.compute()
        pred_val[i][j] = diameters.output['diameter']

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(s, v, pred_val, cmap=cm.coolwarm, linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

问题分析

  1. 循环索引与赋值逻辑错误:

    • meshgrid生成的s和v是二维数组,维度为(len(v_original), len(s_original)),原循环用range(len(s))遍历的是二维数组的行数,而非原始s的元素数量
    • 赋值时用i_min + i和v_min + j是错误的,应该直接使用meshgrid生成的实际坐标值,而非索引偏移
    • pred_val的赋值索引颠倒,原代码初始化维度为(len(v), len(s)),但循环中用pred_val[i][j]赋值,导致维度不匹配
  2. 数组范围不一致:

    • 生成v数组时用np.arange(v_min, v_max + 0.1, 0.1),超出了velocity变量的universe范围(原universe是到v_max=5),可能导致模糊逻辑计算异常

修复方案

  1. 遍历meshgrid生成的每个网格点,直接获取对应的slope和velocity数值
  2. 修正pred_val的赋值索引,保证与s、v的维度一致
  3. 统一v数组的范围,与velocity的universe保持一致

修复后代码

d = 0.2
i_min = 1 / d
i_max = pipe.max_slope(d=d) # float value
slope = ctrl.Antecedent(np.arange(i_min, i_max + 1, 1), 'slope')

v_min = 0
v_max = 5
velocity = ctrl.Antecedent(np.arange(v_min, v_max, 0.1), 'velocity')
diameter = ctrl.Consequent(np.arange(1, 4, 1), 'diameter')

# Populate slope with membership functions.
slope['low'] = fuzz.trapmf(slope.universe, [i_min, i_min, i_min + 20, 50])
slope['medium'] = fuzz.trapmf(slope.universe, [25, 40, 120, 150])
slope['high'] = fuzz.trapmf(slope.universe, [100, 150, i_max, i_max])

# Populate velocity with membership functions.
velocity['low'] = fuzz.trimf(velocity.universe, [v_min, v_min, 0.5 * v_max])
velocity['medium'] = fuzz.trimf(velocity.universe, [v_min, 0.5 * v_max, v_max])
velocity['high'] = fuzz.trimf(velocity.universe, [0.5 * v_max, v_max, v_max])

# Populate dimension 
diameter['reduction'] = fuzz.trimf(diameter.universe, [1, 1, 1])
diameter['optimal'] = fuzz.trimf(diameter.universe, [1, 2, 3])
diameter['increase'] = fuzz.trimf(diameter.universe, [2, 3, 3])

# Define rules
r1 = ctrl.Rule(slope['low'] & velocity['low'] | velocity['medium'], diameter['reduction'])
r2 = ctrl.Rule(slope['low'] & velocity['high'] | velocity['medium'], diameter['optimal'])
r3 = ctrl.Rule(slope['medium'] & velocity['medium'], diameter['optimal'])
r4 = ctrl.Rule(slope['high'] & velocity['high'] | slope['medium'], diameter['increase'])

# Create model
diameter_ctrl = ctrl.ControlSystem([r1, r2, r3, r4])
diameters = ctrl.ControlSystemSimulation(diameter_ctrl)

# Model using
diameters.input['slope'] = 150
diameters.input['velocity'] = 5

diameters.compute()
print(diameters.output['diameter'])


# Create 3D chart
s_original = np.arange(i_min, i_max + 1, 1)
v_original = np.arange(v_min, v_max, 0.1)
s, v = np.meshgrid(s_original, v_original)

# 初始化pred_val维度与s、v一致
pred_val = np.zeros_like(s)

# 遍历每个网格点
for j in range(s.shape[0]):
    for i in range(s.shape[1]):
        diameters.input['slope'] = s[j, i]
        diameters.input['velocity'] = v[j, i]
        diameters.compute()
        pred_val[j, i] = diameters.output['diameter']

fig = plt.figure()
ax = fig.add_subplot(projection='3d')  # 替代gca,更规范
surf = ax.plot_surface(s, v, pred_val, cmap='coolwarm', linewidth=0, antialiased=False)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()

内容的提问来源于stack exchange,提问作者Rafał

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:39:35