Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drawing a 3d box in a 3d scatterplot using plotly

Tags:

python

plotly

I was trying to plot a 3d box in a 3d scatterplot. Basically, this was the result of an optimization problem (background is here). The box is the largest empty box possible given all the points.

In the plotly docs I noticed an example of a 3d cube built using 3dmesh. I copied this:

import plotly.graph_objects as go
x=[ 0.93855, 0.20203, 0.54967, 0.58658, 0.39931, 0.06736, 0.61786, 0.36016, 0.12761, 0.71581, 0.81998, 0.04528, 0.08231, 0.41814, 0.58679, 0.21181, 0.34489, 0.21812, 0.46830, 0.81898,
 0.57360, 0.18453, 0.99792, 0.37970, 0.51954, 0.84264, 0.22431, 0.31440, 0.23893, 0.28493, 0.76353, 0.45365, 0.44480, 0.94911, 0.98050, 0.28615, 0.02626, 0.85477, 0.60404, 0.47469,
 0.10588, 0.55919, 0.42194, 0.34432, 0.80530, 0.88291, 0.53627, 0.45454, 0.01345, 0.84411, 0.04520, 0.35532, 0.45255, 0.99365, 0.72259, 0.08634, 0.78806, 0.28674, 0.57993, 0.84025,
 0.22766, 0.51236, 0.83945, 0.21910, 0.41881, 0.18910, 0.00183, 0.59310, 0.12687, 0.45273, 0.14348, 0.66694, 0.28690, 0.32822, 0.93954, 0.34411, 0.25276, 0.14377, 0.08142, 0.05422,
 0.51448, 0.48659, 0.66585, 0.25156, 0.69205, 0.21175, 0.72413, 0.92027, 0.79572, 0.13293, 0.81984, 0.25584, 0.42517, 0.41333, 0.75978, 0.60823, 0.83418, 0.37497, 0.10177, 0.01215]
y=[ 0.61424, 0.39918, 0.57526, 0.04537, 0.24058, 0.18701, 0.18450, 0.82907, 0.66274, 0.96315, 0.58458, 0.12807, 0.38695, 0.30646, 0.88417, 0.63859, 0.40404, 0.06445, 0.19149, 0.91259,
 0.99317, 0.67468, 0.12954, 0.11868, 0.79252, 0.98170, 0.74706, 0.28944, 0.55650, 0.91190, 0.26978, 0.94868, 0.82534, 0.37846, 0.38055, 0.42637, 0.26349, 0.09109, 0.10308, 0.63728,
 0.37470, 0.85528, 0.19407, 0.29683, 0.71095, 0.72789, 0.47052, 0.54725, 0.62322, 0.52442, 0.32547, 0.54581, 0.51336, 0.58652, 0.76841, 0.00042, 0.80743, 0.32560, 0.29931, 0.19091,
 0.95850, 0.42236, 0.70728, 0.85435, 0.79661, 0.14909, 0.80658, 0.36827, 0.46344, 0.92196, 0.09802, 0.02856, 0.73966, 0.55969, 0.34595, 0.80634, 0.18350, 0.84283, 0.04560, 0.41515,
 0.50151, 0.52665, 0.44211, 0.48040, 0.39643, 0.99743, 0.18206, 0.09721, 0.33793, 0.69245, 0.97670, 0.70870, 0.75288, 0.51147, 0.22298, 0.84305, 0.62014, 0.41474, 0.82815, 0.42865]
z=[ 0.13338, 0.81253, 0.46946, 0.76145, 0.83335, 0.96434, 0.79175, 0.20481, 0.60056, 0.26519, 0.89917, 0.16271, 0.02890, 0.49017, 0.18970, 0.16751, 0.47065, 0.85533, 0.73768, 0.14031,
 0.92923, 0.11933, 0.40330, 0.46713, 0.69964, 0.25784, 0.87656, 0.25886, 0.64603, 0.92604, 0.83728, 0.71988, 0.48486, 0.57123, 0.78618, 0.70429, 0.30544, 0.20687, 0.47584, 0.58176,
 0.43336, 0.35453, 0.96509, 0.98293, 0.88605, 0.70571, 0.51733, 0.09292, 0.69618, 0.76415, 0.82743, 0.99876, 0.86101, 0.58373, 0.03917, 0.60540, 0.59567, 0.94481, 0.35552, 0.80555,
 0.97449, 0.31020, 0.61952, 0.48569, 0.50740, 0.69248, 0.01918, 0.04973, 0.21958, 0.98663, 0.09143, 0.24220, 0.96312, 0.66227, 0.91103, 0.26285, 0.28079, 0.10938, 0.07499, 0.34065,
 0.83692, 0.33815, 0.89640, 0.06275, 0.01852, 0.08153, 0.88351, 0.08171, 0.87036, 0.51620, 0.90021, 0.67128, 0.36607, 0.54804, 0.72661, 0.18951, 0.11629, 0.46170, 0.24500, 0.88841]

fig = go.Figure(data=[
     go.Scatter3d(x=x, y=y, z=z,
                  mode='markers',
                  marker=dict(size=2)
                 ),
     go.Mesh3d(
        # 8 vertices of a cube
        x=[0.608, 0.608, 0.998, 0.998, 0.608, 0.608, 0.998, 0.998],
        y=[0.091, 0.963, 0.963, 0.091, 0.091, 0.963, 0.963, 0.091],
        z=[0.140, 0.140, 0.140, 0.140, 0.571, 0.571, 0.571, 0.571],

        i = [7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
        j = [3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
        k = [0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6],
        opacity=0.6,
        color='#DC143C'
    )                    
    ])
fig.show()

However, the picture shows really the triangles. Any better way to draw a 3d box (in Plotly)?

enter image description here

like image 696
Erwin Kalvelagen Avatar asked Feb 24 '20 08:02

Erwin Kalvelagen


2 Answers

For me using the argument flatshading = True did the job.

Code

fig = go.Figure(data=[
     go.Scatter3d(x=x, y=y, z=z,
                  mode='markers',
                  marker=dict(size=2)
                 ),
     go.Mesh3d(
        # 8 vertices of a cube
        x=[0.608, 0.608, 0.998, 0.998, 0.608, 0.608, 0.998, 0.998],
        y=[0.091, 0.963, 0.963, 0.091, 0.091, 0.963, 0.963, 0.091],
        z=[0.140, 0.140, 0.140, 0.140, 0.571, 0.571, 0.571, 0.571],

        i = [7, 0, 0, 0, 4, 4, 6, 6, 4, 0, 3, 2],
        j = [3, 4, 1, 2, 5, 6, 5, 2, 0, 1, 6, 3],
        k = [0, 7, 2, 3, 6, 7, 1, 1, 5, 5, 7, 6],
        opacity=0.6,
        color='#DC143C',
        flatshading = True
    )                    
    ])

Output

enter image description here

like image 181
SimonT Avatar answered Oct 12 '22 16:10

SimonT


You can use Poly3DCollection to create shape that you need with defining shape corners.

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
from itertools import product

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

# create list of corners
z = list(product([-1,1], repeat=3))

# set verts connectors
verts = [[z[0],z[1],z[5],z[4]], [z[4],z[6],z[7],z[5]], [z[7], z[6], z[2], z[3]], [z[2], z[0], z[1], z[3]],
         [z[5], z[7], z[3], z[1]], [z[0], z[2], z[6], z[4]]]


ax.set_xlim3d(-2,2)
ax.set_ylim3d(-2,2)
ax.set_zlim3d(-2,2)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')

# plot sides
ax.add_collection3d(Poly3DCollection(verts,facecolors='blue', linewidths=1, edgecolors='black', alpha=.1))

plt.show()

Output:

enter image description here

like image 26
Zaraki Kenpachi Avatar answered Oct 12 '22 16:10

Zaraki Kenpachi