# charts.shape SVG path data for the marks of a chart: lines, filled areas, step lines, smooth monotone curves, bar rectangles, arcs and pie angles. Inputs are already in pixels (put the data through `charts.scale` first); the outputs are strings for `` and numbers for ``, the same in TypeScript, Python and Rust, so a server-rendered chart and a browser-rendered one match to the character. This is a group: install only what you draw, e.g. `require charts.shape ^1.0.0 only=linePath`. Every path function uses `linePath`'s helpers, so `linePath` always comes along. ## Numbers in paths Every coordinate is rounded to 2 decimal places by `math.round-float` (half away from zero on the stored double) and printed by `text.format-decimal` with trailing zeros dropped: `10`, `10.5`, `0.13`, never `10.00`, `1e-7` or `-0`. A hundredth of a pixel is invisible, and fixed text is what makes the three languages agree. The path grammar follows d3-shape exactly: commands with no spaces (`M10,20L30,40`), and `C` with its three points separated by commas. ## Lines, areas and steps - `linePath` is d3.line with `curveLinear`. A point whose `y` is null is a gap: the line stops and starts again with a new `M`. A run of a single point becomes `Mx,yZ`, which d3 emits so that a round line cap still draws a dot. - `areaPath` is d3.area: along the top edge (`y1`) left to right, back along the baseline (`y0`) right to left, then `Z`. `y0` is per point, so stacked areas pass their lower band edge. A null `y1` is a gap. - `stepPath` is d3.curveStepBefore (`before`), d3.curveStep (`middle`) and d3.curveStepAfter (`after`), including d3's extra final `L` for `middle`. The midpoint is computed as d3 does, `x0 x (1 - t) + x1 x t`. ## Monotone curves `monotoneCurve` is d3.curveMonotoneX: cubic Hermite segments, written as Béziers, whose tangents are chosen by the Fritsch–Carlson rule so the curve is monotone wherever the data is. It never invents a bump between two equal values or dips below a flat start before a rise, which a Catmull-Rom or cardinal spline does. The interior tangent is d3's `(sign(s0) + sign(s1)) x min(|s0|, |s1|, |p| / 2)` with `p` the weighted mean slope; the end tangents come from the one-sided slope. Two points are a straight `L`; one is `Mx,yZ`. Within an unbroken run x must strictly increase: d3 silently produces a broken path otherwise, and here it is an error. ## Bars `barRects` turns bars given in pixels (`band` start and `thickness` across the axis, `base` and `value` pixels along it) into rectangles. Edges are rounded, and widths and heights are the differences of the rounded edges, so two bars that share an edge still share it exactly after rounding (rounding each width separately leaves hairline gaps). A bar below its baseline gets a positive height and its `y` at the top edge, as `` needs. `vertical` bars stand on the x axis; `horizontal` bars grow along x. ## Arcs `arcPath` takes angles in radians from 12 o'clock, increasing clockwise (as d3.arc), so a point at angle `a` and radius `r` is `(cx + r sin a, cy - r cos a)`. The sine and cosine come from `math.sin-cos`, not the platform, so arc ends round the same way everywhere. The format: - Ring segment: `M` outer start, `A ro,ro,0,large,sweep,` outer end, `L` inner end, `A ri,ri,0,large,1-sweep,` inner start, `Z`. - `innerRadius` 0 is a wedge: after the outer arc, `L cx,cy Z`. - `large` is 1 when the span is more than half a turn (exactly half is 0); `sweep` is 1 when the arc runs clockwise (end after start), 0 otherwise. - A span of a full turn or more is a full circle. One SVG arc cannot end where it starts (it draws nothing), so it is two half arcs, `M start A ... opposite A ... start Z`; a ring adds its hole as a second subpath drawn the other way round, so the nonzero fill rule leaves it empty. - Zero span or zero outer radius is `""`. Radii must satisfy 0 <= innerRadius <= outerRadius. d3's corner radius and padRadius are not supported. ## Pie angles `pieAngles` is d3.pie with `sort(null)`: slices in input order, each value's share of the span from `startAngle` to `endAngle` (capped at one full turn; an end before the start runs anticlockwise), with `padAngle` between slices (capped at an equal share each). One difference: d3 returns each slice's angles including its pad and leaves the arc generator to trim it; here half the pad is already trimmed from each side, so the angles go straight into `arcPath`. Angles are rounded to 6 decimal places; the running total is not, so the last slice still ends at the end angle. Zero values are empty slices; negative values and a negative pad are errors (d3 quietly treats negatives as zero). Sources: d3-shape (github.com/d3/d3-shape: line, area, curveStep, curveMonotoneX, pie); F. N. Fritsch and R. E. Carlson, "Monotone Piecewise Cubic Interpolation", SIAM Journal on Numerical Analysis 17(2), 1980, pp. 238-246; W3C, Scalable Vector Graphics (SVG) 2, "Paths" chapter (path data grammar and elliptical arc flags, section 9.3.8, and the out-of-range parameters note on arcs whose end point equals their start). ## Notices Portions follow d3-shape (https://github.com/d3/d3-shape), Copyright 2010-2022 Mike Bostock, under the ISC License; the full notice is in NOTICE. 1.0.1 adds its attribution notices (NOTICE). The code and the tests are unchanged.