© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2021
M. Cywiak, D. CywiakMulti-Platform Graphics Programming with Kivyhttps://doi.org/10.1007/978-1-4842-7113-1_12

12. Plotting Functions in Spherical Coordinates

Moisés Cywiak1   and David Cywiak2
(1)
Leon, Guanajuato, Mexico
(2)
Queretaro, Mexico
 

In this chapter, we describe fundamental elements for calculating and plotting functions in spherical coordinates. For the working examples, we focus on the so-called spherical harmonics polynomials, encountered on diverse physical problems, as is the case with electron orbitals derived from Schrödinger’s differential equation. These polynomials, represented as Yl, m, are characterized by two positive integers, l and m, with |m| ≤ l. The polynomials are functions of the zenithal and azimuthal coordinates, as described in the following sections.

Figure 12-1 shows a screenshot of the program running on an Android cell phone with a plot of ‖Re(Y3, 2)‖2.
../images/510726_1_En_12_Chapter/510726_1_En_12_Fig1_HTML.jpg
Figure 12-1

Screenshot of the program running on an Android cell phone showing a plot of ‖Re(Y3, 2)‖2

To begin, we describe the spherical-coordinate system in the following section.

12.1 Overview of Spherical Coordinates

Figure 12-2 depicts a typical three-dimensional spherical-coordinate system.
../images/510726_1_En_12_Chapter/510726_1_En_12_Fig2_HTML.jpg
Figure 12-2

Typical spherical-coordinate system

In Figure 12-2, the parameters θ and ϕ represent the zenithal or polar and azimuthal angular coordinates, respectively. To generate points over a complete sphere, we need 0 < θ < π and 0 < ϕ < 2π. The r parameter is referred to as the radial distance.

From Figure 12-2, the coordinates of a point can be written as follows:
$$ x= rsinleft(	heta 
ight)mathit{cos}left(phi 
ight) $$
(12.1)
$$ y= rsinleft(	heta 
ight)mathit{sin}left(phi 
ight) $$
(12.2)
$$ z= rcosleft(	heta 
ight) $$
(12.3)

Equations (12.1)-(12.3) will be used to transform a three-dimensional differential equation from Cartesian coordinates into spherical coordinates.

In the following section, we present our working example, which consists of solving the well-known Schrödinger’s differential equation expressed in spherical coordinates.

12.2 Spherical Differential Equation Working Example

Consider the three-dimensional Schrödinger’s differential equation in Cartesian coordinates :
$$ frac{-mathrm{hslash}2}{2M}left(frac{partial^2psi left(x,y,z
ight)}{partial {x}^{{}^2}}+frac{partial^2psi left(x,y,z
ight)}{partial {y}^{{}^2}}+frac{partial^2psi left(x,y,z
ight)}{partial {z}^{{}^2}}
ight)+frac{q}{4pi {epsilon}_0r}psi left(x,y,z
ight)= Epsi left(x,y,z
ight) $$
(12.4)

In Equation (12.4), the ψ(x, y, z) function will represent, in principle, all the possible spatial positions that a charged particle, with charge q and mass M, can take under the influence of a potential distribution function equal to $$ frac{q}{r} $$. The term is the well-known Plank’s constant . The parameter ϵ0 represents vacuum permittivity.

By using Equations (12.1)-(12.3), we can express Equation (12.4) in spherical coordinates, as follows:
$$ frac{-{mathrm{hslash}}^{{}^2}}{2M}left[frac{partial^2psi left(r,	heta, phi 
ight)}{partial {r}^{{}^2}}+frac{2}{r}frac{partial psi left(r,	heta, phi 
ight)}{partial r}+frac{1}{r^{{}^2}}frac{partial^2psi left(r,	heta, phi 
ight)}{partial {	heta}^2}+frac{mathit{cos}left(	heta 
ight)}{r^{{}^2}mathit{sin}left(	heta 
ight)}frac{partial psi left(r,	heta, phi 
ight)}{partial 	heta }+frac{1}{r^{{}^2}{mathit{sin}}^{{}^2}left(	heta 
ight)}frac{partial^{{}^2}psi left(r,	heta, phi 
ight)}{partial {phi}^{{}^2}}
ight]+frac{q}{4pi {epsilon}_0r}psi left(r,	heta, phi 
ight)= Epsi left(r,	heta, phi 
ight) $$
(12.5)

