2014-11-04 151 views
7

我有一个三列的目录data,我想制作它们的三维图以及每个轴的投影作为另一个平面中的投影轮廓两个轴。到目前为止,我可以使用matplotlib来制作3D绘图,但仍未显示任何数据属性。使用轮廓在三个平面上绘制三维图的投影

from mpl_toolkits.mplot3d import axes3d 
import matplotlib.pyplot as plt 
from numpy import * 
data=loadtxt('test.cat') 
X=data[:,0] 
Y=data[:,1] 
Z=data[:,2] 
fig = plt.figure() 
ax = fig.add_subplot(111, projection='3d') 
ax.scatter(X, Y, Z, c='r', marker='.') 
ax.set_xlabel('X') 
ax.set_ylabel('Y') 
ax.set_zlabel('Z') 

plt.show() 

我怎么能绘制数据的每个平面colorbar以及投影?

回答

2

根据你想要做的,你需要使用zdir参数为contourcontourf功能。这里的一个示例:

import matplotlib.pyplot as plt 
import numpy as np 
from mpl_toolkits.mplot3d import Axes3D 

fig = plt.figure() 
ax = Axes3D(fig) 
X = np.arange(-4, 4, 0.25) 
Y = np.arange(-4, 4, 0.25) 
X, Y = np.meshgrid(X, Y) 
R = np.sqrt(X ** 2 + Y ** 2) 
Z = np.sin(R) 


ax.contourf(X, Y, Z, zdir='x', offset=-4, cmap=plt.cm.hot) 
ax.contour(X, Y, Z, zdir='x', offset=-4, colors='k') 
ax.contourf(X, Y, Z, zdir='y', offset=4, cmap=plt.cm.hot) 
ax.contour(X, Y, Z, zdir='y', offset=4, colors='k') 
ax.contourf(X, Y, Z, zdir='z', offset=-1, cmap=plt.cm.hot) 
ax.contour(X, Y, Z, zdir='z', offset=-1, colors='k') 

plt.show() 

随着结果: enter image description here

2

嗯,的确,显示难以数据。也许沿一个轴创建一些切片并创建一定数量的2D图是最好的。然而3D情节是幻想。我对数据进行了一些调整,结果如您所做的那样产生了一个3D图,并与投影分开绘制了一个图。

  • 的点的颜色是根据缺少
  • 添加透明度,得到密度的一个想法
  • 两个图相同的不停轴

enter image description here enter image description here

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

data = np.loadtxt('test.cat', skiprows=1) 

X=data[:,0] 
Y=data[:,1] 
Z=data[:,2] 

plt.figure() 
ax1 = plt.subplot(111, projection='3d') 

ax1.scatter(X, Y, Z, c='b', marker='.', alpha=0.2) 
ax1.set_xlabel('X - axis') 
ax1.set_ylabel('Y - axis') 
ax1.set_zlabel('Z - axis') 

plt.figure() 
ax2 = plt.subplot(111, projection='3d') 

plt.hot() 

cx = np.ones_like(X) * ax1.get_xlim3d()[0] 
cy = np.ones_like(X) * ax1.get_ylim3d()[1] 
cz = np.ones_like(Z) * ax1.get_zlim3d()[0] 

ax2.scatter(X, Y, cz, c=Z, marker='.', lw=0, alpha=0.2) 
ax2.scatter(X, cy, Z, c=-Y, marker='.', lw=0, alpha=0.2) 
ax2.scatter(cx, Y, Z, c=X, marker='.', lw=0, alpha=0.2) 
ax2.set_xlim3d(ax1.get_xlim3d()) 
ax2.set_ylim3d(ax1.get_ylim3d()) 
ax2.set_zlim3d(ax1.get_zlim3d()) 
ax2.set_xlabel('X - axis') 
ax2.set_ylabel('Y - axis') 
ax2.set_zlabel('Z - axis') 
+0

我真的很感兴趣的是,在每个平面上都有一个轮廓图,它将第三个轴的投影描述为一个颜色代码。 – Dalek 2014-11-05 18:09:09

4

这里的希望,我不是拍蚊子用[非常难看]大炮,我最近做了一个Binning_Array类学校的项目,我想这也许能够帮助你: ThreeBinners

import numpy as np 
import matplotlib.pyplot as plt 
import binning_array as ba 
from mpl_toolkits.mplot3d import axes3d 

data = np.loadtxt('test.cat') 
X = data[:,0] 
Y = data[:,1] 
Z = data[:,2] 

n_points = data.shape[0] 

