Angular momentum#

What You Need to Know

  • Angular momentum is essential in both classical and quantum mechanics. In classical mechanics, all isolated systems conserve angular momentum (along with energy and linear momentum). This conservation law simplifies calculations for systems such as planetary orbits, rotations of rigid bodies, and many other dynamic systems.

  • In quantum mechanics, angular momentum is similarly fundamental, especially in understanding atomic structure and other systems with rotational symmetry.

  • Angular momentum in QM is represented by an operator—a vector operator, to be specific, much like the momentum operator.

  • However, unlike the linear momentum operator, the three components of the angular momentum operator do not commute.

L vs p Overview#

Property

Linear Momentum

Angular Momentum

Nature

Linear motion in a straight line

Rotational motion around an axis

Vector form

\(\vec{p} = m \cdot \vec{v}\)

\(\vec{L} = \vec{p}\times\vec{r}\)

Scalar form

\( |\vec{p}| = m \cdot v\)

\( |\vec{L}| = I \cdot \omega\)

Mass for point particles

\(m\)

\(I=mr^2\)

Kinetic Energy

\(\frac{p^2}{2m}\)

\(\frac{L^2}{2I}\)

QM operators

\(\hat{p_x}=-i\hbar\frac{\partial}{\partial x}\)

\({\hat{L_x} = yp_z - zp_y}\)

Conservation Principle

Law of Conservation of Linear Momentum

Law of Conservation of Angular Momentum

Conservation Condition

No net external force acting on a closed system

No net external torque acting on a closed system

Classical angular momentum#

DeD0

Fig. 71 Angular momemntum in classical mechanics is a vector quantity defined by the cross product of position vector and linear momentum. Direction is determined by using the thumb rule.#

  • In classical mechanics, the angular momentum is defined via a corss product of position and linear momentum. The cross product is convenient to write using a determinant:

\[\begin{split}{\vec{L} = \vec{r}\times\vec{p} = \begin{vmatrix} \vec{i} & \vec{j} & \vec{k}\\ x & y & z\\ p_x & p_y & p_z\\ \end{vmatrix}= \left(yp_z - zp_y\right)\vec{i} + \left(zp_x - xp_z\right)\vec{j} + \left(xp_y - yp_x\right)\vec{k}}\end{split}\]
  • where \(\vec{i}, \vec{j}\) and \(\vec{k}\) denote unit vectors along the \(x, y\) and \(z\) axes. \(p_x\) and \(L_x\) are components of linear and angular momentum respectively

The Cartesian components of angular momentum

\[{L_x = yp_z - zp_y}\]
\[{L_y = zp_x - xp_z}\]
\[{L_z = xp_y - yp_x}\]
\[{\vec{L}^2 = \vec{L}\cdot\vec{L} = L_x^2 + L_y^2 + L_z^2}\]

Spherical coordinates#

  • Spherical coordinates are more convenient for rotational problems where we replace \((x,y,z)\) by \((r, \phi, \theta)\).

  • For instance when considering rotation with fixed orbit \(r=const\) we are able to eliminate one degree of freedom associated with radial direction.

DeD0

Fig. 72 Spherical coordinate system is defined by radial coordinate \(r\), azimuthal angle \(\phi\) and polar angle \(\theta\).#

Cartesian to spherical conversion

\[x={\color{blue} r}{\color{green}sin\theta} {\color{orange} cos\phi}\]
\[y={\color{blue} r}{\color{green} sin\theta} {\color{orange} sin\phi}\]
\[z={\color{blue} r} {\color{green} cos\theta}\]
\[Radius:\,\,\,{\color{blue} 0<{r}<\infty}\]
\[Azimuthal\, angle:{\color{orange}\,\,\,0<\phi<2\pi}\]
\[Polar\, angle:\,\,\,{\color{green} 0<\theta<\pi}\]

Volume Element

\[ dV = {\color{blue} r^2} {\color{blue} dr} \cdot {\color{green}\sin \theta} {\color{green}d\theta} \cdot {\color{orange}d\phi} \]

Laplacian

