Szukaj…


Uwagi

Rysowanie trójwymiarowe w matplotlib było historycznie trochę kłopotliwe, ponieważ silnik renderujący jest z natury 2d. Fakt, że konfiguracje 3D są renderowane poprzez wykreślanie jednego fragmentu 2D po drugim, sugeruje, że często występują problemy z renderowaniem związane z pozorną głębią obiektów. Istotą problemu jest to, że dwa niepołączone obiekty mogą znajdować się całkowicie za sobą lub całkowicie przed sobą, co prowadzi do artefaktów, jak pokazano na poniższym rysunku dwóch powiązanych ze sobą pierścieni (kliknij, aby uzyskać animowany gif):

Wykres 3D dwóch powiązanych ze sobą pierścieni przedstawiających artefakt

Można to jednak naprawić. Ten artefakt istnieje tylko podczas drukowania wielu powierzchni na tym samym wykresie - ponieważ każdy z nich jest renderowany jako płaski kształt 2D, z jednym parametrem określającym odległość widoku. Zauważysz, że na jednej skomplikowanej powierzchni nie występuje ten sam problem.

Sposobem zaradzenia temu jest połączenie obiektów wykresu za pomocą przezroczystych mostów:

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()

Dwie powierzchnie przecinają się wzajemnie wprowadź opis zdjęcia tutaj

Tworzenie trójwymiarowych osi

Osie Matplotlib są domyślnie dwuwymiarowe. Aby utworzyć wykresy trójwymiarowe, musimy zaimportować klasę Axes3D z zestawu narzędzi mplot3d , co umożliwi nowy rodzaj rzutowania osi, a mianowicie '3d' :

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

Oprócz prostych uogólnień wykresów dwuwymiarowych (takich jak wykresy liniowe, wykresy rozrzutu, wykresy słupkowe, wykresy konturowe ), dostępnych jest kilka metod rysowania powierzchni , na przykład 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()

Axes3D z wykresem powierzchni



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow