{"spec_id":"heatmap-stripes-climate","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nheatmap-stripes-climate: Climate Warming Stripes\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-06-02\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_rect,\n    element_text,\n    geom_tile,\n    ggplot,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_fill_gradient2,\n    theme,\n    theme_void,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\n\n# Data - synthetic global temperature anomalies (1850-2024) relative to 1961-1990 baseline\nnp.random.seed(42)\nyears = np.arange(1850, 2025)\nn_years = len(years)\n\nbaseline_trend = np.where(\n    years < 1910,\n    -0.3 + (years - 1850) * 0.002,\n    np.where(years < 1970, -0.15 + (years - 1910) * 0.002, -0.03 + (years - 1970) * 0.018),\n)\nnoise = np.random.normal(0, 0.08, n_years)\nanomalies = baseline_trend + noise\n\nbaseline_mask = (years >= 1961) & (years <= 1990)\nanomalies = anomalies - anomalies[baseline_mask].mean()\n\ndf = pd.DataFrame({\"year\": years, \"anomaly\": np.round(anomalies, 3), \"row\": \"temp\"})\n\nvmax = max(abs(df[\"anomaly\"].min()), abs(df[\"anomaly\"].max()))\n\n# Title fontsize — scale linearly from 16px baseline at 67 chars\ntitle = \"heatmap-stripes-climate · python · letsplot · anyplot.ai\"\nn = len(title)\nratio = 67 / n if n > 67 else 1.0\ntitle_fontsize = max(11, round(16 * ratio))\n\n# Plot - warming stripes: pure color, no axes, no legend\nplot = (\n    ggplot(df, aes(x=\"year\", y=\"row\", fill=\"anomaly\"))\n    + geom_tile(\n        width=1.0,\n        height=10.0,\n        tooltips=layer_tooltips().line(\"Year: @year\").line(\"Anomaly: @anomaly °C\").format(\"@anomaly\", \".3f\"),\n    )\n    + scale_fill_gradient2(low=\"#4467A3\", mid=PAGE_BG, high=\"#AE3030\", midpoint=0, limits=[-vmax, vmax], name=\"\")\n    + labs(title=title)\n    + theme_void()\n    + theme(\n        plot_title=element_text(size=title_fontsize, color=INK),\n        legend_position=\"none\",\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        plot_margin=[30, 10, 10, 10],\n    )\n    + ggsize(800, 450)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}