\[ \nabla^2 = \frac{{\partial^2}}{{\partial x^2}} + \frac{{\partial^2}}{{\partial y^2}} + \frac{{\partial^2}}{{\partial z^2}} \]
\[ \nabla^2 = {\color{blue}\frac{1}{r^2} \frac{\partial}{\partial r} \left(r^2 \frac{\partial}{\partial r}\right)} + {\color{green}\frac{1}{{\color{blue} r^2} \sin(\theta)}} {\color{green} \frac{\partial}{\partial \theta} \left(\sin(\theta) \frac{\partial}{\partial \theta}\right)} + { \frac{{\color{green} 1}}{{\color{blue} r^2} {\color{green} \sin^2(\theta)}} {\color{orange}\frac{\partial^2}{\partial \phi^2}}} \]

Example

Compute volume of cube and sphere using cartesian and spherical cooridnates by integrating volume elements

Example

Write down laplacian for a rigid rotor problem \(r=const\). Show what equations result when you separate the two angular variables by pluggin in \(\psi(r, \theta, \phi)\)

Quantum angular momentum#

  • In quantum mechanics, the classical angular momentum is replaced by the corresponding quantum mechanical operator.

  • In spherical coordinates, the angular momentum operators can be written in the following form. The derivations are quite tedious involving multiple applications of chain rule but its just a straightforward math procedure. Note that the choice of \(z\)-axis here was arbitrary. Sometimes the physical system implies such axis naturally (for example, the direction of an external magnetic field).

\[{\hat{L}_x = -i\hbar\left(y\frac{\partial}{\partial z} - z\frac{\partial}{\partial y}\right)}\]
\[{\hat{L}_y = -i\hbar\left(z\frac{\partial}{\partial x} - x\frac{\partial}{\partial z}\right)}\]
\[{\hat{L}_z = -i\hbar\left(x\frac{\partial}{\partial y} - y\frac{\partial}{\partial x}\right)}\]
\[\hat{L}^2=\hat{L_x}^2+\hat{L_y}^2+\hat{L_z}^2\]
\[{\hat{L}_x = i\hbar\left(\sin(\phi)\frac{\partial}{\partial\theta} + \cot(\theta)\cos(\phi)\frac{\partial}{\partial\phi}\right)}\]
\[{\hat{L}_y = i\hbar\left(-\cos(\phi)\frac{\partial}{\partial\theta} + \cot(\theta)\sin(\phi)\frac{\partial}{\partial\phi}\right)}\]
\[{\hat{L}_z = -i\hbar\frac{\partial}{\partial\phi}}\]
\[{\vec{\hat{L}}^2 = -\hbar^2\underbrace{\left[\frac{1}{\sin(\theta)}\frac{\partial}{\partial\theta}\left(\sin(\theta)\frac{\partial}{\partial\theta}\right) + \frac{1}{\sin^2(\theta)}\frac{\partial^2}{\partial\phi^2}\right]}_{\equiv \Lambda^2}}\]

Example

Find the eigenfunctions and eigenvalues of the operator \(\hat{L}_z\):

\[\hat{L}_z = -i\hbar\frac{\partial}{\partial\phi}\]

Components of angular momentum do not commute!#

  • Unlike linear momentum components of angular momentum do not commute!

  • This implies that it is not possible to measure any of the Cartesian angular momentum pairs simultaneously with an infinite precision (the Heisenberg uncertainty relation).

  • Note the cyclical nature of commutations between components

Eignefunctions and eigenvalues of \(L\) and \(L_z\)#

  • Since operators of component and angular momentum square commute is possible to find functions that are eigenfunctions of both \(\vec{\hat{L}}^2\) and \(\hat{L}_z\).

Eignefunctions and eigenvalues of angular momentum

