Clinical Audiogram — Makie.jl

A standardized clinical audiogram that displays hearing test results, plotting hearing threshold (dB HL) against test frequency for each ear. The y-axis is inverted so that 0 dB HL (best hearing) sits at the top and increasing hearing loss extends downward, while the x-axis is logarithmic spanning the standard audiometric frequencies (125 Hz to 8 kHz). Thresholds are marked with the conventional symbols — a circle (O) for the right ear in red and a cross (X) for the left ear in blue — and connected per ear, with shaded horizontal bands indicating severity of hearing loss (normal, mild, moderate, severe, profound).

Clinical Audiogram rendered with Makie.jl

Julia source (Makie.jl)

# anyplot.ai
# audiogram-clinical: Clinical Audiogram
# Library: makie 0.22.10 | Julia 1.11.9
# Quality: 89/100 | Created: 2026-06-15

using CairoMakie
using Colors
using Random

Random.seed!(42)

# Theme tokens
const THEME       = get(ENV, "ANYPLOT_THEME", "light")
const PAGE_BG     = THEME == "light" ? colorant"#FAF8F1" : colorant"#1A1A17"
const ELEVATED_BG = THEME == "light" ? colorant"#FFFDF6" : colorant"#242420"
const INK         = THEME == "light" ? colorant"#1A1A17" : colorant"#F0EFE8"
const INK_SOFT    = THEME == "light" ? colorant"#4A4A44" : colorant"#B8B7B0"
const INK_MUTED   = THEME == "light" ? colorant"#6B6A63" : colorant"#A8A79F"

# Audiogram follows standard audiological color conventions (semantic exception):
# right ear → red (Imprint position 5), left ear → blue (Imprint position 3)
const RIGHT_EAR_COLOR = colorant"#AE3030"
const LEFT_EAR_COLOR  = colorant"#4467A3"

# Pure-tone audiometry data — noise-induced high-frequency sensorineural notch
const FREQUENCIES     = Float64[125, 250, 500, 1000, 2000, 4000, 8000]
const THRESHOLD_RIGHT = Float64[10,  10,  15,  20,   35,   65,   50]
const THRESHOLD_LEFT  = Float64[15,  15,  20,  25,   40,   70,   55]

# Severity band fill alpha — dark mode reduced to prevent over-saturation
band_alpha = THEME == "light" ? 0.12f0 : 0.14f0

# Severity bands: (y_low, y_high, label, fill_color)
# Colors derived from exact Imprint palette members:
#   IP1 #009E73 (pos 1 — green), IP4 #BD8233 (pos 4 — ochre), IP5 #AE3030 (pos 5 — red)
bands = [
    (-10.0,  25.0, "Normal",      RGBAf(0.000f0, 0.620f0, 0.451f0, band_alpha)),
    ( 25.0,  40.0, "Mild",        RGBAf(0.741f0, 0.510f0, 0.200f0, band_alpha)),
    ( 40.0,  55.0, "Moderate",    RGBAf(0.741f0, 0.510f0, 0.200f0, band_alpha * 1.4f0)),
    ( 55.0,  70.0, "Mod. Severe", RGBAf(0.682f0, 0.188f0, 0.188f0, band_alpha)),
    ( 70.0,  90.0, "Severe",      RGBAf(0.682f0, 0.188f0, 0.188f0, band_alpha * 1.5f0)),
    ( 90.0, 120.0, "Profound",    RGBAf(0.682f0, 0.188f0, 0.188f0, band_alpha * 2.0f0)),
]

# Figure — square canvas (audiograms are conventionally square)
fig = Figure(
    resolution      = (1200, 1200),
    fontsize        = 14,
    backgroundcolor = PAGE_BG,
)

ax = Axis(
    fig[1, 1];
    title             = "audiogram-clinical · julia · makie · anyplot.ai",
    titlesize         = 20,
    titlecolor        = INK,
    xlabel            = "Frequency (Hz)",
    ylabel            = "Hearing Level (dB HL)",
    xlabelsize        = 14,
    ylabelsize        = 14,
    xlabelcolor       = INK,
    ylabelcolor       = INK,
    xticklabelsize    = 12,
    yticklabelsize    = 12,
    xticklabelcolor   = INK_SOFT,
    yticklabelcolor   = INK_SOFT,
    xtickcolor        = INK_SOFT,
    ytickcolor        = INK_SOFT,
    backgroundcolor   = PAGE_BG,
    topspinevisible   = false,
    rightspinevisible = false,
    leftspinecolor    = INK_SOFT,
    bottomspinecolor  = INK_SOFT,
    xscale            = log10,
    yreversed         = true,
    xticks            = ([125, 250, 500, 1000, 2000, 4000, 8000],
                         ["125", "250", "500", "1k", "2k", "4k", "8k"]),
    yticks            = collect(-10:10:120),
    limits            = (90, 10000, -10, 120),
    xgridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15f0),
    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15f0),
    xminorgridvisible = false,
    yminorgridvisible = false,
)

# Severity bands drawn below data; labels centered in each band at 1 kHz
for (y1, y2, label, band_color) in bands
    hspan!(ax, y1, y2; color = band_color)
    text!(ax, 1000.0, (y1 + y2) / 2;
          text     = label,
          color    = INK_MUTED,
          fontsize = 12,
          align    = (:center, :center))
end

# Focal-point emphasis on clinically significant 4 kHz sensorineural notch
text!(ax, 4700.0, 56.0;
      text     = "4 kHz notch",
      color    = INK_SOFT,
      fontsize = 10,
      align    = (:left, :center))

# Connecting lines (drawn first so markers sit on top)
lines!(ax, FREQUENCIES, THRESHOLD_RIGHT;
       color     = RIGHT_EAR_COLOR,
       linewidth = 2.5)
lines!(ax, FREQUENCIES, THRESHOLD_LEFT;
       color     = LEFT_EAR_COLOR,
       linewidth = 2.5,
       linestyle = :dash)

# Markers — right ear: filled circle (O), left ear: × cross (X)
scatter!(ax, FREQUENCIES, THRESHOLD_RIGHT;
         color       = RIGHT_EAR_COLOR,
         marker      = :circle,
         markersize  = 16,
         strokewidth = 1.5,
         strokecolor = PAGE_BG)
scatter!(ax, FREQUENCIES, THRESHOLD_LEFT;
         color      = LEFT_EAR_COLOR,
         marker     = :xcross,
         markersize = 18,
         strokewidth = 0)

# Inset legend
leg_entries = [
    [MarkerElement(marker = :circle, color = RIGHT_EAR_COLOR, markersize = 14,
                   strokewidth = 1.5, strokecolor = PAGE_BG),
     LineElement(color = RIGHT_EAR_COLOR, linewidth = 2.5)],
    [MarkerElement(marker = :xcross, color = LEFT_EAR_COLOR, markersize = 14),
     LineElement(color = LEFT_EAR_COLOR, linewidth = 2.5, linestyle = :dash)],
]
leg_labels = ["Right Ear (O)", "Left Ear (X)"]

Legend(fig[1, 1], leg_entries, leg_labels;
       tellwidth       = false,
       tellheight      = false,
       halign          = :right,
       valign          = :bottom,
       margin          = (20, 20, 20, 20),
       framevisible    = true,
       framecolor      = INK_SOFT,
       backgroundcolor = ELEVATED_BG,
       labelcolor      = INK,
       fontsize        = 12,
       patchsize       = (22, 12),
)

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

Part of Clinical Audiogram on anyplot.ai.

Other implementations