{"spec_id":"scatter-connected-temporal","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nscatter-connected-temporal: Connected Scatter Plot with Temporal Path\nLibrary: seaborn 0.13.2 | Python 3.13.16\nQuality: 86/100 | Updated: 2026-10-08\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.collections import LineCollection\nfrom matplotlib.colors import LinearSegmentedColormap\n\n\n# Theme-adaptive chrome tokens (Imprint palette)\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 sequential colormap: brand green (early) → blue (recent)\nimprint_seq = LinearSegmentedColormap.from_list(\"imprint_seq\", [\"#009E73\", \"#4467A3\"])\n\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# Monthly closing price vs. average daily trading volume for a fictional stock, Jan 2023 – Dec 2024\nmonths = pd.period_range(\"2023-01\", periods=24, freq=\"M\")\nt = np.arange(len(months), dtype=float)\nn = len(months)\n\nprice = np.array(\n    [\n        102,\n        108,\n        115,\n        121,\n        118,\n        109,\n        98,\n        92,\n        95,\n        104,\n        113,\n        125,\n        134,\n        129,\n        121,\n        117,\n        124,\n        136,\n        148,\n        155,\n        149,\n        141,\n        146,\n        158,\n    ],\n    dtype=float,\n)\nvolume = np.array(\n    [\n        4.1,\n        4.6,\n        5.8,\n        6.4,\n        5.9,\n        7.8,\n        9.6,\n        10.4,\n        8.2,\n        6.1,\n        5.3,\n        5.9,\n        7.1,\n        6.3,\n        5.5,\n        5.0,\n        5.4,\n        6.8,\n        8.1,\n        9.0,\n        7.4,\n        6.2,\n        5.8,\n        7.5,\n    ]\n)\n\nX_LABEL = \"Average Daily Volume (million shares)\"\nY_LABEL = \"Closing Price (USD)\"\ndf = pd.DataFrame({X_LABEL: volume, Y_LABEL: price, \"Month\": t})\n\n# Canvas: landscape 16:9 → exactly 3200×1800 px\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\nfig.subplots_adjust(left=0.11, bottom=0.13, right=0.88, top=0.82)\n\n# Background: seaborn KDE contours showing where price/volume spent most of the two years\nsns.kdeplot(data=df, x=X_LABEL, y=Y_LABEL, levels=3, color=INK_SOFT, alpha=0.2, linewidths=0.7, bw_adjust=1.2, ax=ax)\n\n# Temporal path: LineCollection with Imprint sequential gradient\nnorm = plt.Normalize(t[0], t[-1])\npoints = np.column_stack([volume, price])\nsegments = np.array([[points[i], points[i + 1]] for i in range(n - 1)])\nlc = LineCollection(segments, cmap=imprint_seq, norm=norm, linewidths=1.8, zorder=2, alpha=0.85)\nlc.set_array(t[:-1])\nax.add_collection(lc)\n\n# Scatter markers with temporal hue encoding via seaborn continuous palette\nsns.scatterplot(\n    data=df,\n    x=X_LABEL,\n    y=Y_LABEL,\n    hue=\"Month\",\n    hue_norm=(t[0], t[-1]),\n    palette=imprint_seq,\n    s=120,\n    edgecolor=PAGE_BG,\n    linewidth=0.6,\n    legend=False,\n    zorder=3,\n    ax=ax,\n)\n\n# Directional arrow on temporal path (Jun→Jul 2023 segment makes time direction explicit)\ni_dir = 5\nax.annotate(\n    \"\",\n    xy=(volume[i_dir + 1], price[i_dir + 1]),\n    xytext=(volume[i_dir], price[i_dir]),\n    arrowprops={\"arrowstyle\": \"-|>\", \"color\": INK, \"lw\": 1.4, \"mutation_scale\": 14},\n    zorder=4,\n)\n\n# Key time-point annotations: start, volume spike, rally peak, end\nkey_points = {0: (-8, -22), 7: (-6, -24), 11: (-34, 14), 19: (6, 14), n - 1: (14, 8)}\nfor idx, offset in key_points.items():\n    ax.annotate(\n        months[idx].strftime(\"%b %Y\"),\n        (volume[idx], price[idx]),\n        textcoords=\"offset points\",\n        xytext=offset,\n        fontsize=9,\n        fontweight=\"bold\",\n        color=INK,\n        arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"lw\": 0.9, \"connectionstyle\": \"arc3,rad=0.2\"},\n    )\n\n# Narrative subtitle\nax.text(\n    0.5,\n    1.03,\n    \"Fictional stock: how price and trading volume moved together, Jan 2023 – Dec 2024\",\n    transform=ax.transAxes,\n    fontsize=8,\n    color=INK_SOFT,\n    ha=\"center\",\n    va=\"bottom\",\n    style=\"italic\",\n)\n\nax.set_xlabel(X_LABEL, fontsize=10)\nax.set_ylabel(Y_LABEL, fontsize=10)\nax.set_title(\n    \"scatter-connected-temporal · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", pad=22, color=INK\n)\nax.tick_params(axis=\"both\", labelsize=8)\nsns.despine(ax=ax)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\n\nax.set_xlim(volume.min() - 0.8, volume.max() + 0.8)\nax.set_ylim(price.min() - 10, price.max() + 10)\n\n# Colorbar for temporal scale\nsm = plt.cm.ScalarMappable(cmap=imprint_seq, norm=norm)\nsm.set_array([])\ncbar = fig.colorbar(sm, ax=ax, pad=0.02, aspect=30, shrink=0.85)\ncbar.set_ticks([0, 6, 12, 18, 23])\ncbar.set_ticklabels([months[i].strftime(\"%b %Y\") for i in (0, 6, 12, 18, 23)])\ncbar.set_label(\"Month\", fontsize=8, color=INK)\ncbar.ax.tick_params(labelsize=7, colors=INK_SOFT)\ncbar.outline.set_edgecolor(INK_SOFT)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}