{"spec_id":"andrews-curves","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nandrews-curves: Andrews Curves for Multivariate Data\nLibrary: letsplot 4.9.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-15\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_line,\n    element_rect,\n    element_text,\n    geom_line,\n    ggplot,\n    ggsize,\n    labs,\n    scale_color_manual,\n    scale_x_continuous,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\nfrom sklearn.datasets import load_iris\nfrom sklearn.preprocessing import StandardScaler\n\n\nLetsPlot.setup_html()\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\"\nRULE = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette (first series always #009E73)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Set seed for reproducibility\nnp.random.seed(42)\n\n# Load and prepare data\niris = load_iris()\nX = iris.data\ny = iris.target\nfeature_names = iris.feature_names\ntarget_names = iris.target_names\n\n# Normalize variables to similar scales\nscaler = StandardScaler()\nX_scaled = scaler.fit_transform(X)\n\n# Create DataFrame with normalized features and species\ndf_features = pd.DataFrame(X_scaled, columns=feature_names)\ndf_features[\"species\"] = [target_names[i] for i in y]\n\n# Andrews curves transformation\n# f(t) = x1/sqrt(2) + x2*sin(t) + x3*cos(t) + x4*sin(2t) + x5*cos(2t) + ...\nt_values = np.linspace(-np.pi, np.pi, 200)\n\ncurves_data = []\nfor idx, row in df_features.iterrows():\n    values = row[feature_names].values\n    species = row[\"species\"]\n\n    for t in t_values:\n        # Fourier expansion\n        y_val = values[0] / np.sqrt(2)\n        for i in range(1, len(values)):\n            if i % 2 == 1:\n                y_val += values[i] * np.sin((i // 2 + 1) * t)\n            else:\n                y_val += values[i] * np.cos((i // 2) * t)\n\n        curves_data.append({\"t\": t, \"y\": y_val, \"observation\": idx, \"species\": species})\n\ndf_curves = pd.DataFrame(curves_data)\n\n# Map species to Okabe-Ito colors\nspecies_colors = {\n    target_names[0]: IMPRINT[0],  # setosa: #009E73 (brand green)\n    target_names[1]: IMPRINT[1],  # versicolor: #C475FD (vermillion)\n    target_names[2]: IMPRINT[2],  # virginica: #4467A3 (blue)\n}\n\n# Create plot\nplot = (\n    ggplot(df_curves, aes(x=\"t\", y=\"y\", group=\"observation\", color=\"species\"))\n    + geom_line(alpha=0.4, size=0.8)\n    + scale_color_manual(values=list(species_colors.values()))\n    + scale_x_continuous(breaks=[-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi], labels=[\"-π\", \"-π/2\", \"0\", \"π/2\", \"π\"])\n    + labs(\n        x=\"Parameter t (radians)\",\n        y=\"Fourier Function Value\",\n        title=\"andrews-curves · letsplot · anyplot.ai\",\n        color=\"Species\",\n    )\n    + theme_minimal()\n    + theme(\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_grid_major=element_line(color=RULE, size=0.3),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_line=element_line(color=INK_SOFT, size=0.5),\n        plot_title=element_text(size=24, color=INK),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_title=element_text(size=18, color=INK),\n        legend_text=element_text(size=16, color=INK_SOFT),\n        legend_position=\"right\",\n    )\n    + ggsize(1600, 900)\n)\n\n# Save PNG (scale 3x to get 4800 × 2700 px)\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=3)\n\n# Save HTML for interactivity\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}