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>
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.