Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Selected Reading
How do I plot a spectrogram the same way that pylab's specgram() does? (Matplotlib)
A spectrogram is a visual representation of the spectrum of frequencies of a signal as it varies with time. Matplotlib's specgram() function provides an easy way to create spectrograms similar to pylab's implementation.
Creating Sample Data
First, let's create a composite signal with different frequency components ?
import matplotlib.pyplot as plt
import numpy as np
# Set figure parameters
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
# Create time series data
dt = 0.0005
t = np.arange(0.0, 20.0, dt)
# Signal components
s1 = np.sin(2 * np.pi * 100 * t) # 100 Hz sine wave
s2 = 2 * np.sin(2 * np.pi * 400 * t) # 400 Hz sine wave
s2[t <= 10] = s2[12 <= t] = 0 # Only present between 10-12 seconds
nse = 0.01 * np.random.random(size=len(t)) # Add noise
# Composite signal
x = s1 + s2 + nse
print(f"Signal length: {len(x)} samples")
print(f"Sampling frequency: {int(1.0/dt)} Hz")
Signal length: 40000 samples Sampling frequency: 2000 Hz
Plotting Time Series and Spectrogram
Now let's create subplots to show both the time domain signal and its spectrogram ?
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["figure.figsize"] = [7.50, 3.50]
plt.rcParams["figure.autolayout"] = True
# Create sample data
dt = 0.0005
t = np.arange(0.0, 20.0, dt)
s1 = np.sin(2 * np.pi * 100 * t)
s2 = 2 * np.sin(2 * np.pi * 400 * t)
s2[t <= 10] = s2[12 <= t] = 0
nse = 0.01 * np.random.random(size=len(t))
x = s1 + s2 + nse
# Spectrogram parameters
NFFT = 1024 # Number of data points used in each block for FFT
Fs = int(1.0 / dt) # Sampling frequency
# Create subplots
fig, (ax1, ax2) = plt.subplots(nrows=2)
# Plot time series
ax1.plot(t, x)
ax1.set_title('Time Domain Signal')
ax1.set_ylabel('Amplitude')
ax1.grid(axis="x", ls="dotted", lw=2, color="red")
ax1.margins(x=0)
# Plot spectrogram
Pxx, freqs, bins, im = ax2.specgram(x, NFFT=NFFT, Fs=Fs, noverlap=900)
ax2.set_title('Spectrogram')
ax2.set_xlabel('Time (s)')
ax2.set_ylabel('Frequency (Hz)')
ax2.grid(axis="x", ls="dotted", lw=2, color="red")
plt.tight_layout()
plt.show()
[Displays a two-panel plot with time series on top and spectrogram below showing frequency content over time]
Key Parameters
| Parameter | Description | Effect |
|---|---|---|
NFFT |
FFT window size | Higher values = better frequency resolution |
Fs |
Sampling frequency | Determines frequency axis scaling |
noverlap |
Overlap between windows | Higher values = smoother time resolution |
Understanding the Output
The specgram() function returns four values ?
import matplotlib.pyplot as plt
import numpy as np
# Sample signal
t = np.linspace(0, 1, 1000)
signal = np.sin(2 * np.pi * 50 * t) + 0.5 * np.sin(2 * np.pi * 120 * t)
fig, ax = plt.subplots()
Pxx, freqs, bins, im = ax.specgram(signal, NFFT=256, Fs=1000)
print(f"Power spectral density shape: {Pxx.shape}")
print(f"Frequency bins: {len(freqs)} from {freqs[0]:.1f} to {freqs[-1]:.1f} Hz")
print(f"Time bins: {len(bins)} from {bins[0]:.3f} to {bins[-1]:.3f} s")
plt.xlabel('Time (s)')
plt.ylabel('Frequency (Hz)')
plt.title('Spectrogram with Return Values')
plt.colorbar(im, label='Power/Frequency (dB/Hz)')
plt.show()
Power spectral density shape: (129, 8) Frequency bins: 129 from 0.0 to 500.0 Hz Time bins: 8 from 0.128 to 0.896 s
Conclusion
Use matplotlib.pyplot.specgram() to create spectrograms identical to pylab's implementation. Adjust NFFT and noverlap parameters to control frequency and time resolution trade-offs.
Advertisements
