Scatter plots are the first look at correlation, clusters and outliers in any dataset.
ax.scatter(x, y) draws one marker per point without connecting them, which is what you want when the order of points means nothing. Its power is that size and color can encode two more variables:
s=marker area in points squared, a scalar or one value per point.c=a single color, or an array of numbers mapped through a colormap (cmap="viridis").alpha=transparency; essential when points overlap heavily.edgecolors="white"andlinewidths=to separate touching markers.
When c is numeric, scatter returns a PathCollection that knows its color mapping, so fig.colorbar(sc, ax=ax) adds a scale explaining the colors.
Note that s is an area, not a radius: doubling s makes markers look about 1.4 times wider. If you map a variable to s, scale it so the smallest values are still visible.
For a single plain color and thousands of points, ax.plot(x, y, "o", linestyle="none") is noticeably faster than scatter, because it creates one line object instead of a collection with per-point properties. For hundreds of thousands of points, overplotting makes any scatter unreadable; consider alpha, a hexbin or a 2D histogram instead.
Example
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(0)
x = rng.normal(size=200)
y = 2 * x + rng.normal(size=200)
size = rng.uniform(10, 80, size=200)
fig, ax = plt.subplots()
sc = ax.scatter(x, y, s=size, c=y, cmap="viridis", alpha=0.7)
fig.colorbar(sc, ax=ax, label="y value")
print(type(sc).__name__) # PathCollection
print(sc.get_offsets().shape) # (200, 2)
print(np.corrcoef(x, y)[0, 1].round(2)) # 0.88 (strong positive)
fig.savefig("scatter.png")Remember
- Use scatter when point order has no meaning
ssets marker area andcpluscmapmaps a variable to color- Add
fig.colorbar(sc, ax=ax)whenever color encodes numbers
Watch out for
- Passing a radius-like value to
s, which is an area, so sizes look exaggerated.