Edges in 3D

This tutorial show how to plot edges in 3D, using

Setup

import oat_python as oat
import plotly
import plotly.graph_objects as go
import numpy as np

We’ll use a cycle graph on N vertices as an example. Here we generate N evenly spaced points on a circle, which will be the vertices of the graph.

N               =   60

# Generate N points in the xy-plane
points          =   oat.point_cloud.circle( n_points=N, )

# Add a z-coordinate to make the points 3D
points          =   np.hstack( (
                        points,
                        np.sin(np.linspace(0, 6*np.pi, N)).reshape(-1, 1))
                    )
points
array([[ 1.00000000e+00,  0.00000000e+00,  0.00000000e+00],
       [ 9.94521895e-01,  1.04528463e-01,  3.14076712e-01],
       [ 9.78147601e-01,  2.07911691e-01,  5.96367359e-01],
       [ 9.51056516e-01,  3.09016994e-01,  8.18302776e-01],
       [ 9.13545458e-01,  4.06736643e-01,  9.57422038e-01],
       [ 8.66025404e-01,  5.00000000e-01,  9.99645611e-01],
       [ 8.09016994e-01,  5.87785252e-01,  9.40700267e-01],
       [ 7.43144825e-01,  6.69130606e-01,  7.86551556e-01],
       [ 6.69130606e-01,  7.43144825e-01,  5.52800065e-01],
       [ 5.87785252e-01,  8.09016994e-01,  2.63102564e-01],
       [ 5.00000000e-01,  8.66025404e-01, -5.32221748e-02],
       [ 4.06736643e-01,  9.13545458e-01, -3.64160575e-01],
       [ 3.09016994e-01,  9.51056516e-01, -6.38244184e-01],
       [ 2.07911691e-01,  9.78147601e-01, -8.47734428e-01],
       [ 1.04528463e-01,  9.94521895e-01, -9.71429893e-01],
       [ 6.12323400e-17,  1.00000000e+00, -9.96812007e-01],
       [-1.04528463e-01,  9.94521895e-01, -9.21311978e-01],
       [-2.07911691e-01,  9.78147601e-01, -7.52570770e-01],
       [-3.09016994e-01,  9.51056516e-01, -5.07665800e-01],
       [-4.06736643e-01,  9.13545458e-01, -2.11382624e-01],
       [-5.00000000e-01,  8.66025404e-01,  1.06293486e-01],
       [-5.87785252e-01,  8.09016994e-01,  4.13212186e-01],
       [-6.69130606e-01,  7.43144825e-01,  6.78311836e-01],
       [-7.43144825e-01,  6.69130606e-01,  8.74763085e-01],
       [-8.09016994e-01,  5.87785252e-01,  9.82684125e-01],
       [-8.66025404e-01,  5.00000000e-01,  9.91152831e-01],
       [-9.13545458e-01,  4.06736643e-01,  8.99312130e-01],
       [-9.51056516e-01,  3.09016994e-01,  7.16456740e-01],
       [-9.78147601e-01,  2.07911691e-01,  4.61092501e-01],
       [-9.94521895e-01,  1.04528463e-01,  1.59063496e-01],
       [-1.00000000e+00,  1.22464680e-16, -1.59063496e-01],
       [-9.94521895e-01, -1.04528463e-01, -4.61092501e-01],
       [-9.78147601e-01, -2.07911691e-01, -7.16456740e-01],
       [-9.51056516e-01, -3.09016994e-01, -8.99312130e-01],
       [-9.13545458e-01, -4.06736643e-01, -9.91152831e-01],
       [-8.66025404e-01, -5.00000000e-01, -9.82684125e-01],
       [-8.09016994e-01, -5.87785252e-01, -8.74763085e-01],
       [-7.43144825e-01, -6.69130606e-01, -6.78311836e-01],
       [-6.69130606e-01, -7.43144825e-01, -4.13212186e-01],
       [-5.87785252e-01, -8.09016994e-01, -1.06293486e-01],
       [-5.00000000e-01, -8.66025404e-01,  2.11382624e-01],
       [-4.06736643e-01, -9.13545458e-01,  5.07665800e-01],
       [-3.09016994e-01, -9.51056516e-01,  7.52570770e-01],
       [-2.07911691e-01, -9.78147601e-01,  9.21311978e-01],
       [-1.04528463e-01, -9.94521895e-01,  9.96812007e-01],
       [-1.83697020e-16, -1.00000000e+00,  9.71429893e-01],
       [ 1.04528463e-01, -9.94521895e-01,  8.47734428e-01],
       [ 2.07911691e-01, -9.78147601e-01,  6.38244184e-01],
       [ 3.09016994e-01, -9.51056516e-01,  3.64160575e-01],
       [ 4.06736643e-01, -9.13545458e-01,  5.32221748e-02],
       [ 5.00000000e-01, -8.66025404e-01, -2.63102564e-01],
       [ 5.87785252e-01, -8.09016994e-01, -5.52800065e-01],
       [ 6.69130606e-01, -7.43144825e-01, -7.86551556e-01],
       [ 7.43144825e-01, -6.69130606e-01, -9.40700267e-01],
       [ 8.09016994e-01, -5.87785252e-01, -9.99645611e-01],
       [ 8.66025404e-01, -5.00000000e-01, -9.57422038e-01],
       [ 9.13545458e-01, -4.06736643e-01, -8.18302776e-01],
       [ 9.51056516e-01, -3.09016994e-01, -5.96367359e-01],
       [ 9.78147601e-01, -2.07911691e-01, -3.14076712e-01],
       [ 9.94521895e-01, -1.04528463e-01, -7.34788079e-16]])

