Создание четырехмерного точечного графика с использованием Matplotlib в Python - PullRequest
0 голосов
/ 29 января 2019

По сути, я пытаюсь создать четырехмерную диаграмму рассеяния с 4 столбцами данных (см. Образец ниже).

X (mm)  Y (mm)  Z (mm)  Diameter (mm)
11.096  11.0972 13.2401 124.279
14.6836 11.0389 8.37134 138.949
19.9543 11.1025 31.1912 138.949
15.4079 10.9505 31.1639 152.21
20.6372 14.5175 6.94501 152.211
20.47   11.225  31.3612 152.211
19.0432 11.3234 8.93819 152.213
29.4091 10.1331 26.6354 186.417
12.9391 10.6616 28.9523 186.418
29.9102 10.4828 25.1129 186.418
30.5483 12.163  15.9116 186.418
19.0631 10.5784 30.9791 186.418
9.65332 10.8563 12.975  186.419
8.4003  11.0417 17.0181 186.419
26.0134 10.6857 9.41572 186.419
13.7451 11.1495 28.7108 186.419

Первые три столбца данных (X, Y, Z)являются координатными позициями 4-го столбца данных (диаметр), поэтому я смог сгенерировать трехмерную диаграмму рассеяния этих позиций.Тем не менее, я пытаюсь нанести эти диаметры на разные цветовые маркеры на основе определенных пороговых значений (т.е. диаметры менее 100 мм - красные, 101-200 мм - синие, 201-300 мм - зеленые и т. Д.).цвет маркеров определяется, он будет строить эти маркеры на основе своих координат X, Y, Z.Я попытался написать простой цикл for, чтобы сделать это, но по какой-то причине он становится очень медленным / медленным и будет отображать только один цвет.Кто-нибудь может увидеть, если что-то не так с моим подходом?Спасибо!

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas
import os

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

os.chdir(r'C:\Users\Me\Documents')
data = pandas.read_excel("Diameter Report", "Data")

X = data['X (mm)'].values.tolist()
Y = data['Y (mm)'].values.tolist()
Z = data['Z (mm)'].values.tolist()
dims = data['Diameter (mm)'].values.tolist()

for i in dims:
    if i < int(100):
        ax.plot(X, Y, Z, c='r', marker='o')
    elif i >= int(101) and i <200:
        ax.plot(X, Y, Z, c='b', marker='o')
    elif i >= int(201) and i <300:
        ax.plot(X, Y, Z, c='g', marker='o')

ax.set_xlabel('Center X (mm)')
ax.set_ylabel('Center Y (mm)')
ax.set_zlabel('Center Z (mm)')

plt.show()

Resulting plot

Ответы [ 2 ]

0 голосов
/ 29 января 2019

Вот несколько более общее решение, в котором вы можете явно указать желаемые диапазоны независимо от расстояния.У меня не было полных данных, поэтому я изменил ваши лимиты с 100, 200, 300 до 140, 180, 200 на основе предоставленных данных.

Пара вещей:

  • Возможно, вы захотите использовать scatter3d, как вы упомянули в своем вопросе, вместо plot.
  • Я использую NumPy для чтения данных, потому что таким образом вы будете иметь данные в виде массивов NumPy, которые делаютЛегко маскировать и нарезать.
  • Здесь я создаю 3 условные маски в зависимости от величины dims.
  • Затем вы сохраняете эти маски в списке, а затем перебираете его, чтобы использовать одну маску за раз.

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

X, Y, Z, dims = np.loadtxt('sample.txt', unpack=True, skiprows=1)

mask1 = (dims<140)
mask2 = ((dims>=140) & (dims<180))
mask3 = ((dims>=180) & (dims<200))

masks = [mask1, mask2, mask3]
colors = ['r', 'b', 'g'] # color order as you specified in the question

for mask, color in zip(masks, colors): 
    ax.scatter3D(X[mask], Y[mask], Z[mask], c=color)

ax.set_xlabel('Center X (mm)')
ax.set_ylabel('Center Y (mm)')
ax.set_zlabel('Center Z (mm)')
plt.show()

enter image description here

0 голосов
/ 29 января 2019

Кажется, что пороговые значения для значений расположены на одинаковом расстоянии, поэтому вы можете просто разделить на 100 и усечь дальнейшие десятичные разряды.Это позволяет построить один разброс вместо сотен графиков.

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

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

data = pandas.read_excel("Diameter Report", "Data")

X = data['X (mm)'].values
Y = data['Y (mm)'].values
Z = data['Z (mm)'].values
dims = data['Diameter (mm)'].values

ax.scatter(X,Y,Z, c=(dims/100).astype(int), marker="o", cmap="brg")

ax.set_xlabel('Center X (mm)')
ax.set_ylabel('Center Y (mm)')
ax.set_zlabel('Center Z (mm)')

plt.show()

Более общий случай произвольных границ, вероятно, лучше всего решить, используя BoundaryNorm и цветовую карту с таким количеством разных цветов, как в классификациях.

import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import pandas as pd

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

d = np.random.rand(10,4)
d[:,3] = np.random.randint(1,300, 10)
data = pd.DataFrame(d, columns=["X (mm)","Y (mm)","Z (mm)","Diameter (mm)"])

X = data['X (mm)'].values
Y = data['Y (mm)'].values
Z = data['Z (mm)'].values
dims = data['Diameter (mm)'].values

bounds = [0,100,200,300]
colors = ["b", "r", "g"]
cmap = mcolors.ListedColormap(colors)
norm = mcolors.BoundaryNorm(bounds, len(colors))

sc = ax.scatter(X,Y,Z, c=dims, marker="o", cmap=cmap, norm=norm)

ax.set_xlabel('Center X (mm)')
ax.set_ylabel('Center Y (mm)')
ax.set_zlabel('Center Z (mm)')
fig.colorbar(sc)
plt.show()

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...