{"spec_id":"line-stock-comparison","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nline-stock-comparison: Stock Price Comparison Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 81/100 | Updated: 2026-05-23\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\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#AE3030\", \"#4467A3\"]\n\n# Set seaborn theme BEFORE figure creation\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)\nsns.set_context(\"notebook\", font_scale=1.0)\n\n# Data - Generate synthetic stock price data for 4 tech companies over 1 year\nnp.random.seed(42)\n\ndates = pd.date_range(\"2024-01-01\", periods=252, freq=\"B\")  # Business days\nsymbols = [\"AAPL\", \"GOOGL\", \"MSFT\", \"SPY\"]\n\n# Generate realistic stock price movements using geometric Brownian motion\ndata = []\nfor symbol in symbols:\n    if symbol == \"AAPL\":\n        drift, volatility = 0.0008, 0.018\n    elif symbol == \"GOOGL\":\n        drift, volatility = 0.0006, 0.022\n    elif symbol == \"MSFT\":\n        drift, volatility = 0.0010, 0.016\n    else:  # SPY (index, lower volatility)\n        drift, volatility = 0.0005, 0.010\n\n    returns = np.random.normal(drift, volatility, len(dates))\n    price = 100 * np.exp(np.cumsum(returns))  # Start at 100 (already rebased)\n\n    for date, p in zip(dates, price, strict=True):\n        data.append({\"date\": date, \"symbol\": symbol, \"rebased_price\": p})\n\ndf = pd.DataFrame(data)\n\n# Plot — landscape canvas (3200×1800)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\npalette_map = dict(zip(symbols, IMPRINT, strict=True))\n\nsns.lineplot(\n    data=df, x=\"date\", y=\"rebased_price\", hue=\"symbol\", hue_order=symbols, palette=palette_map, linewidth=2.5, ax=ax\n)\n\n# Reference line at 100 (starting point)\nax.axhline(y=100, color=INK_SOFT, linestyle=\"--\", linewidth=1.0, alpha=0.6)\n\n# Style\nax.set_xlabel(\"Date\", fontsize=10, color=INK)\nax.set_ylabel(\"Rebased Price (Start = 100)\", fontsize=10, color=INK)\nax.set_title(\"line-stock-comparison · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# Move legend to upper-left where lines haven't diverged yet (seaborn-idiomatic)\nsns.move_legend(ax, \"upper left\", title=\"Symbol\", fontsize=8, title_fontsize=8)\n\n# Grid — y-axis only for line chart\nax.yaxis.grid(True, alpha=0.10, linewidth=0.8)\nax.set_axisbelow(True)\n\n# Spines — remove top and right (seaborn-idiomatic)\nsns.despine(ax=ax)\n\n# Rotate x-axis dates for readability\nfig.autofmt_xdate(rotation=30)\n\n# Save — no bbox_inches='tight' per seaborn canvas rule\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}