在Python中使用Matplotlib制作4-D散点图

时间:2019-01-29 16:46:22

标签: python matplotlib

本质上,我正在尝试制作包含4列数据的4-D散点图(请参见下面的示例)。

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)是数据的第四列(直径)的坐标位置,因此我能够生成这些位置的3-D散点图。但是,我试图根据某些阈值用不同的颜色标记来绘制这些直径(例如,小于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 :(得分:2)

似乎这些值的阈值是等距的,因此您可以将其除以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

答案 1 :(得分:1)

这是一个稍微通用的解决方案,您可以在不考虑间距的情况下显式指定所需的范围。我没有完整的数据,因此我根据提供的数据将您的限制从100、200、300更改为140、180、200。

几件事:

  • 您可能希望使用问题中提到的scatter3d而不是plot
  • 我正在使用NumPy读取数据,因为这样您将以NumPy数组的形式获取数据,从而使屏蔽和切片变得容易。
  • 在这里,我根据dims的大小创建3个条件掩码。
  • 接下来,将这些掩码存储在列表中,然后对其进行迭代以一次使用一个掩码。

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