{"spec_id":"scatter-regression-linear","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nscatter-regression-linear: Scatter Plot with Linear Regression\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens (Imprint palette — prompts/default-style-guide.md \"Theme-adaptive Chrome\")\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.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\nFONT_FAMILY = \"Arial, Helvetica, sans-serif\"\n\nBRAND = \"#009E73\"  # Imprint palette position 1 — ALWAYS first series\nACCENT = \"#C475FD\"  # Imprint palette position 2\n\n# Data - study hours vs exam scores (clipped to a realistic 0-100% range)\nnp.random.seed(42)\nn_points = 100\nstudy_hours = np.random.uniform(2, 10, n_points)\nnoise = np.random.normal(0, 6, n_points)\nexam_scores = np.clip(study_hours * 4.5 + 45 + noise, 0, 100)\n\n# Linear regression\nn = len(study_hours)\nx_mean = np.mean(study_hours)\nslope, intercept = np.polyfit(study_hours, exam_scores, 1)\n\ny_pred = slope * study_hours + intercept\nresiduals = exam_scores - y_pred\nss_res = np.sum(residuals**2)\nss_tot = np.sum((exam_scores - np.mean(exam_scores)) ** 2)\nr_squared = 1 - ss_res / ss_tot\n\n# Regression line and confidence interval\nx_line = np.linspace(study_hours.min() - 0.5, study_hours.max() + 0.5, 100)\ny_line = slope * x_line + intercept\n\n# Calculate 95% confidence interval\nss_xx = np.sum((study_hours - x_mean) ** 2)\nmse = ss_res / (n - 2)\nse_line = np.sqrt(mse * (1 / n + (x_line - x_mean) ** 2 / ss_xx))\nt_val = 1.98\nci_upper = y_line + t_val * se_line\nci_lower = y_line - t_val * se_line\n\n# Create figure\nfig = go.Figure()\n\n# Confidence interval band\nfig.add_trace(\n    go.Scatter(\n        x=np.concatenate([x_line, x_line[::-1]]),\n        y=np.concatenate([ci_upper, ci_lower[::-1]]),\n        fill=\"toself\",\n        fillcolor=\"rgba(0, 158, 115, 0.15)\",\n        line=dict(color=\"rgba(0, 158, 115, 0.35)\", width=1),\n        hoverinfo=\"skip\",\n        name=\"95% CI\",\n        showlegend=True,\n    )\n)\n\n# Scatter points\nfig.add_trace(\n    go.Scatter(\n        x=study_hours,\n        y=exam_scores,\n        mode=\"markers\",\n        marker=dict(size=8, color=BRAND, opacity=0.55, line=dict(width=0.5, color=PAGE_BG)),\n        name=\"Data points\",\n        hovertemplate=\"Study Hours: %{x:.1f}<br>Exam Score: %{y:.1f}<extra></extra>\",\n    )\n)\n\n# Regression line\nfig.add_trace(\n    go.Scatter(\n        x=x_line,\n        y=y_line,\n        mode=\"lines\",\n        line=dict(color=ACCENT, width=3),\n        name=f\"Linear Regression (R² = {r_squared:.3f})\",\n        hoverinfo=\"skip\",\n    )\n)\n\n# Equation annotation\nequation = f\"y = {slope:.2f}x + {intercept:.1f}\"\nfig.add_annotation(\n    x=0.98,\n    y=0.05,\n    xref=\"paper\",\n    yref=\"paper\",\n    text=f\"{equation}<br>R² = {r_squared:.3f}\",\n    showarrow=False,\n    font=dict(size=12, color=INK),\n    align=\"right\",\n    bgcolor=ELEVATED_BG,\n    borderpad=8,\n)\n\n# Layout\ntitle_text = \"scatter-regression-linear · python · plotly · anyplot.ai\"\nfig.update_layout(\n    autosize=False,\n    font=dict(family=FONT_FAMILY, color=INK),\n    title=dict(text=title_text, font=dict(size=16, color=INK), x=0.5, xanchor=\"center\"),\n    xaxis=dict(\n        title=dict(text=\"Study Hours per Day\", font=dict(size=12, color=INK)),\n        tickfont=dict(size=10, color=INK_SOFT),\n        gridcolor=GRID,\n        showgrid=True,\n        zeroline=False,\n        linecolor=INK_SOFT,\n        linewidth=1,\n        showspikes=True,\n        spikemode=\"across\",\n        spikesnap=\"cursor\",\n        spikedash=\"dot\",\n        spikecolor=INK_SOFT,\n        spikethickness=1,\n    ),\n    yaxis=dict(\n        title=dict(text=\"Exam Score (%)\", font=dict(size=12, color=INK)),\n        tickfont=dict(size=10, color=INK_SOFT),\n        gridcolor=GRID,\n        showgrid=True,\n        zeroline=False,\n        linecolor=INK_SOFT,\n        linewidth=1,\n        showspikes=True,\n        spikemode=\"across\",\n        spikesnap=\"cursor\",\n        spikedash=\"dot\",\n        spikecolor=INK_SOFT,\n        spikethickness=1,\n    ),\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    legend=dict(x=0.02, y=0.98, xanchor=\"left\", yanchor=\"top\", font=dict(size=10, color=INK_SOFT), bgcolor=ELEVATED_BG),\n    margin=dict(l=80, r=40, t=80, b=60),\n    hovermode=\"closest\",\n)\n\n# Save as PNG and HTML — hard target 3200x1800 (see prompts/library/plotly.md \"Canvas\")\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}