Analogous to Equation (12.4), ψ(r, θ, ϕ) in Equation (12.5) gives valid spatial positions expressed in spherical coordinates for a particle with energy E, charge q, and mass M in a hydrogen-like atom with attractive potential equal to q/r.

Equation (12.5) can be solved using the method of separation of variables, proposing a solution of the product of three functions, as follows:
$$ psi left(r,	heta, phi 
ight)=R(r)Tleft(	heta 
ight)Fleft(phi 
ight) $$
(12.6)
After substituting Equation (12.6) into Equation (12.5), we see that the differential equations that correspond to the functions R(r) and T(θ) are not common ones, and therefore, they must be solved by suitable methods referred to as series expansion methods. Under these conditions, the overall solution corresponds to the product of three differential equations, as follows.
  • Solutions for R(r) are spherical Bessel functions.

  • Solutions for T(θ) are associated Legendre polynomials, typically written as Pl, m(cos(θ)).

  • Solutions for F(ϕ) are exponentials in the form exp(imϕ). The parameter i represents the imaginary unit.

For our example, we will focus on the case r equal to a constant. Therefore, ψ(r, θ, ϕ) becomes a function of only θ and ϕ. This condition will permit us to focus on the orbitals that the electrons follow in hydrogen-like atoms. These orbitals correspond to spherical-harmonics functions, defined as follows:
$$ {Y}_{l.m}left(	heta, phi 
ight)=sqrt{frac{2l+1}{4pi}frac{left(l-m
ight)!}{left(l+m
ight)!}}{P}_{l.m}left(mathit{cos}left(	heta 
ight)
ight)mathit{exp}left( imphi 
ight) $$
(12.7)

In Equation (12.7), the square root is a normalization factor.

The atomic orbitals correspond to probabilistic spatial distributions, which analytically correspond to the square of the absolute real value of the harmonics functions, expressed as follows:
$$ {left|mathit{operatorname{Re}}left({Y}_{l.m}left(	heta, phi 
ight)
ight)
ight|}^2={left|sqrt{frac{2l+1}{4pi}frac{left(l-m
ight)!}{left(l+m
ight)!}}{P}_{l.m}left(mathit{cos}left(	heta 
ight)
ight)mathit{cos}left( mphi 
ight)
ight|}^{{}^2} $$
(12.8)

To plot Equation (12.8) for a set of different l, m values, we need to calculate Pl, m(θ, ϕ). In the following section, we focus on this subject. For illustrative purposes, the normalization factor will not be considered.

12.3 The Associated Legendre Polynomials

It can be analytically demonstrated that the associated Legendre polynomials can be generated using the following equation:
$$ {P}_{l,m}=frac{1}{2^ll!}{left(1-{x}^2
ight)}^{frac{m}{2}}frac{d^{m+l}}{dx^{m+l}}{left({x}^2-1
ight)}^l $$
(12.9)

In Equation (12.9), we used the change of variable, x =  cos (θ). The l! expression represents the factorial of the integer l, calculated by the following expression, l!= l(l − 1)(l − 2)⋯(1).

In this case, we will use SymPy to symbolically calculate derivatives and factorials. The code in Listing 12-1 allows us to generate some Legendre polynomials .
import sympy as sp
x=sp.symbols("x");
def Plm(l,m ):
    N=( 1/(2**l) )*(1 /sp.factorial(l) )
    return N * (  (1-x**2)**(m/2)  )
           * sp.diff( (x**2-1)**l, x,m+l );
L_Num=3; M_Num=2; #Legendre l,m orders
R=sp.lambdify( x, Plm(L_Num,M_Num) );
Listing 12-1

Generating Legendre polynomials

In this code, x=sp.symbols("x") declares the variable x as symbolic, as described in Chapter 11. As a consequence, as Plm(l,m) function uses this variable for symbolic calculations, the function itself is, in turn a symbolic function.

The R=sp.lambdify( x, Plm(L_Num,M_Num) ) directive assigns to l, the value L_Num and m, the value M_NUM, respectively, 3 and 2 in this example. After executing sp.lambdify, we obtain the numerical function R(x).

