使用Axes3D.voxels绘制三维整数点列表时遇维度错误的解决方案咨询
Axes3D.voxels绘制三维整数点列表时遇维度错误的解决方案咨询
我明白你遇到的问题了——Axes3D.voxels() 确实不接受直接传入三维点列表,它需要的是一个三维布尔数组来标记每个体素位置是否被填充。下面我来帮你分析错误原因,并给出两种可行的解决方案:
错误原因解析
你传入的cap和body是二维的点列表(每个元素是[x,y,z]坐标),但voxels()要求第一个参数必须是形状为(x_dim, y_dim, z_dim)的三维数组,用来表示空间中每个体素的填充状态,这就是为什么会抛出ValueError: Argument filled must be 3-dimensional的原因。另外你代码里的点筛选逻辑也有语法错误,比如cap = [lambda p : p[2] == roof - 1, crust]这种写法无法正确筛选点,需要调整。
解决方案一:将点列表转换为三维布尔数组
既然你的点范围是(-15,-15,0)到(15,15,9),我们可以先把这些坐标转换为非负的数组索引,再创建对应大小的三维布尔数组,标记出存在体素的位置。具体步骤如下:
- 先修正点筛选的逻辑:
# 正确筛选顶部和主体的点 roof = 8 cap_points = [p for p in crust if p[2] == roof - 1] body_points = [p for p in crust if p[2] < roof - 1] if level > 1 else None
- 将点列表转换为三维布尔数组:
import numpy as np # 把所有点转为numpy数组方便处理 all_points = np.array(crust) # 计算偏移量,让所有坐标转为非负(数组索引不能为负) x_offset = -np.min(all_points[:, 0]) y_offset = -np.min(all_points[:, 1]) z_offset = -np.min(all_points[:, 2]) # 计算每个维度的总大小 x_size = np.max(all_points[:, 0]) + x_offset + 1 y_size = np.max(all_points[:, 1]) + y_offset + 1 z_size = np.max(all_points[:, 2]) + z_offset + 1 # 创建全False的三维布尔数组 filled = np.zeros((x_size, y_size, z_size), dtype=bool) # 标记所有存在体素的位置 for x, y, z in all_points: filled[x + x_offset, y + y_offset, z + z_offset] = True # 拆分顶部和主体的体素数组 cap_filled = filled.copy() target_z_idx = (roof - 1) + z_offset # 只保留顶部层的体素 cap_filled[:, :, :target_z_idx] = False cap_filled[:, :, target_z_idx+1:] = False body_filled = filled.copy() if body_points else None if body_filled is not None: # 只保留主体层的体素 body_filled[:, :, target_z_idx:] = False
- 用转换后的数组绘制体素:
# 绘制顶部体素 ax.voxels(cap_filled, facecolors=colors[0], edgecolors=colors[1]) # 绘制主体体素(如果存在) if body_filled is not None: ax.voxels(body_filled, facecolors=colors[1], edgecolors=colors[0]) screen.draw()
解决方案二:直接绘制单个立方体(替代voxels)
如果你不想创建庞大的三维数组,也可以手动为每个点绘制对应的立方体。Matplotlib的mpl_toolkits.mplot3d.art3d模块提供了Cube3D类,可以用来创建单个立方体:
from mpl_toolkits.mplot3d.art3d import Cube3D def draw_cube(ax, x, y, z, face_color, edge_color): # 以整数坐标为中心,绘制边长为1的立方体 cube = Cube3D([x-0.5, y-0.5, z-0.5], 1, 1, 1) cube.set_facecolor(face_color) cube.set_edgecolor(edge_color) ax.add_artist(cube) # 绘制顶部点的立方体 for x, y, z in cap_points: draw_cube(ax, x, y, z, colors[0], colors[1]) # 绘制主体点的立方体 if body_points: for x, y, z in body_points: draw_cube(ax, x, y, z, colors[1], colors[0]) # 调整坐标轴范围适配立方体 ax.set_xlim(-15.5, 15.5) ax.set_ylim(-15.5, 15.5) ax.set_zlim(-0.5, 9.5) screen.draw()
补充说明
- 方案一适合体素分布比较密集的情况,绘制效率更高;方案二更适合点数量较少的场景,节省内存。
- 你代码中原来的
map变量名建议修改,因为map是Python内置函数,避免命名冲突。
备注:内容来源于stack exchange,提问作者David Wallace
相关产品推荐
相关产品推荐

