{"spec_id":"residual-plot","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nresidual-plot: Residual Plot\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove script directory from path to avoid importing local altair.py\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != script_dir]\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\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\nOKABE_ITO_1 = \"#009E73\"  # Brand green for main data\nOUTLIER_COLOR = \"#AE3030\"  # imprint red — outliers (>2σ)\n\n# Data: Simulate a linear regression scenario with some non-linearity\nnp.random.seed(42)\nn = 150\n\n# Generate realistic housing price prediction scenario\nx = np.linspace(1000, 3000, n)  # House size in sq ft\nnoise = np.random.randn(n) * 15000\ny_true = 50000 + 150 * x + 0.02 * (x - 2000) ** 2 + noise  # True prices with slight curvature\ny_pred = 50000 + 155 * x  # Linear model predictions\n\nresiduals = y_true - y_pred\nstd_residual = np.std(residuals)\n\n# Identify outliers (beyond ±2 standard deviations)\nis_outlier = np.abs(residuals) > 2 * std_residual\n\n# Create DataFrame\ndf = pd.DataFrame(\n    {\n        \"Fitted Values ($)\": y_pred,\n        \"Residuals ($)\": residuals,\n        \"Outlier\": np.where(is_outlier, \"Outlier (>2σ)\", \"Normal\"),\n    }\n)\n\n# Base scatter plot with color encoding for outliers\nscatter = (\n    alt.Chart(df)\n    .mark_point(size=120, opacity=0.7)\n    .encode(\n        x=alt.X(\"Fitted Values ($):Q\", title=\"Fitted Values ($)\", scale=alt.Scale(nice=True)),\n        y=alt.Y(\"Residuals ($):Q\", title=\"Residuals ($)\", scale=alt.Scale(nice=True)),\n        color=alt.Color(\n            \"Outlier:N\",\n            scale=alt.Scale(domain=[\"Normal\", \"Outlier (>2σ)\"], range=[OKABE_ITO_1, OUTLIER_COLOR]),\n            legend=alt.Legend(title=\"Point Type\", titleFontSize=18, labelFontSize=16),\n        ),\n        tooltip=[\"Fitted Values ($):Q\", \"Residuals ($):Q\", \"Outlier:N\"],\n    )\n)\n\n# Zero reference line\nzero_line = (\n    alt.Chart(pd.DataFrame({\"y\": [0]})).mark_rule(color=INK_SOFT, strokeWidth=2, strokeDash=[8, 4]).encode(y=\"y:Q\")\n)\n\n# ±2 standard deviation bands\nbands_df = pd.DataFrame({\"y\": [2 * std_residual, -2 * std_residual], \"label\": [\"+2σ\", \"-2σ\"]})\n\nband_lines = alt.Chart(bands_df).mark_rule(color=INK_SOFT, strokeWidth=1.5, strokeDash=[4, 4]).encode(y=\"y:Q\")\n\n# Add LOWESS-like trend using polynomial regression\nloess_df = df.copy()\nloess_df = loess_df.sort_values(\"Fitted Values ($)\")\n\nloess_line = (\n    alt.Chart(loess_df)\n    .transform_loess(\"Fitted Values ($)\", \"Residuals ($)\", bandwidth=0.3)\n    .mark_line(color=INK_SOFT, strokeWidth=3)\n    .encode(x=\"Fitted Values ($):Q\", y=\"Residuals ($):Q\")\n)\n\n# Combine all layers\nchart = (\n    alt.layer(zero_line, band_lines, scatter, loess_line)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(text=\"residual-plot · altair · anyplot.ai\", fontSize=28, anchor=\"middle\"),\n    )\n    .configure_view(strokeWidth=0, fill=PAGE_BG)\n    .configure_axis(\n        labelFontSize=18,\n        titleFontSize=22,\n        gridOpacity=0.10,\n        domainColor=INK_SOFT,\n        tickColor=INK_SOFT,\n        gridColor=INK,\n        labelColor=INK_SOFT,\n        titleColor=INK,\n    )\n    .configure_title(color=INK)\n    .configure_legend(\n        fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK, orient=\"right\", padding=10\n    )\n)\n\n# Save outputs\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\nchart.save(f\"plot-{THEME}.html\")\n"}