Данные графика, хранящиеся в файле с использованием (mayavi) mlab.contour3d?
Я изо всех сил пытаюсь сделать простой contour3d график в Mayavi, используя данные, которые считываются из файла. Данные представляют собой обычную трехмерную декартову сетку в виде
x1 y1 z1 val(x1,y1,z1)
x1 y1 z2 val(x1,y1,z2)
. . . .
x1 y1 z_K val(x1,y1,z_K)
x1 y2 z1 val(x1,y2,z1)
. . . .
. . . .
x_L y_M z_K val(x_L,y_M,z_K)
(Здесь первые 3 значения в каждой строке дают координаты (x,y,z) точки, в то время как 4-е значение дает значение скаляра в этой точке. Я могу вставить минимальный файл примера, если это полезно)
Файл данных может быть успешно прочитан с использованием numpy.loadtxt, но как мне перейти к построению изоповерхности с использованием (mayavi) mlab.contour3d? Я думаю, что выходной массив по умолчанию из loadtxt не в правильном формате для mlab.contour3d.
Все примеры, которые мне удалось найти в mlab.contour3d, генерируют сетку с использованием ogrid, а затем изображают простую функцию (sin и т. Д.) Этой сетки. Мне удалось успешно запустить эти примеры, но они не говорят мне, как читать данные из файла в правильный формат массива, готового к построению. Я уверен, что это помогло бы многим новичкам в подобной ситуации, если бы кто-то мог дать мне указатель; построение трехмерных данных, хранящихся в файле, сгенерированном другой программой, несомненно, должно быть одной из самых распространенных задач, которые должны выполнять ученые.
1 ответ
Я нашел следующее, чтобы работать хорошо.
x, y, z, d - это одномерные числовые массивы из необработанного входного текстового файла, где d = f(x,y,z)
# Import relevant modules
import numpy as np
import scipy.interpolate as si
from mayavi import mlab
# Generate the figure
figure = mlab.figure()
# Generate the 3D mesh
xi, yi, zi = np.meshgrid(*([np.linspace(0,1,100)] * 3))
# Interpolate d over the 3D mesh
di = si.griddata((x, y, z), d, (xi, yi, zi))
# Generate the desired figure
min_d = d.min()
max_d = d.max()
grid = mlab.pipeline.scalar_field(di)
mlab.pipeline.volume(grid, vmin=min_d, vmax=min_d + .5*(max_d-min_d))
# Other good options too
## mlab.contour3d(di, vmin=min_d, vmax=min_d + .8*(max_d-min_d))
## pts = mlab.points3d(x, y, z, d)
mlab.axes()
mlab.show()
Извиняюсь перед г-ном Е. за задержку с ответом, у меня не было доступа в интернет в выходные дни. Однако у меня был доступ к компьютеру, и я нашел ответ на свой вопрос, хотя и немного некрасивый. Я уверен, что следующий метод может быть улучшен, и, по причинам, изложенным выше, я знаю, что это важное базовое использование программного обеспечения для 3D-черчения, поэтому, если у кого-то есть какие-либо улучшения, которые они могут предложить, они будут очень благодарны. В следующем объяснении предполагается, что вы используете Linux, но я уверен, что сделать то же самое (например, сохранить и запустить файлы python) просто в других ОС.
Сначала создайте образец файла данных. Реальные данные поступают из программы на Фортране, но для целей текущего тестирования я буду использовать python для генерации образца файла данных. Сохраните следующий код в файле "gen-data.py" (скопируйте его в свой любимый текстовый редактор и затем нажмите "Сохранить как" и т. д.)
#!/usr/bin/python
import numpy as numpy
# run this program with
#" python gen-data.py > stream.out "
# to generate sample data file stream.out
x_low = -1 ; x_upp = 1 ; NX = 5
y_low = -2 ; y_upp = 2 ; NY = 3
z_low = -3 ; z_upp = 3 ; NZ = 3
x_arr = numpy.linspace(x_low,x_upp,num = NX, endpoint=True)
y_arr = numpy.linspace(y_low,y_upp,num = NY, endpoint=True)
z_arr = numpy.linspace(z_low,z_upp,num = NZ, endpoint=True)
#the following line generates data (for distance from the origin)
# over a structured grid
for x in x_arr:
for y in y_arr:
for z in z_arr:
print x , y , z , x**2 + y**2 + z**2
Запустите программу, используя python gen-data.py > stream.out, который будет хранить образец файла данных описанного выше типа в файле данных "stream.out". У вас должен быть файл со значениями:
-1,0 -2,0 -3,0 14,0
-1,0 -2,0 0,0 5,0
-1,0 -2,0 3,0 14,0
-1,0 0,0 -3,0 10,0
-1,0 0,0 0,0 1,0
-1,0 0,0 3,0 10,0
-1,0 2,0 -3,0 14,0
-1,0 2,0 0,0 5,0
-1,0 2,0 3,0 14,0
-0,5 -2,0 -3,0 13,25
,,,,
0,5 2,0 3,0 13,25
1,0 -2,0 -3,0 14,0
1,0 -2,0 0,0 5,0
1,0 -2,0 3,0 14,0
1,0 0,0 -3,0 10,0
1,0 0,0 0,0 1,0
1,0 0,0 3,0 10,0
1,0 2,0 -3,0 14,0
1,0 2,0 0,0 5,0
1,0 2,0 3,0 14,0
Каждая строка в файле данных имеет вид
x y z V(x,y,z)
где x, y, z описывают координаты x,y,x точки в пространстве, а V (x, y, z) обозначает значение скаляра в этой точке.
Построение данных
Наша проблема заключается в том, как построить эти данные с помощью Mayavi - я особенно заинтересован в построении изоповерхностей, что может быть достигнуто с помощью команды contour3d. Многочисленные примеры в Интернете показывают данные построения contour3d, которые генерируются с помощью команды mgrid. (Есть также примеры использования команды ogrid, но для меня mgrid было легче понять). Стратегия: если мы сможем манипулировать нашими данными, чтобы они имели ту же форму и форму, что и выходные данные команды mgrid, мы сможем построить ее. Анализируя выходные данные mgrid, стало ясно, что для хранения координат x, y и z необходимы 3 трехмерных числовых массива и еще один массив трехмерных чисел для хранения скалярных значений (V выше) в этих точках. Следующая программа выполняет эти шаги. Я думаю, что программу, безусловно, можно улучшить: подпрограмма fill_up_array, я уверен, может быть заменена однострочником кем-то, кто знает о нарезке массивов в python, и, вероятно, есть другие места, которые можно улучшить. Я не могу не думать, что все это, вероятно, может быть сделано в 1 или 2 строки для кого-то, кто знает, что они делают в numpy/mayavi, но следующая программа, я считаю, проста для понимания, и она работает (вы должны увидеть усеченные сферические поверхности на графике, который появляется).
Сохраните следующий файл в "hope.py" и запустите с
python hope.py
import numpy
from mayavi import mlab
def fill_up_array(output_arr,source_arr,nx,ny,nz,posn):
# takes a slice of results from source_arr and writes to output_arr
# there is probably an easy one liner to do this ?
#TODO: add checks to ensure input is sensible
for i in range(nx):
for j in range(ny):
for k in range(nz):
output_arr[i][j][k] = source_arr[i][j][k][posn]
# these numbers have to correspond to those used in gen-data.py
NX = 5 ; NY = 3 ; NZ = 3
NDIM = 4 # number of columns in data file, 4 for current example
#initialise arrays:
# xx will contain x coordinate of data point
# yy will contain y coordinate of data point
# zz will contain z coordinate of data point
# VV will contain sample scalar value at (x,y,z)
xx = numpy.zeros((NX,NY,NZ))
yy = numpy.zeros((NX,NY,NZ))
zz = numpy.zeros((NX,NY,NZ))
VV = numpy.zeros((NX,NY,NZ))
#now read in values from stream.out file to these arrays
full = numpy.loadtxt("stream.out")
fy = numpy.reshape(full, (NX,NY,NZ,NDIM))
fill_up_array(xx,fy,NX,NY,NZ,0)
fill_up_array(yy,fy,NX,NY,NZ,1)
fill_up_array(zz,fy,NX,NY,NZ,2)
fill_up_array(VV,fy,NX,NY,NZ,3)
#test plot
mlab.contour3d(xx, yy, zz, VV)
mlab.show()