matplotlib의 표면 플롯


104

3D 공간에서 일련의 점을 나타내는 3- 튜플 목록이 있습니다. 이 모든 점을 포함하는 표면을 플로팅하고 싶습니다.

패키지 의 plot_surface함수는 mplot3d인수 X, Y 및 Z가 2d 배열이어야합니다. plot_surface표면을 그리는 데 올바른 기능 이 있으며 데이터를 필요한 형식으로 변환하려면 어떻게해야합니까?

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


모든 중복 표면에 태그를 지정하고 중복을 서로 닫으십시오. 또한 meshgrid 생성에 관한 항목에 대해 numpy , mesh 태그 를 지정하십시오.
smci

답변:


120

표면의 경우 3- 튜플 목록과 약간 다르므로 2d 배열의 도메인에 대한 그리드를 전달해야합니다.

일부 기능이 아닌 3D 점 목록 만 f(x, y) -> z있으면 해당 3D 점 구름을 지표면으로 삼각 측량하는 여러 방법이 있기 때문에 문제가 발생합니다.

다음은 매끄러운 표면의 예입니다.

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

3d


1
안녕하세요, 감사합니다. f(x,y) -> z처음에 OP와 같은 목록 접근 방식을 사용하는 것보다 함수 가 더 많은 정보를 얻는 방법에 대해 자세히 설명해 주시겠습니까 ?
그레고리 쿤

16
그러나 z가 x와 y의 함수가 아닌 독립 변수 인 경우 어떻게합니까?
Labibah

4
이 경우에는 plot_trisurf대신 살펴 봐야합니다 . 그러나 내가 언급했듯이 표면을 삼각 측량해야하고 여러 솔루션이 있기 때문에 중요하지 않습니다. 기본 예로서 (0, 0, 0.2), (0, 1, 0), (1, 1, 0.2), (1, 0, 0)에 의해 주어진 4 개의 점만 고려하십시오. 위에서 보면 약간 접힌 정사각형처럼 보입니다. 그러나 어떤 대각선을 따라 "접힘"이 발생합니까? 0.2에서 "높은"대각선입니까 아니면 0에서 "낮은"대각선입니까? 둘 다 유효한 표면입니다! 따라서 잘 정의 된 솔루션을 갖기 전에 삼각 측량 알고리즘을 선택해야합니다.
wim

왜 mpl_toolkits.mplot3d에서 Axes3D를 가져 오지만 Axes3D는 위 코드의 어느 곳에서도 사용되지 않습니까?
絢瀬絵里

5
이 가져 오기에는 부작용이 있습니다. 이 가져 오기 없이는 kwarg projection='3d'를 호출에 fig.add_subplot사용할 수 없습니다.
2015 년

33

일부 파일에서 직접 데이터를 읽고 플롯 할 수 있습니다.

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

필요한 경우 vmin 및 vmax를 전달하여 컬러 바 범위를 정의 할 수 있습니다.

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

표면

보너스 섹션

이 경우 인공 데이터를 사용하여 대화 형 플롯을 수행하는 방법을 궁금합니다.

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
엄밀히 말하면 판다는 여기에서 필요하지 않습니다.
Downer

이 음모를 재현하는 데 어려움이 있습니다. 이를 달성하기 위해 (더 작은) 샘플 값은 무엇입니까?
JRsz

21

나는 방금이 같은 문제를 만났습니다. I 균등 대신에 2-D 어레이 (3) 1-D 어레이에 데이터 이격 한 matplotlibplot_surface욕구를. 내 데이터가 a에 있었 pandas.DataFrame으므로 여기에 3 개의 1-D 배열을 플롯하도록 수정 한 matplotlib.plot_surface예가 있습니다.

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

그것이 원래의 예입니다. 이 다음 비트를 추가하면 3 개의 1-D 배열에서 동일한 플롯이 생성됩니다.

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

결과 수치는 다음과 같습니다.

여기에 이미지 설명 입력 여기에 이미지 설명 입력


표면에 나오는 선 (위 이미지)을 제거 할 수 있는지 궁금합니다. 표면에 비늘 모양 대신 광택이 나는 느낌을 줄 수 있습니까? 감사합니다. @ stvn66
회절

@diffracteD, 더 작은 그리드 크기를 사용해보십시오. 윤곽 사이의 너비를 설정하는 것이 거의 확실합니다. 더 미세한 그리드에서 평가함으로써 기본적으로 "픽셀 크기"를 줄이고 해상도를 높여 부드러운 그라데이션에 접근해야합니다.
스티븐 C. 하웰

특정 카테고리에 따라 위의 표면을 색칠하는 방법이 있습니까? 예를 들어. 범주 x, y, z 는 데이터 형식이며 특정 범주에 따라 x, y, z를 통과하는 표면에 색상을 지정하고 싶습니다.
Rudresh Ajgaonkar

@RudreshAjgaonkar, 세 가지 각각에 대해 원하는 색상을 사용하여 각 범주에 대해 하나씩 세 가지 개별 플롯 명령을 사용할 수 있어야합니다.
Steven C. Howell

샘플 코드를 제공해 주시겠습니까? 나는 matplotlib와 python에 꽤 익숙합니다.
Rudresh Ajgaonkar

4

