{"spec_id":"line-multi","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nline-multi: Multi-Line Comparison Plot\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\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\"\n\n# Imprint palette (first series always #009E73)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Configure seaborn theme\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.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Data: Monthly sales for 4 product lines over 12 months\nnp.random.seed(42)\nmonths = np.arange(1, 13)\nmonth_labels = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\n# Generate realistic sales patterns for different product categories\n# Electronics: Strong growth with holiday spike\nelectronics = 50 + np.cumsum(np.random.randn(12) * 5 + 3)\nelectronics[10:] += 30  # Holiday boost\n\n# Apparel: Seasonal with summer and winter peaks\napparel = 40 + 15 * np.sin(np.linspace(0, 2 * np.pi, 12)) + np.random.randn(12) * 3\n\n# Home & Garden: Spring/summer peak\nhome_garden = 30 + 20 * np.sin(np.linspace(-np.pi / 2, 3 * np.pi / 2, 12)) + np.random.randn(12) * 4\n\n# Sports: Steady with slight seasonal variation\nsports = 35 + 5 * np.sin(np.linspace(0, 2 * np.pi, 12) + np.pi / 4) + np.cumsum(np.random.randn(12) * 2)\n\n# April (index 3): Home & Garden and Sports would otherwise sit ~2 units apart on\n# a ~140-unit axis, hiding one marker behind the other — nudge them apart\nhome_garden[3] -= 6\nsports[3] += 4\n\n# Create long-format DataFrame for seaborn\ndf = pd.DataFrame(\n    {\n        \"Month\": np.tile(months, 4),\n        \"Sales (thousands USD)\": np.concatenate([electronics, apparel, home_garden, sports]),\n        \"Product Line\": ([\"Electronics\"] * 12 + [\"Apparel\"] * 12 + [\"Home & Garden\"] * 12 + [\"Sports\"] * 12),\n    }\n)\n\n# Plot — canvas fixed at figsize x dpi = 3200x1800px (16:9), no bbox_inches='tight'\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Soft underlay glow behind Electronics to sharpen its lead-series hierarchy\nax.plot(months, electronics, color=IMPRINT[0], linewidth=6, alpha=0.16, solid_capstyle=\"round\", zorder=1)\n\nsns.lineplot(\n    data=df,\n    x=\"Month\",\n    y=\"Sales (thousands USD)\",\n    hue=\"Product Line\",\n    style=\"Product Line\",\n    markers=True,\n    dashes=False,\n    linewidth=2.5,\n    markersize=8,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=1.3,\n    errorbar=None,\n    palette=IMPRINT,\n    ax=ax,\n    zorder=2,\n)\n\n# Callout: the holiday spike is the clearest story beat in the data\nax.annotate(\n    \"Holiday season lifts\\nElectronics sharply\",\n    xy=(12, electronics[-1]),\n    xytext=(9.65, electronics[-1] + 14),\n    fontsize=8,\n    color=INK_SOFT,\n    ha=\"left\",\n    arrowprops={\"arrowstyle\": \"-\", \"color\": INK_SOFT, \"linewidth\": 1},\n    bbox={\"boxstyle\": \"round,pad=0.3\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"linewidth\": 0.8},\n)\n\n# Styling\ntitle = \"line-multi · python · seaborn · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", pad=14, color=INK)\nax.set_xlabel(\"Month\", fontsize=10, color=INK)\nax.set_ylabel(\"Sales (thousands USD)\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# Set x-ticks to month names\nax.set_xticks(months)\nax.set_xticklabels(month_labels, fontsize=8)\n\n# Subtle grid\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8)\nax.xaxis.grid(False)\n\n# Refined L-shaped frame\nsns.despine(ax=ax, offset=6, trim=False)\n\n# Legend styling — sns.move_legend repositions seaborn's auto-built hue+style legend\nsns.move_legend(ax, loc=\"upper left\", title=\"Product Line\", title_fontsize=9, fontsize=8, framealpha=0.95)\n\nfig.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}