{"spec_id":"sparkline-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nsparkline-basic: Basic Sparkline\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-06-16\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-adaptive chrome (Imprint palette) ---------------------------------\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Imprint palette — first series is ALWAYS brand green\nBRAND = \"#009E73\"  # brand green — the sparkline line\nLOW = \"#AE3030\"  # matte red — semantic anchor for the low point\n\n# Data — daily readings for six dashboard KPIs ----------------------------\nrng = np.random.default_rng(42)\nmetrics = [\n    (\"Revenue\", \"$\", \"K\", 124.0, 0.9),\n    (\"Active Users\", \"\", \"K\", 48.0, 0.7),\n    (\"Conversion\", \"\", \"%\", 3.4, 0.04),\n    (\"Avg Session\", \"\", \"s\", 182.0, 2.2),\n    (\"Churn\", \"\", \"%\", 2.3, 0.05),\n    (\"NPS\", \"\", \"\", 54.0, 0.8),\n]\nN_DAYS = 40\nmeta = {m[0]: m for m in metrics}\norder = [m[0] for m in metrics]\n\nrecords = []\nfor name, _prefix, _suffix, base, vol in metrics:\n    walk = np.cumsum(rng.normal(0, vol, N_DAYS))\n    y = base + walk - walk[0]\n    for day, value in enumerate(y):\n        records.append({\"metric\": name, \"day\": day, \"value\": value})\ndf = pd.DataFrame(records)\n\n# Theme — strip every default chrome element; sparklines carry none --------\nsns.set_theme(\n    style=\"white\",\n    rc={\"figure.facecolor\": PAGE_BG, \"axes.facecolor\": PAGE_BG, \"text.color\": INK, \"font.family\": \"sans-serif\"},\n)\n\n# Idiomatic seaborn small-multiples: relplot builds the faceted grid -------\ng = sns.relplot(\n    data=df,\n    x=\"day\",\n    y=\"value\",\n    col=\"metric\",\n    col_order=order,\n    col_wrap=2,\n    kind=\"line\",\n    color=BRAND,\n    linewidth=2.2,\n    height=1.5,\n    aspect=2.6,\n    facet_kws={\"sharex\": False, \"sharey\": False, \"despine\": True},\n)\ng.set_titles(col_template=\"\")\ng.set_axis_labels(\"\", \"\")\ng.figure.set_size_inches(8, 4.5)\ng.figure.set_dpi(400)\n\n# Per-facet sparkline detailing: area fill, focal dots, value + trend delta\nfor ax, name in zip(g.axes.flat, order, strict=True):\n    prefix, suffix = meta[name][1], meta[name][2]\n    sub = df[df[\"metric\"] == name]\n    x = sub[\"day\"].to_numpy()\n    y = sub[\"value\"].to_numpy()\n\n    ax.fill_between(x, y.min(), y, color=BRAND, alpha=0.12, linewidth=0)\n\n    # Highlight min (red), max (brand green), and the current value\n    i_min, i_max = int(np.argmin(y)), int(np.argmax(y))\n    ax.scatter(i_min, y[i_min], color=LOW, s=42, zorder=5, edgecolors=PAGE_BG, linewidths=1.2)\n    ax.scatter(i_max, y[i_max], color=BRAND, s=42, zorder=5, edgecolors=PAGE_BG, linewidths=1.2)\n    ax.scatter(x[-1], y[-1], color=BRAND, s=60, zorder=6, edgecolors=PAGE_BG, linewidths=1.4)\n\n    # Breathing room above/below the trace\n    span = y.max() - y.min()\n    ax.set_ylim(y.min() - span * 0.35, y.max() + span * 0.45)\n    ax.set_xlim(-1, N_DAYS + 7)\n\n    # Metric label (top-left) — the only text chrome a sparkline keeps\n    ax.set_title(name, loc=\"left\", fontsize=9, fontweight=\"bold\", color=INK, pad=4)\n\n    # Current value + trend delta vs. start (arrow makes direction explicit)\n    last = y[-1]\n    delta = (last - y[0]) / y[0] * 100\n    arrow, dcolor = (\"▲\", BRAND) if delta >= 0 else (\"▼\", LOW)\n    ax.text(\n        0.99,\n        0.93,\n        f\"{prefix}{last:,.1f}{suffix}\",\n        transform=ax.transAxes,\n        ha=\"right\",\n        va=\"top\",\n        fontsize=10,\n        fontweight=\"bold\",\n        color=INK,\n    )\n    ax.text(\n        0.99,\n        0.60,\n        f\"{arrow} {abs(delta):.1f}%\",\n        transform=ax.transAxes,\n        ha=\"right\",\n        va=\"top\",\n        fontsize=8.5,\n        color=dcolor,\n    )\n\n    # Pure sparkline: remove all remaining axes chrome\n    ax.set_xticks([])\n    ax.set_yticks([])\n    for spine in ax.spines.values():\n        spine.set_visible(False)\n\ng.figure.suptitle(\"sparkline-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK_SOFT)\ng.figure.subplots_adjust(left=0.04, right=0.97, top=0.88, bottom=0.05, hspace=0.45, wspace=0.12)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}