{"spec_id":"histogram-epidemic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nhistogram-epidemic: Epidemic Curve (Epi Curve)\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-06-02\n\"\"\"\n\nimport os\n\nimport matplotlib.dates as mdates\nimport matplotlib.patheffects as pe\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\n\n\n# Theme tokens — Imprint palette chrome\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 categorical palette — positions 1→3 for the three case classifications\nCONFIRMED_COLOR = \"#009E73\"  # brand green — always first series\nPROBABLE_COLOR = \"#4467A3\"  # blue\nSUSPECT_COLOR = \"#BD8233\"  # ochre\nCUMULATIVE_COLOR = \"#AE3030\"  # matte red — total burden / severity semantic anchor\n\n# Data — two-wave outbreak scenario, 90-day regional epidemic\nnp.random.seed(42)\ndates = pd.date_range(\"2024-01-15\", periods=90, freq=\"D\")\n\nconfirmed_base = np.concatenate(\n    [\n        np.random.poisson(3, 10),\n        np.random.poisson(12, 10),\n        np.random.poisson(35, 10),\n        np.random.poisson(55, 10),\n        np.random.poisson(15, 10),\n        np.random.poisson(8, 10),\n        np.random.poisson(30, 10),\n        np.random.poisson(50, 10),\n        np.random.poisson(18, 10),\n    ]\n)\nprobable = np.maximum(0, (confirmed_base * np.random.uniform(0.1, 0.3, 90)).astype(int))\nsuspect = np.maximum(0, (confirmed_base * np.random.uniform(0.05, 0.15, 90)).astype(int))\nconfirmed = np.maximum(0, confirmed_base - probable - suspect)\n\ndf = pd.DataFrame({\"date\": dates, \"Confirmed\": confirmed, \"Probable\": probable, \"Suspect\": suspect})\ncumulative = (df[\"Confirmed\"] + df[\"Probable\"] + df[\"Suspect\"]).cumsum()\ntotal_per_day = df[\"Confirmed\"] + df[\"Probable\"] + df[\"Suspect\"]\n\n# Plot — landscape canvas: figsize=(8, 4.5) × dpi=400 → 3200×1800 px\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nbar_width = 0.8\nax.bar(\n    df[\"date\"],\n    df[\"Confirmed\"],\n    width=bar_width,\n    label=\"Confirmed\",\n    color=CONFIRMED_COLOR,\n    edgecolor=PAGE_BG,\n    linewidth=0.3,\n)\nax.bar(\n    df[\"date\"],\n    df[\"Probable\"],\n    width=bar_width,\n    bottom=df[\"Confirmed\"],\n    label=\"Probable\",\n    color=PROBABLE_COLOR,\n    edgecolor=PAGE_BG,\n    linewidth=0.3,\n)\nax.bar(\n    df[\"date\"],\n    df[\"Suspect\"],\n    width=bar_width,\n    bottom=df[\"Confirmed\"] + df[\"Probable\"],\n    label=\"Suspect\",\n    color=SUSPECT_COLOR,\n    edgecolor=PAGE_BG,\n    linewidth=0.3,\n)\n\n# Cumulative line on secondary axis\nax2 = ax.twinx()\nax2.plot(df[\"date\"], cumulative, color=CUMULATIVE_COLOR, linewidth=2.0, alpha=0.85, label=\"Cumulative\")\nax2.fill_between(df[\"date\"], cumulative, alpha=0.07, color=CUMULATIVE_COLOR)\nax2.set_ylabel(\"Cumulative Cases\", fontsize=10, color=CUMULATIVE_COLOR)\nax2.tick_params(axis=\"y\", labelsize=8, colors=CUMULATIVE_COLOR, labelcolor=CUMULATIVE_COLOR)\nax2.spines[\"top\"].set_visible(False)\nax2.spines[\"left\"].set_visible(False)\nax2.spines[\"bottom\"].set_visible(False)\nax2.spines[\"right\"].set_color(CUMULATIVE_COLOR)\n\n# Intervention annotation lines\nlockdown_date = pd.Timestamp(\"2024-02-10\")\nvaccine_date = pd.Timestamp(\"2024-03-15\")\ntext_stroke = [pe.withStroke(linewidth=2, foreground=PAGE_BG)]\ny_label_pos = total_per_day.max() * 0.93\n\nax.axvline(lockdown_date, color=INK_MUTED, linestyle=\"--\", linewidth=1.0, alpha=0.8)\nax.axvline(vaccine_date, color=INK_MUTED, linestyle=\"--\", linewidth=1.0, alpha=0.8)\nax.text(\n    lockdown_date, y_label_pos, \" Lockdown\", fontsize=7, color=INK_SOFT, va=\"top\", ha=\"left\", path_effects=text_stroke\n)\nax.text(\n    vaccine_date,\n    y_label_pos,\n    \" Vaccination\\n campaign\",\n    fontsize=7,\n    color=INK_SOFT,\n    va=\"top\",\n    ha=\"left\",\n    path_effects=text_stroke,\n)\n\n# Style\ntitle = \"histogram-epidemic · python · matplotlib · anyplot.ai\"\nn = len(title)\ntitle_fontsize = max(8, round(12 * 67 / n)) if n > 67 else 12\n\nax.set_xlabel(\"Date of Symptom Onset\", fontsize=10, color=INK)\nax.set_ylabel(\"Daily New Cases\", fontsize=10, color=INK)\nax.set_title(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax.xaxis.set_major_locator(mdates.WeekdayLocator(interval=2))\nax.xaxis.set_major_formatter(mdates.DateFormatter(\"%b %d\"))\nplt.setp(ax.xaxis.get_majorticklabels(), rotation=30, ha=\"right\")\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nax.set_axisbelow(True)\n\n# Combined legend from both axes\nlines_bars, labels_bars = ax.get_legend_handles_labels()\nlines_cum, labels_cum = ax2.get_legend_handles_labels()\nleg = ax.legend(lines_bars + lines_cum, labels_bars + labels_cum, fontsize=8, loc=\"upper left\", framealpha=0.9)\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Save — bbox_inches must stay default (None) to preserve exact 3200×1800 canvas\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}