{"spec_id":"line-loss-training","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nline-loss-training: Training Loss Curve\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nTRAIN_COLOR = \"#009E73\"  # Position 1 - bluish green (brand)\nVAL_COLOR = \"#C475FD\"  # Position 2 - vermillion\n\n# Data - Simulated neural network training with different trajectory\nnp.random.seed(42)\nepochs = np.arange(1, 71)  # 70 epochs (differentiate from 100-epoch letsplot)\n\n# Training loss: linear-like decay with small noise, flattens near end\ntrain_base = 2.0 - 0.025 * epochs + np.random.normal(0, 0.025, len(epochs))\ntrain_loss = np.maximum(train_base, 0.1)\n\n# Validation loss: similar pattern but with larger noise and divergence after epoch ~45\nval_base = 2.0 - 0.020 * epochs + np.random.normal(0, 0.04, len(epochs))\n# Add gentle divergence effect\ndivergence_effect = np.where(epochs > 45, 0.015 * np.sqrt(np.maximum(epochs - 45, 0)), 0)\nval_loss = val_base + divergence_effect\nval_loss = np.maximum(val_loss, 0.15)\n\n# Find minimum validation loss epoch\nmin_val_idx = np.argmin(val_loss)\nmin_val_epoch = epochs[min_val_idx]\nmin_val_loss = val_loss[min_val_idx]\n\n# Create figure\nfig = go.Figure()\n\n# Training loss curve\nfig.add_trace(\n    go.Scatter(\n        x=epochs,\n        y=train_loss,\n        mode=\"lines\",\n        name=\"Training Loss\",\n        line=dict(color=TRAIN_COLOR, width=4),\n        hovertemplate=\"Epoch %{x}<br>Training Loss: %{y:.3f}<extra></extra>\",\n    )\n)\n\n# Validation loss curve\nfig.add_trace(\n    go.Scatter(\n        x=epochs,\n        y=val_loss,\n        mode=\"lines\",\n        name=\"Validation Loss\",\n        line=dict(color=VAL_COLOR, width=4),\n        hovertemplate=\"Epoch %{x}<br>Validation Loss: %{y:.3f}<extra></extra>\",\n    )\n)\n\n# Optimal stopping point marker\nfig.add_trace(\n    go.Scatter(\n        x=[min_val_epoch],\n        y=[min_val_loss],\n        mode=\"markers\",\n        name=\"Optimal Epoch\",\n        marker=dict(color=VAL_COLOR, size=20, symbol=\"diamond\", line=dict(color=INK, width=2)),\n        hovertemplate=\"Optimal Epoch: %{x}<br>Min Validation Loss: %{y:.3f}<extra></extra>\",\n    )\n)\n\n# Add vertical line at optimal epoch using shape\nfig.add_shape(\n    type=\"line\",\n    x0=min_val_epoch,\n    x1=min_val_epoch,\n    y0=0,\n    y1=max(train_loss.max(), val_loss.max()),\n    line=dict(color=VAL_COLOR, width=1.5, dash=\"dash\"),\n    opacity=0.3,\n)\n\n# Update layout with theme-adaptive styling\nfig.update_layout(\n    title=dict(text=\"line-loss-training · plotly · anyplot.ai\", font=dict(size=28, color=INK), x=0.5, xanchor=\"center\"),\n    xaxis=dict(\n        title=dict(text=\"Epoch\", font=dict(size=22, color=INK)),\n        tickfont=dict(size=18, color=INK_SOFT),\n        gridcolor=GRID,\n        gridwidth=1,\n        linecolor=INK_SOFT,\n        linewidth=1.5,\n        zerolinecolor=INK_SOFT,\n        zerolinewidth=0,\n    ),\n    yaxis=dict(\n        title=dict(text=\"Cross-Entropy Loss\", font=dict(size=22, color=INK)),\n        tickfont=dict(size=18, color=INK_SOFT),\n        gridcolor=GRID,\n        gridwidth=1,\n        linecolor=INK_SOFT,\n        linewidth=1.5,\n        zerolinecolor=INK_SOFT,\n        zerolinewidth=0,\n    ),\n    legend=dict(\n        font=dict(size=18, color=INK_SOFT), bgcolor=ELEVATED_BG, bordercolor=INK_SOFT, borderwidth=1.5, x=0.72, y=0.97\n    ),\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    margin=dict(l=120, r=100, t=110, b=110),\n    hovermode=\"x unified\",\n)\n\n# Save outputs\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}