{"spec_id":"bump-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nbump-basic: Basic Bump Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-29\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\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\"\nANYPLOT_AMBER = \"#DDCC77\"\n\n# Imprint palette — 8 hues, canonical order, first series always #009E73\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\n\n# Data — Tech company market cap rankings by quarter (2022–2023)\ncompanies = [\"Apple\", \"Microsoft\", \"Amazon\", \"Alphabet\", \"Nvidia\"]\nquarters = [\"Q1'22\", \"Q2'22\", \"Q3'22\", \"Q4'22\", \"Q1'23\", \"Q2'23\", \"Q3'23\", \"Q4'23\"]\n\nranks_data = {\n    \"Apple\": [1, 1, 1, 1, 1, 1, 2, 2],\n    \"Microsoft\": [2, 2, 2, 2, 2, 2, 1, 1],\n    \"Amazon\": [3, 3, 4, 4, 4, 5, 5, 5],\n    \"Alphabet\": [4, 4, 3, 3, 3, 3, 4, 4],\n    \"Nvidia\": [5, 5, 5, 5, 5, 4, 3, 3],\n}\n\nrows = []\nfor company, r_list in ranks_data.items():\n    for q, r in zip(quarters, r_list, strict=False):\n        rows.append({\"Company\": company, \"Quarter\": q, \"Rank\": r})\ndf = pd.DataFrame(rows)\n\n# Theme-adaptive seaborn setup\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\npalette = IMPRINT_PALETTE[: len(companies)]\nmarkers = {\"Apple\": \"o\", \"Microsoft\": \"s\", \"Amazon\": \"D\", \"Alphabet\": \"^\", \"Nvidia\": \"P\"}\n\n# Figure-level relplot — leverages seaborn's FacetGrid API for layout control\ng = sns.relplot(\n    data=df,\n    x=\"Quarter\",\n    y=\"Rank\",\n    hue=\"Company\",\n    style=\"Company\",\n    markers=markers,\n    dashes=False,\n    markersize=14,\n    linewidth=3,\n    palette=palette,\n    hue_order=companies,\n    sort=False,\n    kind=\"line\",\n    height=4.5,\n    aspect=16 / 9,\n    legend=False,\n)\ng.figure.set_dpi(400)\ng.figure.set_facecolor(PAGE_BG)\n\nax = g.axes[0, 0]\nax.set_facecolor(PAGE_BG)\n\n# Rank 1 at top\nax.invert_yaxis()\nax.set_yticks([1, 2, 3, 4, 5])\nax.xaxis.grid(False)\nax.yaxis.grid(True)\nsns.despine(ax=ax)\n\n# Alpha hierarchy — de-emphasize lower final-ranked companies\nfinal_ranks = {c: ranks_data[c][-1] for c in companies}\nfor line in ax.get_lines():\n    label = line.get_label()\n    if label in final_ranks:\n        fr = final_ranks[label]\n        line.set_alpha(1.0 if fr <= 2 else (0.75 if fr == 3 else 0.55))\n\n# Crossing highlight — Apple/Microsoft overtake between Q2'23 (idx 5) and Q3'23 (idx 6)\n# Categorical x-axis maps quarters to integer positions 0–7\nCROSSING_X = 5.5\nax.axvline(x=CROSSING_X, color=ANYPLOT_AMBER, alpha=0.45, linewidth=1.5, linestyle=\"--\", zorder=0)\n# Label near rank 1 (top of inverted y-axis) where Apple/Microsoft cross\n# ax.get_xaxis_transform(): x=data coords, y=axes fraction (1=top of display)\nax.text(\n    CROSSING_X,\n    0.90,\n    \"overtake\",\n    fontsize=7,\n    color=ANYPLOT_AMBER,\n    ha=\"center\",\n    va=\"bottom\",\n    style=\"italic\",\n    transform=ax.get_xaxis_transform(),\n)\n\n# Style\ntitle = \"bump-basic · python · seaborn · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK, pad=12)\nax.set_xlabel(\"Quarter\", fontsize=10, color=INK)\nax.set_ylabel(\"Market Cap Rank\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# End-of-line labels replacing legend\nn_quarters = len(quarters)\nfor i, company in enumerate(companies):\n    rank = ranks_data[company][-1]\n    fr = rank\n    alpha_val = 1.0 if fr <= 2 else (0.75 if fr == 3 else 0.55)\n    ax.annotate(\n        company,\n        xy=(n_quarters - 1, rank),\n        xytext=(10, 0),\n        textcoords=\"offset points\",\n        fontsize=8,\n        fontweight=\"bold\" if rank <= 2 else \"normal\",\n        color=palette[i],\n        va=\"center\",\n        alpha=alpha_val,\n    )\n\ng.figure.subplots_adjust(left=0.09, right=0.87, top=0.90, bottom=0.13)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}