matplotlib'de yüzey grafikleri


105

3B uzayda bir dizi noktayı temsil eden 3'lü bir listem var. Tüm bu noktaları kapsayan bir yüzey çizmek istiyorum.

plot_surfaceFonksiyon mplot3dargümanlar, X, Y ve Z, 2d diziler olacak şekilde paket gerektirir. plot_surfaceYüzey çizimi için doğru işlev mi ve verilerimi gerekli formata nasıl dönüştürürüm?

data = [(x1,y1,z1),(x2,y2,z2),.....,(xn,yn,zn)]


Lütfen tüm bu yinelenen yüzeyleri etiketlemeye başlayın ve yinelenenleri birbiriyle kapatın. Ayrıca etiket numpy , örgü meshgrid nesil üzeresiniz olanlar için.
smci

Yanıtlar:


121

Yüzeyler için, 3'lü bir listeden biraz farklıdır, 2d dizilerindeki etki alanı için bir ızgara geçirmelisiniz.

Eğer sahip olduğunuz tek şey bir fonksiyondan ziyade 3B noktaların bir listesiyse f(x, y) -> z, o zaman bir problem yaşarsınız çünkü bu 3B nokta bulutunu bir yüzeye üçgenlemenin birden fazla yolu vardır.

İşte pürüzsüz bir yüzey örneği:

import numpy as np
from mpl_toolkits.mplot3d import Axes3D  
# Axes3D import has side effects, it enables using projection='3d' in add_subplot
import matplotlib.pyplot as plt
import random

def fun(x, y):
    return x**2 + y

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = y = np.arange(-3.0, 3.0, 0.05)
X, Y = np.meshgrid(x, y)
zs = np.array(fun(np.ravel(X), np.ravel(Y)))
Z = zs.reshape(X.shape)

ax.plot_surface(X, Y, Z)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

3 boyutlu


1
Merhaba bunun için teşekkürler. Bir işleve sahip olmanın f(x,y) -> zsize sadece OP'nin başlangıçta sahip olduğu gibi bir liste yaklaşımı kullanmaktan daha fazla bilgiyi nasıl getirdiğini ayrıntılarıyla açıklayabilir misiniz?
Gregory Kuhn

16
Fakat z bağımsız bir değişkense ve x ve y'nin bir fonksiyonu olmadığında ne yaparsınız?
Labibah

4
Bu durumda, belki de plot_trisurfonun yerine bakmalısınız . Ama bahsettiğim gibi, bu önemsiz değil çünkü yüzeyi üçgenlemeniz gerekiyor ve birden fazla çözüm var. Temel bir örnek olarak, (0, 0, 0.2), (0, 1, 0), (1, 1, 0.2), (1, 0, 0) ile verilen 4 noktayı düşünün. Yukarıdan bakıldığında, içinde hafif bir kıvrım olan bir kareye benziyor. Ama "kıvrım" hangi köşegen boyunca meydana gelir? 0,2'de "yüksek" diyagonal mi yoksa 0'da "düşük" diyagonal mi? Her ikisi de geçerli yüzeylerdir! Bu nedenle, iyi tanımlanmış bir çözüme sahip olmadan önce bir üçgenleme algoritması seçmeniz gerekir.
wim

Neden mpl_toolkits.mplot3d'den Axes3D'yi içe aktarırken, Axes3D yukarıdaki kodun hiçbir yerinde kullanılmıyor?
絢 瀬 絵 里

5
Bu ithalatın yan etkileri var. Kwarg kullanma projection='3d'çağrısında fig.add_subplotbu ithalat olmadan kullanılamaz.
wim

34

Verileri doğrudan bir dosyadan ve arsadan okuyabilirsiniz

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

x,y,z = np.loadtxt('your_file', unpack=True)

fig = plt.figure()
ax = Axes3D(fig)
surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1)
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.savefig('teste.pdf')
plt.show()

Gerekirse, renk çubuğu aralığını tanımlamak için vmin ve vmax'ı geçebilirsiniz, örn.

surf = ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.1, vmin=0, vmax=2000)

yüzey

Bonus Bölümü

Bu durumda yapay verilerle bazı etkileşimli arsaların nasıl yapılacağını merak ediyordum.

from __future__ import print_function
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
from IPython.display import Image

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

def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))

