Lines rather than cones?

I have 2 color-coded point clouds (scatters):

fx2, fy2, fz2 = [[coord+random.random()*4 for coord in coords] for coords in [fx1, fy1, fz1]]
fig1 = go.Figure(data=[go.Scatter3d(z=fz1, x=fx1, y=fy1, mode='markers')])
fig2 = go.Figure(data=[go.Scatter3d(z=fz2, x=fx2, y=fy2, mode='markers', marker={'color': 'red'})])
fig = go.Figure(data=fig1.data + fig2.data)

This works fine, but when I want to show them as a vector field, it only shows the cones if I truncate the length of the vectors to as fraction of their intended length. Therefore, this doesn’t work:

fig = go.Figure(data=go.Cone(x=fx1, y=fy1, z=fz1, u=fx2, v=fy2, w=fz2 , sizemode="absolute", sizeref=2, anchor="tip"))
fig.update_layout(title=plot_label, autosize=False,
                  width=1024, height=1024,
                  margin=dict(l=65, r=50, b=65, t=90))
fig.show()

So what I’d like to try next to work around the problem is, rather than plotting cones, I want to keep the two point clouds as in the first snippet of code, and connect them with line segments, in hopes that line segments won’t trigger the bug.

But the only solution I see out there entails zipping the two 3D vectors together into 1 3D vector and then placing a None between each pair of coordinates so as to fool Scatter into doing line segments when it thinks its doing polylines. But then this fails to provide the different colors to differentiate the two scatters.

Hi @jabowery, I’m not sure I fully understand what you are trying to do.

As far as I understood, you want do visually connect two point clouds pointwise via lines. The point clouds have to have different colors.

If this is the case, I came up with a possible solution for that. I said possible, because I think it’s going to be pretty limited as for the size of the point cloud (number of points). I tried with a fairly small cloud an managed to produce this:

code:

import plotly.graph_objects as go
import numpy as np

# prepare base data (fisrt point cloud)
x, y, z = np.meshgrid(np.arange(2) * 2, np.arange(2) * 3, np.arange(3) * 4)
x = x.flatten()
y = y.flatten()
z = z.flatten()

# second point cloud
x1 = x + 10
y1 = y + 10
z1 = z + 10

# combine into arrays
x = np.c_[x, x1]
y = np.c_[y, y1]
z = np.c_[z, z1]


# create base figure
fig = go.Figure()

# create traces in loop, each point pair is one trace
for idx in range(x.shape[0]):
    fig.add_scatter3d(
        x=x[idx],
        y=y[idx],
        z=z[idx],
        mode='markers+lines',
        marker_color=['darkblue', 'crimson'],
        line_color='black',
        showlegend=False
)
fig.update_layout(width=900, height=900)
1 Like

Hi,

a way to preserve the colors of the different point clouds could be this (example from the github link):

import plotly.graph_objs as go

def create_colors_list(list_of_coordinates):
    # count None
    count=sum(val is None for val in list_of_coordinates)
    
    # initiate variables
    colors = []
    c=0
    
    # create colors list
    while c < count + 1:
        colors.extend(['crimson', 'green'])
        colors.append('rgba(0,0,0,0)')
        # ^^ dummy color, opacity = 0
        c += 1
    return colors

# create figure
fig = go.Figure()

x = [1, 4, None, 2, 3, None, 3, 4]
y = [0, 0, None, 1, 1, None, 2, 2]

# create list of colors
colors = create_colors_list(x)

# add trace
fig.add_trace(
    go.Scatter(
        x=x, 
        y=y, 
        mode='markers+lines', 
        marker={'color': colors, 'size': 12},
        line={'color': 'black'}
    )
)
fig.show()

creates:
newplot (40)

Your first suggestion worked with the large number of line segments and is actually better, for our purposes, than cones as the lines are less prone to block lines of sight through the point clouds. The only change I made to the add_scatter3d call to make things a bit more visually aesthetic was change the line to a bit less opaque, the marker size smaller and an endpoint to a lighter color:

            marker_color=['yellow', 'crimson'], marker_size=3,
            line_color='rgba(0,0,0,.35)',

Perfect, glad I could be of help, thanks for the feedback.