简体   繁体   中英

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:

在此处输入图像描述

Ie 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?

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.

plotly graph

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM