'Visualizing the permutohedron in 3D plot
I am trying to plot the Permutohedron in python using plotly, numpy, and pandas.
This is my current code:
import plotly.express as px
import numpy as np
import itertools
import pandas as pd
order = 4
items = range(1, order+1)
permuted_items = np.array([*itertools.permutations(items)])
def closest_nodes(node, nodes):
# Returns the instances in nodes that are closest to node
nodes = np.asarray(nodes)
dist_2 = np.sum((nodes - node)**2, axis=1)**.5
indices = np.where(dist_2 == dist_2.min())[0]
return nodes[indices]
xyzs = []
colors = []
for i, point in enumerate(permuted_items[:-1]):
closest_points = closest_nodes(point, permuted_items[i+1:])
for c_point in closest_points:
xyzs.extend([point[:3], c_point[:3]])
# Get unique string as color to group above line while plotting
c = str(point) + str(c_point[:3])
colors.extend([c, c])
lines = np.array(xyzs)
x, y, z = lines.T
plotting_data = pd.DataFrame({
"X": x,
"Y": y,
"Z": z,
"color": colors
})
fig = px.line_3d(plotting_data, x='X', y='Y', z='Z', color="color")
fig.show()
But this plots something that is very skewed:
I.e. my way of showing this shape in 3d (by removing the last dimension) changes the length of each line such that each line does not have a length of sqrt(2).
In reality, this is the shape I am after:
Any help?
Solution 1:[1]
In this case, you need to project your points onto a 3D space, instead of omitting the forth coordinate. The 3x4 matrix transformation is provided here
https://blogs.mathworks.com/graphics/2016/01/29/tiling-hexagons-and-other-permutohedra/
Working code:
import plotly.express as px
import numpy as np
import itertools
import pandas as pd
order = 4
items = range(1, order+1)
permuted_items = np.array([*itertools.permutations(items)])
#Project the points onto 3D space--
A = np.array([[np.sqrt(2)/2, -np.sqrt(2)/2, 0, 0],\
[np.sqrt(6)/6, np.sqrt(6)/6, -np.sqrt(2/3), 0],\
[np.sqrt(12)/12, np.sqrt(12)/12, np.sqrt(12)/12, -np.sqrt(3)/2]])
permuted_items = np.einsum('ik,ak->ai',A,permuted_items)
#----------------------------------
xyzs = []
colors = []
for i, point in enumerate(permuted_items):
d = np.linalg.norm(permuted_items-point[np.newaxis,:],axis=1)
#Inspired by https://stackoverflow.com/questions/31352486/can-numpy-argsort-handle-ties
js = (abs(d - d[d.argsort()[1]])<1e-3).nonzero()[0]
for j in js:
xyzs.extend([point,permuted_items[j]])
# Get unique string as color to group above line while plotting
c = str(point) + str(permuted_items[j])
colors.extend([c, c])
lines = np.array(xyzs)
x, y, z = lines.T
plotting_data = pd.DataFrame({
"X": x,
"Y": y,
"Z": z,
"color": colors,
})
fig = px.line_3d(plotting_data, x='X', y='Y', z='Z', color="color")
fig.show()
Note that I have rewritten the part on computing the smallest distance.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | romanodev |