Triangular wireplot on sphere


In [2]:
import numpy as np
from __future__ import division

Sphere parameterization:


In [3]:
def sphere(theta, phi): 
    x=np.cos(phi)*np.cos(theta)
    y=np.cos(phi)*np.sin(theta)
    z=np.sin(phi)  
    return x,y,z

In [4]:
theta=np.linspace(0,2*np.pi,40)
phi=np.linspace(-np.pi/2, np.pi/2, 30)
theta,phi=np.meshgrid(theta,phi)
x,y,z=sphere(theta,phi)

Choose three non-collinear points in the parametric plane, i.e. give the $\theta, \varphi$ coordinates for these points:


In [5]:
A=np.array([0, np.pi/12])
B=np.array([np.pi/3, np.pi/12])
C=np.array([np.pi/4, 7*np.pi/16])

In [6]:
T=[A,B,C]# Parametric triangle of vertices A,B,C

We define a triangulation of the triangle $T$ giving first the barycentric coordinates of the triangulation points, and then calculating their cartesian coordinates:


In [7]:
def barycentric(n):
    return [(i/n,j/n, 1-(i+j)/n) for i in range(n,-1, -1) for j in range(n-i, -1, -1)]

In [8]:
cartesian_coords=lambda  T, w: w[0]*T[0]+w[1]*T[1]+w[2]*T[2]

The following function selects successively three consecutive points from the list of the triangulation points, and creates a list of sub-triangles:


In [9]:
def triangles(n, point):
    triplets=[]
    i=0
    j=1
    for nr in range(1,n+1):
        for k in range(nr):
            triplets.append([point[i], point[j], point[j+1]])
            i+=1
            j+=1
        j+=1
    return triplets

In order to plot the triangular wireframe on the sphere we are setting $n=8$, as being the number of points on each side of the triangle $T$:


In [10]:
n=8
bar=barycentric(n)
pts_tri=[cartesian_coords(T, w) for w in bar]#list of triangulation points
tri=triangles(n, pts_tri)#list of sub-triangles in T

Instead of evaluating the parameterization only at the triangulation points, we also evaluate it at the middle of each side of a sub-triangle associated to the defined triangulation:


In [11]:
def divide_sides(t):
    pts=[t[k] for k in range(3)]+[t[0]]
    for k in range(1, 7, 2):
        m=int((k-1)/2)
        pts.insert(k, (t[m]+t[(m+1)%3])/2)
    return pts

In [12]:
import plotly.plotly as py
from plotly.graph_objs import *
import plotly.tools as tls
py.sign_in('empet', 'my_api_key')

In [13]:
trace = Surface(
        z=z, 
        x=x,  
        y=y,   
        colorscale='Viridis',
        )

In [14]:
def line_pts(tri, surface, color='#0000A0'):
    # tri is the list of triangulation sub-triangles
    # surface is the function implementing a surface parameterization
    lines = []
    for t in tri:
        pts=divide_sides(t)
        coords=zip(*[surface(pts[k][0], pts[k][1]) for k in range(7)])
        lines.append(Scatter3d(x=coords[0], 
                               y=coords[1],
                               z=coords[2], 
                               mode='lines', 
                               line=Line(color=color,  
                                         width=5)))
    return lines

In [15]:
axis = dict(
showbackground=True, 
backgroundcolor="rgb(230, 230,230)",
gridcolor="rgb(255, 255, 255)",      
zerolinecolor="rgb(255, 255, 255)",  
    )
    
data = Data([trace]+line_pts(tri, sphere))#plot both the sphere as a Surface object and the triangular wireframe
layout = Layout(
         title='Triangular wireframe on  sphere',
         width=700,
         height=700,
        scene=Scene(  
         xaxis=XAxis(axis),
         yaxis=YAxis(axis), 
         zaxis=ZAxis(axis), 
        ),
    showlegend=False
    )
    

fig1 = Figure(data=data, layout=layout)
py.plot(fig1, filename='triangular-wireplot-2')


Out[15]:
u'https://plot.ly/~empet/6954'

Now we are plotting only the triangular wireframe:


In [16]:
data1 = Data(line_pts(tri, sphere))
layout.update(width=600,
              height=600)
fig2 = Figure(data=data1, layout=layout)
py.plot(fig2, filename='triangular-wireplot-3')


Out[16]:
u'https://plot.ly/~empet/6965'

In a similar way we can generate any triangular wireframe on a surface given by a parameterization or the explicit equation $z=f(x,y)$.


In [1]:
from IPython.core.display import HTML
def  css_styling():
    styles = open("./custom.css", "r").read()
    return HTML(styles)
css_styling()


Out[1]: