{"spec_id":"line-yield-curve","library":"makie","language":"julia","code":"# anyplot.ai\n# line-yield-curve: Yield Curve (Interest Rate Term Structure)\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 91/100 | Created: 2026-06-10\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# Theme tokens\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\",\n    colorant\"#C475FD\",\n    colorant\"#4467A3\",\n    colorant\"#BD8233\",\n    colorant\"#AE3030\",\n    colorant\"#2ABCCD\",\n    colorant\"#954477\",\n    colorant\"#99B314\",\n]\nconst ANYPLOT_AMBER = colorant\"#DDCC77\"\n\n# Data: U.S. Treasury yield curves on three dates\nmaturity_years  = [0.083, 0.25, 0.5, 1.0, 2.0, 3.0, 5.0, 7.0, 10.0, 20.0, 30.0]\nmaturity_labels = [\"1M\", \"3M\", \"6M\", \"1Y\", \"2Y\", \"3Y\", \"5Y\", \"7Y\", \"10Y\", \"20Y\", \"30Y\"]\n\nyields_jan2021 = [0.09, 0.08, 0.09, 0.10, 0.13, 0.21, 0.45, 0.74, 1.07, 1.62, 1.84]\nyields_oct2022 = [3.30, 3.82, 4.20, 4.48, 4.47, 4.35, 4.20, 4.05, 4.00, 4.15, 4.05]\nyields_jul2023 = [5.34, 5.49, 5.49, 5.45, 4.87, 4.55, 4.36, 4.22, 3.97, 4.18, 3.95]\n\n# Inversion band: from 2Y onward, shade between 2Y reference yield and actual curve\ninv_start = 5\ninv_x     = maturity_years[inv_start:end]\ninv_upper = fill(yields_jul2023[inv_start], length(inv_x))\ninv_lower = yields_jul2023[inv_start:end]\n\n# Title\ntitle_str  = \"U.S. Treasury Yields · line-yield-curve · julia · makie · anyplot.ai\"\ntitle_n    = length(title_str)\ntitle_size = max(14, round(Int, 20 * 67 / title_n))\n\n# Plot\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = title_str,\n    titlesize          = title_size,\n    titlecolor         = INK,\n    xlabel             = \"Maturity\",\n    ylabel             = \"Yield (%)\",\n    xlabelsize         = 14,\n    ylabelsize         = 14,\n    xlabelcolor        = INK,\n    ylabelcolor        = INK,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    xticklabelsize     = 12,\n    yticklabelsize     = 12,\n    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    backgroundcolor    = PAGE_BG,\n    topspinevisible    = false,\n    rightspinevisible  = false,\n    leftspinecolor     = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    xgridvisible       = false,\n    ygridcolor         = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    xscale             = log10,\n    xticks             = (maturity_years, maturity_labels),\n)\n\n# Inversion shading (amber warning zone where short-term yields exceed long-term)\nband!(ax, inv_x, inv_lower, inv_upper; color = (ANYPLOT_AMBER, 0.30))\n\n# Inversion zone label (inside the amber band, between inv_lower and inv_upper at 7Y)\ntext!(ax, [7.0], [4.55];\n    text      = [\"Inverted zone\"],\n    color     = ANYPLOT_AMBER,\n    fontsize  = 11,\n    align     = (:center, :center))\n\n# Jan 2021 near-zero annotation in the empty band between the two clusters\ntext!(ax, [2.5], [2.2];\n    text      = [\"COVID-era near-zero rates\"],\n    color     = INK_SOFT,\n    fontsize  = 10,\n    align     = (:left, :center))\n\n# Yield curves\nscatterlines!(ax, maturity_years, yields_jan2021;\n    color       = IMPRINT_PALETTE[1],\n    linewidth   = 2.5,\n    markersize  = 10,\n    strokewidth = 0,\n    label       = \"Jan 2021 (normal)\")\n\nscatterlines!(ax, maturity_years, yields_oct2022;\n    color       = IMPRINT_PALETTE[2],\n    linewidth   = 2.5,\n    markersize  = 10,\n    strokewidth = 0,\n    label       = \"Oct 2022 (flat)\")\n\nscatterlines!(ax, maturity_years, yields_jul2023;\n    color       = IMPRINT_PALETTE[3],\n    linewidth   = 2.5,\n    markersize  = 10,\n    strokewidth = 0,\n    label       = \"Jul 2023 (inverted)\")\n\naxislegend(ax;\n    position        = :rt,\n    backgroundcolor = ELEVATED_BG,\n    labelcolor      = INK_SOFT,\n    framecolor      = INK_SOFT,\n    framewidth      = 0.5,\n    patchsize       = (20f0, 10f0))\n\nylims!(ax, -0.3, 6.4)\n\n# Save\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}