In [1]:
import numpy as np
import pandas as pd
from lets_plot import *

LetsPlot.setup_html()
$$x(\theta,\varphi)=(R+r\cos\theta)\cos\varphi$$$$y(\theta,\varphi)=(R+r\cos\theta)\sin\varphi$$$$z(\theta,\varphi)=r\sin\theta$$
In [2]:
n = 20
R = 15
r = 1
In [3]:
theta = np.linspace(0, 2*np.pi, n)
phi = np.linspace(0, 2*np.pi, n)
In [4]:
def torus(theta, phi, R, r):
    delta = (R + r*np.cos(theta))
    x = delta*np.cos(phi)
    y = delta*np.sin(phi)
    z = r*np.sin(theta)
    return x, y, z
In [5]:
x, y, z = torus(theta, phi, R, r)
In [6]:
thetas, phis = np.meshgrid(theta, phi)
theta, phi = thetas.reshape(-1), phis.reshape(-1)
In [7]:
x, y, z = torus(theta, phi, R, r)
In [8]:
X = np.vstack((x, y, z)).T
In [9]:
def rotation_matrices(theta_x, theta_y, theta_z):
    Rx = [[1, 0, 0],
      [0, np.cos(theta_x), -np.sin(theta_x)],
      [0, np.sin(theta_x), np.cos(theta_x)]]
    Ry = [[np.cos(theta_y), 0, np.sin(theta_y)], 
      [0, 1, 0], 
      [-np.sin(theta_y), 0, np.cos(theta_y)]]
    Rz = [[np.cos(theta_z), -np.sin(theta_z), 0], 
      [np.sin(theta_z), np.cos(theta_z), 0], 
      [0, 0, 1]]
    return Rx, Ry, Rz
In [10]:
Rx, Ry, Rz = rotation_matrices(np.pi/6, np.pi/3, np.pi/6)
In [11]:
X_rotated = ((X.dot(Rx)).dot(Ry)).dot(Rz)
In [12]:
torus_data = pd.DataFrame(X_rotated, columns=['x', 'y', 'z'])
torus_data['longitudinal'] = np.tile(np.arange(n), n)
torus_data['cross-sectional'] = np.repeat(np.arange(n), n)
In [13]:
ggplot(torus_data) \
        + geom_path(aes('x', 'y', group='longitudinal'), alpha=0.5, color='blue') \
        + geom_path(aes('x', 'y', group='cross-sectional'), alpha=0.5, color='red') \
        + theme(legend_position='none')
Out[13]: