seaborn.objects makes complex layered, faceted plots explicit and composable instead of hunting for function-specific parameters.
seaborn.objects (conventionally import seaborn.objects as so) is a newer, declarative API. You build a so.Plot specification step by step:
(so.Plot(df, x="week", y="minutes", color="plan")
.add(so.Line(), so.Agg())
.add(so.Band(), so.Est(errorbar="se"))
.facet(col="region")
.label(x="Week", y="Minutes"))The pieces:
- Marks draw:
Dot,Dots,Line,Lines,Path,Bar,Bars,Area,Band,Range,Dash,Text. - Stats transform data before drawing:
Agg(mean by default),Est(estimate with error interval),Hist,KDE,Count,Perc,PolyFit. - Moves adjust positions:
Dodge,Stack,Jitter,Shift,Norm. - Plot methods:
.add(mark, stat, move, **variables)adds a layer,.facet(col=, row=, wrap=),.pair(x=[...]),.scale(...),.limit(...),.label(...),.layout(size=...),.theme({...}),.share(...).
Each method returns a new Plot, so specifications are immutable and reusable: define a base plot and derive variants. Nothing is drawn until the plot is displayed in a notebook, .show(), .save("file.png"), or compiled with .plot().
Variables can be set on Plot for all layers or on a single .add call. .on(ax) or .on(fig) draws into an existing Matplotlib Axes or figure, so you can mix with classic code.
The API is still marked experimental in 0.13, but it covers most common plots.
Example
import matplotlib
matplotlib.use("Agg")
import seaborn as sns
import seaborn.objects as so
import pandas as pd
import numpy as np
rng = np.random.default_rng(8)
df = pd.DataFrame({"week": np.tile(np.arange(1, 7), 40),
"plan": np.repeat(["free", "pro"], 120),
"region": np.tile(np.repeat(["eu", "us"], 6), 20)})
df["minutes"] = 20 + 3 * df.week + (df.plan == "pro") * 8 + rng.normal(0, 6, 240)
base = so.Plot(df, x="week", y="minutes", color="plan")
p = (base.add(so.Line(marker="o"), so.Agg())
.add(so.Band(), so.Est(errorbar="se"))
.facet(col="region")
.label(x="Week", y="Minutes per day")
.layout(size=(8, 3.5)))
plotter = p.plot() # compile without showing
print(len(plotter._figure.axes)) # 2: one per region
p.save("objects.png")
print(type(base).__name__, base is p) # Plot False: methods return new PlotsRemember
- Compose
so.Plot(...)with.add(mark, stat, move)layers - Marks draw, stats transform, moves adjust positions
- Plot methods return new objects; nothing renders until shown, saved or plotted
Watch out for
- Expecting
.add(...)to modify a Plot in place; it returns a new Plot you must keep.