임마누엘은 내가 (그리고 아마도 많은 다른 사람들이) 찾고있는 답을 얻었다. 3 개의 개별 배열에 3D 분산 데이터가있는 경우 pandas는 놀라운 도움이되며 다른 옵션보다 훨씬 더 잘 작동합니다. 자세히 설명하기 위해 x, y, z가 임의의 변수라고 가정합니다. 제 경우에는 서포트 벡터 머신을 테스트하고 있었기 때문에 c, 감마 및 오류였습니다. 데이터를 표시 할 수있는 여러 가지 잠재적 선택 사항이 있습니다.

  • scatter3D (cParams, gammas, avg_errors_array)-작동하지만 지나치게 단순합니다.
  • plot_wireframe (cParams, gammas, avg_errors_array)-작동하지만 데이터가 제대로 정렬되지 않으면 실제 과학 데이터의 대량 청크가있는 경우처럼보기 흉하게 보일 것입니다.
  • ax.plot3D (cParams, gammas, avg_errors_array)-와이어 프레임과 유사

데이터의 와이어 프레임 플롯

데이터의 와이어 프레임 플롯

데이터의 3D 분산

데이터의 3D 분산

코드는 다음과 같습니다.

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

최종 출력은 다음과 같습니다.

xyz 데이터의 plot_trisurf


3

공식 예를 확인하십시오. X, Y 및 Z는 실제로 2d 배열이며 numpy.meshgrid ()는 1d x 및 y 값에서 2d x, y 메시를 얻는 간단한 방법입니다.

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

3 튜플을 3 1d 배열로 변환하는 비단뱀적인 방법이 있습니다.

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)

다음은 mtaplotlib delaunay 삼각 분할 (보간)입니다. 1d x, y, z를 호환되는 것으로 변환합니다 (?) :

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


아니요 ... XYZ는이 예에서 2 차원입니다.

나는 바로 잡았다. 연결된 예제와 같이 데이터의 간격이 균일 한 경우 meshgrid ()를 사용하십시오. 데이터가 균일하지 않은 경우 예를 들어 griddata ()로 보간하십시오.
Dima Tisnek 2012

1

에서 matlab에 내가 사용하는 비슷한했던 delaunay온 기능 x, y좌표 만 (안 z다음과 음모를 꾸미고,) trimesh또는 trisurf사용z 높이로 .

SciPy에는 Matlab의 QHull 라이브러리와 동일한 기본 QHull 라이브러리를 기반으로 하는 Delaunay 클래스가 있습니다.delaunay 함수 가 있으므로 동일한 결과를 얻어야합니다.

거기 에서 python-matplotlib 예제의 Plotting 3D Polygons 를 원하는대로 변환하는 코드 몇 줄이 있어야합니다 Delaunay. 각 삼각형 다각형의 사양이 제공됩니다.


를 기반으로 한이 답변을 참조하십시오 ax.plot_trisurf(..).
Evgeni Sergeev 2014 년

1

불규칙한 도메인 유형 문제를 가진 다른 사람들에게 도움이 될 수있는 몇 가지 추가 생각을 추가합니다. 사용자가 3 개의 벡터 / 목록 (x, y, z)이있는 경우, z가 직사각형 격자에 표면으로 그려지는 2D 솔루션을 나타내는 경우 ArtifixR의 'plot_trisurf ()'주석을 적용 할 수 있습니다. 유사한 예이지만 직사각형이 아닌 도메인은 다음과 같습니다.

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

위의 코드는 다음을 생성합니다.

직사각형이 아닌 그리드 문제에 대한 표면도

그러나 이것은 모든 문제, 특히 문제가 불규칙한 영역에 정의 된 경우 모든 문제를 해결하지 못할 수 있습니다. 또한 도메인에 오목한 영역이 하나 이상있는 경우 delaunay 삼각 측량으로 인해 도메인 외부에 스퓨리어스 삼각형이 생성 될 수 있습니다. 이러한 경우 올바른 표면 표현을 얻으려면 이러한 불량 삼각형을 삼각 측량에서 제거해야합니다. 이러한 상황에서 사용자는 이러한 삼각형을 프로그래밍 방식으로 제거 할 수 있도록 들로네 삼각 분할 계산을 명시 적으로 포함해야 할 수 있습니다. 이러한 상황에서 다음 코드는 이전 플롯 코드를 대체 할 수 있습니다.


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

아래에 솔루션 1) 스퓨리어스 삼각형이있는 그림과 2) 제거 된 그림이 나와 있습니다.

여기에 이미지 설명 입력

제거 된 삼각형

위의 내용이 솔루션 데이터에서 오목한 상황을 가진 사람들에게 도움이되기를 바랍니다.


0

데이터를 사용하여 3D 표면을 직접 만드는 것은 불가능합니다. pykridge 와 같은 도구를 사용하여 보간 모델을 구축하는 것이 좋습니다 . 이 프로세스에는 다음 세 단계가 포함됩니다.

  1. 다음을 사용하여 보간 모델 훈련 pykridge
  2. 에서 그리드 작성 XY사용meshgrid
  3. 값 보간 Z

그리드와 해당 Z값 을 생성 했으므로 이제 plot_surface. 데이터 크기에 따라 meshgrid함수가 잠시 실행될 수 있습니다. 해결 방법은 np.linspacefor XY축을 사용하여 균일 한 간격의 샘플을 만든 다음 보간을 적용하여 필요한 Z값 을 추론하는 것 입니다. 이 경우, 보간 값은 원래 다른 수 Z있기 때문 XY변경되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.