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.

Updated on: 2026-03-25T22:35:55+05:30

543 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements