Matplotlib 3D打印:设置右侧纵横比
问题描述
我正在使用matplotlib来绘制3D图像。打印时,长度/宽度/高度自动缩放,与其实际值不成正比,即长度是高度的6倍,但图片显示的三个轴的比例几乎相同(见下文第一张图片)。
如何修改配置以使其按照如下所示的垂直轴值以正确的比例显示?
以下是我的代码:
from py3dbp import Packer, Bin, Item
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
import matplotlib.pyplot as plt
import random
def cuboid_data2(o, size=(1, 1, 1)):
X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]],
[[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]],
[[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
[[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
[[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]],
[[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]]
X = np.array(X).astype(float)
for i in range(3):
X[:, :, i] *= size[i]
X += np.array(o)
return X
def plotCubeAt2(positions, sizes=None, colors=None, **kwargs):
if not isinstance(colors, (list, np.ndarray)): colors = ["C0"] * len(positions)
if not isinstance(sizes, (list, np.ndarray)): sizes = [(1, 1, 1)] * len(positions)
g = []
for p, s, c in zip(positions, sizes, colors):
g.append(cuboid_data2(p, size=s))
return Poly3DCollection(np.concatenate(g),
facecolors=np.repeat(colors, 6), **kwargs)
# containers = [
# [250, 250, 500],
# [500, 500, 400],
# [300, 300, 300],
# [300, 300, 200],
# [300, 300, 100],
# [500, 500, 500]
# ]
# containers = [
# # [12000000, 2350000, 2697000],
# # [12000000, 2350000, 2697000],
# # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # ]
containers = [
[589.5, 235, 239],
[1202.4, 235, 269],
# [1202.4, 235, 269],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
]
packer = Packer()
containerX = 0
containerY = 0
containerZ = 0
for i, t in enumerate(range(len(containers))):
containerX = containers[t][0]
containerY = containers[t][1]
containerZ = containers[t][2]
i += 1
packer.add_bin(Bin('40HC-' + str(i), containerX, containerY, containerZ, 18000.0))
for i in range(50):
packer.add_item(Item('BoxA_' + str(i), 44, 39, 70, 8.20))
for i in range(35):
packer.add_item(Item('BoxB_' + str(i), 65, 38, 40, 14))
for i in range(31):
packer.add_item(Item('BoxC_' + str(i), 43, 52, 47, 10))
for i in range(38):
packer.add_item(Item('BoxD_' + str(i), 60, 45, 40, 14))
for i in range(11):
packer.add_item(Item('BoxE_' + str(i), 42, 46, 54, 9.70))
for i in range(525):
packer.add_item(Item('BoxF_' + str(i), 62, 45, 35, 14.5))
# packer.pack()
# packer.pack(bigger_first=False)
packer.pack(bigger_first=False, distribute_items=True, number_of_decimals=3)
for b in packer.bins:
positions = []
sizes = []
colors = []
print(":::::::::::", b.string())
print("FITTED ITEMS:")
for item in b.items:
print("====> ", item.string())
x = float(item.position[0])
y = float(item.position[1])
z = float(item.position[2])
positions.append((x, y, z))
sizes.append(
(float(item.get_dimension()[0]), float(item.get_dimension()[1]), float(item.get_dimension()[2])))
colorList = ["crimson", "limegreen", "g", "r", "c", "m", "y", "k"]
if item.width == 44:
colors.append(colorList[0])
if item.width == 65:
colors.append(colorList[1])
if item.width == 43:
colors.append(colorList[2])
if item.width == 60:
colors.append(colorList[3])
if item.width == 42:
colors.append(colorList[4])
if item.width == 62:
colors.append(colorList[5])
print("UNFITTED ITEMS:")
for item in b.unfitted_items:
print("====> ", item.string())
print("***************************************************")
print("***************************************************")
# colorList = ["crimson", "limegreen", "g", "r", "c", "m", "y", "k"]
#
# for i in range(len(b.items)):
# f = random.randint(0, 7)
# colors.append(colorList[f])
if len(colors) > 0:
fig = plt.figure()
fig.canvas.set_window_title(b.string().split("(")[0])
ax = fig.gca(projection='3d')
ax.set_aspect('auto')
pc = plotCubeAt2(positions, sizes, colors=colors, edgecolor="k")
ax.add_collection3d(pc)
ax.set_xlim([0, float(b.string().split(",")[0].split("(")[1].split("x")[0])])
ax.set_ylim([0, float(b.string().split(",")[0].split("(")[1].split("x")[1])])
ax.set_zlim([0, float(b.string().split(",")[0].split("(")[1].split("x")[2])])
plt.show()
更新
containers = [
[1203, 235, 259],
[1203, 235, 259],
# [1202.4, 235, 269],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
]
我已更新matplotlib以使用.SET_BOX_Aspect函数。似乎有两个问题:
x y z轴标签严重重叠。它不会自动调整。
使用.SET_BOX_ACTIVE后,绘图图片变得更小。放大图形图像时,轴不会相应地自动放大。因此,中心的图像将与边缘的轴重叠,这是相似的。
此外,尽管绘制成功,但仍显示错误消息。
RuntimeWarning: divide by zero encountered in double_scalars dz /= az .......... x, y, z = proj3d.inv_transform(xd, yd, z, self.M) File "C:UsersJackAppDataLocalProgramsPythonPython36libsite-packagesmpl_toolkitsmplot3dproj3d.py", line 125, in inv_transform iM = linalg.inv(M) File "<__array_function__ internals>", line 6, in inv File "C:UsersJackAppDataRoamingPythonPython36site-packages umpylinalglinalg.py", line 546, in inv ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj) File "C:UsersJackAppDataRoamingPythonPython36site-packages umpylinalglinalg.py", line 88, in _raise_linalgerror_singular raise LinAlgError("Singular matrix") numpy.linalg.LinAlgError: Singular matrix
有没有缓解上述问题的方法?
解决方案
如果您有长方体的顶点坐标,则可以使用matplotlib.axes.Axes.set_box_aspect
,如this answer中所述。
这意味着在绘制之前,您必须在代码的底部添加以下行:
positions_array = np.array(positions)
ax.set_box_aspect((np.ptp(positions_array[:, 0]), np.ptp(positions_array[:, 1]), np.ptp(positions_array[:, 2])))
from py3dbp import Packer, Bin, Item
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import numpy as np
import matplotlib.pyplot as plt
import random
def cuboid_data2(o, size=(1, 1, 1)):
X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]],
[[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]],
[[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]],
[[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]],
[[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]],
[[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]]
X = np.array(X).astype(float)
for i in range(3):
X[:, :, i] *= size[i]
X += np.array(o)
return X
def plotCubeAt2(positions, sizes=None, colors=None, **kwargs):
if not isinstance(colors, (list, np.ndarray)): colors = ["C0"] * len(positions)
if not isinstance(sizes, (list, np.ndarray)): sizes = [(1, 1, 1)] * len(positions)
g = []
for p, s, c in zip(positions, sizes, colors):
g.append(cuboid_data2(p, size=s))
return Poly3DCollection(np.concatenate(g),
facecolors=np.repeat(colors, 6), **kwargs)
# containers = [
# [250, 250, 500],
# [500, 500, 400],
# [300, 300, 300],
# [300, 300, 200],
# [300, 300, 100],
# [500, 500, 500]
# ]
# containers = [
# # [12000000, 2350000, 2697000],
# # [12000000, 2350000, 2697000],
# # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # # [12000000, 2350000, 2697000],
# # ]
containers = [
[589.5, 235, 239],
[1202.4, 235, 269],
# [1202.4, 235, 269],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
# [12.024, 2.350, 2.69],
]
packer = Packer()
containerX = 0
containerY = 0
containerZ = 0
for i, t in enumerate(range(len(containers))):
containerX = containers[t][0]
containerY = containers[t][1]
containerZ = containers[t][2]
i += 1
packer.add_bin(Bin('40HC-' + str(i), containerX, containerY, containerZ, 18000.0))
for i in range(50):
packer.add_item(Item('BoxA_' + str(i), 44, 39, 70, 8.20))
for i in range(35):
packer.add_item(Item('BoxB_' + str(i), 65, 38, 40, 14))
for i in range(31):
packer.add_item(Item('BoxC_' + str(i), 43, 52, 47, 10))
for i in range(38):
packer.add_item(Item('BoxD_' + str(i), 60, 45, 40, 14))
for i in range(11):
packer.add_item(Item('BoxE_' + str(i), 42, 46, 54, 9.70))
for i in range(525):
packer.add_item(Item('BoxF_' + str(i), 62, 45, 35, 14.5))
# packer.pack()
# packer.pack(bigger_first=False)
packer.pack(bigger_first=False, distribute_items=True, number_of_decimals=3)
for b in packer.bins:
positions = []
sizes = []
colors = []
print(":::::::::::", b.string())
print("FITTED ITEMS:")
for item in b.items:
print("====> ", item.string())
x = float(item.position[0])
y = float(item.position[1])
z = float(item.position[2])
positions.append((x, y, z))
sizes.append(
(float(item.get_dimension()[0]), float(item.get_dimension()[1]), float(item.get_dimension()[2])))
colorList = ["crimson", "limegreen", "g", "r", "c", "m", "y", "k"]
if item.width == 44:
colors.append(colorList[0])
if item.width == 65:
colors.append(colorList[1])
if item.width == 43:
colors.append(colorList[2])
if item.width == 60:
colors.append(colorList[3])
if item.width == 42:
colors.append(colorList[4])
if item.width == 62:
colors.append(colorList[5])
print("UNFITTED ITEMS:")
for item in b.unfitted_items:
print("====> ", item.string())
print("***************************************************")
print("***************************************************")
# colorList = ["crimson", "limegreen", "g", "r", "c", "m", "y", "k"]
#
# for i in range(len(b.items)):
# f = random.randint(0, 7)
# colors.append(colorList[f])
if len(colors) > 0:
fig = plt.figure()
fig.canvas.set_window_title(b.string().split("(")[0])
ax = fig.gca(projection='3d')
ax.set_aspect('auto')
pc = plotCubeAt2(positions, sizes, colors=colors, edgecolor="k")
ax.add_collection3d(pc)
ax.set_xlim([0, float(b.string().split(",")[0].split("(")[1].split("x")[0])])
ax.set_ylim([0, float(b.string().split(",")[0].split("(")[1].split("x")[1])])
ax.set_zlim([0, float(b.string().split(",")[0].split("(")[1].split("x")[2])])
positions_array = np.array(positions)
ax.set_box_aspect((np.ptp(positions_array[:, 0]), np.ptp(positions_array[:, 1]), np.ptp(positions_array[:, 2])))
plt.show()
相关文章