{"spec_id":"andrews-curves","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nandrews-curves: Andrews Curves for Multivariate Data\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-15\n\"\"\"\n\nimport os\nimport sys\n\n\n# Handle import shadowing: remove current directory from path to avoid\n# importing local matplotlib.py or seaborn.py instead of the real libraries\ncwd = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if not (p == cwd or p.startswith(cwd + os.sep))]\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\n# Okabe-Ito palette (first series always #009E73)\nIMPRINT = [\n    \"#009E73\",  # bluish green (brand)\n    \"#C475FD\",  # vermillion\n    \"#4467A3\",  # blue\n]\n\n# Data\ndf = sns.load_dataset(\"iris\")\n\n# Normalize variables to similar scales\nfeatures = [\"sepal_length\", \"sepal_width\", \"petal_length\", \"petal_width\"]\nfor col in features:\n    df[col + \"_norm\"] = (df[col] - df[col].mean()) / df[col].std()\n\nnorm_features = [f + \"_norm\" for f in features]\n\n# Generate t values from -π to π\nt = np.linspace(-np.pi, np.pi, 200)\n\n# Compute Andrews curves for all observations\ncurves_data = []\nfor idx, row in df.iterrows():\n    values = row[norm_features].values.astype(float)\n    # Andrews curve: f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + ...\n    curve_vals = np.full_like(t, values[0] / np.sqrt(2))\n    for i in range(1, len(values)):\n        if i % 2 == 1:\n            curve_vals = curve_vals + values[i] * np.sin((i + 1) // 2 * t)\n        else:\n            curve_vals = curve_vals + values[i] * np.cos(i // 2 * t)\n\n    for t_val, y_val in zip(t, curve_vals, strict=True):\n        curves_data.append({\"t\": t_val, \"f(t)\": y_val, \"species\": row[\"species\"], \"obs_id\": idx})\n\ncurves_df = pd.DataFrame(curves_data)\n\n# Theme-adaptive seaborn styling\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)\n\n# Plot\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# Plot Andrews curves using lineplot with grouped data\nsns.lineplot(\n    data=curves_df,\n    x=\"t\",\n    y=\"f(t)\",\n    hue=\"species\",\n    palette=IMPRINT,\n    alpha=0.4,\n    linewidth=2.5,\n    units=\"obs_id\",\n    estimator=None,\n    ax=ax,\n)\n\n# Style\nax.set_xlabel(\"t\", fontsize=20, color=INK)\nax.set_ylabel(\"f(t)\", fontsize=20, color=INK)\nax.set_title(\"andrews-curves · seaborn · anyplot.ai\", fontsize=24, color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Set x-axis ticks to show π values\nax.set_xticks([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi])\nax.set_xticklabels([\"-π\", \"-π/2\", \"0\", \"π/2\", \"π\"], fontsize=16)\n\n# Legend\nax.legend(title=\"Species\", fontsize=16, title_fontsize=18, loc=\"upper right\", framealpha=0.95)\n\n# Grid (subtle, solid lines)\nax.grid(True, alpha=0.10, linewidth=0.8, linestyle=\"-\")\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}