In [1]:
import plotly.offline as py
import plotly.tools as tls
from plotly.graph_objs import *
import numpy as np
from numpy import pi, cos, sin, exp, log, sqrt
from random import random
py.init_notebook_mode()
In [2]:
zero=np.array([0,0,0])
In [3]:
def rotation_matrix(axis, theta):
    #based on http://stackoverflow.com/a/6802723
    """
    Return the rotation matrix associated with counterclockwise rotation about
    the given axis by theta radians.
    """
    axis = np.asarray(axis)
    theta = np.asarray(theta)
    axis = axis/sqrt(np.dot(axis, axis))
    a = cos(theta/2.0)
    b, c, d = -axis*sin(theta/2.0)
    aa, bb, cc, dd = a*a, b*b, c*c, d*d
    bc, ad, ac, ab, bd, cd = b*c, a*d, a*c, a*b, b*d, c*d
    return np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)],
                     [2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)],
                     [2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])
In [14]:
def arrow(r0=zero,dr=zero,color='black',head_frac=0.1,head_ang=pi/12,head_count=7,name=''):
    r0=np.asarray(r0)
    dr=np.asarray(dr)
    a=np.cross(dr,[random() for i in range(3)]) #rotation axis perpendicular to dr
    [ra,rb]=[rotation_matrix(axis,angle) for (axis,angle) in [(a,head_ang),(dr,2*pi/head_count)]]
    piece=-head_frac*np.dot(ra,dr)
    steps=[r0,dr,piece,-piece]
    for i in range(head_count-1):
        piece=np.dot(rb,piece)
        steps += [piece,-piece]
    path,position=[],zero
    for step in steps:
        position = position + step
        path.append(position)
    lp=[list(p) for p in path]
    [x,y,z]=list(zip(*lp))
    trace = Scatter3d(x=x,y=y,z=z,mode='lines',line=Line(color=color,width=3),name=name)
    return(trace)
In [16]:
[u,v,w]=[np.asarray(l) for l in [[5,-1,3],[2,2,-1],[0,0,7]]]
parallelepiped=Data([arrow(r0=r0,dr=dr,color=color,name=name) for (r0,dr,color,name) in [
    (zero,u,'red','u'),(zero,v,'green','v'),(zero,w,'blue','w'),
    (w,u,'red','u'),(u,v,'green','v'),(v,w,'blue','w'),
    (v,u,'red','u'),(w,v,'green','v'),(u,w,'blue','w'),
    (v+w,u,'red','u'),(w+u,v,'green','v'),(u+v,w,'blue','w')
    ]])
py.iplot(Figure(data=parallelepiped))
In []: