DEMO: Visualizing waves#

import numpy as np  
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from ipywidgets import interact, interactive
import scipy  
from scipy.constants import physical_constants, hbar, h, c, k, m_e, Rydberg, e, N_A

%matplotlib inline
%config InlineBackend.figure_format='retina'

try:
    from google.colab import output
    output.enable_custom_widget_manager()
    print('All good to go')
except:
    print('Okay we are not in Colab just proceed as if nothing happened')
Okay we are not in Colab just proceed as if nothing happened

Standing and traveling waves in 1D#

We begin by plotting a simple periodic function using numpy (np) and matplotlib.pyplot (plt)

\[y = \sin(kx)=\sin\left(\frac{2\pi}{\lambda} x\right)\]
L=0.3            # Try different wavelengths

x = np.linspace(0.0, 1.0, 1000)

y = np.sin(2 * np.pi * x/L)

plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x1666eec40>]
../_images/b0a77726734e88abe4226d4a391119896a44732031854a5399152909288d3d32.png

By putting above example inside a python function will make wavelength exploration convenient

def wave1d(L=2):
    
    x = np.linspace(0.0, 1.0, 1000)
    
    y = np.sin(2*np.pi * x / L )

    plt.plot(x, y, label=f'L={L}')
    
    plt.xlabel('x')
    plt.xlabel('y')
    plt.legend()
    plt.title('Sine waves')
    plt.ylim(-1,1)
    plt.show()
# Change wavelength
wave1d(L=0.5)
../_images/003c3e7ae777fac5856c689e4310243026e0cf3477e5d2a0c0414e91414272fe.png

Interact with waves#

  • By adding @widgets.interact(parameters=(init,final)) to our functions we can interactively parameters in the function using slider widgets.

interactive(wave1d, L=(0.1, 2))

Traveling, standing waves and wave interference#

def wavef2(k=10, t=0, phi=0, v=1):

    x     = np.linspace(0, 1., 1000)
    
    wave1 = np.sin(k*(x-v*t)) 
    wave2 = np.sin(k*(x-v*t)+phi)    #try flipping the direction of velocity to get standing wave
    
    plt.plot(x, wave1,   lw=2, color='blue')
    plt.plot(x, wave2,   lw=2,  color='green')
    plt.plot(x, wave1+wave2, lw=3,  color='red')
    
    plt.ylim([-2.5, 2.5])
    plt.legend(['Wave1','Wave2','Wave1+Wave2'])
    plt.grid('on')
    plt.show()
interactive(wavef2, k=(2, 20), t=(0,50.0,0.1), phi=(0, 2*np.pi, np.pi/8),v=1)

Traveling wave as a function of time and position#

import plotly.express as px

def wave_x_t(A = 1, k = 1.0, omega = 1, phi = 0):
    
    # Create a grid of x and t values
    x = np.linspace(0, 2 * np.pi, 50)
    t = np.linspace(0, 2 * np.pi, 50)
    X, T = np.meshgrid(x, t)

    # Calculate the wave amplitude for each combination of x and t
    Y = A * np.sin(k * X - omega * T + phi)

    return px.scatter_3d(x=X.ravel(), 
              y=T.ravel(), 
              z=Y.ravel(), 
              color = Y.ravel(),
              labels={'x': 'Position', 'y': 'Time', 'z': 'Amplitude'},
              width=1000, 
              height=1000)
wave_x_t(A=1, k = 1.0, omega=2, phi=0)

Normal modes of 1D guitar string#

def guitar1d(n=1, t=0):
    
    v=1
    L=1
    omega= np.pi*v/L
    x = np.linspace(0, +1., 1000)
    
    y = np.sin(n*np.pi * x/L) * np.cos(omega*t)
    
    plt.plot(x, y, lw=3)
    plt.title(label=f'Normal mode # {n}')
    plt.grid('--')
    plt.ylim(-1,1)
    plt.show()
interactive(guitar1d, n=(1,10), t=(0, 10, 0.1))

1D guitar vibrations as linear combination of normal modes#

For simplicity we will combine two modes with two different mode numbers and shifted with resepct to each ophter by a phase \(\phi\).

