1

Using plotly.graph_objects modules Scatter3D & scatter3d.Line I can't get the line colors to fall within the range of the define color scale.

I tried the following code, that plots points as markers & lines by appending the respective "go.Scatter3D" into a data-list that is given as data to "go.FigureWidget"

import numpy as np
import plotly.graph_objects as go

# define function
def get_3D_plot_stack(x,y,z,connections,elongation_values):

    data_list = [] #initializing empty list

    ### Points, gathering data and appending to data_list
    for i,(xi,yi,zi) in enumerate(zip(x,y,z)): # looping through each point_list
        data_list.append(go.Scatter3d(x=[xi], y=[yi], z=[zi],
                                      mode='markers',
                                      marker=dict(color='black',size=2),
                                      showlegend= False))

    ### Lines, gathering data and appending to data_list
    for i,(conn,elongation_i) in enumerate(zip(connections,elongation_values)):
        xi_conn = [x[conn[0]], x[conn[1]]]
        yi_conn = [y[conn[0]], y[conn[1]]]
        zi_conn = [z[conn[0]], z[conn[1]]]

        data_list.append(go.Scatter3d(
                                    x=xi_conn, y=yi_conn, z=zi_conn,
                                    mode='lines',
                                    line=go.scatter3d.Line(
                                        width = 4,
                                        color=elongation_i,
                                        colorscale='Viridis',
                                        showscale=True, #set to TRUE
                                    ),
                                showlegend=False
                            ))
    
    ### Create figure
    fig = go.FigureWidget(data=data_list)

    fig.show()
    return()

x,y,z = np.random.random_sample((3,10)) # random points
connections = np.array([[0,1],[9,2],[2,3],[5,7],[6,8],[2,8],[1,2],[4,5]]) # line connections
elongation_values = np.random.random_sample((len(connections))) # random colors

get_3D_plot_stack(x,y,z,connections,elongation_values)

The results show that each colorbar values are plotted (ugly) and that the lines of the colors fall outside of the 'Viridis' colorscale

An improvement is made, by plotting the colorbar values for all lines once. This doesn't resolve the issue however (and neither does an implementation of the colorbar using the older workaround found in this GitHub issue: https://github.com/plotly/plotly.py/issues/1085 )

import numpy as np
import plotly.graph_objects as go

def get_3D_plot_stack(x,y,z,connections,elongation_values):

    data_list = [] #initializing an empty list

    ### Points, gathering data and appending to data_list
    for i,(xi,yi,zi) in enumerate(zip(x,y,z)): # looping through each point_list
        data_list.append(go.Scatter3d(x=[xi], y=[yi], z=[zi],
                                      mode='markers',
                                      marker=dict(color='black',size=2),
                                      showlegend= False))

    ### Lines, gathering data and appending to data_list
    x_conn, y_conn, z_conn = np.empty((len(connections),2)), np.empty((len(connections),2)), np.empty((len(connections),2))
    for i,(conn,elongation_i) in enumerate(zip(connections,elongation_values)):
        xi_conn = [x[conn[0]], x[conn[1]]]
        yi_conn = [y[conn[0]], y[conn[1]]]
        zi_conn = [z[conn[0]], z[conn[1]]]

        # storing data
        x_conn[i], y_conn[i], z_conn[i] = xi_conn, yi_conn, zi_conn

        data_list.append(go.Scatter3d(
                                    x=xi_conn, y=yi_conn, z=zi_conn,
                                    mode='lines',
                                    line=go.scatter3d.Line(
                                        width = 4,
                                        color=elongation_i,
                                        colorscale='Viridis',
                                        showscale=False, #set to FALSE
                                    ),
                                showlegend=False
                            ))
    
    ## getting the colorbar once
    line_trace_all = go.Scatter3d( x=x_conn, y=y_conn, z=z_conn,
                                    mode='lines',
                                    line=go.scatter3d.Line(
                                        color=elongation_values,
                                        colorscale='Viridis',
                                        showscale=True),
                                    showlegend=False)
    
    data_list.append(line_trace_all)

    ### Create figure
    fig = go.FigureWidget(data=data_list)

    fig.show()
    return()

x,y,z = np.random.random_sample((3,10))
connections = np.array([[0,1],[9,2],[2,3],[5,7],[6,8],[2,8],[1,2],[4,5]]) #random
elongation_values = np.random.random_sample((len(connections)))

get_3D_plot_stack(x,y,z,connections,elongation_values)

Figure shows how colorbar values are only plotted once, but the colors are still off..

JIST
  • 1,139
  • 2
  • 8
  • 30

1 Answers1

0

The code below seeks to accomplish this using matplotlib. My understanding is that elongation_values represents the indices of the points to be connected; you want the colours to be defined by elongation_values; and the colour bar should be scaled to the range of elongation_values.

The code first plots the scatter points. Then it iterates over connections, each time plotting a line that joins two points defined by connections.

enter image description here

import matplotlib.pyplot as plt
import matplotlib
import numpy as np

#Random points
np.random.seed(8)
rand_pts = np.random.random_sample(size=(10, 3))
x_vals, y_vals, z_vals = rand_pts.T

#Lines connecting some points, and their colours
connections = np.array([[0, 1], [9, 2], [2, 3], [5, 7], [6, 8], [2, 8], [1, 2], [4, 5]]) # line connections
elongation_values = np.random.random_sample((len(connections))) # random colors

fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(projection='3d')
colourmap = matplotlib.cm.viridis

#Plot points
ax.scatter3D(x_vals, y_vals, z_vals, c='k', s=60, alpha=1)

#For each entry in 'connections', plot a line joining two points
for (conn0, conn1), elong_val in zip(connections, elongation_values):
    x0, y0, z0 = rand_pts[conn0]
    x1, y1, z1 = rand_pts[conn1]
    
    ax.plot3D([x0, x1], [y0, y1], [z0, z1], c=colourmap(elong_val), linewidth=3.2)

#Make a new axis for the colourbar, positioning it at the right
ax_pos = ax.get_position()
cax = fig.add_axes([ax_pos.x0 + ax_pos.width * 1.1, ax_pos.y0 + 0.1, ax_pos.width / 15, ax_pos.height * 0.7])
#Add colorbar
# First define a scale where the min elongation is mapped to 0, and
# the max elongation is mapped to 1
colour_scaling = matplotlib.colors.Normalize(vmin=elongation_values.min(),
                                             vmax=elongation_values.max())
fig.colorbar(matplotlib.cm.ScalarMappable(norm=colour_scaling, cmap=colourmap), cax=cax)
some3128
  • 1,430
  • 1
  • 2
  • 8