{"spec_id":"scatter-regression-linear","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nscatter-regression-linear: Scatter Plot with Linear Regression\nLibrary: matplotlib 3.11.1 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.transforms import blended_transform_factory\n\n\n# Theme tokens (Imprint)\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\"\nBRAND = \"#009E73\"  # Imprint palette position 1\nSECONDARY = \"#C475FD\"  # Imprint palette position 2, for regression line\n\n# Data: study hours vs exam scores (realistic educational context)\nnp.random.seed(42)\nn_points = 80\nx = np.random.uniform(1, 10, n_points)  # Study hours\nnoise = np.random.normal(0, 8, n_points)\ny = 35 + 6 * x + noise  # Exam scores\ny = np.clip(y, 20, 100)  # Realistic score range\n\n# Linear regression using numpy polyfit (leveraging library ecosystem)\ncoefficients = np.polyfit(x, y, 1)\nslope, intercept = coefficients[0], coefficients[1]\n\n# Coefficient of determination\ny_pred = np.polyval(coefficients, x)\nss_res = np.sum((y - y_pred) ** 2)\nss_tot = np.sum((y - np.mean(y)) ** 2)\nr_squared = 1 - (ss_res / ss_tot)\n\n# Largest residual: notable outlier worth calling out\noutlier_idx = np.argmax(np.abs(y - y_pred))\n\n# Regression line and 95% confidence interval\nx_line = np.linspace(x.min() - 0.5, x.max() + 0.5, 100)\ny_line = np.polyval(coefficients, x_line)\n\nx_mean = np.mean(x)\nss_xx = np.sum((x - x_mean) ** 2)\nse_y = np.sqrt(ss_res / (n_points - 2))\nse_line = se_y * np.sqrt(1 / n_points + (x_line - x_mean) ** 2 / ss_xx)\nt_val = 1.99  # 95% CI, df ~ 78\nci_upper = y_line + t_val * se_line\nci_lower = y_line - t_val * se_line\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Confidence interval band (SECONDARY color, low alpha)\nax.fill_between(x_line, ci_lower, ci_upper, alpha=0.2, color=SECONDARY, label=\"95% CI\", zorder=1)\n\n# Rug plot: marginal x-distribution along the bottom, drawn in a blended\n# transform (data x, axes y) so it hugs the axis regardless of y-range.\ntrans_x = blended_transform_factory(ax.transData, ax.transAxes)\nax.plot(x, np.full_like(x, 0.015), \"|\", transform=trans_x, color=BRAND, alpha=0.5, markersize=7, zorder=1)\n\n# Scatter points (BRAND green as first series)\nax.scatter(x, y, s=130, alpha=0.7, color=BRAND, edgecolors=PAGE_BG, linewidth=0.5, zorder=3)\n\n# Regression line (SECONDARY color)\nax.plot(x_line, y_line, color=SECONDARY, linewidth=2.5, label=\"Regression Line\", zorder=2)\n\n# Callout for the largest residual, showing how far the point strays from the fit\nax.annotate(\n    \"Largest residual\",\n    xy=(x[outlier_idx], y[outlier_idx]),\n    xytext=(x[outlier_idx] + 1.4, y[outlier_idx] + 10),\n    fontsize=8,\n    color=INK_SOFT,\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"linewidth\": 1},\n    zorder=4,\n)\n\n# Annotation: equation and R-squared\nequation = f\"y = {slope:.2f}x + {intercept:.2f}\"\nr_text = f\"R² = {r_squared:.3f}\"\nax.text(\n    0.04,\n    0.94,\n    f\"{equation}\\n{r_text}\",\n    transform=ax.transAxes,\n    fontsize=9,\n    verticalalignment=\"top\",\n    color=INK,\n    bbox={\"boxstyle\": \"round,pad=0.4\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.95},\n)\n\n# Title and axis labels (title short enough to use the default 12pt)\ntitle = \"scatter-regression-linear · python · matplotlib · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK)\nax.set_xlabel(\"Study Hours (hrs)\", fontsize=10, color=INK)\nax.set_ylabel(\"Exam Score (points)\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# Grid: both axes, subtle (scatter convention)\nax.grid(True, alpha=0.15, linewidth=0.8, color=INK)\nax.set_axisbelow(True)\n\n# Spine styling\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax.spines[spine].set_color(INK_SOFT)\n\n# Legend styling\nleg = ax.legend(fontsize=8, loc=\"lower right\")\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    leg.get_frame().set_linewidth(0.8)\n    for text in leg.get_texts():\n        text.set_color(INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}