``````

In [1]:

import numpy as np
import itertools
import plotly.graph_objs as go
init_notebook_mode(connected=True)

``````
``````

requirejs.config({paths: { 'plotly': ['https://cdn.plot.ly/plotly-latest.min']},});if(!window.Plotly) {{require(['plotly'],function(plotly) {window.Plotly=plotly;});}}

``````

We will use this convention for spherical polars:

``````

In [2]:

def p2c(r, theta, phi):
"""Convert polar unit vector to cartesians"""
return [r * np.sin(theta) * np.cos(phi),
r * np.sin(theta) * np.sin(phi),
r * np.cos(theta)]

``````
``````

In [3]:

class Arrow:
def __init__(self, theta, phi, out, width=5, color='rgb(0,0,0)'):
"""
Args:
theta (float) - radians [0, π]
phi (float) - radians [0, 2π]
out (bool) - True if outgoing, False if incoming (to the origin)
width (int) - line thickness
color (hex/rgb) - line color
"""
self.theta = theta
self.phi = phi
self.out = out
self.width = width
self.color = color

wing_length, wing_angle = self._find_wing_coord()

shaft_xyz = p2c(1., self.theta, self.phi)
wings_xyz = [p2c(wing_length, self.theta + wing_angle, self.phi),
p2c(wing_length, self.theta - wing_angle, self.phi)]

self.shaft = go.Scatter3d(
x=[0, shaft_xyz[0]],
y=[0, shaft_xyz[1]],
z=[0, shaft_xyz[2]],
showlegend=False, mode='lines', line={'width': self.width, 'color': self.color}
)
self.wings = go.Scatter3d(
x=[wings_xyz[0][0], shaft_xyz[0] / 2., wings_xyz[1][0]],
y=[wings_xyz[0][1], shaft_xyz[1] / 2., wings_xyz[1][1]],
z=[wings_xyz[0][2], shaft_xyz[2] / 2., wings_xyz[1][2]],
showlegend=False, mode='lines', line={'width': self.width, 'color': self.color}
)

self.data = [self.shaft, self.wings]

def _find_wing_coord(self):
"""Finds polar coordinates of arrowhead wing ends"""
frac = 0.1
r = 0.5
sin45 = np.sin(np.pi / 4.)

if self.out == True:
d = r - frac * sin45
elif self.out == False:
d = r + frac * sin45
else:
raise TypeError("arg: out must be True or False")

a = np.sqrt(frac**2 * sin45**2 + d**2)
alpha = np.arccos(d / a)
return [a, alpha]

``````
``````

In [4]:

arr1 = Arrow(theta=0.2*np.pi, phi=0.1*np.pi, out=False, width=2)
arr2 = Arrow(theta=0.7*np.pi, phi=0.9*np.pi, out=True, width=2)

layout = {
'autosize': True,
'scene': {
'aspectmode': 'cube',
'xaxis': {'range': [-1, 1], 'autorange': False, 'zeroline': True},
'yaxis': {'range': [-1, 1], 'autorange': False, 'zeroline': True},
'zaxis': {'range': [-1, 1], 'autorange': False, 'zeroline': True},
'camera': {
'up': {'x': 0, 'y': 1, 'z': 0} # DOESN'T WORK -- WHY NOT!?
}
}
}

plot_data = arr1.data + arr2.data # joins lists
# plot_data = arr1.data

fig = go.Figure(data=plot_data, layout=layout)
iplot(fig)

``````
``````

require(["plotly"], function(Plotly) { window.PLOTLYENV=window.PLOTLYENV || {};window.PLOTLYENV.BASE_URL="https://plot.ly";Plotly.newPlot("e7ab2cb9-0660-4738-b5c1-4bea9a41df90", [{"type": "scatter3d", "x": [0, 0.5590169943749475], "y": [0, 0.1816356320013402], "z": [0, 0.8090169943749475], "showlegend": false, "mode": "lines", "line": {"width": 2, "color": "rgb(0,0,0)"}}, {"type": "scatter3d", "x": [0.37344324042664945, 0.2795084971874737, 0.26463069545250734], "y": [0.12133906423965914, 0.0908178160006701, 0.08598372518033143], "z": [0.42015194369149633, 0.4045084971874737, 0.5032773312469879], "showlegend": false, "mode": "lines", "line": {"width": 2, "color": "rgb(0,0,0)"}}, {"type": "scatter3d", "x": [0, -0.7694208842938134], "y": [0, 0.25000000000000006], "z": [0, -0.587785252292473], "showlegend": false, "mode": "lines", "line": {"width": 2, "color": "rgb(0,0,0)"}}, {"type": "scatter3d", "x": [-0.2907756989077313, -0.3847104421469067, -0.3698326404119409], "y": [0.09447875176101111, 0.12500000000000003, 0.12016590917966155], "z": [-0.3095360726502597, -0.2938926261462365, -0.19512379208672265], "showlegend": false, "mode": "lines", "line": {"width": 2, "color": "rgb(0,0,0)"}}], {"autosize": true, "scene": {"aspectmode": "cube", "xaxis": {"range": [-1, 1], "autorange": false, "zeroline": true}, "yaxis": {"range": [-1, 1], "autorange": false, "zeroline": true}, "zaxis": {"range": [-1, 1], "autorange": false, "zeroline": true}, "camera": {"up": {"x": 0, "y": 1, "z": 0}}}}, {"showLink": true, "linkText": "Export to plot.ly"})});

``````
``````

In [ ]:

``````