{"spec_id":"ice-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nice-basic: Individual Conditional Expectation (ICE) Plot\nLibrary: plotly 6.9.0 | Python 3.13.15\nQuality: 90/100 | Updated: 2026-08-17\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prevent this file (plotly.py) from shadowing the plotly package\n_here = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.normpath(os.path.abspath(p or \".\")) != _here]\n\nimport numpy as np\nimport plotly.colors as pc\nimport plotly.graph_objects as go\nfrom sklearn.ensemble import GradientBoostingRegressor\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)\"\nBRAND = \"#009E73\"\n\n# Data — synthetic housing dataset\nnp.random.seed(42)\nn_houses = 120\n\nsqft = np.random.uniform(800, 3500, n_houses)\nbedrooms = np.random.randint(2, 6, n_houses).astype(float)\nhouse_age = np.random.uniform(1, 50, n_houses)\nlot_size = np.random.uniform(3000, 15000, n_houses)\nneighborhood_score = np.random.uniform(3, 10, n_houses)\n\nsale_price = (\n    150 * sqft\n    + 8000 * bedrooms\n    - 1200 * house_age\n    + 5 * lot_size\n    + 15000 * neighborhood_score\n    + np.random.normal(0, 25000, n_houses)\n)\n\nX = np.column_stack([sqft, bedrooms, house_age, lot_size, neighborhood_score])\nmodel = GradientBoostingRegressor(n_estimators=100, max_depth=4, random_state=42)\nmodel.fit(X, sale_price)\n\n# ICE predictions: vary square footage, hold all other features fixed per house\nsqft_grid = np.linspace(sqft.min(), sqft.max(), 80)\nice_preds = np.zeros((n_houses, len(sqft_grid)))\nfor j, val in enumerate(sqft_grid):\n    X_mod = X.copy()\n    X_mod[:, 0] = val\n    ice_preds[:, j] = model.predict(X_mod)\n\npdp = ice_preds.mean(axis=0)\n\n# ICE line colors from the Imprint sequential colormap, mapped to house age\nIMPRINT_SEQ = [\"#009E73\", \"#4467A3\"]\nage_norm = (house_age - house_age.min()) / (house_age.max() - house_age.min())\nraw_colors = pc.sample_colorscale(IMPRINT_SEQ, age_norm.tolist())\nice_colors = [c.replace(\"rgb(\", \"rgba(\").replace(\")\", \", 0.30)\") for c in raw_colors]\n\n# Plot\nfig = go.Figure()\n\n# ICE lines colored by house age (Imprint sequential)\nfor i in range(n_houses):\n    fig.add_trace(\n        go.Scatter(\n            x=sqft_grid,\n            y=ice_preds[i],\n            mode=\"lines\",\n            line=dict(width=1, color=ice_colors[i]),\n            showlegend=False,\n            hoverinfo=\"skip\",\n        )\n    )\n\n# PDP overlay — bold brand-green curve\nfig.add_trace(\n    go.Scatter(\n        x=sqft_grid,\n        y=pdp,\n        mode=\"lines\",\n        name=\"Partial Dependence (PDP)\",\n        line=dict(width=3.5, color=BRAND),\n        showlegend=True,\n    )\n)\n\n# Annotate the region where house-age most strongly separates predictions\nspread = ice_preds.max(axis=0) - ice_preds.min(axis=0)\ndivergence_idx = int(np.argmax(spread))\ndivergence_x = sqft_grid[divergence_idx]\ndivergence_y = ice_preds[:, divergence_idx].max()\n\n# Rug plot — distribution of observed square footage values\ny_range = ice_preds.max() - ice_preds.min()\ny_rug = ice_preds.min() - y_range * 0.05\nfig.add_trace(\n    go.Scatter(\n        x=sqft,\n        y=[y_rug] * n_houses,\n        mode=\"markers\",\n        marker=dict(symbol=\"line-ns\", size=10, color=INK_SOFT, line=dict(width=1, color=INK_SOFT)),\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\n\n# Dummy trace to render the house age colorbar\nfig.add_trace(\n    go.Scatter(\n        x=[None],\n        y=[None],\n        mode=\"markers\",\n        marker=dict(\n            colorscale=[[0.0, IMPRINT_SEQ[0]], [1.0, IMPRINT_SEQ[1]]],\n            color=[house_age.min(), house_age.max()],\n            cmin=house_age.min(),\n            cmax=house_age.max(),\n            colorbar=dict(\n                title=dict(text=\"House Age (yrs)\", font=dict(size=11, color=INK_SOFT)),\n                tickfont=dict(size=10, color=INK_SOFT),\n                thickness=14,\n                len=0.75,\n                x=1.02,\n                bgcolor=ELEVATED_BG,\n                bordercolor=INK_SOFT,\n                borderwidth=1,\n            ),\n            showscale=True,\n        ),\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\n\n# Style\nfig.update_layout(\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    title=dict(text=\"ice-basic · python · plotly · anyplot.ai\", font=dict(size=16, color=INK), x=0.5, xanchor=\"center\"),\n    xaxis=dict(\n        title=dict(text=\"Square Footage (sq ft)\", font=dict(size=12, color=INK)),\n        tickfont=dict(size=10, color=INK_SOFT),\n        gridcolor=GRID,\n        linecolor=INK_SOFT,\n        zerolinecolor=GRID,\n        showgrid=True,\n        mirror=False,\n    ),\n    yaxis=dict(\n        title=dict(text=\"Predicted Sale Price (USD)\", font=dict(size=12, color=INK)),\n        tickfont=dict(size=10, color=INK_SOFT),\n        gridcolor=GRID,\n        linecolor=INK_SOFT,\n        zerolinecolor=GRID,\n        showgrid=True,\n        tickformat=\"$,.0f\",\n        range=[y_rug - y_range * 0.02, ice_preds.max() + y_range * 0.03],\n    ),\n    legend=dict(\n        bgcolor=ELEVATED_BG,\n        bordercolor=INK_SOFT,\n        borderwidth=1,\n        font=dict(size=10, color=INK_SOFT),\n        x=0.02,\n        y=0.98,\n        xanchor=\"left\",\n        yanchor=\"top\",\n    ),\n    margin=dict(l=70, r=110, t=60, b=50),\n)\n\nfig.add_annotation(\n    x=divergence_x,\n    y=divergence_y,\n    text=\"House age divergence widest here\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=INK_SOFT,\n    ax=-120,\n    ay=50,\n    font=dict(size=10, color=INK),\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}