Frequency Spectrum Plot — Makie.jl

A frequency spectrum plot displays signal amplitude or power across a range of frequencies, showing the frequency domain representation of time-series data. This visualization reveals the frequency components present in a signal, making it essential for identifying dominant frequencies, harmonics, and noise characteristics. It is fundamental in signal processing, audio engineering, and vibration analysis.

Frequency Spectrum Plot rendered with Makie.jl

Renders

Julia source (Makie.jl)

# anyplot.ai
# spectrum-basic: Frequency Spectrum Plot
# Library: makie 0.21.9 | Julia 1.11.9
# Quality: 86/100 | Created: 2026-09-09

using CairoMakie
using Colors
using Random

Random.seed!(42)

# --- Theme tokens -----------------------------------------------------------
THEME    = get(ENV, "ANYPLOT_THEME", "light")
PAGE_BG  = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
INK      = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
INK_SOFT = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"
IMPRINT_PALETTE = [
    colorant"#009E73", colorant"#C475FD", colorant"#4467A3", colorant"#BD8233",
    colorant"#AE3030", colorant"#2ABCCD", colorant"#954477", colorant"#99B314",
]

# --- Data --------------------------------------------------------------------
# Synthetic vibration signal from a rotating machine: shaft rotation (42 Hz),
# a gear-mesh harmonic (126 Hz), a bearing-fault tone (310 Hz), plus noise.
sample_rate = 2048.0
n_samples = 2048
t = (0:(n_samples - 1)) ./ sample_rate

shaft_hz = 42.0
gearmesh_hz = 126.0
bearing_hz = 310.0

signal = 1.0 .* sin.(2π * shaft_hz .* t) .+
         0.5 .* sin.(2π * gearmesh_hz .* t) .+
         0.25 .* sin.(2π * bearing_hz .* t) .+
         0.05 .* randn(n_samples)

# Discrete Fourier transform (positive-frequency half), vectorized as a
# matrix-vector product since FFTW is not available in this runtime.
bin_index = collect(0:(n_samples ÷ 2))
sample_index = collect(0:(n_samples - 1))
angle_matrix = (-2π / n_samples) .* (bin_index * sample_index')
spectrum = sqrt.((cos.(angle_matrix) * signal) .^ 2 .+ (sin.(angle_matrix) * signal) .^ 2) ./ n_samples

frequency = bin_index .* (sample_rate / n_samples)
amplitude_db = 20 .* log10.(spectrum .+ 1e-6)

# Keep only the audible/mechanical band of interest (skip the DC bin for log scale)
mask = frequency .>= 1.0
frequency = frequency[mask]
amplitude_db = amplitude_db[mask]

# Locate the actual peak bin nearest each named harmonic, so the annotation
# sits exactly on the rendered curve rather than the theoretical frequency.
function nearest_peak_index(target_hz, window_hz = 8.0)
    candidates = findall(f -> abs(f - target_hz) <= window_hz, frequency)
    candidates[argmax(amplitude_db[candidates])]
end

peak_names = ["shaft", "gear mesh", "bearing fault"]
peak_targets = [shaft_hz, gearmesh_hz, bearing_hz]
peak_indices = [nearest_peak_index(f) for f in peak_targets]
peak_freqs = frequency[peak_indices]
peak_amps = amplitude_db[peak_indices]
peak_labels = ["$(round(Int, f)) Hz · $name" for (f, name) in zip(peak_freqs, peak_names)]

# --- Plot ---------------------------------------------------------------------
title_str = "spectrum-basic · julia · makie · anyplot.ai"

fig = Figure(
    resolution = (1600, 900),
    fontsize = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title = title_str,
    titlesize = 20,
    titlecolor = INK,
    xlabel = "Frequency (Hz)",
    ylabel = "Amplitude (dB)",
    xlabelsize = 14,
    ylabelsize = 14,
    xlabelcolor = INK,
    ylabelcolor = INK,
    xticklabelsize = 12,
    yticklabelsize = 12,
    xticklabelcolor = INK_SOFT,
    yticklabelcolor = INK_SOFT,
    xtickcolor = INK_SOFT,
    ytickcolor = INK_SOFT,
    xscale = log10,
    backgroundcolor = PAGE_BG,
    topspinevisible = false,
    rightspinevisible = false,
    leftspinecolor = INK_SOFT,
    bottomspinecolor = INK_SOFT,
    ygridcolor = RGBAf(INK.r, INK.g, INK.b, 0.15),
    xgridvisible = false,
    yminorgridvisible = false,
)

lines!(ax, frequency, amplitude_db; color = IMPRINT_PALETTE[1], linewidth = 2.5)

# Highlight the three dominant harmonics with markers + labels, giving the
# viewer a guided read of the shaft/gear-mesh/bearing-fault components.
scatter!(
    ax, peak_freqs, peak_amps;
    color = IMPRINT_PALETTE[1], markersize = 14,
    strokewidth = 2, strokecolor = PAGE_BG,
)
text!(
    ax, peak_freqs, peak_amps;
    text = peak_labels, color = INK, fontsize = 13,
    align = (:center, :bottom), offset = (0, 10),
)

# --- Save -----------------------------------------------------------------
save("plot-$(THEME).png", fig; px_per_unit = 2)

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/spectrum-basic/makie/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "spectrum-basic",
  "language": "julia",
  "library": "makie",
  "page": "https://anyplot.ai/spectrum-basic/julia/makie",
  "hub": "https://anyplot.ai/spectrum-basic",
  "code_json": "https://api.anyplot.ai/specs/spectrum-basic/makie/code",
  "spec_json": "https://api.anyplot.ai/specs/spectrum-basic",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/spectrum-basic/julia/makie/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/spectrum-basic/julia/makie/plot-dark.png",
  "quality_score": 86.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Frequency Spectrum Plot on anyplot.ai.

Other implementations