def plot(i):

    fig = plt.figure()
    ax = plt.axes(projection='3d')

    theta = 2 * np.pi * np.random.random(1000)
    r = i * np.random.random(1000)
    x = np.ravel(r * np.sin(theta))
    y = np.ravel(r * np.cos(theta))
    z = f(x, y)

    ax.plot_trisurf(x, y, z, cmap='viridis', edgecolor='none')
    fig.tight_layout()

interactive_plot = interactive(plot, i=(2, 10))
interactive_plot

5
kesinlikle, pandalar burada gereksizdir.
downer

Bu arsayı yeniden üretmekte zorlanıyorum. Bunu başarmak için bazı (daha küçük) örnek değerler ne olabilir?
JRsz

21

Ben de aynı problemle karşılaştım. Ben eşit yerine, 2-D dizileri 3 1-D dizileri olan verilerin aralıklı olan matplotlibbireyin plot_surfaceistediği. Verilerim bir içindeydi, pandas.DataFramebu yüzden işte 3 adet 1-D dizisini çizmek için yapılan değişikliklere matplotlib.plot_surfaceörnek .

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
import matplotlib.pyplot as plt
import numpy as np

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Original Code')

Orijinal örnek budur. Bu sonraki bitin eklenmesi, 3 1-D dizisinden aynı grafiği oluşturur.

# ~~~~ MODIFICATION TO EXAMPLE BEGINS HERE ~~~~ #
import pandas as pd
from scipy.interpolate import griddata
# create 1D-arrays from the 2D-arrays
x = X.reshape(1600)
y = Y.reshape(1600)
z = Z.reshape(1600)
xyz = {'x': x, 'y': y, 'z': z}

# put the data into a pandas DataFrame (this is what my data looks like)
df = pd.DataFrame(xyz, index=range(len(xyz['x']))) 

# re-create the 2D-arrays
x1 = np.linspace(df['x'].min(), df['x'].max(), len(df['x'].unique()))
y1 = np.linspace(df['y'].min(), df['y'].max(), len(df['y'].unique()))
x2, y2 = np.meshgrid(x1, y1)
z2 = griddata((df['x'], df['y']), df['z'], (x2, y2), method='cubic')

fig = plt.figure()
ax = fig.gca(projection='3d')
surf = ax.plot_surface(x2, y2, z2, rstride=1, cstride=1, cmap=cm.coolwarm,
    linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)
plt.title('Meshgrid Created from 3 1D Arrays')
# ~~~~ MODIFICATION TO EXAMPLE ENDS HERE ~~~~ #

plt.show()

İşte ortaya çıkan rakamlar:

görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin


Yüzeyde gelen çizgileri (yukarıdaki resim) kaldırmak mümkün mü diye merak ediyordum, yani yüzeye pullu görünüm yerine parlak bir görünüm vermek mümkün mü? teşekkür ederim. @ stvn66
diffracteD

@diffracteD, daha küçük bir ızgara boyutu kullanmayı deneyin. Konturlar arasındaki genişliği belirleyen şeyin bu olduğundan neredeyse eminim. Daha ince bir ızgarada değerlendirerek, esasen "piksel boyutunu" düşürmeli ve çözünürlüğü artırarak daha yumuşak bir gradyana yaklaşmalısınız.
Steven C. Howell

Yukarıdaki yüzeyi belirli kategorilere göre renklendirmenin bir yolu var mı? Örn. Kategori x, y, z veri formatıdır ve x, y, z'den geçen yüzeyi belirli bir kategoriye göre renklendirmek istiyorum.
Rudresh Ajgaonkar

@RudreshAjgaonkar, kategorilerinizin her biri için bir tane olmak üzere üç ayrı çizim komutunu kullanabilmelisiniz, üçünün her biri için istediğiniz rengi kullanarak.
Steven C. Howell

lütfen bir örnek kod verebilir misiniz? matplotlib ve python'da oldukça yeniyim.
Rudresh Ajgaonkar

4

