{"spec_id":"gantt-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\ngantt-basic: Basic Gantt Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\nfrom datetime import datetime\n\nimport matplotlib.dates as mdates\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\n\n\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\"\n\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\n# Data - Construction Project Timeline starting mid-February\ntasks_data = {\n    \"task\": [\n        \"Site Preparation\",\n        \"Foundation Work\",\n        \"Structural Framing\",\n        \"Roofing\",\n        \"Exterior Walls\",\n        \"Interior Framing\",\n        \"Electrical Work\",\n        \"Plumbing Installation\",\n        \"HVAC Installation\",\n        \"Drywall & Finishing\",\n        \"Painting\",\n        \"Final Inspection\",\n    ],\n    \"start\": [\n        \"2026-02-15\",\n        \"2026-02-22\",\n        \"2026-03-15\",\n        \"2026-04-12\",\n        \"2026-03-22\",\n        \"2026-04-19\",\n        \"2026-05-03\",\n        \"2026-05-03\",\n        \"2026-05-10\",\n        \"2026-05-17\",\n        \"2026-06-07\",\n        \"2026-06-21\",\n    ],\n    \"end\": [\n        \"2026-02-21\",\n        \"2026-03-14\",\n        \"2026-04-11\",\n        \"2026-05-02\",\n        \"2026-04-18\",\n        \"2026-05-02\",\n        \"2026-05-16\",\n        \"2026-05-30\",\n        \"2026-05-23\",\n        \"2026-06-06\",\n        \"2026-06-20\",\n        \"2026-06-28\",\n    ],\n    \"category\": [\n        \"Foundation\",\n        \"Foundation\",\n        \"Structure\",\n        \"Structure\",\n        \"Exterior\",\n        \"Interior\",\n        \"Systems\",\n        \"Systems\",\n        \"Systems\",\n        \"Finishing\",\n        \"Finishing\",\n        \"Finalization\",\n    ],\n}\n\ndf = pd.DataFrame(tasks_data)\ndf[\"start\"] = pd.to_datetime(df[\"start\"])\ndf[\"end\"] = pd.to_datetime(df[\"end\"])\ndf[\"duration\"] = (df[\"end\"] - df[\"start\"]).dt.days\n\ndf = df.sort_values(\"start\").reset_index(drop=True)\ndf[\"start_num\"] = mdates.date2num(df[\"start\"])\n\n# Set seaborn style with theme-adaptive colors\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Category palette using Okabe-Ito\ncategory_order = [\"Foundation\", \"Structure\", \"Exterior\", \"Interior\", \"Systems\", \"Finishing\", \"Finalization\"]\ncategory_palette = {\n    \"Foundation\": IMPRINT[0],\n    \"Structure\": IMPRINT[1],\n    \"Exterior\": IMPRINT[2],\n    \"Interior\": IMPRINT[3],\n    \"Systems\": IMPRINT[4],\n    \"Finishing\": IMPRINT[5],\n    \"Finalization\": INK_SOFT,\n}\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\n\n# Use seaborn barplot with hue for category coloring\nsns.barplot(\n    data=df,\n    y=\"task\",\n    x=\"duration\",\n    hue=\"category\",\n    hue_order=category_order,\n    palette=category_palette,\n    orient=\"h\",\n    dodge=False,\n    ax=ax,\n    edgecolor=PAGE_BG,\n    linewidth=1.5,\n    alpha=0.9,\n    legend=False,\n)\n\n# Shift bars to start date positions\nfor bar, start_num in zip(ax.patches, df[\"start_num\"], strict=True):\n    bar.set_x(start_num)\n\n# Format x-axis as dates\nax.xaxis_date()\nax.xaxis.set_major_formatter(mdates.DateFormatter(\"%b %d\"))\nax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=0, interval=2))\n\n# Add current date indicator\ntoday = datetime(2026, 5, 10)\nax.axvline(x=mdates.date2num(today), color=\"#E74C3C\", linestyle=\"--\", linewidth=2.5, label=\"Today\", alpha=0.8)\n\n# Styling\nax.set_xlabel(\"Timeline\", fontsize=20, color=INK)\nax.set_ylabel(\"Tasks\", fontsize=20, color=INK)\nax.set_title(\"gantt-basic · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK, pad=20)\nax.tick_params(axis=\"x\", labelsize=16, colors=INK_SOFT, rotation=45)\nax.tick_params(axis=\"y\", labelsize=16, colors=INK_SOFT)\n\n# Remove y-axis grid, keep x-axis grid subtle\nax.grid(axis=\"x\", alpha=0.10, linestyle=\"-\", linewidth=0.8)\n\n# Create legend positioned outside plot area\nlegend_elements = [\n    plt.Rectangle((0, 0), 1, 1, facecolor=color, edgecolor=INK_SOFT, linewidth=1, label=cat)\n    for cat, color in category_palette.items()\n    if cat in df[\"category\"].values\n]\nlegend_elements.append(plt.Line2D([0], [0], color=\"#E74C3C\", linestyle=\"--\", linewidth=2.5, label=\"Today\"))\n\nax.legend(handles=legend_elements, loc=\"upper left\", bbox_to_anchor=(1.01, 1), fontsize=14, framealpha=0.95)\n\n# Invert y-axis to have first task at top\nax.invert_yaxis()\n\n# Set x-axis limits with padding\ndate_min = df[\"start\"].min() - pd.Timedelta(days=3)\ndate_max = df[\"end\"].max() + pd.Timedelta(days=3)\nax.set_xlim(mdates.date2num(date_min), mdates.date2num(date_max))\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}