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

将np.array([list,list])传入3D绘图器返回空结果的问题排查

3D曲面与等高线绘图为空的问题分析与解决

问题背景

你尝试用轨迹点的x、y、apf列表绘制3D势能曲面和等高线,但通过np.array([x,x])这类方式传递数据后,绘图结果为空。核心问题出在数据结构不符合3D绘图函数的要求,同时代码里还有几处逻辑错误导致数据无效。

核心问题拆解

  1. 3D绘图函数的输入要求错误
    plot_surface和contourf需要的是二维网格数据:

    • X和Y必须是通过np.meshgrid生成的二维矩阵,代表平面上所有网格点的坐标;
    • Z是对应每个网格点的函数值,同样是二维矩阵。
      你用np.array([x,x])只是把一维的轨迹点数组重复了两行,本质还是一维数据的堆叠,无法形成曲面所需的网格结构,自然无法绘制出曲面。
  2. APF值计算的逻辑错误
    循环里计算apf.append(APF(...))时,传入的是start.X和start.Y,而不是当前移动的temp.X和temp.Y,导致apf列表里全是初始点的势能值,数据没有变化,即使能绘图也只会是一个平面。

  3. 轨迹记录的隐藏问题
    Point类的move方法是修改自身属性后返回自己,所以trajectory里的所有元素都是同一个Point实例,最后x、y列表里的数值其实都是最后一次移动后的结果(因为每次append的是当前temp的X/Y,但temp是同一个对象,后续修改会影响之前的记录)。

解决方法与修改后的代码

要绘制整个势能曲面,我们需要先生成覆盖目标区域的网格,计算每个网格点的APF值,再用这些网格数据绘图;同时修正轨迹计算和APF记录的逻辑:

import numpy as np
import math
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm

class Point(object):
    def __init__(self,x,y):
        self.X = x
        self.Y = y
    def distance(self, goal):
        dx = self.X - goal.X
        dy = self.Y - goal.Y
        return math.hypot(dx, dy)
    def move(self, xGrad, yGrad):
        # 返回新的Point实例,避免修改原对象导致轨迹记录错误
        return Point(self.X - xGrad*1e-2, self.Y - yGrad*1e-2)

def APF(a, r, currentX, currentY, goalX, goalY, obstacles):
    attr = a*math.hypot(currentX-goalX, currentY-goalY)**2
    repl = 0
    for item in obstacles:
        dist = math.hypot(currentX-item.point.X, currentY-item.point.Y)
        # 避免距离过小时的除零错误
        if dist < 1e-3:
            repl += float('inf')
        else:
            repl += 1/(dist**2)
    repl *= r
    return attr + repl

def gradX(a, r, h, currentX, currentY, goalX, goalY, obstacles):
    num1 = APF(a, r, currentX+h, currentY, goalX, goalY, obstacles)
    num2 = APF(a, r, currentX-h, currentY, goalX, goalY, obstacles)
    return (num1-num2)/(2*h)

def gradY(a, r, h, currentX, currentY, goalX, goalY, obstacles):
    num1 = APF(a, r, currentX, currentY+h, goalX, goalY, obstacles)
    num2 = APF(a, r, currentX, currentY-h, goalX, goalY, obstacles)
    return (num1-num2)/(2*h)

class Obstacle(object):
    def __init__(self, point, radius):
        self.point = point
        self.radius = radius

if __name__== "__main__" :
    start = Point(1.0, 1.0)
    goal = Point(8.0, 8.0)
    p1 = Point(3.0, 3.0)
    p2 = Point(5.0, 6.0)
    p3 = Point(7.0, 6.0)
    obs1 = Obstacle(p1, 0.5)
    obs2 = Obstacle(p2, 0.5)
    obs3 = Obstacle(p3, 0.5)
    obstacles = [obs1, obs2, obs3]
    
    # 1. 生成覆盖区域的网格数据,用于绘制3D曲面
    x_grid = np.linspace(0, 9, 50)
    y_grid = np.linspace(0, 9, 50)
    X, Y = np.meshgrid(x_grid, y_grid)
    Z = np.zeros_like(X)
    # 计算每个网格点的APF值
    for i in range(X.shape[0]):
        for j in range(X.shape[1]):
            Z[i,j] = APF(0.5, 1, X[i,j], Y[i,j], goal.X, goal.Y, obstacles)
    
    # 2. 重新计算轨迹(修正原逻辑错误)
    trajectory = [start]
    h = 10e-4
    a = 0.5
    r = 1
    temp = start
    maxiter = 1000
    i = 0
    while temp.distance(goal) > 1e-3 and i < maxiter:
        i += 1
        # 计算当前点的梯度
        gx = gradX(a, r, h, temp.X, temp.Y, goal.X, goal.Y, obstacles)
        gy = gradY(a, r, h, temp.X, temp.Y, goal.X, goal.Y, obstacles)
        # 生成新的点,避免修改原对象
        temp = temp.move(gx, gy)
        trajectory.append(temp)
    
    # 提取轨迹的坐标
    traj_x = [p.X for p in trajectory]
    traj_y = [p.Y for p in trajectory]
    traj_apf = [APF(a, r, p.X, p.Y, goal.X, goal.Y, obstacles) for p in trajectory]
    
    # 3. 绘制3D曲面和等高线,同时叠加轨迹
    fig = plt.figure(figsize=(12,8))
    ax = fig.add_subplot(111, projection='3d')
    
    # 绘制3D势能曲面
    surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.6, cmap=cm.coolwarm)
    # 绘制等高线(投影到z=-20的平面)
    cset = ax.contourf(X, Y, Z, zdir='z', offset=-20, cmap=cm.coolwarm)
    # 绘制路径轨迹
    ax.plot(traj_x, traj_y, traj_apf, color='black', linewidth=2, label='Path')
    
    ax.set_xlabel('X')
    ax.set_ylabel('Y')
    ax.set_zlabel('APF Value')
    ax.set_zlim(-20, np.max(Z)*1.1)
    ax.legend()
    plt.colorbar(surf, shrink=0.5, aspect=5)
    plt.show()

修改说明

  • 网格数据生成:用np.linspace和np.meshgrid生成覆盖目标区域的二维网格,计算每个点的APF值,这样plot_surface就能正确绘制曲面。
  • 轨迹记录修正:move方法返回新的Point实例,避免同一个对象被反复修改导致轨迹记录错误;循环里用当前temp的坐标计算梯度和APF值。
  • 除零错误处理:在APF计算中加入距离过小的判断,避免障碍物附近出现除零错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:59:36