участки поверхности в matplotlib
У меня есть список из 3-х кортежей, представляющих набор точек в 3D пространстве. Я хочу построить поверхность, которая охватывает все эти точки. Функция plot_surface в пакете mplot3d требует в качестве аргументов X, Y и Z, которые являются 2d-массивами. Является ли plot_surface правильной функцией для построения поверхности и как я могу преобразовать свои данные в требуемый формат ?
data = [(x1,y1,z1),(x2,y2,z2),.....,(xn,yn,zn)]
7 ответов:
для поверхностей это немного отличается от списка 3-кортежей, вы должны передать в сетке для домена в 2d массивах.
Если все, что у вас есть, это список 3d точек, а не какая-то функция
f(x, y) -> z, тогда у вас будет проблема, потому что существует несколько способов триангуляции этого 3D-облака точек в поверхность.вот пример гладкой поверхности:
import numpy as np from mpl_toolkits.mplot3d import Axes3D # This import has side effects required for the kwarg projection='3d' in the call to fig.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(x,y) for x,y in zip(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 1-d массивах вместо 2-D массивов, которые
matplotlib' splot_surfaceхочет. Мои данные оказались вpandas.DataFrameтак вотmatplotlib.plot_surfaceпример С модификациями для построения 3 1-D массивов.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()вот результат цифры:
Я делаю это с некоторыми линиями в python, используя панд, сюжет прекрасен!
from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm import numpy as np import pandas as pd from sys import argv file = argv[1] x,y,z = np.loadtxt(file, unpack=True) df = pd.DataFrame({'x': x, 'y': y, 'z': z}) fig = plt.figure() ax = Axes3D(fig) 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('teste.pdf') plt.show()при необходимости вы можете передать vmin и vmax для определения диапазона цветовой панели, например
surf = ax.plot_trisurf(df.x, df.y, df.z, cmap=cm.jet, linewidth=0.1, vmin=0, vmax=2000)
Регистрация официальный пример. X, Y и Z действительно 2d массивы, numpy.meshgrid () - это простой способ получить 2d X,Y mesh из 1d 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 Делоне триангуляции (интерполяции), он преобразует 1d x, y, z в нечто совместимое (?):
http://matplotlib.sourceforge.net/api/mlab_api.html#matplotlib.mlab.griddata
в Matlab я сделал что-то подобное с помощью на
x,yтолько координаты (неz), то заговор сtrimeshилиtrisurf, используяzкак высота.составляющей имеет Делоне класс, который основан на той же базовой библиотеке QHull, что и Matlab
delaunayфункция есть, поэтому вы должны получить одинаковые результаты.оттуда должно быть несколько строк кода для преобразования этого построение 3D Полигоны в python-matplotlib пример в том, что вы хотите достичь, как
Delaunayдает вам спецификацию каждого треугольного полигона.
просто чтобы вмешаться, у Эмануэля был ответ, который я (и, вероятно, многие другие) ищу. Если у вас есть 3D-разбросанные данные в 3 отдельных массивах, 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 разброс данные
код выглядит так:
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()вот окончательный результат:
невозможно непосредственно создать 3d-поверхность с использованием ваших данных. Я бы рекомендовал вам построить модель интерполяции с помощью некоторых инструментов, таких как pykridge. Процесс будет включать в себя три этапа:
- обучите интерполяционную модель с помощью
pykridge- построить сетку от
XиYиспользуяmeshgrid- интерполировать значения для
Zсоздав свою сетку и соответствующий
Zзначения, теперь вы готовы к работе сplot_surface. Обратите внимание, что в зависимости от размера ваших данных,meshgridфункция может работать в течение некоторого времени. Обходной путь заключается в создании равномерно расположенных образцов с помощьюnp.linspaceнаXиYоси, затем применить интерполяцию, чтобы сделать вывод о необходимостиZзначения. Если это так, то интерполированные значения могут отличаться от исходныхZ, потому чтоXиYизменились.







Comments