Facets and coordinates

Facets partition rows into panels before panel stats. Coordinates present trained scales (flip, etc.) without rewriting aesthetic mappings.

Facet a comparison

<GGPlot data={cars} aes={{ x: "weight", y: "economy" }}>
  <FacetWrap field="vehicleClass" ncol={2} />
  <GeomPoint />
</GGPlot>

facet wrap, free-y.

Coordinates

Prefer coord flip for horizontal bars over swapping x/y semantics. Horizontal bar.

Scale transforms versus coordinate transforms

A scale transform changes the values consumed by statistics and positions. A coordinate transform leaves those computations alone and projects the final geometry:

// The linear fit consumes log10(exposure).
gg(rows, aes({ x: "exposure", y: "response" }))
  .geomSmooth({ method: "lm" })
  .scaleXLog10();

// The fit consumes exposure; only its rendered geometry is curved.
gg(rows, aes({ x: "exposure", y: "response" }))
  .geomSmooth({ method: "lm" })
  .coordTransform({ x: "log10" });

The portable JSON form is strict and callback-free:

{
  "type": "transform",
  "x": {
    "transform": "log10",
    "limits": [1, 1000],
    "reverse": false,
    "expand": false
  },
  "clip": true
}

Use coordTransform or its identical ggplot2-style alias coord_transform. In Svelte it is a <CoordTransform> child, which takes the same options (<Coord value={coordTransform({ … })} /> is the escape hatch for a coordinate computed elsewhere):

<GGPlot data={rows} aes={{ x: "exposure", y: "response" }}>
  <CoordTransform x="log10" y="sqrt" />
  <GeomPoint />
  <GeomSmooth method="lm" />
</GGPlot>

Coordinate limits create a post-stat viewport: they do not censor rows or recompute a fit. Coordinate inversion runs before scale inversion, so tooltip, interval, and brush-zoom values remain semantic. Nonlinear lines, smooths, areas, smooth confidence bands, and segments use bounded adaptive tessellation; synthetic render vertices never become inspectable data. Set clip: false only for intentional panel overflow.

Preserve physical data-unit ratios

Use coordFixed() when equal data units must have equal physical lengths. The layout reserves titles, axes, and responsive guides first, then centers the largest exact-ratio data rectangle in the remaining allocation. Panel fill, grids, marks, clipping, axes, and facet strips occupy only that rectangle; letterbox gutters use the theme paper role by default.

gg(rows, aes({ x: "x", y: "y" }))
  .geomLine()
  .coordFixed({ ratio: 1 });

ratio is physical y-unit length divided by physical x-unit length. The camelCase helper, builder .coordFixed(), coord_fixed, coordEqual, and coord_equal all emit the same strict JSON. Free positional facet scales are rejected with coord-fixed-free-scales; use fixed facet scales when panels must share one physical comparison. On an unusually constrained container the ratio is never stretched: minor furniture is removed, the SVG declares data-gg-layout="degraded", and authors receive one coord-fixed-degraded warning. See the runnable fixed-aspect example.

Non-identity coordinate transforms reject band and temporal axes with coord-transform-continuous or coord-transform-temporal. Domains that cross log10/sqrt boundaries fail with coord-transform-domain and exact recovery guidance.