Issue
I am using matplotlib to plot 3D image. when plotting, the length/width/height is automatically scaled which is not proportional to its actual value, i.e. the length is 6 times bigger than the height but the picture shows almost the same scale for the three axis (see below first one pic).
How do I modify the configuration to allow it display in a correct propotion according to the acual axis value like the below one?
below is my code:
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()
UPDATE
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],
]
I have updated matplotlib to use .set_box_aspect function. there seems to be two problems:
the x y z axis label is severely overlaped. It does not auto adjust.
the drawing picture becomes much smaller after using .set_box_aspect. When enlarging the drawing image, the axis does not auto enlarge accordingly. Hence, the image at center will overlap with the axis at edge, which is akward.
plus, there are showing error messages despite of sucessful drawing.
RuntimeWarning: divide by zero encountered in double_scalars dz /= az .......... x, y, z = proj3d.inv_transform(xd, yd, z, self.M) File "C:\Users\Jack\AppData\Local\Programs\Python\Python36\lib\site-packages\mpl_toolkits\mplot3d\proj3d.py", line 125, in inv_transform iM = linalg.inv(M) File "<__array_function__ internals>", line 6, in inv File "C:\Users\Jack\AppData\Roaming\Python\Python36\site-packages\numpy\linalg\linalg.py", line 546, in inv ainv = _umath_linalg.inv(a, signature=signature, extobj=extobj) File "C:\Users\Jack\AppData\Roaming\Python\Python36\site-packages\numpy\linalg\linalg.py", line 88, in _raise_linalgerror_singular raise LinAlgError("Singular matrix") numpy.linalg.LinAlgError: Singular matrix
Are there ways to mitigate above problems?
Solution
If you have the coordinates of verteces of boxes, then you can use matplotlib.axes.Axes.set_box_aspect
as explained in this answer.
This means that you have to add these lines at the bottom of your code, just before plotting:
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()
Answered By - Zephyr
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.