A spectrogram displaying time-frequency representation of a signal as a heatmap. It shows how the frequency content of a signal changes over time, with color intensity representing the amplitude or power at each time-frequency point. Essential for analyzing non-stationary signals where frequency characteristics vary, revealing patterns invisible in time-domain or frequency-domain views alone.

""" anyplot.ai
spectrogram-basic: Spectrogram Time-Frequency Heatmap
Library: seaborn 0.13.2 | Python 3.13.13
Quality: 86/100 | Updated: 2026-05-15
"""
import os
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from scipy import signal
# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
# Data - chirp signal with increasing frequency
np.random.seed(42)
sample_rate = 4000 # Hz
duration = 2.0 # seconds
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
# Create a chirp signal: frequency increases from 100 Hz to 800 Hz
f0, f1 = 100, 800
chirp_signal = signal.chirp(t, f0=f0, f1=f1, t1=duration, method="linear")
# Add some noise for realism
chirp_signal += np.random.randn(len(chirp_signal)) * 0.1
# Compute spectrogram using scipy
nperseg = 256 # Window size
noverlap = 200 # Overlap for smoother visualization
frequencies, times, Sxx = signal.spectrogram(chirp_signal, fs=sample_rate, nperseg=nperseg, noverlap=noverlap)
# Convert to dB scale for better visualization
Sxx_dB = 10 * np.log10(Sxx + 1e-10)
# Create plot
fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)
ax.set_facecolor(PAGE_BG)
# Flip data vertically so low frequencies are at bottom (standard convention)
Sxx_dB_flipped = np.flipud(Sxx_dB)
# Use seaborn heatmap for the spectrogram visualization
sns.heatmap(
Sxx_dB_flipped,
ax=ax,
cmap="viridis",
cbar=True,
cbar_kws={"label": "Power (dB)", "shrink": 0.8},
xticklabels=False,
yticklabels=False,
rasterized=True,
)
# Set proper axis labels and ticks
# Calculate tick positions for time axis
time_tick_positions = np.linspace(0, Sxx_dB.shape[1], 5)
time_tick_labels = [f"{t:.1f}" for t in np.linspace(0, duration, 5)]
ax.set_xticks(time_tick_positions)
ax.set_xticklabels(time_tick_labels, fontsize=16, color=INK_SOFT)
# Calculate tick positions for frequency axis (low to high, bottom to top)
freq_tick_positions = np.linspace(0, Sxx_dB.shape[0], 5)
freq_tick_labels = [f"{int(f)}" for f in np.linspace(frequencies[0], frequencies[-1], 5)]
ax.set_yticks(freq_tick_positions)
ax.set_yticklabels(freq_tick_labels[::-1], fontsize=16, color=INK_SOFT)
# Labels and styling
ax.set_xlabel("Time (s)", fontsize=20, color=INK)
ax.set_ylabel("Frequency (Hz)", fontsize=20, color=INK)
ax.set_title("spectrogram-basic · seaborn · anyplot.ai", fontsize=24, color=INK, pad=20)
# Style the colorbar
cbar = ax.collections[0].colorbar
cbar.ax.tick_params(labelsize=14, colors=INK_SOFT)
cbar.ax.yaxis.label.set_size(18)
cbar.ax.yaxis.label.set_color(INK)
# Set spine colors
for spine in ax.spines.values():
spine.set_color(INK_SOFT)
plt.tight_layout()
plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)
Part of Spectrogram Time-Frequency Heatmap on anyplot.ai.