{"spec_id":"line-yield-curve","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nline-yield-curve: Yield Curve (Interest Rate Term Structure)\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-06-10\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent local files (matplotlib.py, etc.) from shadowing installed packages\n_script_dir = os.path.dirname(os.path.abspath(__file__))\nif _script_dir in sys.path:\n    sys.path.remove(_script_dir)\nif \"\" in sys.path:\n    sys.path.remove(\"\")\nif \".\" in sys.path:\n    sys.path.remove(\".\")\n\nimport matplotlib.pyplot as plt\nimport matplotlib.ticker as mticker\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens — Imprint palette (see prompts/default-style-guide.md)\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# Imprint categorical palette — hybrid-v3 sort, first series always #009E73\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\nSEMANTIC_RED = \"#AE3030\"  # Imprint anchor — bad / loss / error\n\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.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data — U.S. Treasury yield curves on three dates\nmaturities = [\"1M\", \"3M\", \"6M\", \"1Y\", \"2Y\", \"3Y\", \"5Y\", \"7Y\", \"10Y\", \"20Y\", \"30Y\"]\nmaturity_years = [1 / 12, 0.25, 0.5, 1, 2, 3, 5, 7, 10, 20, 30]\n\ncurves = {\n    \"2021-07-15 (Normal)\": [0.05, 0.05, 0.06, 0.09, 0.25, 0.46, 0.83, 1.13, 1.34, 1.86, 1.99],\n    \"2023-07-15 (Inverted)\": [5.28, 5.40, 5.47, 5.40, 4.87, 4.55, 4.18, 4.07, 3.98, 4.22, 4.05],\n    \"2024-09-15 (Flat)\": [4.96, 4.92, 4.72, 4.25, 3.60, 3.48, 3.44, 3.52, 3.65, 4.03, 4.01],\n}\n\nrows = []\nfor date_label, yields in curves.items():\n    for m_label, m_years, y_pct in zip(maturities, maturity_years, yields, strict=True):\n        rows.append({\"Date\": date_label, \"maturity\": m_label, \"maturity_years\": m_years, \"yield_pct\": y_pct})\ndf = pd.DataFrame(rows)\n\n# Canvas — 3200×1800 px landscape (figsize=(8, 4.5) × dpi=400)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Plot\nsns.lineplot(\n    data=df,\n    x=\"maturity_years\",\n    y=\"yield_pct\",\n    hue=\"Date\",\n    style=\"Date\",\n    markers=True,\n    dashes=False,\n    palette=IMPRINT_PALETTE[:3],\n    linewidth=2.5,\n    markersize=8,\n    ax=ax,\n)\n\n# Shade 2Y–10Y inversion zone (Imprint semantic-red: loss / danger)\ninv_yields = np.array(curves[\"2023-07-15 (Inverted)\"])\nidx_2y = maturity_years.index(2)\nidx_10y = maturity_years.index(10)\nyield_2y = inv_yields[idx_2y]\nyield_10y = inv_yields[idx_10y]\nif yield_2y > yield_10y:\n    ax.fill_between([2, 10], yield_10y, yield_2y, alpha=0.10, color=SEMANTIC_RED, zorder=0)\n    ax.text(6, (yield_2y + yield_10y) / 2, \"2Y–10Y Inversion\", fontsize=9, color=SEMANTIC_RED, ha=\"center\", va=\"center\")\n\n# Style\ntitle = \"U.S. Treasury Yield Curves · line-yield-curve · python · seaborn · anyplot.ai\"\nn = len(title)\ntitle_fontsize = max(8, round(12 * 67 / n)) if n > 67 else 12\nax.set_title(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK)\nax.set_xlabel(\"Maturity\", fontsize=10, color=INK)\nax.set_ylabel(\"Yield (%)\", fontsize=10, color=INK)\n\nax.set_xscale(\"log\")\nax.set_xticks(maturity_years)\nax.set_xticklabels(maturities, fontsize=8)\nax.xaxis.set_minor_locator(mticker.NullLocator())\nax.xaxis.set_minor_formatter(mticker.NullFormatter())\nax.tick_params(axis=\"y\", labelsize=8)\n\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8)\n\n# Seaborn-idiomatic refinements\nsns.despine(ax=ax)\nhandles, labels = ax.get_legend_handles_labels()\nax.legend(handles, labels, loc=\"center left\", title=\"Date\", fontsize=8, title_fontsize=9, frameon=False)\n\n# Save — no bbox_inches='tight' (avoids canvas trimming from 3200×1800)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}