\[{{\hat{L}}^2 Y_l^m(\theta,\phi) = \hbar^2 l(l+1)\cdot Y_l^m(\theta,\phi)}\]
\[{\hat{L}_zY^m_l(\theta,\phi) = \hbar m \cdot Y_l^m(\theta,\phi)}\]
  • Eigenfunctions: \(Y_l^m(\theta,\phi) \)

  • Angular quantum number: \(l = 0,1,2,3...\)

  • Magnetic quantum number: \(|m| = 0,1,2,3,...l\)

  • Note that here \(m\) has nothing to do with magnetism but the name originates from the fact that (electron or nuclear) spins follow the same laws of angular momentum.

  • Functions \(Y_l^m\) are called spherical harmonics. Examples of spherical harmonics with various values of \(l\) and \(m\) are given below (with Condon-Shortley phase convention

Spherical harmonics#

  • Spherical harmonics, denoted as \(Y_{lm}(\theta, \phi)\) or \(|l, m\rangle\) are important in many theoretical and practical applications, e.g., the representation of multipole electrostatic and electromagnetic fields, computation of atomic orbital electron configurations, representation of gravitational fields, MRI imaging for streamline tractography, and the magnetic fields of planetary bodies and stars.

  • Spherical harmonics emerge from the angular part of the solutions to the Laplace equation \(\nabla^2 f=0\) in spherical coordinates which is the type of equation we obtained for Rigid Rotor problem and will see once more in Hydrogen atom problem.

\( Y_{lm}(\theta, \phi) \)

Expression

Colatitudinal Nodes

Azimuthal Nodes

\( Y_{00} \)

\( \frac{1}{\sqrt{4\pi}} \)

0

0

\( Y_{10} \)

\( \sqrt{\frac{3}{4\pi}} \cos(\theta) \)

1 (equatorial)

0

\( Y_{1-1} \)

\( \sqrt{\frac{3}{4\pi}} \sin(\theta) e^{-i\phi} \)

0

1

\( Y_{20} \)

\( \sqrt{\frac{5}{16\pi}} (3\cos^2(\theta) - 1) \)

2 (colatitudinal rings)

0

\( Y_{2-1} \)

\( \sqrt{\frac{15}{4\pi}} \sin(\theta) \cos(\theta) e^{-i\phi} \)

1 (equatorial)

1

\( Y_{2-2} \)

\( \sqrt{\frac{15}{4\pi}} \sin^2(\theta) e^{-2i\phi} \)

0

2

Nodes of Spherical Harmonics#

The nodal structure of spherical harmonics is influenced by both the degree \( l \) and the order \(m\), defining the number and type of nodes as follows:

  1. Colatitudinal Nodes (Polar Nodes): The variable \( \theta \) defines “polar” nodes, which appear as circular bands around the sphere. The expression in \( \cos(\theta) \) or \( \sin(\theta) \) creates colatitudinal nodes:

    • For example, \( Y_{10} \) with \( \cos(\theta) \) has a single node at \( \theta = \pi/2 \), creating an equatorial node.

    • \( Y_{20} \), with \( (3\cos^2(\theta) - 1) \), introduces two polar nodes, dividing the sphere into three regions along the colatitude.

  2. Azimuthal Nodes (Longitudinal Nodes): The variable \( \phi \) defines “azimuthal” nodes due to the terms \(e^{im\phi}\), which create lines of longitude where the function changes phase. The number of azimuthal nodes is determined by \( |m| \):

    • If \( m = 0 \), there are no azimuthal nodes, as seen in \( Y_{00} \) and \( Y_{10} \).

    • For \( m = \pm 1 \), a single azimuthal node occurs (e.g., \( Y_{1-1} \), \( Y_{2-1} \)), and for \( m = \pm 2 \), two azimuthal nodes appear (e.g., \( Y_{2-2} \)).

  3. Total Nodes: equal to sum of nodes coming from polar and longitudinal nodes and are exactly equal to \(l\). E. gl=0 no nodes, l=4 four nodes.

Orthogonality of Spherical Harmonics#

The orthogonality of spherical harmonics is expressed as:

\[ \langle l', m'| l, m \rangle = \delta_{l,l'}\delta_{m,m'} \]

This orthogonality condition can be explicitly written as:

\[ \int_0^{\pi} \int_0^{2\pi} Y_{l'}^{m'*}(\theta, \phi) Y_l^m(\theta, \phi) \sin(\theta) \, d\theta \, d\phi = \delta_{l,l'}\delta_{m,m'} \]
Hide code cell source
import numpy as np
from scipy.special import sph_harm
from scipy.integrate import dblquad

def orthogonality_test(l1, m1, l2, m2):
    """
    Computes the orthogonality integral of spherical harmonics Y(l1, m1) and Y(l2, m2).
    
    Parameters:
    l1, m1 (int): Degree and order of the first spherical harmonic.
    l2, m2 (int): Degree and order of the second spherical harmonic.
    
    Returns:
    float: The result of the orthogonality integral.
    """
    # Define the integrand for the orthogonality condition
    def integrand(theta, phi):
        Y_lm1 = sph_harm(m1, l1, phi, theta)
        Y_lm2 = sph_harm(m2, l2, phi, theta)
        return np.real(Y_lm1 * np.conj(Y_lm2)) * np.sin(theta)
    
    # Perform the integration over theta (0 to pi) and phi (0 to 2*pi)
    integral, error = dblquad(integrand, 0, 2 * np.pi, lambda _: 0, lambda _: np.pi)
    return integral

# Test orthogonality between different spherical harmonics
print("Orthogonality Tests:")
print(f"∫ Y(1,0) * Y(1,0)* = {orthogonality_test(1, 0, 1, 0):.5f} (should be close to 1)")
print(f"∫ Y(1,0) * Y(1,1)* = {orthogonality_test(1, 0, 1, 1):.5f} (should be close to 0)")
print(f"∫ Y(1,1) * Y(2,1)* = {orthogonality_test(1, 1, 2, 1):.5f} (should be close to 0)")
print(f"∫ Y(2,1) * Y(2,1)* = {orthogonality_test(2, 1, 2, 1):.5f} (should be close to 1)")
print(f"∫ Y(2,0) * Y(2,-1)* = {orthogonality_test(2, 0, 2, -1):.5f} (should be close to 0)")
Orthogonality Tests:
∫ Y(1,0) * Y(1,0)* = 1.00000 (should be close to 1)
∫ Y(1,0) * Y(1,1)* = -0.00000 (should be close to 0)
∫ Y(1,1) * Y(2,1)* = 0.00000 (should be close to 0)
∫ Y(2,1) * Y(2,1)* = 1.00000 (should be close to 1)
∫ Y(2,0) * Y(2,-1)* = 0.00000 (should be close to 0)

Plotting Spherical Harmonics#

  • Here we will visualize spherical harmonic on a 3D sphere of radius 1. Radidus is fixed so there are only two variables which dictate nodal features:

  • Colatitudinal nodes depend on \( l \) and represent bands around the sphere, arising from terms in \( \cos(\theta) \) or \( \sin(\theta) \).

  • Azimuthal nodes depend on \( |m| \) and create longitudinal nodes based on \( e^{im\phi} \).

Hide code cell source
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.special import sph_harm
from mpl_toolkits.mplot3d import Axes3D

def generate_spherical_harmonic_data(l, m):
    """
    Generates the data needed to plot the spherical harmonic for given l and m values.
    
    Parameters:
    l (int): Degree of the spherical harmonic.
    m (int): Order of the spherical harmonic.

    Returns:
    tuple: (x, y, z, fcolors_normalized) where:
        - x, y, z are the Cartesian coordinates of the spherical surface,
        - fcolors_normalized is the color data for plotting.
    """
    
    # Define theta and phi grids
    phi = np.linspace(0, np.pi, 100)          # colatitude
    theta = np.linspace(0, 2 * np.pi, 100)    # azimuth
    phi, theta = np.meshgrid(phi, theta)

    # Cartesian coordinates for the unit sphere
    x = np.sin(phi) * np.cos(theta)
    y = np.sin(phi) * np.sin(theta)
    z = np.cos(phi)

    # Calculate the spherical harmonic Y(l, m) and normalize it to [-1, 1] for color mapping
    fcolors = sph_harm(m, l, theta, phi).real
    fcolors_normalized = (fcolors - fcolors.min()) / (fcolors.max() - fcolors.min())
    
    return x, y, z, fcolors_normalized

\(l=1\) harmonics#

Hide code cell source
# Define the range of m and l values for the first three spherical harmonics
harmonics = [(0, 1), (1, 1), (-1, 1)]  # List of (m, l) pairs to plot

# Create a figure to hold three subplots in one row
fig = plt.figure(figsize=(18, 6))
fig.suptitle("First Three Spherical Harmonics", fontsize=16)

for i, (m, l) in enumerate(harmonics, start=1):

    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m)

    # Create a subplot for each (m, l) pair in one row
    ax = fig.add_subplot(1, 3, i, projection='3d')
    ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=cm.seismic(fcolors_normalized), 
                    linewidth=0, antialiased=False)

    # Customize each subplot
    ax.set_title(f"$Y_{{{l},{m}}}$", fontsize=14)
    ax.set_box_aspect([1, 1, 1])  # Ensures spherical aspect ratio
    ax.set_axis_off()             # Turn off axes for clarity

