CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-seaborn

Statistical data visualization library for Python built on matplotlib

Pending
Overview
Eval results
Files

objects-interface.mddocs/

Objects Interface

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.

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.

Core Imports

from seaborn.objects import Plot

Common imports for marks, stats, and moves:

from seaborn.objects import (
    Plot, 
    # Marks
    Dot, Dots, Line, Lines, Path, Bar, Bars, Area, Band, Text,
    # Stats  
    Stat, Agg, Est, Count, Hist, KDE,
    # Moves
    Move, Dodge, Jitter, Stack, Shift, Norm,
    # Scales
    Scale, Continuous, Nominal, Boolean, Temporal
)

Capabilities

Plot Orchestration

The main interface for declarative plotting that orchestrates data, marks, stats, and scales.

class Plot:
    def __init__(self, *args, data=None, **variables):
        """
        Initialize plot with data source and variable mappings.
        
        Parameters:
        - data: DataFrame or dict with columnar data
        - **variables: mappings from variables to data columns (x=, y=, color= etc.)
        """
    
    def add(self, mark, *transforms, orient=None, legend=True, label=None, data=None, **variables):
        """
        Add a layer with mark and optional transforms.
        
        Parameters:
        - mark: Mark instance defining visual representation
        - *transforms: Stat and/or Move instances for data transformation
        - orient: "x" or "y" orientation, inferred if not specified
        - legend: whether to include layer in legend
        - label: label for legend entry
        - data: override data source for this layer
        - **variables: additional variable mappings for this layer
        
        Returns:
        Plot instance for method chaining
        """
    
    def facet(self, col=None, row=None, order=None, wrap=None):
        """
        Create subplots with conditional data subsets.
        
        Parameters:
        - col: variable for subplot columns
        - row: variable for subplot rows  
        - order: dict specifying order of facet levels
        - wrap: wrap columns after this number
        
        Returns:
        Plot instance for method chaining
        """
    
    def pair(self, x=None, y=None, wrap=None, cross=True):
        """
        Create subplots by pairing multiple x/y variables.
        
        Parameters:
        - x: list of variables for x-axis pairing
        - y: list of variables for y-axis pairing
        - wrap: wrap columns after this number
        - cross: if False, pair variables in order rather than crossing
        
        Returns:
        Plot instance for method chaining
        """
    
    def scale(self, **scales):
        """
        Specify data-to-visual property mappings.
        
        Parameters:
        - x, y: Scale instances for coordinate mappings
        - color, fill, linestyle, etc.: Scale instances for aesthetic mappings
        
        Returns:
        Plot instance for method chaining
        """
    
    def share(self, **shares):
        """
        Control sharing of axis limits/ticks across subplots.
        
        Parameters:
        - x, y: True (share all), False (independent), or "col"/"row" (share within)
        
        Returns:
        Plot instance for method chaining
        """
    
    def limit(self, **limits):
        """
        Control range of visible data.
        
        Parameters:
        - x, y: tuple of (min, max) values or single values for symmetric limits
        
        Returns:
        Plot instance for method chaining
        """
    
    def label(self, title=None, legend=None, **variables):
        """
        Control labels for axes, legends, and subplots.
        
        Parameters:
        - title: main plot title
        - legend: legend title
        - **variables: axis labels (x=, y=, color= etc.)
        
        Returns:
        Plot instance for method chaining
        """
    
    def layout(self, size=None, engine=None, extent=None):
        """
        Control figure size and layout.
        
        Parameters:
        - size: tuple of (width, height) in inches
        - engine: layout engine ("constrained" or "tight")
        - extent: subplot area as fraction of figure
        
        Returns:
        Plot instance for method chaining
        """
    
    def theme(self, config):
        """
        Control plot appearance via matplotlib rc parameters.
        
        Parameters:
        - config: dict of matplotlib rcParams
        
        Returns:
        Plot instance for method chaining
        """
    
    def on(self, target):
        """
        Use existing matplotlib figure/axes for drawing.
        
        Parameters:
        - target: matplotlib Figure, Axes, or SubFigure
        
        Returns:
        Plot instance for method chaining
        """
    
    def save(self, loc, **kwargs):
        """
        Compile and save plot to file.
        
        Parameters:
        - loc: output filename or path-like object
        - **kwargs: additional arguments passed to matplotlib savefig
        
        Returns:
        Plot instance for method chaining
        """
    
    def show(self, **kwargs):
        """
        Compile and display plot.
        
        Parameters:
        - **kwargs: additional arguments passed to matplotlib show
        """