At this point, it may be interesting to inspect the analytical expression of some associated Legendre polynomials. Listing 12-2 converts the equations given in the previous code to LaTeX. This expression can be visualized in a text editor.
import sympy as sp
x=sp.symbols("x");
#Associated Legendre l, m orders
L_Num=3; M_Num=3; # l, m orders
def Plm(l,m ):
    N=( 1/(2**l) )*(1 /sp.factorial(l) );
    return N * (  (1-x**2)**(m/2)  )
* sp.diff( (x**2-1)**l, x,m+l );
R=  Plm(L_Num,M_Num);
R1=sp.simplify(R);
T=sp.latex(R1); # Convert expression to LaTeX
# Replace   symbols by spaces to allow printing the equation.
A=T.replace("\"," ");
# A can be printed in a text editor
Listing 12-2

Code for Visualizing Symbolic Equations with LaTeX

In this code, the following directive:
T=sp.latex(R1),
converts the symbolic expression R into a LaTeX expression T. However, to print the corresponding formulas in a text editor, we remove the symbol \ by using the following code:
A=T.replace("\"," ").
Listing 12-3 gives some associated Legendre polynomials obtained with the code in Listing 12-2. When required, we have replaced rational exponents with their equivalent fractions.
P0, 0(x) = 1;
Listing 12-3

List of Some Associated Legendre Polynomials

$$ {P}_{1,0}(x)=x;kern0.5em {P}_{1,1}(x)=1{left(1-{x}^2
ight)}^{frac{1}{2}} $$
$$ {P}_{2,0}(x)=frac{3}{2}{x}^2-frac{1}{2};{P}_{2,1}(x)=3x{left(1-{x}^2
ight)}^{frac{1}{2}}{P}_{2,2}(x)=3left(1-{x}^2
ight) $$
$$ {P}_{3,0}(x)=xleft(frac{5}{2}{x}^2-372
ight);{P}_{3,1}(x)={left(1-{x}^2
ight)}^{frac{1}{2}}left(frac{15}{2}{x}^2-frac{3}{2}
ight);{P}_{3,2}(x)=15xleft(1-{x}^2
ight);kern0.5em {P}_{3,3}(x)=15{left(1-{x}^2
ight)}^{frac{3}{2}} $$
As indicated, x =  cos (θ). Therefore, we will use NumPy to create a one-dimensional array for θ with entries in the range 0 < θ < π, to substitute x with its corresponding cosine values. Similarly, we will create a second array for ϕ, with values between 0 and 2 π. The corresponding code is shown in Listing 12-4.
import numpy as np
N=40;
Pi=np.pi;
Theta=np.zeros(N+1);
Phi=np.zeros(N+1);
for n in range(0,N+1):
    Theta[n]=n/N*Pi;
    Phi[n]=n/N*2*Pi;
Listing 12-4

Creating and Filling the Angular Axes

In this code, we generate the arrays Theta and Phi, each with 41 entries. The first array holds numbers ranging from 0 to π in equally spaced steps. The second array stores numbers from 0 to 2π. The first entry, called Theta[0], is equal to 0, while the last entry, Theta[40], is equal to π. In turn, Phi[0] is equal to 0 and Phi[40] is 2π.

To calculate the values of the associated Legendre polynomials, we use the following directive within a for loop, with n ranging from 0 to N:
R( np.cos(Theta[n]) )
The complete code needed to print the corresponding values is shown in Listing 12-5.
import numpy as np
import sympy as sp
x=sp.symbols("x");
def Plm(l,m ):
    N=( 1/(2**l) )*(1 /sp.factorial(l) )
    return N * (  (1-x**2)**(m/2)  )
           * sp.diff( (x**2-1)**l, x,m+l );
L_Num=3; M_Num=2; #Legendre l,m orders
R=sp.lambdify( x, Plm(L_Num,M_Num) );
N=40;
Pi=np.pi;
Theta=np.zeros(N+1); Phi=np.zeros(N+1);
for n in range(0,N+1):
    Theta[n]=n/N*Pi;
    Phi[n]=n/N*2*Pi;
for n in range(0,N+1):
    print(  R(np.cos(Theta[n]))  );
Listing 12-5

Code for Printing Numerical Values of the Symbolic Function

At this point, we are ready to calculate the values corresponding to Equation (12.9). However, we may wonder if SymPy has a built-in function for the associated Legendre polynomials. The answer is yes. Therefore, instead of the code listed previously, we could use this:
Plm=sp.assoc_legendre(L_Num,M_Num, x);
R=sp.lambdify(x,Plm);

We can verify that both methods give the same results by comparing some values.

We are now in the position of plotting some spherical harmonics functions. In the following section, we describe our method for plotting the orbitals given in Equation (12.8).

12.4 Plotting Functions in Spherical Coordinates

The program generates the associated Legendre polynomials using the code shown in Listing 12-1, which creates the numerical function R(x) to provide the associated Legendre polynomials, Pl, m(x).

To create the 3D perspective, as in previous chapters, we use the required perspective parameters with the following values:
D=4000;
VX=600; VY=120; VZ=0;
Factor0 =(D-VZ) / (D/2-VZ);

The Factor0 variable is used to shift the plot to the center of the screen.

To calculate the spherical harmonics as functions of θ and ϕ, we use the code in Listing 12-6.
N=40;
Pi=np.pi;
Theta=np.zeros(N+1); Phi=np.zeros(N+1);
for n in range(0,N+1):
    Theta[n]=n/N*Pi;
    Phi[n]=n/N*2*Pi;
Listing 12-6

Creating the Angular Arrays

The code creates two arrays, each with 41 entries for the angular variables with 0 < θ < π and 0 < ϕ < 2π.

Now, we proceed to calculate the orbitals given by Equation (12.8) with the code in Listing 12-7.
import numpy as np
import sympy as sp
x=sp.symbols("x");
def Plm(l,m ):
    N=( 1/(2**l) )*(1 /sp.factorial(l) )
    return N * (  (1-x**2)**(m/2)  )
           * sp.diff( (x**2-1)**l, x,m+l );
L_Num=3; M_Num=2; #Legendre l,m orders
R=sp.lambdify( x, Plm(L_Num,M_Num) );
N=40;
Pi=np.pi;
Theta=np.zeros(N+1); Phi=np.zeros(N+1);
for n in range(0,N+1):
    Theta[n]=n/N*Pi;
    Phi[n]=n/N*2*Pi;
F=np.zeros( (N+1,N+1) );
for n in range(0,N+1):
    for m in range(0,N+1):
        F[n][m]=np.abs( R(np.cos(Theta[n]))
             *np.cos(M_Num*Phi[m]) )**2;
print(F);
Listing 12-7

Calculating Orbitals

In this code, the F=np.zeros( (N+1,N+1) ) directive creates the variable F, representing a two-dimensional (N+1)*(N+1) array to store the absolute square real values of Yl. m(θ, ϕ).

To plot F, we create the mesh arrays with appropriate dimensions using the following code.
x1=np.zeros( (N+1,N+1) );
y=np.zeros( (N+1,N+1) );
z1=np.zeros( (N+1,N+1) );

Now, we will use Equations (12.1)-(12.3) to create the plot. In these equations, the radial distance r is considered constant.

We have to assign the appropriate role to each variable, as described in previous chapters. The vertical height corresponds to the y-axis, the horizontal length corresponds to the x-axis, and the depth to the z-axis. The code in Listing 12-8 assigns the corresponding parameters appropriately.
x1=np.zeros( (N+1,N+1) );
y=np.zeros( (N+1,N+1) );
z1=np.zeros( (N+1,N+1) );
L=2.5;
for n in range(0,N+1):
    for m in range(0,N+1):
        x1[n][m]=L*F[n][m]*np.sin(Theta[n])
        *np.cos(Phi[m]);
        z1[n][m]=L*F [n][m]*np.sin(Theta[n])
        *np.sin(Phi[m])+D/2;
        y[n][m]=L*F[n][m]*np.cos(Theta[n]);
Listing 12-8

Filling Mesh and Vertical Coordinates

In this code, we included a scale factor L for enlarging or shrinking the plot as required. Finally, GraphFunction(B) and RotateFunction(B, Sense) are in charge of plotting and rotating the function, similarly to the previous chapters.

The code for main.py and File.kv is shown in Listings 12-9 and 12-10, respectively.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Line, Color
from kivy.clock import Clock
import os
import numpy as np
import sympy as sp
from kivy.lang import Builder
Builder.load_file(
    os.path.join(os.path.dirname(os.path.abspath(
                __file__)), 'File.kv')
                 );
#Avoid Form1 of being resizable
from kivy.config import Config
Config.set("graphics","resizable", False)
Config.set('graphics', 'width',  '480');
Config.set('graphics', 'height', '680');
x=sp.symbols("x");
def Plm(l,m ):
    N=( 1/(2**l) )*(1 /sp.factorial(l) )
    return N * (  (1-x**2)**(m/2)  )
           * sp.diff( (x**2-1)**l, x,m+l );
L_Num=3; M_Num=2; #Legendre l,m orders
R=sp.lambdify( x, Plm(L_Num,M_Num) );
D=4000;
VX=600; VY=1200; VZ=0;
Factor0 =(D-VZ) / (D/2-VZ);
N=40;
Pi=np.pi;
Theta=np.zeros(N+1); Phi=np.zeros(N+1);
for n in range(0,N+1):
    Theta[n]=n/N*Pi;
    Phi[n]=n/N*2*Pi;
M_Num=2; N_Num=3; #Legendre m,n orders
F=np.zeros( (N+1,N+1) );
for n in range(0,N+1):
    for m in range(0,N+1):
        F[n,m]=np.abs( R(np.cos(Theta[n]))
                       *np.cos(M_Num*Phi[m]) )**2;
x1=np.zeros( (N+1,N+1) );
y=np.zeros( (N+1,N+1) );
z1=np.zeros( (N+1,N+1) );
L=2.4;
for n in range(0,N+1):
    for m in range(0,N+1):
        x1[n][m]=L*F[n][m]*np.sin(Theta[n])
                  *np.cos(Phi[m]);
        z1[n][m]=L*F [n][m]*np.sin(Theta[n])
                  *np.sin(Phi[m])+D/2;
        y[n][m]=L*F[n][m]*np.cos(Theta[n]);
 #Array to store list of points
PointList=np.zeros( (N+1,2) );
def GraphFunction(B):
    global x1,y, z1, N, D, VX, VY, VZ;
    B.ids.Screen1.canvas.clear(); #Clear the screen
    #Choose color to draw
    B.ids.Screen1.canvas.add( Color(1,0,0) );
    for n in range (0,N+1): #Draw horizontal lines
        for m in range (0,N+1):
            Factor=(D-VZ)/(D-z1[n][m]-VZ);
            xA=XC+Factor*(x1[n][m]-VX)+Factor0*VX;
            yA=YC+Factor*(y[n][m]-VY)+Factor0*VY;
            PointList[m]=xA,yA;
        B.ids.Screen1.canvas.add( Line(points=
                    PointList.tolist(), width=1.3));
    for n in range (0,N+1): #Drawing vertical lines
        for m in range (0,N+1, 1):
            Factor=(D-VZ)/(D-z1[m][n]-VZ);
            xA=XC+Factor*(x1[m][n]-VX)+Factor0*VX;
            yA=YC+Factor*(y[m][n]-VY)+Factor0*VY;
            PointList[m]=xA,yA;
        B.ids.Screen1.canvas.add( Line(points=
                    PointList.tolist(), width=1.3));
def RotateFunction(B, Sense):
    global x1, y, z1, D, N;
    if Sense==-1:
        Theta=np.pi/180*(-4.0);
    else :
        Theta=np.pi/180*(4.0);
    Cos_Theta=np.cos(Theta)
    Sin_Theta=np.sin(Theta);
    X0=0;  Y0=0;  Z0=D/2 # Center of rotation
    for n in range(0,N+1):
        for m in range(0,N+1):
            if (B.ids.Button3.state=="down" or
                       B.ids.Button4.state=="down"):
                yP=(y[n][m]-Y0)*Cos_Theta
                    + (x1[n][m]-X0)*Sin_Theta + Y0;
                xP=-(y[n][m]-Y0)*Sin_Theta
                    +(x1[n][m]-X0)*Cos_Theta + X0;
                y[n][m]=yP;
                x1[n][m]=xP;
            if (B.ids.Button5.state=="down" or
                        B.ids.Button6.state=="down"):
                yP=(y[n][m]-Y0)*Cos_Theta
                    + (z1[n][m]-Z0)*Sin_Theta + Y0;
                zP=-(y[n][m]-Y0)*Sin_Theta
                    +(z1[n][m]-Z0)*Cos_Theta + Z0;
                y[n][m]=yP;
                z1[n][m]=zP;
            if (B.ids.Button7.state=="down" or
                       B.ids.Button8.state=="down"):
                xP=(x1[n][m]-X0)*Cos_Theta
                    + (z1[n][m]-Z0)*Sin_Theta + X0;
                zP=-(x1[n][m]-X0)*Sin_Theta
                    +(z1[n][m]-Z0)*Cos_Theta + Z0;
                x1[n][m]=xP;
                z1[n][m]=zP ;
class Form1(FloatLayout):
    def __init__(Handle, **kwargs):
        super(Form1, Handle).__init__(**kwargs);
        Event1=Clock.schedule_once(Handle.Initialize);
    def Initialize(B, *args):
        global W,H, XC,YC;
        W,H=B.ids.Screen1.size;
        XI,YI=B.ids.Screen1.pos
        XC=XI+int (W/2);
        YC=YI+int(H/2);
    def Button1_Click(B):
        GraphFunction(B);
    def Button2_Click(B):
        B.ids.Screen1.canvas.clear();
    def Button3_Click(B):
        RotateFunction(B,1),
        GraphFunction(B);
    def Button4_Click(B):
        RotateFunction(B,-1),
        GraphFunction(B);
    def Button5_Click(B):
        RotateFunction(B,-1),
        GraphFunction(B);
    def Button6_Click(B):
        RotateFunction(B,1),
        GraphFunction(B);
    def Button7_Click(B):
        RotateFunction(B,-1),
        GraphFunction(B);
    def Button8_Click(B):
        RotateFunction(B,1),
        GraphFunction(B);
# This is the Start Up code.
class StartUp (App):
    def build (BU):
        BU.title="Form1"
        return Form1();
if __name__ =="__main__":
    StartUp().run();
Listing 12-9

Code for the main.py File

#:set W 440
#:set H 440
<Form1>:
    id : Form1
    StencilView:
        id: Screen1
        size_hint: None,None
        pos_hint: {"x":0.04, "y":0.34}
        size: W,H
        canvas.before:
            Color:
                rgba: 0.9, 0.9, 0, 1
            RoundedRectangle:
                pos:  self.pos
                size: self.size
    Button:
        id: Button1
        on_press: Form1.Button1_Click()
        text: "Button1"
        size_hint: None,None
        pos_hint: {"x": 0.2, "y":0.03}
        size: 100,30
    Button:
        id: Button2
        on_press: Form1.Button2_Click()
        text: "Button2"
        size_hint: None,None
        pos_hint: {"x": 0.63, "y":0.03}
        size: 100,30
    Button :
        id: Button3
        on_press: Form1.Button3_Click()
        text: "Button3"
        size_hint: None,None
        pos_hint: {"x": 0.05, "y":0.12}
        size: 100,30
        always_release: True
    Button:
        id: Button4
        on_press: Form1.Button4_Click()
        text: "Button4"
        size_hint: None,None
        pos_hint: {"x": 0.73, "y":0.12}
        size: 100,30
    Button:
        id: Button5
        on_press: Form1.Button5_Click()
        text: "Button5"
        size_hint: None,None
        pos_hint: {"x": 0.05, "y":0.20}
        size: 100,30
    Button:
        id: Button6
        on_press: Form1.Button6_Click()
        text: "Button6"
        size_hint: None,None
        pos_hint: {"x": 0.73, "y":0.20}
        size: 100,30
    Button :
        id: Button7
        on_press: Form1.Button7_Click()
        text: "Button7"
        size_hint: None,None
        pos_hint: {"x": 0.05, "y":0.28}
        size: 100,30
    Button:
        id: Button8
        on_press: Form1.Button8_Click()
        text: "Button8"
        size_hint: None,None
        pos_hint: {"x": 0.73, "y":0.28}
        size: 100,30
Listing 12-10

Code for the file.kv File

Using this code, we generated the plots of |Pl, m(cos(θ)) cos ()|2 shown in Figure 12-3.
../images/510726_1_En_12_Chapter/510726_1_En_12_Fig3_HTML.jpg
Figure 12-3

Plots for |Pl, m(cos(θ)) cos ()|2obtained with this chapter’s code

12.5 Summary

In this chapter, we introduced elements for plotting functions in spherical coordinates. We introduced analytical concepts on three-dimensional spherical coordinates and illustrated the programming methods with working examples of spherical harmonics polynomials.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset