3D-график рассеяния нескольких файлов, каждый из которых имеет уникальный цвет - PullRequest
0 голосов
/ 08 ноября 2019

Я видел эту ветку , но мои данные немного отличаются. Я хочу создать трехмерный график из нескольких файлов, содержащих координаты x, y, z и цветовой код каждого файла с уникальным цветом, а не каждой координат точки

Код до настоящего времени:

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

files = sorted(glob.glob('mesh_files/*.vtk'))

mesh = []

fig = plt.figure(figsize = (16, 10))
ax = plt.axes(projection = '3d')

colors = cm.rainbow(np.linspace(0, 1, 16))

for file in files:
    mesh.append(meshio.read(file))

    x = [m.points[:, 0] for m in mesh]
    y = [m.points[:, 1] for m in mesh]
    z = [m.points[:, 2] for m in mesh]

    for a,b,c,d in zip(x,y,z,colors):
        plt.scatter(a,b,c,color=d)

Фон

x, y и z - все lists, содержащие numpy arrays

<< <code>len(x)
16

<< <code>len(x[0])
99937

<< <code>x[0].shape
(99937,)

<< <code>type(x)
<class 'list'>

<< <code>type(x[0])
<class 'numpy.ndarray'>

Я считаю, что проблема заключается вс colors и возможным несоответствием размеров

<< <code>len(colors)
16

<< <code>len(colors[0])
4

Ошибка

RuntimeWarning: invalid value encountered in sqrt

РЕДАКТИРОВАТЬ: я могу индивидуально позвонить scatter и вручную ввести другой цвет, чтобы создать график ниже, но это будет длиться вечно с10+ файлов, поэтому я хочу, чтобы это было в цикле или какой-то функции. individually called scatter plots

РЕДАКТИРОВАТЬ 2: Мне удалось получить этот график, и это хорошо, что цвета различны для данных каждого файла, но масштаб z слишком мал по сравнениюна первый график, и похоже, что данные отсутствуют, он должен быть похож на первый график с точки зрения значений глубины z, но с 16 уникальными цветами, как на втором графике. На первом графике отображаются только 3 файла вручную

enter image description here

Ответы [ 4 ]

1 голос
/ 08 ноября 2019

Если вам впоследствии не нужны сетки, вы можете избежать выделения части памяти

...
colors = iter(cm.rainbow(np.linspace(0, 1, 16)))
for file in files:
    plt.scatter(*meshio.read(file).points.T, c=[next(colors)], label=file)
plt.legend()
plt.show()

или, если вам понадобятся сетки позже, мы можем использовать контейнер

...
meshes = []
colors = iter(cm.rainbow(np.linspace(0, 1, 16)))
for file in files:
    meshes.append(meshio.read(file))
    plt.scatter(*meshes[-1].points.T, c=[next(colors)], label=file)
plt.legend()
plt.show()

NB scatter в 3D нуждается x, y и z, все с формой (N,), в то время как meshobj.points имеет форму (N, 3), поэтому мы сначала транспонируем ее (форма теперь (3, N)) инаконец, мы распаковываем (используя звездообразный оператор "*") двумерный массив, чтобы получить запрошенные три (N,) массива.

1 голос
/ 08 ноября 2019

Я думаю, что ваша ошибка происходит из списка мешей, который вы обновляете на каждом шаге. Каждый шаг вы строите весь список мешей так, чтобы ваш первый файл отображался 16 раз в 16 разных цветах.

Простейшим кодом может быть:

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

files = sorted(glob.glob('mesh_files/*.vtk'))

fig = plt.figure(figsize = (16, 10))
ax = plt.axes(projection = '3d')

colors = cm.rainbow(np.linspace(0, 1, len(files)))

for file in files:
    data = meshio.read(file).points

    x = data[:, 0]
    y = data[:, 1]
    z = data[:, 2]

    plt.scatter(x, y, z, color = colors[files.index(file)])

Если вы хотите сохранить все точки в списке с именем mesh, вы можете изменить его как:

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

files = sorted(glob.glob('mesh_files/*.vtk'))
mesh = []

fig = plt.figure(figsize = (16, 10))
ax = plt.axes(projection = '3d')

colors = cm.rainbow(np.linspace(0, 1, len(files)))

for file in files:
    mesh.append(meshio.read(file).points)

    x = mesh[-1][:, 0]
    y = mesh[-1][:, 1]
    z = mesh[-1][:, 2]

    plt.scatter(x, y, z, color = colors[files.index(file)])

так, что вы наносите только точки, соответствующие файлу, который вы только что прочитали на каждом шаге.

0 голосов
/ 11 ноября 2019

Этот код в настоящее время работает для меня, по большей части.

Я изменил plt.scatter... на ax.scatter..., и это исправило проблему масштабирования по оси Z, о которой я упоминал в РЕДАКТИРОВАТЬ 2 выше.

Я также изменился на ax = Axes3D(fig)

Спасибо всем за помощь! Я буду работать с этим сейчас. enter image description here

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

files = sorted(glob.glob('path/to/vtk/files/*_mesh.vtk'))

meshes = []

fig = plt.figure(figsize = (16, 10))
ax = Axes3D(fig)

colors = iter(cm.rainbow(np.linspace(0, 1, len(files))))

for fyle in files:
    ax.scatter(*meshio.read(fyle).points.T, c=[next(colors)])

plt.legend() #legend isn't plotting, will have to fix this
plt.show()
0 голосов
/ 08 ноября 2019

Как упоминалось ранее, проблема, с которой вы сталкиваетесь, заключается в том, в каком цикле происходит выбор цвета.

color = iter(cm.rainbow(np.linspace(0, 1, len(files))))

for file in files:
    d = next(color) #set the color for each file instead of inside the loop
    mesh.append(meshio.read(file))

    x = [m.points[:, 0] for m in mesh]
    y = [m.points[:, 1] for m in mesh]
    z = [m.points[:, 2] for m in mesh]

    for a,b,c in zip(x,y,z):
        plt.scatter(a,b,c,color=d)
...