{"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.13\nQuality: 89/100 | Updated: 2026-06-09\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# U.S. unemployment vs. inflation 1990–2023 (Phillips curve dynamics)\nyears = np.arange(1990, 2024)\nn = len(years)\n\nunemployment = np.array(\n    [\n        5.6,\n        6.8,\n        7.5,\n        6.9,\n        6.1,\n        5.6,\n        5.4,\n        4.9,\n        4.5,\n        4.2,\n        4.0,\n        4.7,\n        5.8,\n        6.0,\n        5.5,\n        5.1,\n        4.6,\n        4.6,\n        5.8,\n        9.3,\n        9.6,\n        8.9,\n        8.1,\n        7.4,\n        6.2,\n        5.3,\n        4.9,\n        4.4,\n        3.9,\n        3.7,\n        8.1,\n        5.4,\n        3.6,\n        3.6,\n    ]\n)\n\ninflation = np.array(\n    [\n        5.4,\n        4.2,\n        3.0,\n        3.0,\n        2.6,\n        2.8,\n        2.9,\n        2.3,\n        1.6,\n        2.2,\n        3.4,\n        2.8,\n        1.6,\n        2.3,\n        2.7,\n        3.4,\n        3.2,\n        2.8,\n        3.8,\n        -0.4,\n        1.6,\n        3.2,\n        2.1,\n        1.5,\n        1.6,\n        0.1,\n        1.3,\n        2.1,\n        2.4,\n        1.8,\n        1.2,\n        4.7,\n        8.0,\n        4.1,\n    ]\n)\n\ndf = pd.DataFrame({\"Unemployment Rate (%)\": unemployment, \"Inflation Rate (%)\": inflation, \"Year\": years})\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 historical Phillips curve regime density\nsns.kdeplot(\n    data=df,\n    x=\"Unemployment Rate (%)\",\n    y=\"Inflation Rate (%)\",\n    levels=3,\n    color=INK_SOFT,\n    alpha=0.2,\n    linewidths=0.7,\n    bw_adjust=1.2,\n    ax=ax,\n)\n\n# Temporal path: LineCollection with Imprint sequential gradient\nnorm = plt.Normalize(years[0], years[-1])\npoints = np.column_stack([unemployment, inflation])\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(years[:-1].astype(float))\nax.add_collection(lc)\n\n# Scatter markers with temporal hue encoding via seaborn continuous palette\nsns.scatterplot(\n    data=df,\n    x=\"Unemployment Rate (%)\",\n    y=\"Inflation Rate (%)\",\n    hue=\"Year\",\n    hue_norm=(years[0], years[-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 (2016→2017 segment makes time direction explicit)\ni_dir = 26  # index of 2016\nax.annotate(\n    \"\",\n    xy=(unemployment[i_dir + 1], inflation[i_dir + 1]),\n    xytext=(unemployment[i_dir], inflation[i_dir]),\n    arrowprops={\"arrowstyle\": \"-|>\", \"color\": INK, \"lw\": 1.4, \"mutation_scale\": 14},\n    zorder=4,\n)\n\n# Key economic turning-point annotations\nkey_points = {\n    0: (-22, 18),  # 1990\n    10: (14, 12),  # 2000\n    19: (14, -18),  # 2009\n    22: (-38, -18),  # 2012\n    29: (-44, -16),  # 2019\n    n - 1: (16, 12),  # 2023\n}\nfor idx, offset in key_points.items():\n    ax.annotate(\n        str(years[idx]),\n        (unemployment[idx], inflation[idx]),\n        textcoords=\"offset points\",\n        xytext=offset,\n        fontsize=8,\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    \"U.S. Phillips Curve Dynamics: Tracing Unemployment vs. Inflation (1990–2023)\",\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(\"Unemployment Rate (%)\", fontsize=10)\nax.set_ylabel(\"Inflation Rate (%)\", 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(unemployment.min() - 0.8, unemployment.max() + 0.8)\nax.set_ylim(inflation.min() - 1.2, inflation.max() + 1.2)\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_label(\"Year\", 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"}