Color scales

Plotly has no native functionality to plot multiple edges on a colorscale in a single trace. If you’d like to plot multiple edges on a colorscale, you can create a separate trace for each edge, and assign a color to each edge individually. Here’s an example.

Get a Plotly colorscale object, which maps values in [0,1] to RGB colors.

colorscale      =   plotly.colors.get_colorscale('Rainbow')

Convert N evenly spaced values in [0,1] to colors using the colorscale. We’ll use these colors for the edges of a cycle graph.

colors          =   plotly.colors.sample_colorscale(
                        colorscale,
                        np.linspace(0, 1, N)
                    )
colors
['rgb(150, 0, 90)', 'rgb(130, 0, 105)', 'rgb(109, 0, 120)', 'rgb(89, 0, 135)', 'rgb(69, 0, 150)', 'rgb(48, 0, 165)', 'rgb(28, 0, 179)', 'rgb(8, 0, 194)', 'rgb(0, 2, 205)', 'rgb(0, 6, 212)', 'rgb(0, 9, 220)', 'rgb(0, 12, 227)', 'rgb(0, 16, 234)', 'rgb(0, 19, 242)', 'rgb(0, 22, 249)', 'rgb(0, 29, 255)', 'rgb(0, 47, 255)', 'rgb(0, 64, 255)', 'rgb(0, 81, 255)', 'rgb(0, 98, 255)', 'rgb(0, 115, 255)', 'rgb(0, 133, 255)', 'rgb(0, 150, 255)', 'rgb(5, 164, 243)', 'rgb(11, 178, 228)', 'rgb(17, 192, 214)', 'rgb(23, 206, 200)', 'rgb(29, 220, 186)', 'rgb(35, 234, 171)', 'rgb(41, 248, 157)', 'rgb(51, 255, 140)', 'rgb(66, 255, 119)', 'rgb(80, 255, 99)', 'rgb(95, 255, 79)', 'rgb(109, 255, 58)', 'rgb(124, 255, 38)', 'rgb(138, 255, 18)', 'rgb(153, 255, 0)', 'rgb(167, 252, 0)', 'rgb(181, 249, 0)', 'rgb(195, 246, 0)', 'rgb(209, 243, 0)', 'rgb(223, 240, 0)', 'rgb(237, 238, 0)', 'rgb(251, 235, 0)', 'rgb(255, 221, 0)', 'rgb(255, 205, 0)', 'rgb(255, 188, 0)', 'rgb(255, 171, 0)', 'rgb(255, 155, 0)', 'rgb(255, 138, 0)', 'rgb(255, 121, 0)', 'rgb(255, 105, 0)', 'rgb(255, 90, 0)', 'rgb(255, 75, 0)', 'rgb(255, 60, 0)', 'rgb(255, 45, 0)', 'rgb(255, 30, 0)', 'rgb(255, 15, 0)', 'rgb(255, 0, 0)']