Emanuel, benim (ve muhtemelen diğerlerinin) aradığı cevabı aldı. 3 ayrı dizide 3 boyutlu dağınık veriye sahipseniz, pandalar inanılmaz bir yardımcıdır ve diğer seçeneklerden çok daha iyi çalışır. Ayrıntılı olarak, x, y, z'nizin bazı rastgele değişkenler olduğunu varsayalım. Benim durumumda bunlar c, gama ve hatalardı çünkü bir destek vektör makinesini test ediyordum. Verileri çizmek için birçok olası seçenek vardır:

  • scatter3D (cParams, gammas, avg_errors_array) - bu işe yarıyor ancak aşırı derecede basittir
  • plot_wireframe (cParams, gammas, avg_errors_array) - bu işe yarar, ancak verileriniz güzel bir şekilde sıralanmazsa çirkin görünecektir, potansiyel olarak gerçek bilimsel veri yığınlarında olduğu gibi
  • ax.plot3D (cParams, gammas, avg_errors_array) - wireframe'e benzer

Verilerin tel kafes grafiği

Verilerin tel kafes grafiği

Verinin 3B dağılımı

Verinin 3B dağılımı

Kod şuna benzer:

    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.set_xlabel('c parameter')
    ax.set_ylabel('gamma parameter')
    ax.set_zlabel('Error rate')
    #ax.plot_wireframe(cParams, gammas, avg_errors_array)
    #ax.plot3D(cParams, gammas, avg_errors_array)
    #ax.scatter3D(cParams, gammas, avg_errors_array, zdir='z',cmap='viridis')

    df = pd.DataFrame({'x': cParams, 'y': gammas, 'z': avg_errors_array})
    surf = ax.plot_trisurf(df.x, df.y, df.z, cmap=cm.jet, linewidth=0.1)
    fig.colorbar(surf, shrink=0.5, aspect=5)    
    plt.savefig('./plots/avgErrs_vs_C_andgamma_type_%s.png'%(k))
    plt.show()

İşte nihai çıktı:

xyz verilerinin plot_trisurf'u


3

resmi örneği kontrol edin. X, Y ve Z gerçekte 2d dizilerdir, numpy.meshgrid (), 1d x ve y değerlerinden 2d x, y mesh elde etmenin basit bir yoludur.

http://matplotlib.sourceforge.net/mpl_examples/mplot3d/surface3d_demo.py

İşte 3'lü dizilerinizi 3 1d dizilerine dönüştürmenin pitonik yolu.

data = [(1,2,3), (10,20,30), (11, 22, 33), (110, 220, 330)]
X,Y,Z = zip(*data)
In [7]: X
Out[7]: (1, 10, 11, 110)
In [8]: Y
Out[8]: (2, 20, 22, 220)
In [9]: Z
Out[9]: (3, 30, 33, 330)

İşte mtaplotlib delaunay nirengi (interpolasyon), 1d x, y, z'yi uyumlu bir şeye dönüştürür (?):

http://matplotlib.sourceforge.net/api/mlab_api.html#matplotlib.mlab.griddata


Hayır ... XYZ bu örnekte 2 boyutludur.
wim

Düzeltilmiş durumdayım. Verileriniz bağlantılı örnekte olduğu gibi eşit aralıklıysa meshgrid () kullanın. Verileriniz eşit aralıklı değilse, örneğin griddata () ile enterpolate edin.
Dima Tisnek

2

Düzensiz alan türü sorunları olan başkalarına yardımcı olabilecek bazı düşünceler eklemek için. Kullanıcının üç vektör / listeye (x, y, z) sahip olduğu ve z'nin bir yüzey olarak dikdörtgen bir ızgara üzerine çizileceği bir 2D çözümü temsil ettiği bir durumda, ArtifixR'nin 'plot_trisurf ()' yorumları uygulanabilir. Dikdörtgen olmayan etki alanına sahip benzer bir örnek:

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

# problem parameters
nu = 50; nv = 50
u = np.linspace(0, 2*np.pi, nu,) 
v = np.linspace(0, np.pi, nv,)

xx = np.zeros((nu,nv),dtype='d')
yy = np.zeros((nu,nv),dtype='d')
zz = np.zeros((nu,nv),dtype='d')

# populate x,y,z arrays
for i in range(nu):
  for j in range(nv):
    xx[i,j] = np.sin(v[j])*np.cos(u[i])
    yy[i,j] = np.sin(v[j])*np.sin(u[i])
    zz[i,j] = np.exp(-4*(xx[i,j]**2 + yy[i,j]**2)) # bell curve

# convert arrays to vectors
x = xx.flatten()
y = yy.flatten()
z = zz.flatten()

# Plot solution surface
fig = plt.figure(figsize=(6,6))
ax = Axes3D(fig)
ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0,
                antialiased=False)