\[Mode_1 = cos(\omega t) \cdot sin(n_1\pi \cdot \frac{x}{L})\]
\[Mode_2 = cos(\omega t+\phi) \cdot sin(n_2\pi \cdot \frac{x}{L})\]
def wavef(n1=1, n2=1, phi=0,t=0):
    
    L=1
    omega=1
     
    x = np.linspace(0, +1., 50)
    
    mode1 = np.cos(omega*t) * np.sin(n1*np.pi * x/L)
    
    mode2 = np.cos(omega*t + phi) * np.sin(n2*np.pi * x/L)
    
    plt.plot(x, mode1+mode2, lw=5, color='orange')
    plt.ylim([-2.5, 2.5])
    plt.grid('on')
    plt.show()
interactive(wavef, n1=(1,5), n2=(1,5), phi=(0,2*np.pi), t=(0,100,0.1) )

Normal modes of a 2D membrane#

Below we show two visualizations of 2D membrane normal modes, which allow you to visualize spatial profiles and temporal evolution using interactive sliders.

  • First visualization is using matplotlib which is a static plotting library.

  • Second visualization is using a Plotly a dynamic plotting loibrary allowing you to rotate and interact with plots

def membrane2d_mode(n=1, m=1, t=0):
    '''The function returns 2D grid of points (X, Y) and the value of membrane normal mode at a time t: Z(X, Y, t)
    '''
    
    # Constants
    Lx, Ly = 1.0, 1.0  # Dimensions of the rectangular region
    v      = 0.1 # wave speed 
    omega  = v * np.pi/Lx *  (n**2+m**2)     # Angular rate
    
    # Create a spatial grid
    Nx, Ny = 100, 100
    x, y  = np.linspace(0, Lx, Nx), np.linspace(0, Ly, Ny)
    X, Y  = np.meshgrid(x, y)

    # Compute spatial part of the normal mode
    Z = np.sin(m * np.pi * X / Lx) * np.sin(n * np.pi * Y / Ly) * np.cos(omega*t)
    
    return X, Y, Z
X, Y, Z = membrane2d_mode(n=3, m=2, t=0)

plt.contourf(X, Y, Z)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x16a3ac970>
../_images/26b0335583ba31a056162401b85ef5a92f41656a54fea8c61a6210da9ca14daf.png

Visualization of 2D membrane vibrations using matplotlib#

def viz_membrane2d(n=1, m=1, t=0): 
    '''Normal modes of 2D membrane on a square geometry'''
    
    X, Y, Z = membrane2d_mode(n, m, t)
   
    ### Plot in 3D
    fig = plt.figure(figsize=(9, 4))
    ax1  = fig.add_subplot(1, 2, 1)
    ax1.contourf(X, Y, Z, 40, cmap='RdBu')
    
    ax2  = fig.add_subplot(1, 2, 2, projection='3d')
    ax2.plot_surface(X, Y, Z, cmap='RdBu')
    ax2.set_zlim(-1, 1)
    
    plt.show()
interactive(viz_membrane2d, n=(1,10), m=(1,10), t=(0,100))

Visualization of 2D membrane vibrations using plotly interactive plots#

def viz_membrane2d_plotly(n=1, m=1, t=0): 
    '''Normal modes of 2D membrane on a square geometry using Plotly plot'''
    
    X, Y, Z = membrane2d_mode(n, m, t)
    
    # Create a Plotly subplot with 1 row and 2 columns
    fig = make_subplots(
    rows=1, 
    cols=2, 
    subplot_titles=('2D Contour Plot', '3D Surface Plot'),
    specs=[[{"type": "contour"}, {"type": "surface"}]]
    )
    
    # Add 2D contour plot to the left side
    fig.add_trace(
        go.Contour(x=X.flatten(), y=Y.flatten(), z=Z.flatten(), colorscale='RdBu'),
        row=1, col=1
        )

    # Add 3D surface plot to the right side
    fig.add_trace(
        go.Surface(x=X, y=Y, z=Z,  colorscale='RdBu'),
        row=1, col=2
        )

    # Update layout for better visualization and adjust figure size
    fig.update_layout(
    title_text="2D Contour and 3D Surface plots of 2D Membrane vibrational normal modes",
    width=1000,
    height=500
    )
    
    fig.show()
interact(viz_membrane2d_plotly, n=(1,10), m=(1,10), t=(0,100))
<function __main__.viz_membrane2d_plotly(n=1, m=1, t=0)>