{"spec_id":"heatmap-correlation","library":"makie","language":"julia","code":"# anyplot.ai\n# heatmap-correlation: Correlation Matrix Heatmap\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 90/100 | Created: 2026-08-20\n\nusing CairoMakie\nusing Colors\nusing ColorSchemes\nusing Printf\nusing Random\nusing Statistics\n\nRandom.seed!(42)\n\n# --- Theme tokens -------------------------------------------------------\nTHEME    = get(ENV, \"ANYPLOT_THEME\", \"light\")\nPAGE_BG  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nINK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nINK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nDIV_MID  = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nIMPRINT_DIV = cgrad([colorant\"#AE3030\", DIV_MID, colorant\"#4467A3\"])\n\n# --- Data -----------------------------------------------------------------\n# Monthly returns for 8 asset classes driven by two latent macro factors\n# (equity beta, rate sensitivity) plus idiosyncratic noise, then reduced\n# to a Pearson correlation matrix — a portfolio-diversification scenario.\nasset_names = [\"US Equities\", \"Int'l Equities\", \"Corp Bonds\", \"Treasuries\",\n               \"Real Estate\", \"Commodities\", \"Gold\", \"Cash\"]\nn_assets = length(asset_names)\nn_periods = 300\n\nmarket_factor = randn(n_periods)\nrate_factor = randn(n_periods)\nmarket_loadings = [0.95, 0.85, 0.10, -0.15, 0.55, 0.35, -0.05, 0.0]\nrate_loadings = [-0.10, -0.05, 0.80, 0.90, 0.05, -0.10, 0.15, 0.0]\n\nreturns = zeros(n_periods, n_assets)\nfor i in 1:n_assets\n    returns[:, i] = market_loadings[i] .* market_factor .+\n                    rate_loadings[i] .* rate_factor .+\n                    0.4 .* randn(n_periods)\nend\n\ncorr_matrix = cor(returns)\n\n# --- Plot -------------------------------------------------------------------\nfig = Figure(\n    resolution      = (1200, 1200),\n    fontsize        = 16,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"heatmap-correlation · julia · makie · anyplot.ai\",\n    titlesize          = 26,\n    titlecolor         = INK,\n    xticks             = (1:n_assets, asset_names),\n    yticks             = (1:n_assets, asset_names),\n    xticklabelrotation = π / 4,\n    xticklabelsize     = 15,\n    yticklabelsize     = 15,\n    xticklabelcolor    = INK_SOFT,\n    yticklabelcolor    = INK_SOFT,\n    backgroundcolor    = PAGE_BG,\n    aspect             = 1,\n    yreversed          = true,\n    leftspinecolor     = INK_SOFT,\n    rightspinecolor    = INK_SOFT,\n    topspinecolor      = INK_SOFT,\n    bottomspinecolor   = INK_SOFT,\n    xgridvisible       = false,\n    ygridvisible       = false,\n)\n\n# Strongest off-diagonal pair gets a bolder annotation as a focal point.\noff_diag_pairs = [(i, j) for i in 1:n_assets, j in 1:n_assets if i > j]\nstrongest_i, strongest_j = off_diag_pairs[argmax(abs(corr_matrix[i, j]) for (i, j) in off_diag_pairs)]\n\n# Draw each filled cell as its own rectangle (rather than a single heatmap!)\n# so a thin PAGE_BG stroke can separate cells — Heatmap doesn't support\n# strokewidth/strokecolor in this Makie version, poly! does.\nfor i in 1:n_assets, j in 1:n_assets\n    if i >= j\n        value = corr_matrix[i, j]\n        cell_color = get(IMPRINT_DIV, (value + 1) / 2)\n        poly!(ax, Rect2f(i - 0.5, j - 0.5, 1, 1);\n              color = cell_color, strokewidth = 1, strokecolor = PAGE_BG)\n\n        luminance = 0.299 * cell_color.r + 0.587 * cell_color.g + 0.114 * cell_color.b\n        label_color = luminance > 0.5 ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\n        is_strongest = (i, j) == (strongest_i, strongest_j)\n        text!(ax, i, j; text = @sprintf(\"%.2f\", value),\n              align = (:center, :center),\n              fontsize = is_strongest ? 19 : 15,\n              font = is_strongest ? :bold : :regular,\n              color = label_color)\n    end\nend\n\nlimits!(ax, 0.5, n_assets + 0.5, 0.5, n_assets + 0.5)\n\nColorbar(\n    fig[1, 2];\n    colormap       = IMPRINT_DIV,\n    limits         = (-1, 1),\n    label          = \"Pearson correlation\",\n    labelcolor     = INK,\n    labelsize      = 16,\n    ticklabelcolor = INK_SOFT,\n    ticklabelsize  = 14,\n    ticks          = -1:0.5:1,\n)\n\ncolgap!(fig.layout, 20)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}