Đây là hy vọng tôi sẽ không chụp một con muỗi với [rất xấu xí] pháo, tôi gần đây đã một lớp Binning_Array
cho một dự án trường học và tôi nghĩ rằng nó có thể có thể giúp bạn:
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()
Bạn có thể cũng chỉ sử dụng một Binner, nhưng lưu ý rằng bạn sẽ nhận được vật nơi các mặt phẳng giao nhau:
# ...
# 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()
các binning_array.py đã được thực hiện cho một dự án trường học và không hoàn toàn đánh bóng, nhưng nó đủ cho những gì bạn muốn .
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
Nếu bất kỳ điều gì trên mã sai hoặc bị lỗi, vui lòng nói như vậy và tôi sẽ chỉnh sửa ở trên (dự án trường đã được chấm điểm, vì vậy bạn sẽ không làm bài tập ở nhà).
Ngoài ra, nếu có điều gì không rõ ràng, vui lòng nói để tôi thêm nhận xét hoặc giải thích khi cần.
Tôi thực sự quan tâm đến việc có một âm mưu đường viền trong mỗi mặt phẳng mô tả phép chiếu của trục thứ ba dưới dạng mã màu. – Dalek