Note
Go to the end to download the full example code.
Scatter (Advanced)¶
Scatter — advanced template (regression line + R² + outlier highlight).
Source: dartwork_mpl/asset/prompt/05-templates/advanced/scatter.py ·
MCP dartwork-mpl://template/advanced/scatter.

[VISUAL] ⚠️ TEXT_CONTRAST: Text contrast 1.92:1 is below the 4.5:1 AA threshold for normal text (sample: "SKU #47: price cut but volume didn't ...")
[VISUAL] 💡 TEXT_CONTRAST: Text contrast 3.32:1 is below the 4.5:1 AA threshold for normal text (sample: '60-SKU cross-section; the diamond mar...')
[VISUAL] ⚠️ TEXT_CONTRAST: Text contrast 2.07:1 is below the 4.5:1 AA threshold for normal text (sample: 'Source: synthetic 60-SKU cross-sectio...')
[VISUAL] 💡 GRAYSCALE_SAFETY: Data colors have near-identical grayscale luminance: #00c897/#ffa926
=== FIX SUGGESTIONS ===
[VISUAL] ⚠️ TEXT_CONTRAST: Text contrast 1.92:1 is below the 4.5:1 AA threshold for normal text (sample: "SKU #47: price cut but volume didn't ...")
[VISUAL] 💡 TEXT_CONTRAST: Text contrast 3.32:1 is below the 4.5:1 AA threshold for normal text (sample: '60-SKU cross-section; the diamond mar...')
[VISUAL] ⚠️ TEXT_CONTRAST: Text contrast 2.07:1 is below the 4.5:1 AA threshold for normal text (sample: 'Source: synthetic 60-SKU cross-sectio...')
[VISUAL] 💡 GRAYSCALE_SAFETY: Data colors have near-identical grayscale luminance: #00c897/#ffa926
# ai-template-meta-start
# tier: advanced
# basic_counterpart: scatter
# use_case: Two-variable relationship with regression fit, R-squared annotation, and outlier callout
# difficulty: intermediate
# data_shape: x: list[float], y: list[float]
# tags: scatter, correlation, regression, outlier, annotated, narrative
# narrative: Price vs. demand fit across 60 SKUs; one outlier flagged
# advanced_apis: np.polyfit, np.corrcoef, ax.annotate, axhline, dm.format_axis_currency, dm.validate_with_fixes
# ai-template-meta-end
import matplotlib.pyplot as plt
import numpy as np
import dartwork_mpl as dm
dm.style.use("scientific")
# Synthetic price vs. demand with one obvious outlier (SKU #47).
rng = np.random.default_rng(42)
n = 60
price = rng.uniform(8, 42, size=n)
demand = 220 - 3.4 * price + rng.normal(0, 14, size=n)
# Plant an outlier well above the trend.
outlier_idx = 47
price[outlier_idx] = 32.0
demand[outlier_idx] = 240.0
# Linear fit + R-squared (excluding the outlier so the line tells the
# "normal" story; the outlier then becomes obviously off-trend).
mask = np.arange(n) != outlier_idx
slope, intercept = np.polyfit(price[mask], demand[mask], 1)
fit_line = slope * np.sort(price) + intercept
r = np.corrcoef(price[mask], demand[mask])[0, 1]
r_squared = r * r
# How far the outlier sits above the fitted line, in %, computed from the
# data so the subtitle can never drift from what is actually plotted.
_outlier_fit = slope * price[outlier_idx] + intercept
outlier_pct = (demand[outlier_idx] - _outlier_fit) / _outlier_fit * 100
fig, ax = plt.subplots(figsize=dm.figsize("13cm", "square"))
# Cloud — semi-transparent so the line shows through.
ax.scatter(
price[mask],
demand[mask],
s=18,
color="dc.teal3",
edgecolor="white",
linewidth=0.3,
alpha=0.85,
label="SKU sample",
)
# Outlier — distinct color + marker.
ax.scatter(
price[outlier_idx],
demand[outlier_idx],
s=70,
color="dc.amber5",
edgecolor="white",
linewidth=0.5,
marker="D",
zorder=5,
label="Outlier SKU",
)
# Regression line — drawn on top of the cloud, under the outlier.
ax.plot(
np.sort(price), fit_line, color="dc.teal5", linewidth=dm.lw(0), zorder=4
)
# R-squared annotation in the upper-left, inside the axes.
ax.text(
0.04,
0.96,
f"$R^2 = {r_squared:.2f}$\n$\\beta = {slope:.1f}$ units / \\$",
transform=ax.transAxes,
ha="left",
va="top",
fontsize=dm.fs(-1),
color="oc.gray7",
bbox={
"boxstyle": "round,pad=0.3",
"fc": "white",
"ec": "oc.gray3",
"lw": 0.3,
},
)
# Outlier callout with arrow.
ax.annotate(
"SKU #47:\nprice cut\nbut volume\ndidn't follow",
xy=(price[outlier_idx], demand[outlier_idx]),
xytext=(price[outlier_idx] + 5, demand[outlier_idx] + 25),
fontsize=dm.fs(-1),
color="dc.amber5",
arrowprops={"arrowstyle": "->", "color": "dc.amber5", "lw": 0.5},
)
dm.format_axis_currency(ax, axis="x", symbol="$", decimals=0)
ax.set_xlabel("Unit price")
ax.set_ylabel("Weekly units sold")
ax.legend(loc="lower left", fontsize=dm.fs(-1), frameon=False)
ax.set_title(
"Demand falls cleanly with price — except one SKU",
fontsize=dm.fs(1),
fontweight=dm.fw(1),
loc="left",
pad=18,
)
ax.text(
0.0,
1.02,
f"60-SKU cross-section; the diamond marker sits "
f"{outlier_pct:.0f}% above the fitted line.",
transform=ax.transAxes,
ha="left",
va="bottom",
fontsize=dm.fs(-1),
color="oc.gray6",
)
fig.text(
0.01,
0.005,
"Source: synthetic 60-SKU cross-section (rng seed 42).",
fontsize=dm.fs(-2),
color="oc.gray5",
ha="left",
va="bottom",
)
dm.simple_layout(fig, margin=dm.inch(0.08))
dm.validate_with_fixes(fig)
issues = dm.check_figure_quality(fig)
if issues:
print(f"[scatter-advanced] quality issues: {issues}")
dm.save_formats(fig, "scatter_advanced")
Total running time of the script: (0 minutes 1.092 seconds)