{"spec_id":"spectrum-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nspectrum-basic: Frequency Spectrum Plot\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"  # First series - machinery signal\nACCENT = \"#C475FD\"  # Peak markers\n\n# Data - Create a synthetic signal with multiple frequency components\nnp.random.seed(42)\n\n# Sampling parameters\nsample_rate = 1000  # Hz\nduration = 1.0  # seconds\nn_samples = int(sample_rate * duration)\nt = np.linspace(0, duration, n_samples, endpoint=False)\n\n# Create signal with multiple frequency components (simulating machinery vibration)\n# Fundamental frequency at 50 Hz, harmonics at 100 Hz and 150 Hz, plus some noise\nsignal = (\n    2.0 * np.sin(2 * np.pi * 50 * t)  # 50 Hz fundamental\n    + 1.2 * np.sin(2 * np.pi * 100 * t)  # 100 Hz harmonic\n    + 0.8 * np.sin(2 * np.pi * 150 * t)  # 150 Hz harmonic\n    + 0.3 * np.sin(2 * np.pi * 220 * t)  # 220 Hz component\n    + 0.4 * np.random.randn(n_samples)  # noise\n)\n\n# Compute FFT\nfft_result = np.fft.fft(signal)\nfrequencies = np.fft.fftfreq(n_samples, 1 / sample_rate)\n\n# Take only positive frequencies\npositive_mask = frequencies >= 0\nfrequencies = frequencies[positive_mask]\namplitude = np.abs(fft_result[positive_mask]) * 2 / n_samples  # Normalize amplitude\n\n# Convert to dB scale for better visualization\namplitude_db = 20 * np.log10(amplitude + 1e-10)  # Add small value to avoid log(0)\n\n# Plot\nsns.set_context(\"talk\", font_scale=1.2)\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n    },\n)\n\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Use seaborn lineplot for the spectrum with Okabe-Ito brand color\nsns.lineplot(x=frequencies, y=amplitude_db, ax=ax, color=BRAND, linewidth=2.5)\n\n# Fill under the curve for better visualization\nax.fill_between(frequencies, amplitude_db, alpha=0.3, color=BRAND)\n\n# Mark peak frequencies with Okabe-Ito accent color\npeak_indices = np.where((amplitude_db > -20) & (frequencies > 10))[0]\nfor idx in peak_indices:\n    if amplitude_db[idx] > amplitude_db[max(0, idx - 5) : min(len(amplitude_db), idx + 6)].mean() + 5:\n        ax.axvline(x=frequencies[idx], color=ACCENT, alpha=0.5, linestyle=\"--\", linewidth=1.5)\n\n# Styling\nax.set_xlabel(\"Frequency (Hz)\", fontsize=20, color=INK)\nax.set_ylabel(\"Amplitude (dB)\", fontsize=20, color=INK)\nax.set_title(\"spectrum-basic · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\nax.set_xlim(0, 300)  # Focus on the frequency range of interest\nax.set_ylim(-60, 10)\n\n# Subtle grid on y-axis only\nax.yaxis.grid(True, alpha=0.10, linewidth=0.8, color=INK)\nax.xaxis.grid(False)\n\n# Spine styling\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}