2015-05-17 10 views
6

Ho dati 4D (punti di dispersione 3D + colore) tracciati usando la libreria mplot3d di matplotlib. Per aiutare a analizzare come la nuvola di punti è distribuita nello spazio, mi piacerebbe mostrare una proiezione della nuvola su ciascuno dei 3 piani (XY, XZ, YZ) usando un grafico di istogramma/contorno 2D.Come si può tracciare una proiezione di dati di dispersione 3D sui piani XY/XZ/YZ?

Ecco un MWE che utilizza ax.plot per fare ciò che voglio (come indicato di seguito). Questo funziona tecnicamente, ma penso che la sostituzione del dollaro-shot da ax.plot con i grafici di contorno sarebbe più visivamente piacevole:

import numpy as np 

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

# Prepare sample data - normally distributed 
NSamples = 5000 
vmin, vmax = -2, 2 

X = np.random.normal(loc=-.1, scale=.5, size=(NSamples,)) 
Y = np.random.normal(loc=.1, scale=.25, size=(NSamples,)) 
Z = np.random.normal(loc=0, scale=1, size=(NSamples,)) 

# Create figure, add subplot with 3d projection 
fig = plt.figure(figsize=(5,5)) 
ax = fig.add_subplot(111, projection='3d') 
ax.set_xlabel("X") 
ax.set_ylabel("Y") 
ax.set_zlabel("Z") 
ax.set_xlim(vmin, vmax) 
ax.set_ylim(vmin, vmax) 
ax.set_zlim(vmin, vmax) 

# Plot the data cloud 
ax.scatter(X, Y, Z, s=.5, alpha=.05, color='k') 

# Plot the 2D projections using `plot`. This is the piece I'd like to improve 
ax.plot(X, Y, '+', markersize=.2, color='r', zdir='z', zs=-2.) 
ax.plot(X, Z, '+', markersize=.2, color='g', zdir='y', zs=2.) 
ax.plot(Y, Z, '+', markersize=.2, color='b', zdir='x', zs=-2.) 

plt.savefig("3DScatter.png") 

# Now, I'd *like* for the following histograms to be plotted on each of the XY, XZ, YZ planes 
instead of using `plot` above 
for label, data_x, data_y in [ ['XY', X, Y], ['XZ', X, Z], ['YZ', Y, Z] ]: 
    hist, binx, biny = np.histogram2d(data_x, data_y, bins=[xbins, ybins]) 

    plt.figure(figsize=(5,5)) 
    plt.imshow(hist, extent=[vmin,vmax,vmin,vmax]) 
    plt.xlabel(label[1]) 

Che produce:

3D scatterXY

XZYZ

ecc.

Così da essere pulito r, c'è un modo per tracciare gli istogrammi XY, XZ, YZ 2D tracciati con imshow sopra sugli assi 3D associati? Anche una soluzione basata su contour andrebbe bene.

noti che (io sono abbastanza certo) questo è non una ripetizione di this related question, la cui soluzione funziona solo per i dati 2D (f (x, y)), non 3D (f (x, y, z)).

risposta

4

Se si sta bene con l'utilizzo di contour o contourf, si può fare qualcosa di simile:

import numpy as np 

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

# Prepare sample data - normally distributed 
NSamples = 5000 
vmin, vmax = -2, 2 

X = np.random.normal(loc=-.1, scale=.5, size=(NSamples,)) 
Y = np.random.normal(loc=.1, scale=.25, size=(NSamples,)) 
Z = np.random.normal(loc=0, scale=1, size=(NSamples,)) 

# Create figure, add subplot with 3d projection 
fig = plt.figure(figsize=(5,5)) 
ax = fig.add_subplot(111, projection='3d') 
ax.set_xlabel("X") 
ax.set_ylabel("Y") 
ax.set_zlabel("Z") 
ax.set_xlim(vmin, vmax) 
ax.set_ylim(vmin, vmax) 
ax.set_zlim(vmin, vmax) 

# Plot the data cloud 
ax.scatter(X, Y, Z, s=.5, alpha=.05, color='k') 

hist, binx, biny = np.histogram2d(X, Y) 
x = np.linspace(X.min(), X.max(), hist.shape[0]) 
y = np.linspace(Y.min(), Y.max(), hist.shape[1]) 
x, y = np.meshgrid(x, y) 
ax.contour(x, y, hist, zdir='z', offset=-3.) 

hist, binx, biny = np.histogram2d(X, Z) 
x = np.linspace(X.min(), X.max(), hist.shape[0]) 
z = np.linspace(Z.min(), Z.max(), hist.shape[1]) 
x, z = np.meshgrid(x, z) 
ax.contour(x, hist, z, zdir='y', offset=3) 

hist, binx, biny = np.histogram2d(Y, Z) 
y = np.linspace(Y.min(), Y.max(), hist.shape[0]) 
z = np.linspace(Z.min(), Z.max(), hist.shape[1]) 
z, y = np.meshgrid(z, y) 
ax.contour(hist, y, z, zdir='x', offset=-3) 

ax.set_xlim([-3, 3]) 
ax.set_ylim([-3, 3]) 
ax.set_zlim([-3, 3]) 
+0

Giuro che ho provato proprio questa soluzione, ma è chiaro che non l'ho fatto. Guardando nella mia versione precedente per dove sono andato storto. Funziona esattamente come previsto, grazie! – paradiso

+0

Prego :-) –