{"spec_id":"line-cycle-seasonal","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nline-cycle-seasonal: Cycle Plot (Seasonal Subseries)\nLibrary: matplotlib 3.11.0 | Python 3.13.13\nQuality: 87/100 | Created: 2026-06-15\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.lines import Line2D\n\n\n# Theme tokens\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — position 1 is always the first series\nBRAND = \"#009E73\"\n\n# Data: average monthly temperature (°C) in a mid-latitude city, 2000–2024\nnp.random.seed(42)\nn_years = 25\nmonth_names = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\n# Seasonal baseline (Northern Hemisphere mid-latitude, °C)\nbase_temp = np.array([-2.0, 0.0, 5.5, 11.5, 17.0, 21.5, 24.0, 23.0, 17.5, 11.0, 4.5, -0.5])\n# Warming rate per year per month (°C / year)\nwarming = np.array([0.05, 0.05, 0.04, 0.03, 0.03, 0.02, 0.02, 0.03, 0.03, 0.04, 0.05, 0.05])\n\ntemps = np.zeros((n_years, 12))\nfor y in range(n_years):\n    temps[y] = base_temp + warming * y + np.random.normal(0, 0.7, 12)\n\n# X layout: 12 month groups, each spanning group_span x-units, separated by gap_span\ngroup_span = n_years - 1  # 24 units (25 points spaced 1 apart)\ngap_span = 5\n\nx_group_starts = np.arange(12) * (group_span + gap_span)\ntick_positions = x_group_starts + group_span / 2\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nfor m in range(12):\n    x_vals = x_group_starts[m] + np.arange(n_years)\n    y_vals = temps[:, m]\n    mean_y = y_vals.mean()\n\n    # Thin subseries line with year markers (Imprint brand green)\n    ax.plot(x_vals, y_vals, color=BRAND, linewidth=1.2, alpha=0.75, zorder=2)\n    ax.scatter(x_vals, y_vals, color=BRAND, s=16, alpha=0.75, zorder=3, linewidths=0)\n\n    # Horizontal mean reference line spanning the full group width\n    ax.hlines(mean_y, x_group_starts[m], x_group_starts[m] + group_span, colors=INK, linewidth=2.0, zorder=4)\n\n# Subtle vertical separators between month groups\nfor m in range(1, 12):\n    sep_x = x_group_starts[m] - gap_span / 2\n    ax.axvline(sep_x, color=INK_MUTED, linewidth=0.5, alpha=0.3)\n\n# Warming trend annotation — Jan has the strongest signal (0.05°C/yr × 24 yr = +1.2°C)\njan_warming = warming[0] * (n_years - 1)\nax.text(\n    0.97,\n    0.88,\n    f\"+{jan_warming:.1f}°C Jan trend\\n2000 → 2024\",\n    fontsize=7,\n    color=INK_SOFT,\n    ha=\"right\",\n    va=\"top\",\n    style=\"italic\",\n    transform=ax.transAxes,\n    bbox={\"facecolor\": ELEVATED_BG, \"edgecolor\": INK_MUTED, \"alpha\": 0.85, \"pad\": 3, \"boxstyle\": \"round,pad=0.3\"},\n)\n\n# Axes\nax.set_xticks(tick_positions)\nax.set_xticklabels(month_names, fontsize=8, color=INK_SOFT)\nax.tick_params(axis=\"x\", length=0)\nax.tick_params(axis=\"y\", labelsize=8, colors=INK_SOFT)\nax.set_ylabel(\"Avg. Temperature (°C)\", fontsize=10, color=INK)\n\n# Grid (y-axis only, very subtle)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK, zorder=0)\n\n# Spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\n# X limits — slight padding beyond outermost groups\nax.set_xlim(x_group_starts[0] - 3, x_group_starts[-1] + group_span + 3)\n\n# Title (54 chars < 67 baseline → default fontsize=12)\ntitle = \"line-cycle-seasonal · python · matplotlib · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK)\n\n# Legend\nhandles = [\n    Line2D([0], [0], color=BRAND, linewidth=1.5, label=\"Yearly observations (2000–2024)\"),\n    Line2D([0], [0], color=INK, linewidth=2.0, label=\"Monthly mean\"),\n]\nleg = ax.legend(handles=handles, fontsize=8, loc=\"upper left\", framealpha=0.9)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Layout — fixed subplots_adjust instead of bbox_inches='tight' (avoids canvas drift)\nfig.subplots_adjust(left=0.08, right=0.98, top=0.91, bottom=0.10)\n\n# Save\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}