ax.set_title(r'trisurf example',fontsize=16, color='k')
ax.view_init(60, 35)
fig.tight_layout()
plt.show()

Yukarıdaki kod şunları üretir:

Dikdörtgen olmayan ızgara problemi için yüzey grafiği

Bununla birlikte, özellikle sorunun düzensiz bir alanda tanımlandığı durumlarda bu, tüm sorunları çözmeyebilir. Ayrıca, alanın bir veya daha fazla içbükey alana sahip olması durumunda, delaunay üçgenleme, alanın dışında sahte üçgenlerin üretilmesine neden olabilir. Bu gibi durumlarda, doğru yüzey temsilini elde etmek için bu hileli üçgenlerin üçgenlemeden çıkarılması gerekir. Bu durumlar için, kullanıcının, bu üçgenlerin programlı olarak kaldırılabilmesi için delaunay üçgenleme hesaplamasını açıkça dahil etmesi gerekebilir. Bu koşullar altında, aşağıdaki kod önceki çizim kodunun yerini alabilir:


import matplotlib.tri as mtri 
import scipy.spatial
# plot final solution
pts = np.vstack([x, y]).T
tess = scipy.spatial.Delaunay(pts) # tessilation

# Create the matplotlib Triangulation object
xx = tess.points[:, 0]
yy = tess.points[:, 1]
tri = tess.vertices # or tess.simplices depending on scipy version

#############################################################
# NOTE: If 2D domain has concave properties one has to
#       remove delaunay triangles that are exterior to the domain.
#       This operation is problem specific!
#       For simple situations create a polygon of the
#       domain from boundary nodes and identify triangles
#       in 'tri' outside the polygon. Then delete them from
#       'tri'.
#       <ADD THE CODE HERE>
#############################################################

triDat = mtri.Triangulation(x=pts[:, 0], y=pts[:, 1], triangles=tri)

# Plot solution surface
fig = plt.figure(figsize=(6,6))
ax = fig.gca(projection='3d')
ax.plot_trisurf(triDat, z, linewidth=0, edgecolor='none',
                antialiased=False, cmap=cm.jet)
ax.set_title(r'trisurf with delaunay triangulation', 
          fontsize=16, color='k')
plt.show()

Örnek grafikler, çözüm 1) sahte üçgenlerle ve 2) bunların kaldırıldığı yerleri gösteren aşağıda verilmiştir:

görüntü açıklamasını buraya girin

üçgenler kaldırıldı

Umarım yukarıdakiler, çözüm verilerinde içbükey durumları olan kişilere yardımcı olabilir.


1

Matlab'da, delaunayişlevini kullanarak benzer bir şey yaptım x, ysadece koordinatlar (değil z), sonra yükseklik olarak trimeshveya trisurfkullanarak grafik çizdim z.

Scipy vardır Delaunay Matlab'ın o aynı temel Qhull kütüphane dayanmaktadır sınıf, delaunaysen aynı sonuçları almalıdırlar böylece fonksiyonudur.

Buradan, bu 3B Çokgenleri python-matplotlib'de Çizme örneğini Delaunay, her bir üçgen çokgenin özelliklerini verdiği gibi , ulaşmak istediğiniz şeye dönüştürmek için birkaç satır kod olmalıdır .


Bu cevaba göre bakın ax.plot_trisurf(..).
Evgeni Sergeev

0

Verilerinizi kullanarak doğrudan 3 boyutlu bir yüzey oluşturmak mümkün değildir. Pykridge gibi bazı araçları kullanarak bir enterpolasyon modeli oluşturmanızı tavsiye ederim . Süreç üç adım içerecektir:

  1. Kullanarak bir enterpolasyon modeli eğitin pykridge
  2. Kullanarak Xve Ykullanarak bir ızgara oluşturunmeshgrid
  3. İçin değerleri enterpolate Z

Izgaranızı ve karşılık gelen Zdeğerleri oluşturduktan sonra , artık başlamaya hazırsınız plot_surface. Verilerinizin boyutuna bağlı olarak, meshgridişlevin bir süre çalışabileceğini unutmayın. Çözüm, np.linspacefor Xve Yeksenlerini kullanarak eşit aralıklı örnekler oluşturmak , ardından gerekli Zdeğerleri çıkarmak için enterpolasyon uygulamaktır . Eğer öyleyse, interpolated değerler orijinalinden farklı olabilir Zçünkü Xve Ydeğişti.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.