0
# Objects Interface
1
2
A declarative, object-oriented interface for creating statistical graphics following the Grammar of Graphics approach. The objects interface provides composable classes that can be combined to build customized visualizations through method chaining and layer composition.
3
4
**Core Concept**: Specify what you want to show rather than how to draw it. Build plots by combining data, marks, statistical transformations, positional adjustments, and scales.
5
6
## Core Imports
7
8
```python
9
from seaborn.objects import Plot
10
```
11
12
Common imports for marks, stats, and moves:
13
14
```python
15
from seaborn.objects import (
16
Plot,
17
# Marks
18
Dot, Dots, Line, Lines, Path, Bar, Bars, Area, Band, Text,
19
# Stats
20
Stat, Agg, Est, Count, Hist, KDE,
21
# Moves
22
Move, Dodge, Jitter, Stack, Shift, Norm,
23
# Scales
24
Scale, Continuous, Nominal, Boolean, Temporal
25
)
26
```
27
28
## Capabilities
29
30
### Plot Orchestration
31
32
The main interface for declarative plotting that orchestrates data, marks, stats, and scales.
33
34
```python { .api }
35
class Plot:
36
def __init__(self, *args, data=None, **variables):
37
"""
38
Initialize plot with data source and variable mappings.
39
40
Parameters:
41
- data: DataFrame or dict with columnar data
42
- **variables: mappings from variables to data columns (x=, y=, color= etc.)
43
"""
44
45
def add(self, mark, *transforms, orient=None, legend=True, label=None, data=None, **variables):
46
"""
47
Add a layer with mark and optional transforms.
48
49
Parameters:
50
- mark: Mark instance defining visual representation
51
- *transforms: Stat and/or Move instances for data transformation
52
- orient: "x" or "y" orientation, inferred if not specified
53
- legend: whether to include layer in legend
54
- label: label for legend entry
55
- data: override data source for this layer
56
- **variables: additional variable mappings for this layer
57
58
Returns:
59
Plot instance for method chaining
60
"""
61
62
def facet(self, col=None, row=None, order=None, wrap=None):
63
"""
64
Create subplots with conditional data subsets.
65
66
Parameters:
67
- col: variable for subplot columns
68
- row: variable for subplot rows
69
- order: dict specifying order of facet levels
70
- wrap: wrap columns after this number
71
72
Returns:
73
Plot instance for method chaining
74
"""
75
76
def pair(self, x=None, y=None, wrap=None, cross=True):
77
"""
78
Create subplots by pairing multiple x/y variables.
79
80
Parameters:
81
- x: list of variables for x-axis pairing
82
- y: list of variables for y-axis pairing
83
- wrap: wrap columns after this number
84
- cross: if False, pair variables in order rather than crossing
85
86
Returns:
87
Plot instance for method chaining
88
"""
89
90
def scale(self, **scales):
91
"""
92
Specify data-to-visual property mappings.
93
94
Parameters:
95
- x, y: Scale instances for coordinate mappings
96
- color, fill, linestyle, etc.: Scale instances for aesthetic mappings
97
98
Returns:
99
Plot instance for method chaining
100
"""
101
102
def share(self, **shares):
103
"""
104
Control sharing of axis limits/ticks across subplots.
105
106
Parameters:
107
- x, y: True (share all), False (independent), or "col"/"row" (share within)
108
109
Returns:
110
Plot instance for method chaining
111
"""
112
113
def limit(self, **limits):
114
"""
115
Control range of visible data.
116
117
Parameters:
118
- x, y: tuple of (min, max) values or single values for symmetric limits
119
120
Returns:
121
Plot instance for method chaining
122
"""
123
124
def label(self, title=None, legend=None, **variables):
125
"""
126
Control labels for axes, legends, and subplots.
127
128
Parameters:
129
- title: main plot title
130
- legend: legend title
131
- **variables: axis labels (x=, y=, color= etc.)
132
133
Returns:
134
Plot instance for method chaining
135
"""
136
137
def layout(self, size=None, engine=None, extent=None):
138
"""
139
Control figure size and layout.
140
141
Parameters:
142
- size: tuple of (width, height) in inches
143
- engine: layout engine ("constrained" or "tight")
144
- extent: subplot area as fraction of figure
145
146
Returns:
147
Plot instance for method chaining
148
"""
149
150
def theme(self, config):
151
"""
152
Control plot appearance via matplotlib rc parameters.
153
154
Parameters:
155
- config: dict of matplotlib rcParams
156
157
Returns:
158
Plot instance for method chaining
159
"""
160
161
def on(self, target):
162
"""
163
Use existing matplotlib figure/axes for drawing.
164
165
Parameters:
166
- target: matplotlib Figure, Axes, or SubFigure
167
168
Returns:
169
Plot instance for method chaining
170
"""
171
172
def save(self, loc, **kwargs):
173
"""
174
Compile and save plot to file.
175
176
Parameters:
177
- loc: output filename or path-like object
178
- **kwargs: additional arguments passed to matplotlib savefig
179
180
Returns:
181
Plot instance for method chaining
182
"""
183
184
def show(self, **kwargs):
185
"""
186
Compile and display plot.
187
188
Parameters:
189
- **kwargs: additional arguments passed to matplotlib show
190
"""
191
```
192
193
### Mark Classes
194
195
Visual representation of data through matplotlib artists.
196
197
```python { .api }
198
class Mark:
199
"""Base class for visual representations of data."""
200
def _mappable_props(self):
201
"""Properties that can be mapped from data."""
202
203
def _grouping_props(self):
204
"""Properties used for grouping data."""
205
206
class Dot(Mark):
207
"""A mark suitable for dot plots or scatter plots."""
208
marker: str = "o"
209
pointsize: float = 6
210
stroke: float = 0.75
211
color: str = "C0"
212
alpha: float = 1
213
fill: bool = True
214
edgecolor: str = "auto"
215
edgealpha: float = "auto"
216
edgewidth: float = 0.5
217
edgestyle: str = "-"
218
219
class Dots(Mark):
220
"""Dot mark optimized for handling overplotting with stroke-defined points."""
221
marker: str = "o"
222
pointsize: float = 4
223
stroke: float = 0.75
224
color: str = "C0"
225
alpha: float = 1
226
fill: bool = True
227
fillcolor: str = "auto"
228
fillalpha: float = 0.2
229
230
class Line(Mark):
231
"""Connect data points with lines, sorting along orientation axis."""
232
color: str = "C0"
233
alpha: float = 1
234
linewidth: float = "auto"
235
linestyle: str = "-"
236
marker: str = ""
237
pointsize: float = "auto"
238
fillcolor: str = "auto"
239
edgecolor: str = "auto"
240
edgewidth: float = "auto"
241
242
class Lines(Mark):
243
"""Faster line mark using matplotlib LineCollection for many lines."""
244
color: str = "C0"
245
alpha: float = 1
246
linewidth: float = "auto"
247
linestyle: str = "-"
248
249
class Path(Mark):
250
"""Connect data points in order they appear without sorting."""
251
# Same properties as Line
252
253
class Range(Lines):
254
"""Oriented line marks between min/max values."""
255
# Inherits properties from Lines
256
257
class Dash(Lines):
258
"""Line mark as oriented segments for each datapoint."""
259
width: float = 0.8
260
261
class Bar(Mark):
262
"""Bar mark drawn between baseline and data values."""
263
color: str = "C0"
264
alpha: float = 0.7
265
fill: bool = True
266
edgecolor: str = "auto"
267
edgealpha: float = 1
268
edgewidth: float = "auto"
269
edgestyle: str = "-"
270
width: float = 0.8
271
baseline: float = 0
272
273
class Bars(Mark):
274
"""Optimized bar mark with defaults for histograms."""
275
# Similar properties to Bar with histogram-optimized defaults
276
277
class Area(Mark):
278
"""Fill mark drawn from baseline to data values."""
279
color: str = "C0"
280
alpha: float = 0.2
281
fill: bool = True
282
edgecolor: str = "auto"
283
edgealpha: float = 1
284
edgewidth: float = "auto"
285
edgestyle: str = "-"
286
baseline: float = 0
287
288
class Band(Mark):
289
"""Fill mark representing interval between min and max values."""
290
color: str = "C0"
291
alpha: float = 0.2
292
fill: bool = True
293
edgecolor: str = "auto"
294
edgealpha: float = 1
295
edgewidth: float = 0
296
edgestyle: str = "-"
297
298
class Text(Mark):
299
"""Textual mark to annotate or represent data values."""
300
text: str = ""
301
color: str = "k"
302
alpha: float = 1
303
fontsize: float = "auto"
304
halign: str = "center"
305
valign: str = "center_baseline"
306
offset: float = 4
307
```
308
309
### Statistical Transformations
310
311
Apply statistical transforms before plotting.
312
313
```python { .api }
314
class Stat:
315
"""Base class for statistical transformations."""
316
group_by_orient: bool = False
317
318
def __call__(self, data, groupby, orient, scales):
319
"""Apply statistical transform to data subgroups."""
320
321
class Agg(Stat):
322
"""Aggregate data along value axis using given method."""
323
func: str | callable = "mean"
324
group_by_orient: bool = True
325
326
class Est(Stat):
327
"""Calculate point estimate and error bar interval."""
328
func: str | callable = "mean"
329
errorbar: str | tuple = ("ci", 95)
330
n_boot: int = 1000
331
seed: int | None = None
332
group_by_orient: bool = True
333
334
class Count(Stat):
335
"""Count distinct observations within groups."""
336
group_by_orient: bool = True
337
338
class Hist(Stat):
339
"""Bin observations, count them, optionally normalize/cumulate."""
340
stat: str = "count" # "count", "density", "percent", "probability", "frequency"
341
bins: str | int | list = "auto"
342
binwidth: float | None = None
343
binrange: tuple | None = None
344
common_norm: bool | list = True
345
common_bins: bool | list = True
346
cumulative: bool = False
347
discrete: bool = False
348
349
class KDE(Stat):
350
"""Compute univariate kernel density estimate."""
351
bw_adjust: float = 1
352
bw_method: str | float | callable = "scott"
353
common_norm: bool | list = True
354
common_grid: bool | list = True
355
gridsize: int | None = 200
356
cut: float = 3
357
cumulative: bool = False
358
359
class Perc(Stat):
360
"""Replace data values with percentile ranks."""
361
k: int = 100
362
method: str = "linear"
363
364
class PolyFit(Stat):
365
"""Fit a polynomial regression of given order."""
366
order: int = 2
367
gridsize: int = 100
368
```
369
370
### Positional Adjustments
371
372
Make positional adjustments to reduce overplotting or achieve specific layouts.
373
374
```python { .api }
375
class Move:
376
"""Base class for positional transforms."""
377
group_by_orient: bool = True
378
379
def __call__(self, data, groupby, orient, scales):
380
"""Apply positional transform and return modified data."""
381
382
class Jitter(Move):
383
"""Random displacement along axes to reduce overplotting."""
384
width: float = "auto" # Relative to mark width
385
x: float = 0 # Absolute displacement in x
386
y: float = 0 # Absolute displacement in y
387
seed: int | None = None
388
389
class Dodge(Move):
390
"""Displacement/narrowing of overlapping marks along orientation."""
391
empty: str = "keep" # "keep", "drop", "fill"
392
gap: float = 0
393
by: list | None = None
394
395
class Stack(Move):
396
"""Displacement of overlapping bars/areas along value axis."""
397
# No additional parameters
398
399
class Shift(Move):
400
"""Displacement of all marks with same magnitude/direction."""
401
x: float = 0
402
y: float = 0
403
404
class Norm(Move):
405
"""Divisive scaling on value axis after aggregating within groups."""
406
func: str | callable = "max"
407
where: str | None = None # Query string for subset
408
by: list | None = None # Variables for aggregation groups
409
percent: bool = False
410
group_by_orient: bool = False
411
```
412
413
### Scale Classes
414
415
Control mappings between data values and visual properties.
416
417
```python { .api }
418
class Scale:
419
"""Base class for data-to-visual mappings."""
420
def __call__(self, data):
421
"""Transform data through the scale pipeline."""
422
423
def tick(self, **kwargs):
424
"""Configure tick selection."""
425
426
def label(self, **kwargs):
427
"""Configure label formatting."""
428
429
class Continuous(Scale):
430
"""Numeric scale supporting norms and functional transforms."""
431
values: tuple | str | None = None
432
trans: str | None = None # "log", "sqrt", "symlog", etc.
433
434
def tick(self, locator=None, *, at=None, upto=None, count=None, every=None, between=None, minor=None):
435
"""Configure tick selection for axis/legend."""
436
437
def label(self, formatter=None, *, like=None, base=None, unit=None):
438
"""Configure tick label appearance."""
439
440
class Nominal(Scale):
441
"""Categorical scale without relative importance/magnitude."""
442
values: tuple | str | list | dict | None = None
443
order: list | None = None
444
445
def tick(self, locator=None):
446
"""Configure tick selection."""
447
448
def label(self, formatter=None):
449
"""Configure label formatting."""
450
451
class Boolean(Scale):
452
"""Scale with discrete domain of True/False values."""
453
values: tuple | list | dict | None = None
454
455
def tick(self, locator=None):
456
"""Configure tick selection."""
457
458
def label(self, formatter=None):
459
"""Configure label formatting."""
460
461
class Temporal(Scale):
462
"""Scale for date/time data."""
463
# No transforms available for temporal data
464
465
def tick(self, locator=None, *, upto=None):
466
"""Configure tick selection for dates."""
467
468
def label(self, formatter=None, *, concise=False):
469
"""Configure date label formatting."""
470
```
471
472
## Usage Examples
473
474
### Basic Plot Construction
475
476
```python
477
import seaborn.objects as so
478
import pandas as pd
479
480
# Load data
481
tips = sns.load_dataset("tips")
482
483
# Basic scatter plot
484
(
485
so.Plot(tips, x="total_bill", y="tip")
486
.add(so.Dot())
487
.show()
488
)
489
```
490
491
### Multi-layer Plot with Statistics
492
493
```python
494
# Scatter plot with regression line
495
(
496
so.Plot(tips, x="total_bill", y="tip")
497
.add(so.Dot(alpha=0.5))
498
.add(so.Line(), so.PolyFit(order=1))
499
.label(
500
title="Bill vs Tip with Regression",
501
x="Total Bill ($)",
502
y="Tip ($)"
503
)
504
.show()
505
)
506
```
507
508
### Grouped Data with Aesthetics
509
510
```python
511
# Grouped scatter plot with color mapping
512
(
513
so.Plot(tips, x="total_bill", y="tip", color="time")
514
.add(so.Dot())
515
.scale(color=so.Nominal(values=["skyblue", "orange"]))
516
.show()
517
)
518
```
519
520
### Histogram with Custom Styling
521
522
```python
523
# Histogram with custom bins and styling
524
(
525
so.Plot(tips, x="total_bill")
526
.add(so.Bar(), so.Hist(bins=20))
527
.layout(size=(8, 5))
528
.label(
529
title="Distribution of Total Bills",
530
x="Total Bill ($)",
531
y="Count"
532
)
533
.show()
534
)
535
```
536
537
### Faceted Plot
538
539
```python
540
# Faceted scatter plots
541
(
542
so.Plot(tips, x="total_bill", y="tip")
543
.add(so.Dot(alpha=0.7))
544
.facet(col="time", row="smoker")
545
.label(title="Tips by Time and Smoking Status")
546
.show()
547
)
548
```
549
550
### Advanced Layering with Moves
551
552
```python
553
# Box plot with jittered points
554
(
555
so.Plot(tips, x="day", y="total_bill")
556
.add(so.Range(color="gray"), so.Est(errorbar="sd"))
557
.add(so.Dot(alpha=0.3), so.Jitter(width=0.3))
558
.show()
559
)
560
```
561
562
### Multiple Variables and Pairing
563
564
```python
565
# Pair plot using objects interface
566
numeric_cols = ["total_bill", "tip", "size"]
567
(
568
so.Plot(tips[numeric_cols])
569
.pair(cross=True)
570
.add(so.Dot(alpha=0.5))
571
.show()
572
)
573
```
574
575
### Custom Scales and Transformations
576
577
```python
578
# Log-scale plot with custom color palette
579
(
580
so.Plot(tips, x="total_bill", y="tip", color="size")
581
.add(so.Dot())
582
.scale(
583
x=so.Continuous(trans="log"),
584
color=so.Continuous(values=("lightblue", "darkred"))
585
)
586
.show()
587
)
588
```
589
590
### Stacked Bar Chart
591
592
```python
593
# Stacked bar chart with custom colors
594
(
595
so.Plot(tips, x="day", color="smoker")
596
.add(so.Bar(), so.Count(), so.Stack())
597
.scale(color=so.Nominal(values=["lightcoral", "steelblue"]))
598
.show()
599
)
600
```
601
602
### Text Annotations
603
604
```python
605
# Scatter plot with text labels
606
(
607
so.Plot(tips.head(10), x="total_bill", y="tip")
608
.add(so.Dot())
609
.add(so.Text(text="size"), text="size", offset=8)
610
.show()
611
)
612
```
613
614
## Workflow Pattern
615
616
The typical workflow follows this pattern:
617
618
1. **Initialize**: `so.Plot(data, x=..., y=..., **aesthetics)`
619
2. **Add Layers**: `.add(Mark(), Stat(), Move())` - can chain multiple
620
3. **Configure Scales**: `.scale(x=Scale(), color=Scale(), ...)`
621
4. **Setup Subplots**: `.facet()` or `.pair()` if needed
622
5. **Customize**: `.label()`, `.layout()`, `.theme()`, `.limit()`, `.share()`
623
6. **Render**: `.show()` or `.save()`
624
625
Each method returns a new Plot instance, enabling flexible method chaining and reusable plot specifications.
626
627
## Types
628
629
```python { .api }
630
# Data types
631
DataFrame = pandas.DataFrame
632
Series = pandas.Series
633
ArrayLike = numpy.ndarray | list
634
635
# Property value types
636
Mappable = Any # Direct values, data column references, or special mappings
637
ColorSpec = str | tuple # Color names, hex codes, RGB tuples
638
MarkerSpec = str # Matplotlib marker codes
639
LineStyleSpec = str | tuple # Matplotlib linestyle codes
640
641
# Scale value specifications
642
ScaleValues = tuple | str | list | dict | None
643
TransformSpec = str | tuple[callable, callable] | None
644
645
# Layout specifications
646
SizeSpec = tuple[float, float] # (width, height) in inches
647
LimitSpec = tuple[float, float] | float # (min, max) or symmetric limit
648
```