Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Joint — Bivariate Panel + Marginals

Signature

sp.joint(title, x, y, *, variant="hexbin", marginal="histogram", panel_variant="", marginal_variant="", bins=24, colorscale=None, categories=None, **kwargs) -> Chart

Aliases: sp.joint, sp.jointplot, sp.joint_plot, sp.bivariate, sp.build_joint

Description

sp.joint() composes a bivariate main panel with top and right marginal strips — the SeraPlot equivalent of seaborn's jointplot() / JointGrid. variant= (the panel, "inside") and marginal= (the top/right strips, "outside") are independent, fully open choices — not a fixed enum. Each accepts the name of any registered SeraPlot family from services/plot/statistical/chart_registry.rs (currently ~50: hexbin, scatter, kde, histogram, bar, violin, boxplot, heatmap, orbita, splom, … the same inventory facet() dispatches through), and panel_variant= / marginal_variant= forward straight through as that family's own variant=, so hexbin's outlined/spaced/highlight styles, histogram's cumulative, etc. all work exactly as they do standalone.

sp.joint(x, y, variant="hexbin", marginal="kde")
sp.joint(x, y, variant="kde", marginal="histogram")
sp.joint(x, y, variant="scatter", marginal="bar")
sp.joint(x, y, variant="hexbin", panel_variant="outlined", marginal="kde")

Each region — panel, top strip, right strip — is a real, independently-rendered SeraPlot chart embedded in its own frame, calling the exact same native build_* function facet() uses for its cells; nothing is reimplemented. That also means regions are not pixel-aligned to a shared coordinate system the way a hand-tuned single-SVG composition would be — each chart keeps its own axes/padding — an inherent tradeoff for genuine "any family, any slot" freedom. Not every family produces something meaningful in every slot — that limitation belongs to the target family's own data shape, not to joint() itself. As a marginal, a family only ever receives the single axis of values being summarized (plus generic synthetic labels/categories/series/sizes/words so families expecting those shapes still degrade gracefully); families whose own data model is inherently 2D/matrix/hierarchical/paired — candlestick, chord, circle_pack, correlogram, dendrogram, dumbbell, gantt, hive, heatmap, icicle, orbita, parcats, radar, sankey, scatterternary, slope, splom, sunburst — render blank there, the same honest way orbita renders blank as a panel without a hierarchy.

For a true bivariate (2D) density surface — not just kde's own 1D curve — use variant="kde", panel_variant="contour": kde()'s contour variant fits a product-kernel Gaussian KDE jointly over x and y and shades a smooth density surface with the raw points overlaid, matching seaborn's smooth_bivariate_kde / joint_kde examples. Legacy preset names (layered_bivariate, joint_kde, kde_smooth, smooth_bivariate_kde, …) already resolve to exactly this.

The preset names from earlier releases (hexbin_marginal, joint_histogram / histogram2d, layered_bivariate, joint_kde, kde_smooth, multiple_bivariate_kde, marginal_ticks, regression_marginals) still work as variant= values and resolve to a real family under the hood (resolve_legacy_panel() in joint/variant.rs), so existing code keeps working. heat_scatter — seaborn's correlation matrix drawn as sized/colored scatter dots — isn't a joint/marginal plot at all; use heatmap(variant="bubble") directly.

Data

x (list[float]) — X coordinates. y (list[float]) — Y coordinates.

Parameters

Returns

Chart — object with .html property and .show() method.

The raw entry point — variant= is simply the panel family's own name, and any registered family can fill it.

Call sp.joint(x, y, variant="hexbin", marginal="histogram")
Preview

Hexagonal density panel with KDE curve marginals instead of the default histograms.

Call sp.joint(x, y, variant="hexbin", marginal="kde")
Preview

A 1D KDE panel with histogram marginals — mixing families freely, not just bivariate-native ones.

Call sp.joint(x, y, variant="kde", marginal="histogram")
Preview

Scatter panel with bar-chart marginals.

Call sp.joint(x, y, variant="scatter", marginal="bar")
Preview

panel_variant= forwards to the panel family's own variant — here hexbin's outlined cell style, combined with KDE marginals.

Call sp.joint(x, y, variant="hexbin", panel_variant="outlined", marginal="kde")
Preview

The pre-existing layered_bivariate preset name still resolves (to variant="kde", panel_variant="contour" under the hood — a genuine bivariate density surface, not a flat 1D curve) — old code keeps working, and now renders correctly.

Call sp.joint(x, y, variant="layered_bivariate")
Preview