Default seaborn settings that are fine on a thousand rows can take minutes or produce unreadable blobs on a million.
Most seaborn slowness on big data comes from three sources.
Bootstrapped error bars. Each aggregated point resamples its group n_boot times. With many groups and millions of rows this dominates. Use errorbar=None, errorbar="se", or pre-aggregate with pandas and plot the summary with errorbar=None.
Per-point artists. scatterplot, stripplot and especially swarmplot draw every observation. Swarm placement is quadratic and becomes unusable beyond a few thousand points per category. Alternatives:
- 2D histograms:
sns.histplot(data=df, x=..., y=..., bins=50)or Matplotlib'shexbin; - distribution summaries:
boxenplot(designed for large n) orviolinplot; - a random sample:
df.sample(5_000, random_state=0)for the scatter layer, while statistics use all rows.
KDE on huge arrays. kdeplot evaluates a kernel per point on a grid; histograms with many bins are much faster and show the same shape at that scale.
Also, high-cardinality hue (hundreds of levels) builds a huge legend and many artists; aggregate or filter first. Converting string columns to pandas category dtype speeds up grouping and fixes their order.
Profile with a timer before and after: often one argument, such as errorbar=None, turns a minute-long plot into a second.
Example
import matplotlib
matplotlib.use("Agg")
import time
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
rng = np.random.default_rng(10)
n = 200_000
df = pd.DataFrame({"x": rng.integers(0, 20, n), "g": rng.choice(list("abcd"), n)})
df["y"] = df.x * 0.5 + rng.normal(0, 3, n)
def timed(**kw):
fig, ax = plt.subplots()
t = time.perf_counter()
sns.lineplot(data=df, x="x", y="y", hue="g", ax=ax, **kw)
plt.close(fig)
return time.perf_counter() - t
slow, fast = timed(n_boot=200), timed(errorbar=None)
print(fast < slow) # True: skipping the bootstrap is much faster
ax = sns.histplot(data=df, x="x", y="y", bins=(20, 40), cmap="mako") # not a 200k scatter
ax.figure.savefig("big.png")Remember
- Bootstraps dominate cost: use
errorbar=Noneor 'se' on big data - Replace large scatters and swarms with 2D histograms, boxen plots or samples
- Profile one change at a time; often one argument fixes the speed
Watch out for
- Using swarmplot on tens of thousands of points, which is extremely slow and overflows the category width.