# Adjust layout for a clear view of all subplots in one row
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
../_images/9549bc7f0b48ff404b19d70ff4ac50525216e4e8a57d3ccaa944ddcbb699719e.png

\(l=2\) harmonics#

Hide code cell source
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.special import sph_harm
from mpl_toolkits.mplot3d import Axes3D

# Define l and the range of m values for spherical harmonics with l=2
l = 2
m_values = [-2, -1, 0, 1, 2]

# Create a figure to hold five subplots in a 2x3 layout
fig = plt.figure(figsize=(15, 10))
fig.suptitle("Spherical Harmonics with l=2", fontsize=18)

for i, m in enumerate(m_values, start=1):

    # Calculate the spherical harmonic Y(l, m) and normalize it to [-1, 1] for color mapping
    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m) 

    # Create a subplot for each (m, l) pair in a 2x3 grid
    ax = fig.add_subplot(2, 3, i, projection='3d')
    ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=cm.seismic(fcolors_normalized),
                    linewidth=0, antialiased=False)

    # Customize each subplot
    ax.set_title(f"$Y_{{2,{m}}}$", fontsize=16)
    ax.set_box_aspect([1, 1, 1])  # Ensures spherical aspect ratio
    ax.set_axis_off()             # Turn off axes for clarity

# Adjust layout for a clear view of all subplots in a 2x3 grid
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
../_images/51e40cb8e9156842a15196cb286bfce948dc8a45b37b1d4a32daf4352be3afd8.png