X_min = np.round(np.min(data[:,0])-0.5) 
X_max = np.round(np.max(data[:,0])+0.5) 
Y_min = np.round(np.min(data[:,1])-0.5) 
Y_max = np.round(np.max(data[:,1])+0.5) 
Z_min = np.round(np.min(data[:,2])-0.5) 
Z_max = np.round(np.max(data[:,2])+0.5) 
n_min_bins = 25 
step = min([(X_max-X_min)/n_min_bins, (Y_max-Y_min)/n_min_bins, (Z_max-Z_min)/n_min_bins]) 

# Using three Binners 
BinnerXY = ba.Binning_Array([[X_min, X_max, step], 
          [Y_min, Y_max, step]]) 
BinnerYZ = ba.Binning_Array([[Y_min, Y_max, step], 
          [Z_min, Z_max, step]]) 
BinnerXZ = ba.Binning_Array([[X_min, X_max, step], 
          [Z_min, Z_max, step]]) 

for point in data: 
    BinnerXY.add_value([point[0], point[1]]) 
    BinnerXZ.add_value([point[0], point[2]]) 
    BinnerYZ.add_value([point[1], point[2]]) 

fig = plt.figure() 
ax = [fig.add_subplot(221, projection='3d'), 
     fig.add_subplot(222), 
     fig.add_subplot(223), 
     fig.add_subplot(224)] 

# Plot 2D projections on the 3D graph 
vmin = np.min([BinnerXZ.bin_min(), BinnerYZ.bin_min(), BinnerXY.bin_min()]) 
vmax = np.max([BinnerXZ.bin_max(), BinnerYZ.bin_max(), BinnerXY.bin_max()]) 
levels = np.linspace(vmin,vmax,20) 

xs_c = np.arange(*BinnerXZ.limits[0]) 
zs_c = np.arange(*BinnerXZ.limits[1]) 
ZS_C, XS_C = np.meshgrid(zs_c,xs_c) 
ax[0].contourf(X=XS_C, Y=BinnerXZ.bins, Z=ZS_C, 
       zdir='y', offset=Y_max, 
       vmin=vmin, vmax=vmax, 
       cmap=plt.cm.coolwarm, levels=levels, 
       alpha=0.5) 
xs_c = np.arange(*BinnerXY.limits[0]) 
ys_c = np.arange(*BinnerXY.limits[1]) 
YS_C, XS_C = np.meshgrid(ys_c,xs_c) 
ax[0].contourf(X=XS_C, Y=YS_C, Z=BinnerXY.bins, 
       zdir='z', offset=Z_min, 
       vmin=vmin, vmax=vmax, 
       cmap=plt.cm.coolwarm, levels=levels, 
       alpha=0.5) 
ys_c = np.arange(*BinnerYZ.limits[0]) 
zs_c = np.arange(*BinnerYZ.limits[1]) 
ZS_C, YS_C = np.meshgrid(zs_c, ys_c) 
ax[0].contourf(X=BinnerYZ.bins, Y=YS_C, Z=ZS_C, 
       zdir='x', offset=X_min, 
       vmin=vmin, vmax=vmax, 
       cmap=plt.cm.coolwarm, levels=levels, 
       alpha=0.5) 

# Plot scatter of all data 
ax[0].scatter(X, Y, Z, c='g', marker='.', alpha=0.2) 
ax[0].set_xlabel(r"$x$") 
ax[0].set_ylabel(r"$y$") 
ax[0].set_zlabel(r"$z$") 
max_range = max([X_max-X_min, Y_max-Y_min, Z_max-Z_min])/2. 
pos = [(X_max+X_min)/2., (Y_max+Y_min)/2., (Z_max+Z_min)/2.] 
ax[0].set_xlim(pos[0] - max_range, pos[0] + max_range) 
ax[0].set_ylim(pos[1] - max_range, pos[1] + max_range) 
ax[0].set_zlim(pos[2] - max_range, pos[2] + max_range) 

# Plot 2D histograms 
BinnerXZ.plot_2d_slice(fig=fig, ax=ax[1], xlabel=r"$x$", ylabel=r'$z$') 
BinnerXY.plot_2d_slice(fig=fig, ax=ax[2], xlabel=r"$x$", ylabel=r'$y$') 
BinnerYZ.plot_2d_slice(fig=fig, ax=ax[3], xlabel=r"$y$", ylabel=r'$z$') 
plt.show() 

你可以也只使用一个宾纳,但是请注意,你会得到的文物,其中平面相交: One Binner

# ... 
# Using three Binners 
# ... 
# Using only one Binner (adds a small error! see comments!) 
Binner = ba.Binning_Array([[X_min, X_max, step], 
          [Y_min, Y_max, step], 
          [Z_min, Z_max, step]]) 
for point in data: 
    Binner.add_value([point[0], point[1], Z_min]) 
    Binner.add_value([point[0], Y_max-step, point[2]]) 
    Binner.add_value([X_min, point[1], point[2]]) 
fig = plt.figure() 
ax = [fig.add_subplot(221, projection='3d'), 
     fig.add_subplot(222), 
     fig.add_subplot(223), 
     fig.add_subplot(224)] 
ax[0].scatter(X, Y, Z, c='g', marker='.', alpha=0.2) 
Binner.plot_slices(others={0:X_min, 1:Y_max, 2:Z_min}, fig=fig, ax=ax) 
plt.show() 

的binning_array.py是为一所学校的项目制成,并非完全抛光,但它足以让你想要什么。

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

class Binning_Array: 
    def __init__(self, limits=[[-1.,1.,1.],[-1.,1.,1.]]): 
     """Create a new binning array. 
     The amount of given limits determines the dimension of the array, 
     although only 2 and 3D have been tested. 
     Each limit must be a list of start, stop and step for the 
     axis it represents (x, y or z).""" 
     self.limits = np.array(limits) 
     self._shape = [] 
     for i in xrange(len(self.limits)): 
      self._shape.append((self.limits[i][1]-self.limits[i][0])/\ 
           float(self.limits[i][2])) 
     self._shape = tuple(self._shape) 
     self.dimensions = len(self._shape) 
     self.bins = np.zeros(self._shape) 
     self.outside = 0. 
     self._normalized = 1. 

    def __repr__(self): 
     """Representation method. <<REVIEW>>""" 
     return "Binning Array! Hurray!" 

    def __getitem__(self, index): 
     """Direct acess to read self.bins (use something like self[index]) 
     Direct acess to write would be given by __setitem__ 
     """ 
     return self.bins.__getitem__(index) 

    def position2index(self,position,axis=0): 
     """Convert a given position to an index in axis. 
     If it is outside, it returns -1. 
     """ 
     if self.limits[axis][0] <= position < self.limits[axis][1]: 
      return int((position - self.limits[axis][0])/self.limits[axis][2]) 
     else: return -1 

    def index2position(self, index, axis=0): 
     """Convert a given index to a position in axis. 
     If it is outisde, it returns -1. 
     """ 
     if 0 <= index < self._shape[axis]: 
      return self.limits[axis][0] + self.limits[axis][2] * index 
     else: 
      return -1 

    def add_value(self, position, value=1., verbose=False): 
     """Add a given value to a specified position. 
     If verbose it returns a list with the axies at which the position 
     is outside the scope of this Binning_Array. 
     Not very efficient because of that (verbose was for debugging). 
     """ 
     indexs = [] 
     outside = False 
     if verbose: 
      outs = [] 
     for i in xrange(self.dimensions): 
      # using self.dimensions serves as a filter 
      # if position has non valid shape 
      index = self.position2index(position[i],i) 
      if index == -1: 
       if verbose: 
        outside = True 
        outs.append(i) 
       else: 
        self.outside += value/self._normalized 
        return None # nothing, as it is not verbose 
      else: 
       indexs.append(index) 
     if outside: # the only way to get here is if verbose is True... 
      self.outside += value/self._normalized 
      return outs # so I can just return outs... 
     else: 
      self.bins[tuple(indexs)] += value/self._normalized 
      if verbose: 
       return outs 

    def get_value(self, position, verbose=False): 
     """Return the value at the specified position. 
     If verbose it alse returns a list with the axies at which the position 
     is outside the scope of this Binning_Array. 
     """ 
     indexs = [] 
     outside = False 
     if verbose: 
      outs = [] 
     for i in xrange(self.dimensions): 
      index = self.position2index(position[i],i) 
      if index == -1: 
       if verbose: 
        outside = True 
        outs.append[i] 
       else: 
        return self.outside 
      else: 
       indexs.append(index) 
     if outside: # the only way to get here is if verbose is True 
      return self.outside, outs # so I can just return outs... 
     else: 
      if verbose: 
       return self.bins[tuple(indexs)], outs 
      else: 
       return self.bins[tuple(indexs)] 

    def normalize(self, total=None): 
     """Divide the entire array by the sum of its values (and outside). 
     Any value added after this will be normalized by the same factor. 
     """ 
     if total is None: 
      total = self.n_counts() 
     self.bins /= total 
     self.outside /= total 
     self.normalize *= total 

    def n_counts(self): 
     """Return the number of counts.""" 
     return np.sum(self.bins) + self.outside 

    def bin_max(self): 
     """Return the value of the largest bin.""" 
     return np.max(self.bins) 

    def bin_min(self): 
     """Return the value of the largest bin.""" 
     return np.min(self.bins) 

    def plot_2d_slice(self, cuts=[0,1], others={}, 
         fig=None, ax=None, show=True, **kwargs): 
     """Plot a 2D slice.""" 
     x = min(cuts) 
     y = max(cuts) 
     xs = np.arange(self.limits[x][0], 
         self.limits[x][1] + self.limits[x][2], 
         self.limits[x][2]) 
     ys = np.arange(self.limits[y][0], 
         self.limits[y][1] + self.limits[y][2], 
         self.limits[y][2]) 
     index = [] 
     title = '' 
     for i in xrange(self.dimensions): 
      if i in cuts: 
       appendix = slice(self._shape[i]+1) 
      else: 
       appendix = others.get(i,(self.limits[i][0]+ 
             self.limits[i][1])/2.) 
       title += '%d:%.4e\t' % (i,appendix) 
       appendix = self.position2index(appendix,i) 
      index.append(appendix) 
     index = tuple(index) 
     if fig is None: 
      fig, ax = plt.subplots(1,1) 
     YS,XS = np.meshgrid(ys, xs) 
     graph = ax.pcolormesh (XS, YS, self.bins[index], cmap=plt.cm.coolwarm) 
     fig.colorbar(graph, ax=ax) 
     ax.axis('equal') 
     ax.set_xlim(self.limits[x][0], self.limits[x][1]) 
     ax.set_ylim(self.limits[y][0], self.limits[y][1]) 
     if 'xticks' in kwargs: 
      ax.set_xticks(kwargs['xticks']) 
     if 'yticks' in kwargs.keys(): 
      ax.set_yticks(kwargs['yticks']) 
     if 'xlabel' in kwargs: 
      ax.set_xlabel(kwargs['xlabel']) 
     if 'ylabel' in kwargs: 
      ax.set_ylabel(kwargs['ylabel']) 
     if 'xlim' in kwargs: 
      ax.set_xlim(*kwargs['xlim']) 
     if 'ylim' in kwargs: 
      ax.set_ylim(*kwargs['ylim']) 
     if show: 
      fig.tight_layout() 
      fig.show() 

    def plot_slices(self, others={}, fig=None, ax=None, 
        show=True, projections=True): 
     index = [] 
     pos = [] 
     title = '' 
     for i in xrange(self.dimensions): 
      temp = others.get(i,(self.limits[i][0]+self.limits[i][1])/2.) 
      title += '%d:%.4e\t' % (i,temp) 
      pos.append(temp) 
      index.append(self.position2index(temp,i)) 
     if self.dimensions == 3: 
      if fig is None: 
       fig = plt.figure() 
       if projections: 
        ax = [fig.add_subplot(221, projection='3d'), 
          fig.add_subplot(222), 
          fig.add_subplot(223), 
          fig.add_subplot(224)] 
       else: 
        ax = fig.add_subplot(111, projection='3d') 
      if projections: 
       xs = np.arange(self.limits[0][0], 
           self.limits[0][1] + self.limits[0][2], 
           self.limits[0][2]) 
       ys = np.arange(self.limits[1][0], 
           self.limits[1][1] + self.limits[1][2], 
           self.limits[1][2]) 
       zs = np.arange(self.limits[2][0], 
           self.limits[2][1] + self.limits[2][2], 
           self.limits[2][2]) 
       xs_c = np.arange(*self.limits[0]) 
       ys_c = np.arange(*self.limits[1]) 
       zs_c = np.arange(*self.limits[2]) 
       vmin = np.min(self.bins) 
       vmax = np.max(self.bins) 
       levels = np.linspace(vmin,vmax,20) 
       #graph 0 (3D) 
       ax[0].set_xlabel(r"$x$") 
       ax[0].set_ylabel(r"$y$") 
       ax[0].set_zlabel(r"$z$") 
       #ax[0].axis('equal') #not supported in 3D: 
#http://stackoverflow.com/questions/13685386/\ 
#matplotlib-equal-unit-length-with-equal-aspect-ratio-z-axis-is-not-equal-to 
       max_range = max([xs[-1]-xs[0],ys[-1]-ys[0],zs[-1]-zs[0]])/2. 
#    x_mean = (xs[-1] + xs[0])/2. 
#    y_mean = (ys[-1] + ys[0])/2. 
#    z_mean = (zs[-1] +zs[0])/2. 
       ax[0].set_xlim(pos[0] - max_range, pos[0] + max_range) 
       ax[0].set_ylim(pos[1] - max_range, pos[1] + max_range) 
       ax[0].set_zlim(pos[2] - max_range, pos[2] + max_range) 
       # to understand holes in contour plot: 
#http://stackoverflow.com/questions/18897950/\ 
#matplotlib-pyplot-contourf-function-introduces-holes-or-gaps-when-plotting-regul 
       # graph 1 (2D) 
       ZS, XS = np.meshgrid(zs,xs) 
       ZS_C, XS_C = np.meshgrid(zs_c,xs_c) 
       ax[1].pcolormesh(XS, ZS, self.bins[:,index[1],:], 
          vmin=vmin, vmax=vmax, 
          cmap=plt.cm.coolwarm) 
       ax[0].contourf(X=XS_C, Y=self.bins[:,index[1],:], Z=ZS_C, 
           zdir='y', offset=pos[1], 
           vmin=vmin, vmax=vmax, 
           cmap=plt.cm.coolwarm, levels=levels, 
           alpha=0.5) 
       ax[1].set_xlabel(r"$x$") 
       ax[1].set_ylabel(r"$z$") 
       ax[1].set_xlim(xs[0],xs[-1]) 
       ax[1].set_ylim(zs[0],zs[-1]) 
       ax[1].axis('equal') 
       # graph 2 (2D) 
       YS, XS = np.meshgrid(ys,xs) 
       YS_C, XS_C = np.meshgrid(ys_c,xs_c) 
       ax[2].pcolormesh(XS, YS, self.bins[:,:,index[2]], 
           vmin=vmin, vmax=vmax, 
           cmap=plt.cm.coolwarm) 
       ax[0].contourf(X=XS_C, Y=YS_C, Z=self.bins[:,:,index[2]], 
           zdir='z', offset=pos[2], 
           vmin=vmin, vmax=vmax, 
           cmap=plt.cm.coolwarm, levels=levels, 
           alpha=0.5) 
       ax[2].set_xlabel(r"$x$") 
       ax[2].set_ylabel(r"$y$") 
       ax[2].set_xlim(xs[0],xs[-1]) 
       ax[2].set_ylim(ys[0],ys[-1]) 
       ax[2].axis('equal') 
       # graph 3 (2D) 
       ZS, YS = np.meshgrid(zs, ys) 
       ZS_C, YS_C = np.meshgrid(zs_c, ys_c) 
       ax[3].pcolormesh(YS, ZS, self.bins[index[0],:,:], 
           vmin=vmin, vmax=vmax, 
           cmap=plt.cm.coolwarm) 
       ax[0].contourf(X=self.bins[index[0],:,:], Y=YS_C, Z=ZS_C, 
           zdir='x', offset=pos[0], 
           vmin=vmin, vmax=vmax, 
           cmap=plt.cm.coolwarm, levels=levels, 
           alpha=0.5) 
       ax[3].set_xlabel(r"$y$") 
       ax[3].set_ylabel(r"$z$") 
       ax[3].set_xlim(ys[0],ys[-1]) 
       ax[3].set_ylim(zs[0],zs[-1]) 
       ax[3].axis('equal') 
      else: 
       # update to draw a given slice, use it to plot eaxh axes above! 
       ax.plot(self.XS,self.YS,self.ZS) 
       ax.set_zlabel(r"$z$") 
       ax.set_xlabel(r"$x$") 
       ax.set_ylabel(r"$y$") 
       ax.axis('equal') 
     else: 
      if fig is None: 
       fig, ax = plt.subplots(1) 
      xs = np.arange(self.limits[0][0], 
          self.limits[0][1] + self.limits[0][2], 
          self.limits[0][2]) 
      ys = np.arange(self.limits[1][0], 
          self.limits[1][1] + self.limits[1][2], 
          self.limits[1][2],) 
      YS, XS = np.meshgrid(ys, xs) 
      graph = ax.pcolormesh(XS, YS, self.bins, cmap=plt.cm.coolwarm) 
      fig.colorbar(graph) 
      ax.set_xlim(self.limits[0][0], self.limits[0][1]) 
      ax.set_ylim(self.limits[1][0], self.limits[1][1]) 
      ax.set_title('Energy Distribution') 
      ax.set_xlabel(r"$x$") 
      ax.set_ylabel(r"$y$") 
      ax.axis('equal') 
     if show: 
      fig.tight_layout() 
      fig.show() 
     return fig, ax 

如果对代码的任何错误或窃听请说出来,我会修改上面的(学校项目已经被分级,这样你就不会做功课)。
此外,如果有什么不清楚,请说,所以我根据需要添加评论或解释。

+0

预计情节非常令人印象深刻! – Dalek 2015-07-10 12:42:19