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