在Python中,给定一个N_1 x N_2 x N_3包含0或1的矩阵,我将寻找一种以3D形式将数据显示为N_1 x N_2 x N_3体积为1s的体积像素(体素)的方法。
N_1 x N_2 x N_3
例如,如果1s的坐标为[[1, 1, 1], [4, 1, 2], [3, 4, 1]],则所需的输出将如下所示
[[1, 1, 1], [4, 1, 2], [3, 4, 1]]
看来mplot3Dmatplotlib的模块可以实现这一目标,但我还没有找到这种绘图的任何示例。有谁知道解决这个问题的简单解决方案?
mplot3D
在此先感谢您的帮助。
A.使用 voxels
voxels
从matplotlib 2.1开始,有一个Axes3D.voxels可用的函数,几乎可以满足此处的要求。但是,很难将其定制为不同的尺寸,位置或颜色。
from mpl_toolkits.mplot3d import Axes3D import numpy as np import matplotlib.pyplot as plt N1 = 10 N2 = 10 N3 = 10 ma = np.random.choice([0,1], size=(N1,N2,N3), p=[0.99, 0.01]) fig = plt.figure() ax = fig.gca(projection='3d') ax.set_aspect('equal') ax.voxels(ma, edgecolor="k") plt.show()
要将体素放置在不同位置,请参见如何使用Matplotlib缩放体素尺寸?。
B.使用 Poly3DCollection
手动创建体素可以使过程更加透明,并允许对体素的大小,位置和颜色进行任何类型的自定义。另一个优点是,这里我们创建一个Poly3DCollection而不是多个Poly3DCollection,使此解决方案比inbuild更快voxels。
from mpl_toolkits.mplot3d import Axes3D import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d.art3d import Poly3DCollection def cuboid_data(o, size=(1,1,1)): X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]], [[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]], [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]], [[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]], [[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]], [[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]] X = np.array(X).astype(float) for i in range(3): X[:,:,i] *= size[i] X += np.array(o) return X def plotCubeAt(positions,sizes=None,colors=None, **kwargs): if not isinstance(colors,(list,np.ndarray)): colors=["C0"]*len(positions) if not isinstance(sizes,(list,np.ndarray)): sizes=[(1,1,1)]*len(positions) g = [] for p,s,c in zip(positions,sizes,colors): g.append( cuboid_data(p, size=s) ) return Poly3DCollection(np.concatenate(g), facecolors=np.repeat(colors,6, axis=0), **kwargs) N1 = 10 N2 = 10 N3 = 10 ma = np.random.choice([0,1], size=(N1,N2,N3), p=[0.99, 0.01]) x,y,z = np.indices((N1,N2,N3))-.5 positions = np.c_[x[ma==1],y[ma==1],z[ma==1]] colors= np.random.rand(len(positions),3) fig = plt.figure() ax = fig.gca(projection='3d') ax.set_aspect('equal') pc = plotCubeAt(positions, colors=colors,edgecolor="k") ax.add_collection3d(pc) ax.set_xlim([0,10]) ax.set_ylim([0,10]) ax.set_zlim([0,10]) #plotMatrix(ax, ma) #ax.voxels(ma, edgecolor="k") plt.show()
C.使用 plot_surface
修改此答案的代码(部分基于此答案),可以轻松地将长方体绘制为表面图。
然后可以遍历输入数组,并在找到1对应于数组索引的位置处的长方体后进行迭代。
这样做的好处是您可以在表面上获得漂亮的阴影,从而增加3D效果。缺点是,在某些情况下,多维数据集可能不具有物理性能,例如,对于某些视角,它们可能重叠。
from mpl_toolkits.mplot3d import Axes3D import numpy as np import matplotlib.pyplot as plt def cuboid_data(pos, size=(1,1,1)): # code taken from # https://stackoverflow.com/a/35978146/4124317 # suppose axis direction: x: to left; y: to inside; z: to upper # get the (left, outside, bottom) point o = [a - b / 2 for a, b in zip(pos, size)] # get the length, width, and height l, w, h = size x = [[o[0], o[0] + l, o[0] + l, o[0], o[0]], [o[0], o[0] + l, o[0] + l, o[0], o[0]], [o[0], o[0] + l, o[0] + l, o[0], o[0]], [o[0], o[0] + l, o[0] + l, o[0], o[0]]] y = [[o[1], o[1], o[1] + w, o[1] + w, o[1]], [o[1], o[1], o[1] + w, o[1] + w, o[1]], [o[1], o[1], o[1], o[1], o[1]], [o[1] + w, o[1] + w, o[1] + w, o[1] + w, o[1] + w]] z = [[o[2], o[2], o[2], o[2], o[2]], [o[2] + h, o[2] + h, o[2] + h, o[2] + h, o[2] + h], [o[2], o[2], o[2] + h, o[2] + h, o[2]], [o[2], o[2], o[2] + h, o[2] + h, o[2]]] return np.array(x), np.array(y), np.array(z) def plotCubeAt(pos=(0,0,0),ax=None): # Plotting a cube element at position pos if ax !=None: X, Y, Z = cuboid_data( pos ) ax.plot_surface(X, Y, Z, color='b', rstride=1, cstride=1, alpha=1) def plotMatrix(ax, matrix): # plot a Matrix for i in range(matrix.shape[0]): for j in range(matrix.shape[1]): for k in range(matrix.shape[2]): if matrix[i,j,k] == 1: # to have the plotCubeAt(pos=(i-0.5,j-0.5,k-0.5), ax=ax) N1 = 10 N2 = 10 N3 = 10 ma = np.random.choice([0,1], size=(N1,N2,N3), p=[0.99, 0.01]) fig = plt.figure() ax = fig.gca(projection='3d') ax.set_aspect('equal') plotMatrix(ax, ma) plt.show()