{"spec_id":"gantt-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\ngantt-basic: Basic Gantt Chart\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 95/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\nfrom datetime import datetime, timedelta\n\nimport matplotlib.dates as mdates\nimport matplotlib.pyplot as plt\nfrom matplotlib.patches import Patch\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# Okabe-Ito palette for categories\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\n# Data - Software Development Project\ntasks = [\n    {\n        \"task\": \"Requirements Analysis\",\n        \"start\": datetime(2025, 1, 6),\n        \"end\": datetime(2025, 1, 17),\n        \"category\": \"Planning\",\n    },\n    {\"task\": \"System Design\", \"start\": datetime(2025, 1, 13), \"end\": datetime(2025, 1, 31), \"category\": \"Planning\"},\n    {\"task\": \"Database Setup\", \"start\": datetime(2025, 1, 27), \"end\": datetime(2025, 2, 7), \"category\": \"Development\"},\n    {\n        \"task\": \"Backend Development\",\n        \"start\": datetime(2025, 2, 3),\n        \"end\": datetime(2025, 3, 7),\n        \"category\": \"Development\",\n    },\n    {\n        \"task\": \"Frontend Development\",\n        \"start\": datetime(2025, 2, 10),\n        \"end\": datetime(2025, 3, 14),\n        \"category\": \"Development\",\n    },\n    {\"task\": \"API Integration\", \"start\": datetime(2025, 3, 3), \"end\": datetime(2025, 3, 21), \"category\": \"Development\"},\n    {\"task\": \"Unit Testing\", \"start\": datetime(2025, 3, 10), \"end\": datetime(2025, 3, 28), \"category\": \"Testing\"},\n    {\n        \"task\": \"Integration Testing\",\n        \"start\": datetime(2025, 3, 24),\n        \"end\": datetime(2025, 4, 11),\n        \"category\": \"Testing\",\n    },\n    {\n        \"task\": \"User Acceptance Testing\",\n        \"start\": datetime(2025, 4, 7),\n        \"end\": datetime(2025, 4, 18),\n        \"category\": \"Testing\",\n    },\n    {\"task\": \"Documentation\", \"start\": datetime(2025, 3, 17), \"end\": datetime(2025, 4, 11), \"category\": \"Deployment\"},\n    {\"task\": \"Deployment Prep\", \"start\": datetime(2025, 4, 14), \"end\": datetime(2025, 4, 25), \"category\": \"Deployment\"},\n    {\"task\": \"Go Live\", \"start\": datetime(2025, 4, 28), \"end\": datetime(2025, 5, 2), \"category\": \"Deployment\"},\n]\n\n# Category to color mapping using Okabe-Ito palette\ncategory_colors = {\n    \"Planning\": IMPRINT[0],\n    \"Development\": IMPRINT[1],\n    \"Testing\": IMPRINT[2],\n    \"Deployment\": IMPRINT[3],\n}\n\n# Plot\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Sort tasks by start date for logical ordering\ntasks_sorted = sorted(tasks, key=lambda x: x[\"start\"], reverse=True)\n\n# Draw bars\nbar_height = 0.6\ny_positions = range(len(tasks_sorted))\n\nfor i, task in enumerate(tasks_sorted):\n    start = task[\"start\"]\n    duration = (task[\"end\"] - task[\"start\"]).days\n    color = category_colors[task[\"category\"]]\n\n    ax.barh(i, duration, left=start, height=bar_height, color=color, edgecolor=PAGE_BG, linewidth=1, alpha=0.9)\n\n# Y-axis: task names\nax.set_yticks(y_positions)\nax.set_yticklabels([t[\"task\"] for t in tasks_sorted], fontsize=16, color=INK)\n\n# X-axis: dates\nax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MO, interval=2))\nax.xaxis.set_major_formatter(mdates.DateFormatter(\"%b %d\"))\nax.tick_params(axis=\"x\", labelsize=16, rotation=45, colors=INK_SOFT)\nax.tick_params(axis=\"y\", labelsize=16, colors=INK_SOFT)\n\n# Set x-axis limits with padding\nall_starts = [t[\"start\"] for t in tasks]\nall_ends = [t[\"end\"] for t in tasks]\nax.set_xlim(min(all_starts) - timedelta(days=3), max(all_ends) + timedelta(days=3))\n\n# Add \"today\" marker line (mid-project for demonstration)\ntoday = datetime(2025, 3, 15)\nax.axvline(today, color=INK_MUTED, linewidth=3, linestyle=\"--\", label=\"Today\", zorder=5)\n\n# Style\nax.set_xlabel(\"Project Timeline (2025)\", fontsize=20, color=INK)\nax.set_ylabel(\"Project Tasks\", fontsize=20, color=INK)\nax.set_title(\"gantt-basic · matplotlib · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\n\n# Grid (subtle, only on x-axis)\nax.grid(True, axis=\"x\", alpha=0.15, linewidth=0.8, color=INK)\nax.set_axisbelow(True)\n\n# Legend for categories\nlegend_elements = [Patch(facecolor=color, edgecolor=INK_SOFT, label=cat) for cat, color in category_colors.items()]\nlegend_elements.append(plt.Line2D([0], [0], color=INK_MUTED, linewidth=3, linestyle=\"--\", label=\"Today\"))\nleg = ax.legend(handles=legend_elements, loc=\"upper right\", fontsize=16, framealpha=0.95, fancybox=True)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nfor text in leg.get_texts():\n    text.set_color(INK_SOFT)\n\n# Remove top and right 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\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}