Plot the edges of the graph, using oat_python.plot.trace_2d_for_edge().

# Initialize a list to hold the traces
traces          =   []

# Make a trace for the vertices, to help mark start and end points
vertex_trace    =   oat.plot.trace_3d_for_vertices(
                       points          =   points,
                       marker          =   dict(
                                               color       =   'white',
                                               size        =   5,
                                           ),
                       showlegend      =   True,
                       name            =   "Vertex Trace",
                    )
traces.append(vertex_trace)

# Make one trace per edge, each with a different color. For an explanation of
# the keyword arguments, see the docstring for :func:`oat_python.plot.trace_2d_for_edge`.
for p in range(N):
    edge_trace  =   oat.plot.trace_3d_for_edge(
                       points          =   points,
                       edge            =   [p, (p+1) % N],
                       line            =   dict(
                                               color       =   colors[p],
                                               width       =   6,
                                           ),
                       name            =   f"Trace for edge {p}",
                    )

    traces.append(edge_trace)

# Create a figure with all traces
fig = plotly.graph_objects.Figure(traces)

# Set the title, and make the aspect ratio equal
fig.update_layout(
    title="Using a colorscale by placing edges in separate traces",
    scene = dict(
        aspectratio=go.layout.scene.Aspectratio(x=1, y=1, z=1),
    )
)

# Show the figure
fig


See the Styling in 3D for tips on styling in 3D.

# Apply a dark template
fig.update_layout(template="plotly_dark")
fig


Grouping legend entries

Each trace appears separately in the legend by default. However,

  • You can group multiple traces together in the legend using keyword arguments. See the Legend section of Triangles in 3D for examples.

  • If you do not need to assign different colors to different edges, then you can plot multiple edges in a single trace using oat_python.plot.trace_2d_for_edges(). See the next section for an example.

Grouping multiple edges in a single trace (may improve performance)

If you do not need to assign different colors to different edges, then you can plot multiple edges in a single trace using oat_python.plot.trace_2d_for_edges(). Here’s an example.

# Make a trace for the vertices, to help mark start and end points
vertex_trace    =   oat.plot.trace_3d_for_vertices(
                       points          =   points,
                       marker          =   dict(
                                               color       =   'white',
                                               size        =   5,
                                           ),
                       showlegend      =   True,
                       name            =   "Vertex Trace",
                    )

Make a single trace for all edges, with the same color for all edges. For an explanation of the keyword arguments, see the docstring for oat_python.plot.trace_2d_for_edges().

edge_trace       =   oat.plot.trace_3d_for_edges(
                    points          =   points,
                    edges           =   [ [p, (p+1) % N] for p in range(N) ],
                    line            =   dict(
                                            color       =   "white",
                                            width       =   3,
                                        ),
                    showlegend      =   True,
                    name            =   f"Edge Trace",
                )

# Create a figure with the trace
fig = plotly.graph_objects.Figure([ edge_trace, vertex_trace ])

# Set the title, make the aspect ratio equal, and apply a dark template
fig.update_layout(
    title="Multiple edges in a single trace",
    template="plotly_dark",
    scene = dict(
        aspectratio=go.layout.scene.Aspectratio(x=1, y=1, z=1),
    )
)

# Show the figure
fig


Total running time of the script: (0 minutes 0.090 seconds)

Gallery generated by Sphinx-Gallery