#!/usr/bin/env python # coding: utf-8 # ## 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') # 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') # 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()