Mark Classes

Visual representation of data through matplotlib artists.

class Mark:
    """Base class for visual representations of data."""
    def _mappable_props(self):
        """Properties that can be mapped from data."""
    
    def _grouping_props(self):
        """Properties used for grouping data."""

class Dot(Mark):
    """A mark suitable for dot plots or scatter plots."""
    marker: str = "o"
    pointsize: float = 6
    stroke: float = 0.75
    color: str = "C0"
    alpha: float = 1
    fill: bool = True
    edgecolor: str = "auto"
    edgealpha: float = "auto"  
    edgewidth: float = 0.5
    edgestyle: str = "-"

class Dots(Mark):
    """Dot mark optimized for handling overplotting with stroke-defined points."""
    marker: str = "o"
    pointsize: float = 4
    stroke: float = 0.75
    color: str = "C0"
    alpha: float = 1
    fill: bool = True
    fillcolor: str = "auto"
    fillalpha: float = 0.2

class Line(Mark):
    """Connect data points with lines, sorting along orientation axis."""
    color: str = "C0"
    alpha: float = 1
    linewidth: float = "auto"
    linestyle: str = "-"
    marker: str = ""
    pointsize: float = "auto"
    fillcolor: str = "auto"
    edgecolor: str = "auto"
    edgewidth: float = "auto"

class Lines(Mark):
    """Faster line mark using matplotlib LineCollection for many lines."""
    color: str = "C0"
    alpha: float = 1
    linewidth: float = "auto"
    linestyle: str = "-"

class Path(Mark):
    """Connect data points in order they appear without sorting."""
    # Same properties as Line

class Range(Lines):
    """Oriented line marks between min/max values."""
    # Inherits properties from Lines

class Dash(Lines):
    """Line mark as oriented segments for each datapoint."""
    width: float = 0.8

class Bar(Mark):
    """Bar mark drawn between baseline and data values."""
    color: str = "C0"
    alpha: float = 0.7
    fill: bool = True
    edgecolor: str = "auto"
    edgealpha: float = 1
    edgewidth: float = "auto"
    edgestyle: str = "-"
    width: float = 0.8
    baseline: float = 0

class Bars(Mark):
    """Optimized bar mark with defaults for histograms."""
    # Similar properties to Bar with histogram-optimized defaults

class Area(Mark):
    """Fill mark drawn from baseline to data values."""
    color: str = "C0"
    alpha: float = 0.2
    fill: bool = True
    edgecolor: str = "auto"
    edgealpha: float = 1
    edgewidth: float = "auto"
    edgestyle: str = "-"
    baseline: float = 0

class Band(Mark):
    """Fill mark representing interval between min and max values."""
    color: str = "C0"
    alpha: float = 0.2
    fill: bool = True
    edgecolor: str = "auto"
    edgealpha: float = 1
    edgewidth: float = 0
    edgestyle: str = "-"

class Text(Mark):
    """Textual mark to annotate or represent data values."""
    text: str = ""
    color: str = "k"
    alpha: float = 1
    fontsize: float = "auto"
    halign: str = "center"
    valign: str = "center_baseline"
    offset: float = 4

Statistical Transformations

Apply statistical transforms before plotting.

class Stat:
    """Base class for statistical transformations."""
    group_by_orient: bool = False
    
    def __call__(self, data, groupby, orient, scales):
        """Apply statistical transform to data subgroups."""

class Agg(Stat):
    """Aggregate data along value axis using given method."""
    func: str | callable = "mean"
    group_by_orient: bool = True

class Est(Stat):
    """Calculate point estimate and error bar interval."""
    func: str | callable = "mean"
    errorbar: str | tuple = ("ci", 95)
    n_boot: int = 1000
    seed: int | None = None
    group_by_orient: bool = True

