{"spec_id":"parallel-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nparallel-basic: Basic Parallel Coordinates Plot\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-07-24\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent local matplotlib.py from shadowing the installed matplotlib package\nsys.path = [p for p in sys.path if os.path.abspath(p or \".\") != os.path.dirname(os.path.abspath(__file__))]\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nfrom matplotlib.lines import Line2D\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\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# Data: synthetic hyperparameter search runs across three optimizers,\n# each producing a final validation accuracy — a common ML tuning workflow.\nrng = np.random.default_rng(42)\nn_per_optimizer = 30\n\nconfigs = {\n    \"Adam\": {\n        \"lr_mean\": np.log(0.0015),\n        \"lr_sigma\": 0.5,\n        \"batch_choices\": [16, 32, 64, 128],\n        \"batch_p\": [0.15, 0.35, 0.35, 0.15],\n        \"dropout_mean\": 0.18,\n        \"dropout_sd\": 0.08,\n        \"wd_mean\": np.log(1.0e-4),\n        \"wd_sigma\": 1.0,\n        \"acc_mean\": 0.91,\n        \"acc_sd\": 0.025,\n    },\n    \"RMSprop\": {\n        \"lr_mean\": np.log(0.005),\n        \"lr_sigma\": 0.55,\n        \"batch_choices\": [32, 64, 128],\n        \"batch_p\": [0.25, 0.5, 0.25],\n        \"dropout_mean\": 0.24,\n        \"dropout_sd\": 0.10,\n        \"wd_mean\": np.log(3.0e-4),\n        \"wd_sigma\": 1.0,\n        \"acc_mean\": 0.85,\n        \"acc_sd\": 0.04,\n    },\n    \"SGD\": {\n        \"lr_mean\": np.log(0.03),\n        \"lr_sigma\": 0.6,\n        \"batch_choices\": [64, 128, 256],\n        \"batch_p\": [0.3, 0.4, 0.3],\n        \"dropout_mean\": 0.30,\n        \"dropout_sd\": 0.12,\n        \"wd_mean\": np.log(1.0e-3),\n        \"wd_sigma\": 1.0,\n        \"acc_mean\": 0.79,\n        \"acc_sd\": 0.05,\n    },\n}\n\nrows = []\nfor optimizer, cfg in configs.items():\n    lr = np.clip(rng.lognormal(cfg[\"lr_mean\"], cfg[\"lr_sigma\"], n_per_optimizer), 1.0e-4, 3.0e-1)\n    batch = rng.choice(cfg[\"batch_choices\"], size=n_per_optimizer, p=cfg[\"batch_p\"])\n    dropout = np.clip(rng.normal(cfg[\"dropout_mean\"], cfg[\"dropout_sd\"], n_per_optimizer), 0.0, 0.6)\n    weight_decay = np.clip(rng.lognormal(cfg[\"wd_mean\"], cfg[\"wd_sigma\"], n_per_optimizer), 1.0e-6, 1.0e-2)\n    val_accuracy = np.clip(rng.normal(cfg[\"acc_mean\"], cfg[\"acc_sd\"], n_per_optimizer), 0.5, 0.99)\n    for i in range(n_per_optimizer):\n        rows.append(\n            {\n                \"optimizer\": optimizer,\n                \"learning_rate\": lr[i],\n                \"batch_size\": batch[i],\n                \"dropout\": dropout[i],\n                \"weight_decay\": weight_decay[i],\n                \"val_accuracy\": val_accuracy[i],\n            }\n        )\n\ndf = pd.DataFrame(rows)\ndf[\"run\"] = range(len(df))\n\n# Order predictor axes by correlation strength with the outcome (Val. Accuracy)\n# so adjacent axes are more likely to reveal a relationship, per the spec's\n# \"consider axis ordering to reveal correlations between adjacent variables\".\npredictor_cols = [\"learning_rate\", \"batch_size\", \"dropout\", \"weight_decay\"]\ncorr_to_accuracy = df[predictor_cols + [\"val_accuracy\"]].corr()[\"val_accuracy\"].drop(\"val_accuracy\")\npredictor_cols = corr_to_accuracy.abs().sort_values(ascending=False).index.tolist()\nnumeric_cols = predictor_cols + [\"val_accuracy\"]\n\ndf_norm = df.copy()\nfor col in numeric_cols:\n    col_min = df[col].min()\n    col_max = df[col].max()\n    df_norm[col] = (df[col] - col_min) / (col_max - col_min)\n\ndf_long = df_norm.melt(\n    id_vars=[\"optimizer\", \"run\"], value_vars=numeric_cols, var_name=\"dimension\", value_name=\"normalized_value\"\n)\n\n# Plot\noptimizer_order = [\"Adam\", \"RMSprop\", \"SGD\"]\npalette = {opt: IMPRINT[i] for i, opt in enumerate(optimizer_order)}\n\n# Adam reaches the highest validation accuracy on average — foreground it with\n# higher opacity/linewidth while the other optimizers recede into context.\nemphasis = \"Adam\"\nalpha_map = {\"Adam\": 0.65, \"RMSprop\": 0.16, \"SGD\": 0.16}\nlinewidth_map = {\"Adam\": 2.0, \"RMSprop\": 1.0, \"SGD\": 1.0}\ndraw_order = [opt for opt in optimizer_order if opt != emphasis] + [emphasis]\n\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nfor optimizer in draw_order:\n    subset = df_long[df_long[\"optimizer\"] == optimizer]\n    sns.lineplot(\n        data=subset,\n        x=\"dimension\",\n        y=\"normalized_value\",\n        units=\"run\",\n        estimator=None,\n        color=palette[optimizer],\n        alpha=alpha_map[optimizer],\n        linewidth=linewidth_map[optimizer],\n        ax=ax,\n        legend=False,\n    )\n\n# Vertical axis lines at each dimension\nfor i in range(len(numeric_cols)):\n    ax.axvline(x=i, color=INK_SOFT, linewidth=1.0, alpha=0.4, zorder=0)\n\n# Style\nlabel_by_col = {\n    \"learning_rate\": f\"Learning Rate\\n({df['learning_rate'].min():.1e} – {df['learning_rate'].max():.1e})\",\n    \"batch_size\": f\"Batch Size\\n({df['batch_size'].min():.0f} – {df['batch_size'].max():.0f})\",\n    \"dropout\": f\"Dropout\\n({df['dropout'].min():.2f} – {df['dropout'].max():.2f})\",\n    \"weight_decay\": f\"Weight Decay\\n({df['weight_decay'].min():.1e} – {df['weight_decay'].max():.1e})\",\n    \"val_accuracy\": f\"Val. Accuracy\\n({df['val_accuracy'].min() * 100:.0f}% – {df['val_accuracy'].max() * 100:.0f}%)\",\n}\nlabels = [label_by_col[col] for col in numeric_cols]\nax.set_xticks(range(len(numeric_cols)))\nax.set_xticklabels(labels, fontsize=8, color=INK_SOFT)\nax.tick_params(axis=\"y\", labelsize=8, colors=INK_SOFT)\n\nax.set_xlabel(\"\")\nax.set_ylabel(\"Normalized Value\", fontsize=10, color=INK)\nax.set_title(\"parallel-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.set_xlim(-0.3, len(numeric_cols) - 1 + 0.3)\nax.set_ylim(-0.05, 1.05)\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\n\nlegend_handles = [Line2D([0], [0], color=palette[opt], linewidth=2.2, alpha=0.9, label=opt) for opt in optimizer_order]\nlegend = ax.legend(\n    handles=legend_handles,\n    title=\"Optimizer\",\n    title_fontsize=9,\n    fontsize=8,\n    loc=\"upper left\",\n    bbox_to_anchor=(1.0, 1.02),\n    framealpha=0.92,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\nlegend.get_title().set_color(INK)\nfor text in legend.get_texts():\n    text.set_color(INK_SOFT)\n\n# Add min/max tick annotations on left axis\nfor val, label in [(0.0, \"Min\"), (1.0, \"Max\")]:\n    ax.text(\n        -0.11, val, label, transform=ax.get_yaxis_transform(), fontsize=7.5, color=INK_MUTED, ha=\"right\", va=\"center\"\n    )\n\n# Callout: highlight the key insight (Adam clusters toward higher accuracy)\nadam_acc = df.loc[df[\"optimizer\"] == \"Adam\", \"val_accuracy\"]\nax.annotate(\n    \"Adam configs cluster\\ntoward higher accuracy\",\n    xy=(\n        len(numeric_cols) - 1,\n        (adam_acc.mean() - df[\"val_accuracy\"].min()) / (df[\"val_accuracy\"].max() - df[\"val_accuracy\"].min()),\n    ),\n    xytext=(len(numeric_cols) - 1.85, 0.85),\n    fontsize=8,\n    color=INK,\n    ha=\"center\",\n    va=\"center\",\n    arrowprops={\"arrowstyle\": \"-\", \"color\": INK_SOFT, \"linewidth\": 0.8, \"alpha\": 0.7},\n    bbox={\n        \"boxstyle\": \"round,pad=0.35\",\n        \"facecolor\": ELEVATED_BG,\n        \"edgecolor\": INK_SOFT,\n        \"alpha\": 0.92,\n        \"linewidth\": 0.8,\n    },\n)\n\nfig.subplots_adjust(left=0.15, right=0.85, top=0.90, bottom=0.16)\n\n# Save\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}