Total number of nodes = \(l\)#

Hide code cell source
import numpy as np
import plotly.graph_objects as go
from scipy.special import sph_harm

# Define the range of m and l values for the first three spherical harmonics
harmonics = [(1, 1), (1, 2), (2, 3)]  # List of (m, l) pairs to plot

# Initialize the figure
fig = go.Figure()


# Loop over each harmonic and create a separate subplot
for i, (m, l) in enumerate(harmonics, start=1):
    
    # Calculate the spherical harmonic Y(l, m) and normalize it to [0, 1]
    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m) 
    
    # Add the spherical harmonic to the figure as a surface in a new scene
    fig.add_trace(go.Surface(
        x=x, y=y, z=z,
        surfacecolor=fcolors_normalized,
        colorscale='rdbu',
        showscale=False,
        name=f"$Y_{{{l},{m}}}$",
        scene=f'scene{i}'  # Assign each plot to a different scene
    ))

# Update layout to arrange scenes in a row and add titles as annotations
fig.update_layout(
    title="Three Spherical Harmonics: m=1, l=1, 2, 3",
    scene=dict(domain=dict(x=[0, 0.33]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    scene2=dict(domain=dict(x=[0.33, 0.66]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    scene3=dict(domain=dict(x=[0.66, 1]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    annotations=[
        dict(text="$Y_{2,0}$", x=0.16, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14)),
        dict(text="$Y_{2,1}$", x=0.5, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14)),
        dict(text="$Y_{2,-1}$", x=0.83, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14))
    ]
)

# Display the figure
fig.show()

Alternative visualizations of Spherical Harmonics#

  • Before we visualized spherical harmonics on unit sphere \(|r|=1\). However there are times where we want to visualize how magnitude of spherical harmooc is changing in space.

  • For instnace to visualize \(Y_{1,-1}\sim cos(\theta)\) we could either plot its values on a unit sphere or we could also plot how \(\cos(\theta)\) changes as we move around in space.

Hide code cell source
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from scipy.special import sph_harm

# Set up the subplots with two side-by-side 3D plots
fig = make_subplots(rows=1, cols=2, specs=[[{'is_3d': True}, {'is_3d': True}]])

# Define theta and phi grids for spherical coordinates
theta = np.linspace(0, np.pi, 100)
phi = np.linspace(0, 2 * np.pi, 100)
theta, phi = np.meshgrid(theta, phi)

# Convert spherical to Cartesian coordinates for the surface plots
x = np.sin(theta) * np.cos(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(theta)

# Compute the spherical harmonic Y_{1,-1}
m, l = -1, 1
r0a = np.sqrt(3 / (4 * np.pi)) * y  # Y_{1,-1} harmonic on y-axis
r0 = np.abs(r0a)  # Absolute value for magnitude scaling

# First plot: Scaled by the spherical harmonic (bead-like structure)
fig.add_trace(
    go.Surface(
        x=r0 * x, y=r0 * y, z=r0 * z,  # Scale coordinates by |Y_{1,-1}|
        surfacecolor=r0a,  # Color by Y_{1,-1} values
        colorscale='RdBu'
    ),
    row=1, col=1
)

# Second plot: Standard unit sphere with grayscale color
fig.add_trace(
    go.Surface(
        x=x, y=y, z=z,  # Unit sphere without scaling
        surfacecolor=z,  # Color by z-coordinate for simplicity
        colorscale='RdBu'
    ),
    row=1, col=2
)

# Update layout for both plots
fig.update_layout(
    font_family="JuliaMono",
    showlegend=False,
    margin=dict(l=0, r=0, b=0, t=0),
    paper_bgcolor='rgba(0,0,0,0)',
)

# Set scene properties with adjusted axis limits for each plot
fig.update_scenes(
    dict(
        xaxis=dict(nticks=4, range=[-0.5, 0.5]),  # Limit range to reduce empty space
        yaxis=dict(nticks=4, range=[-0.5, 0.5]),
        zaxis=dict(nticks=4, range=[-0.5, 0.5]),
        aspectratio=dict(x=1, y=1, z=1)
    ),
    row=1, col=1
)
fig.update_scenes(
    dict(
        xaxis=dict(nticks=4, range=[-1.8, 1.8]),
        yaxis=dict(nticks=4, range=[-1.8, 1.8]),
        zaxis=dict(nticks=4, range=[-1.8, 1.8]),
        aspectratio=dict(x=1, y=1, z=1)
    ),
    row=1, col=2
)

# Hide color scales for a cleaner look
fig.update_traces(showscale=False)

# Show the plot
fig.show()
Hide code cell source
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from matplotlib import cm
import matplotlib
import matplotlib.pyplot as plt

# Define theta (angle) values
theta = np.linspace(0, 2 * np.pi, 100)

# Compute spherical harmonic values (scaled sin(theta) for two-lobe structure)
Y_1m1_values = np.sin(theta)  # Y_{1,-1} varies with sin(theta) for the two-lobe shape
r_values = np.abs(Y_1m1_values)  # Radial scaling based on |Y_{1,-1}|

# Set up the color map
cmap = matplotlib.colormaps["RdBu"]
norm = plt.Normalize(vmin=-1, vmax=1)

# Create subplots for two polar plots
fig = make_subplots(rows=1, cols=2, specs=[[{'type': 'polar'}, {'type': 'polar'}]])

# First polar plot: Two-lobed structure with color gradient
for i in range(len(theta) - 1):
    fig.add_trace(
        go.Scatterpolar(
            r=[r_values[i], r_values[i + 1]],
            theta=[np.degrees(theta[i]), np.degrees(theta[i + 1])],
            mode="lines",
            line=dict(color=f"rgba{cmap(norm(Y_1m1_values[i]))}", width=5),
            showlegend=False
        ),
        row=1, col=1
    )

# Second polar plot: Unit circle with consistent color gradient
for i in range(len(theta) - 1):
    fig.add_trace(
        go.Scatterpolar(
            r=[1, 1],  # Fixed radius for unit circle
            theta=[np.degrees(theta[i]), np.degrees(theta[i + 1])],
            mode="lines",
            line=dict(color=f"rgba{cmap(norm(Y_1m1_values[i]))}", width=5),
            showlegend=False
        ),
        row=1, col=2
    )

# Update layout for both polar plots with fixed radius range and equal appearance
fig.update_layout(
    font_family="JuliaMono",
    showlegend=False,
    margin=dict(l=0, r=0, b=0, t=0),
    polar=dict(radialaxis=dict(range=[0, 1.2])),  # First plot axis range
    polar2=dict(radialaxis=dict(range=[0, 1.2]))  # Second plot axis range
)

# Show the plot
fig.show()

Learn More about Spherical Harmonics#