class Count(Stat):
    """Count distinct observations within groups."""
    group_by_orient: bool = True

class Hist(Stat):
    """Bin observations, count them, optionally normalize/cumulate."""
    stat: str = "count"  # "count", "density", "percent", "probability", "frequency"
    bins: str | int | list = "auto"
    binwidth: float | None = None
    binrange: tuple | None = None
    common_norm: bool | list = True
    common_bins: bool | list = True
    cumulative: bool = False
    discrete: bool = False

class KDE(Stat):
    """Compute univariate kernel density estimate."""
    bw_adjust: float = 1
    bw_method: str | float | callable = "scott"
    common_norm: bool | list = True
    common_grid: bool | list = True  
    gridsize: int | None = 200
    cut: float = 3
    cumulative: bool = False

class Perc(Stat):
    """Replace data values with percentile ranks."""
    k: int = 100
    method: str = "linear"

class PolyFit(Stat):
    """Fit a polynomial regression of given order."""
    order: int = 2
    gridsize: int = 100

Positional Adjustments

Make positional adjustments to reduce overplotting or achieve specific layouts.

class Move:
    """Base class for positional transforms."""
    group_by_orient: bool = True
    
    def __call__(self, data, groupby, orient, scales):
        """Apply positional transform and return modified data."""

class Jitter(Move):
    """Random displacement along axes to reduce overplotting."""
    width: float = "auto"  # Relative to mark width
    x: float = 0  # Absolute displacement in x
    y: float = 0  # Absolute displacement in y
    seed: int | None = None

class Dodge(Move):
    """Displacement/narrowing of overlapping marks along orientation."""
    empty: str = "keep"  # "keep", "drop", "fill"
    gap: float = 0
    by: list | None = None

class Stack(Move):
    """Displacement of overlapping bars/areas along value axis."""
    # No additional parameters

class Shift(Move):
    """Displacement of all marks with same magnitude/direction."""
    x: float = 0
    y: float = 0

class Norm(Move):
    """Divisive scaling on value axis after aggregating within groups."""
    func: str | callable = "max"
    where: str | None = None  # Query string for subset
    by: list | None = None  # Variables for aggregation groups
    percent: bool = False
    group_by_orient: bool = False

Scale Classes

Control mappings between data values and visual properties.

class Scale:
    """Base class for data-to-visual mappings."""
    def __call__(self, data):
        """Transform data through the scale pipeline."""
    
    def tick(self, **kwargs):
        """Configure tick selection."""
    
    def label(self, **kwargs):
        """Configure label formatting."""

class Continuous(Scale):
    """Numeric scale supporting norms and functional transforms."""
    values: tuple | str | None = None
    trans: str | None = None  # "log", "sqrt", "symlog", etc.
    
    def tick(self, locator=None, *, at=None, upto=None, count=None, every=None, between=None, minor=None):
        """Configure tick selection for axis/legend."""
    
    def label(self, formatter=None, *, like=None, base=None, unit=None):
        """Configure tick label appearance."""

class Nominal(Scale):
    """Categorical scale without relative importance/magnitude."""
    values: tuple | str | list | dict | None = None
    order: list | None = None
    
    def tick(self, locator=None):
        """Configure tick selection."""
    
    def label(self, formatter=None):
        """Configure label formatting."""

class Boolean(Scale):
    """Scale with discrete domain of True/False values."""
    values: tuple | list | dict | None = None
    
    def tick(self, locator=None):
        """Configure tick selection."""
    
    def label(self, formatter=None):
        """Configure label formatting."""

class Temporal(Scale):
    """Scale for date/time data."""
    # No transforms available for temporal data
    
    def tick(self, locator=None, *, upto=None):
        """Configure tick selection for dates."""
    
    def label(self, formatter=None, *, concise=False):
        """Configure date label formatting."""

Usage Examples

Basic Plot Construction

import seaborn.objects as so
import pandas as pd

# Load data
tips = sns.load_dataset("tips")

# Basic scatter plot
(
    so.Plot(tips, x="total_bill", y="tip")
    .add(so.Dot())
    .show()
)

Multi-layer Plot with Statistics

# Scatter plot with regression line
(
    so.Plot(tips, x="total_bill", y="tip")
    .add(so.Dot(alpha=0.5))
    .add(so.Line(), so.PolyFit(order=1))
    .label(
        title="Bill vs Tip with Regression",
        x="Total Bill ($)",
        y="Tip ($)"
    )
    .show()
)

Grouped Data with Aesthetics

# Grouped scatter plot with color mapping
(
    so.Plot(tips, x="total_bill", y="tip", color="time")
    .add(so.Dot())
    .scale(color=so.Nominal(values=["skyblue", "orange"]))
    .show()
)

Histogram with Custom Styling

# Histogram with custom bins and styling
(
    so.Plot(tips, x="total_bill")
    .add(so.Bar(), so.Hist(bins=20))
    .layout(size=(8, 5))
    .label(
        title="Distribution of Total Bills",
        x="Total Bill ($)",
        y="Count"
    )
    .show()
)

Faceted Plot

# Faceted scatter plots
(
    so.Plot(tips, x="total_bill", y="tip")
    .add(so.Dot(alpha=0.7))
    .facet(col="time", row="smoker")
    .label(title="Tips by Time and Smoking Status")
    .show()
)

Advanced Layering with Moves

# Box plot with jittered points
(
    so.Plot(tips, x="day", y="total_bill")
    .add(so.Range(color="gray"), so.Est(errorbar="sd"))
    .add(so.Dot(alpha=0.3), so.Jitter(width=0.3))
    .show()
)

Multiple Variables and Pairing

# Pair plot using objects interface
numeric_cols = ["total_bill", "tip", "size"]
(
    so.Plot(tips[numeric_cols])
    .pair(cross=True)
    .add(so.Dot(alpha=0.5))
    .show()
)

Custom Scales and Transformations

# Log-scale plot with custom color palette
(
    so.Plot(tips, x="total_bill", y="tip", color="size")
    .add(so.Dot())
    .scale(
        x=so.Continuous(trans="log"),
        color=so.Continuous(values=("lightblue", "darkred"))
    )
    .show()
)

Stacked Bar Chart

# Stacked bar chart with custom colors
(
    so.Plot(tips, x="day", color="smoker")
    .add(so.Bar(), so.Count(), so.Stack())
    .scale(color=so.Nominal(values=["lightcoral", "steelblue"]))
    .show()
)

Text Annotations

# Scatter plot with text labels
(
    so.Plot(tips.head(10), x="total_bill", y="tip")
    .add(so.Dot())
    .add(so.Text(text="size"), text="size", offset=8)
    .show()
)

Workflow Pattern

The typical workflow follows this pattern:

  1. Initialize: so.Plot(data, x=..., y=..., **aesthetics)
  2. Add Layers: .add(Mark(), Stat(), Move()) - can chain multiple
  3. Configure Scales: .scale(x=Scale(), color=Scale(), ...)
  4. Setup Subplots: .facet() or .pair() if needed
  5. Customize: .label(), .layout(), .theme(), .limit(), .share()
  6. Render: .show() or .save()

Each method returns a new Plot instance, enabling flexible method chaining and reusable plot specifications.

Types

# Data types
DataFrame = pandas.DataFrame
Series = pandas.Series  
ArrayLike = numpy.ndarray | list

# Property value types
Mappable = Any  # Direct values, data column references, or special mappings
ColorSpec = str | tuple  # Color names, hex codes, RGB tuples
MarkerSpec = str  # Matplotlib marker codes
LineStyleSpec = str | tuple  # Matplotlib linestyle codes

# Scale value specifications
ScaleValues = tuple | str | list | dict | None
TransformSpec = str | tuple[callable, callable] | None

# Layout specifications
SizeSpec = tuple[float, float]  # (width, height) in inches
LimitSpec = tuple[float, float] | float  # (min, max) or symmetric limit

Install with Tessl CLI

npx tessl i tessl/pypi-seaborn

docs

categorical-plots.md

color-palettes.md

distribution-plots.md

grid-plots.md

index.md

interactive-widgets.md

matrix-plots.md

objects-interface.md

relational-plots.md

styling-themes.md

utilities.md

tile.json