matplotlib
Driedimensionale plots
Zoeken…
Opmerkingen
Driedimensionaal plotten in matplotlib is van oudsher een beetje een kludge, omdat de rendering-engine inherent 2d is. Het feit dat 3D-instellingen worden weergegeven door het ene deel na het andere uit te zetten, impliceert dat er vaak weergaveproblemen zijn met betrekking tot de schijnbare diepte van objecten. De kern van het probleem is dat twee niet-verbonden objecten zich volledig achter elkaar of volledig voor elkaar kunnen bevinden, wat leidt tot artefacten zoals weergegeven in de onderstaande afbeelding van twee met elkaar verbonden ringen (klik voor geanimeerde gif):
Dit kan echter worden opgelost. Dit artefact bestaat alleen bij het plotten van meerdere oppervlakken op dezelfde plot - omdat elk wordt weergegeven als een platte 2D-vorm, met een enkele parameter die de kijkafstand bepaalt. U zult merken dat een enkel gecompliceerd oppervlak niet hetzelfde probleem ondervindt.
De manier om dit te verhelpen is om de plotobjecten samen te voegen met behulp van transparante bruggen:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import erf
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(0, 6, 0.25)
Y = np.arange(0, 6, 0.25)
X, Y = np.meshgrid(X, Y)
Z1 = np.empty_like(X)
Z2 = np.empty_like(X)
C1 = np.empty_like(X, dtype=object)
C2 = np.empty_like(X, dtype=object)
for i in range(len(X)):
for j in range(len(X[0])):
z1 = 0.5*(erf((X[i,j]+Y[i,j]-4.5)*0.5)+1)
z2 = 0.5*(erf((-X[i,j]-Y[i,j]+4.5)*0.5)+1)
Z1[i,j] = z1
Z2[i,j] = z2
# If you want to grab a colour from a matplotlib cmap function,
# you need to give it a number between 0 and 1. z1 and z2 are
# already in this range, so it just works as is.
C1[i,j] = plt.get_cmap("Oranges")(z1)
C2[i,j] = plt.get_cmap("Blues")(z2)
# Create a transparent bridge region
X_bridge = np.vstack([X[-1,:],X[-1,:]])
Y_bridge = np.vstack([Y[-1,:],Y[-1,:]])
Z_bridge = np.vstack([Z1[-1,:],Z2[-1,:]])
color_bridge = np.empty_like(Z_bridge, dtype=object)
color_bridge.fill((1,1,1,0)) # RGBA colour, onlt the last component matters - it represents the alpha / opacity.
# Join the two surfaces flipping one of them (using also the bridge)
X_full = np.vstack([X, X_bridge, np.flipud(X)])
Y_full = np.vstack([Y, Y_bridge, np.flipud(Y)])
Z_full = np.vstack([Z1, Z_bridge, np.flipud(Z2)])
color_full = np.vstack([C1, color_bridge, np.flipud(C2)])
surf_full = ax.plot_surface(X_full, Y_full, Z_full, rstride=1, cstride=1,
facecolors=color_full, linewidth=0,
antialiased=False)
plt.show()
Driedimensionale assen maken
Matplotlib-assen zijn standaard tweedimensionaal. Om driedimensionale plots te maken, moeten we de Axes3D
klasse importeren uit de mplot3d-toolkit , die een nieuw soort projectie voor een assen mogelijk maakt, namelijk '3d'
:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
Naast de eenvoudige generalisaties tweedimensionale plots (zoals lijngrafieken , spreidingsdiagrammen , staafdiagrammen , contourplots ), verschillende oppervlakte plotten werkwijzen zijn bijvoorbeeld ax.plot_surface
:
# generate example data
import numpy as np
x,y = np.meshgrid(np.linspace(-1,1,15),np.linspace(-1,1,15))
z = np.cos(x*np.pi)*np.sin(y*np.pi)
# actual plotting example
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
# rstride and cstride are row and column stride (step size)
ax.plot_surface(x,y,z,rstride=1,cstride=1,cmap='hot')
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$y$')
ax.set_zlabel(r'$\cos(\pi x) \sin(\pi y)$')
plt.show()