@lamatemaga/sterling 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1575 @@
1
+ // src/palette.ts
2
+ function defineSterlingPalette(palette) {
3
+ return palette;
4
+ }
5
+ function sterlingPaletteStyle(palette) {
6
+ const variables = {};
7
+ if (!palette) return variables;
8
+ const surfaceTokens = {
9
+ paper: "paper",
10
+ plot: "surface",
11
+ plotAlt: "surface-2",
12
+ text: "text",
13
+ muted: "muted",
14
+ grid: "grid",
15
+ edge: "edge",
16
+ period: "period"
17
+ };
18
+ for (const [key, value] of Object.entries(palette.surface ?? {})) {
19
+ if (value) variables[`--sterling-${surfaceTokens[key]}`] = value;
20
+ }
21
+ const assignSeries = (name, values) => {
22
+ values?.forEach((value, index) => {
23
+ if (value) variables[`--sterling-${name}-${index + 1}`] = value;
24
+ });
25
+ };
26
+ assignSeries("cat", palette.categorical);
27
+ assignSeries("legend", palette.legend);
28
+ assignSeries("seq", palette.sequential);
29
+ assignSeries("div", palette.divergent);
30
+ assignSeries("heat", palette.heat);
31
+ palette.ramps?.forEach((ramp, familyIndex) => {
32
+ ramp.forEach((value, stopIndex) => {
33
+ if (value) variables[`--sterling-ramp-${familyIndex + 1}-${stopIndex + 1}`] = value;
34
+ });
35
+ });
36
+ return variables;
37
+ }
38
+ var sterlingCategorical = {
39
+ light: [
40
+ "#9A79E7",
41
+ "#25A08D",
42
+ "#D45AC7",
43
+ "#E4A43A",
44
+ "#5A83D7",
45
+ "#E87864",
46
+ "#96AB51",
47
+ "#536B78"
48
+ ],
49
+ dark: [
50
+ "#B69AF2",
51
+ "#5EC9AE",
52
+ "#E88BDD",
53
+ "#F2C46D",
54
+ "#86A8E8",
55
+ "#F29A88",
56
+ "#B7C974",
57
+ "#B7C8D1"
58
+ ],
59
+ print: [
60
+ "#8E68D8",
61
+ "#218C7C",
62
+ "#C653BC",
63
+ "#D39A32",
64
+ "#4F73C6",
65
+ "#DC6A55",
66
+ "#879347",
67
+ "#607986"
68
+ ]
69
+ };
70
+ var sterlingColorNames = [
71
+ "Violet",
72
+ "Teal",
73
+ "Orchid",
74
+ "Amber",
75
+ "Blue",
76
+ "Coral",
77
+ "Moss",
78
+ "Payne"
79
+ ];
80
+ var sterlingChartColors = sterlingColorNames.map(
81
+ (_, index) => `var(--sterling-cat-${index + 1})`
82
+ );
83
+ var sterlingLegendColors = sterlingColorNames.map(
84
+ (_, index) => `var(--sterling-legend-${index + 1})`
85
+ );
86
+ var sterlingDivergentColors = Array.from(
87
+ { length: 11 },
88
+ (_, index) => `var(--sterling-div-${index + 1})`
89
+ );
90
+ var sterlingSequentialColors = Array.from(
91
+ { length: 10 },
92
+ (_, index) => `var(--sterling-seq-${index + 1})`
93
+ );
94
+ var sterlingHeatColors = Array.from(
95
+ { length: 11 },
96
+ (_, index) => `var(--sterling-heat-${index + 1})`
97
+ );
98
+ var sterlingRampStops = 7;
99
+ function sterlingRamp(family, stop) {
100
+ const familyIndex = (family % sterlingColorNames.length + sterlingColorNames.length) % sterlingColorNames.length;
101
+ const clamped = Math.max(1, Math.min(sterlingRampStops, Math.round(stop)));
102
+ return `var(--sterling-ramp-${familyIndex + 1}-${clamped})`;
103
+ }
104
+
105
+ // src/SterlingLegend.tsx
106
+ import { jsx, jsxs } from "react/jsx-runtime";
107
+ function LegendMark({ shape = "circle" }) {
108
+ if (shape === "square") {
109
+ return /* @__PURE__ */ jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "1" });
110
+ }
111
+ if (shape === "triangle") {
112
+ return /* @__PURE__ */ jsx("path", { d: "M 6 1 L 11 10 L 1 10 Z" });
113
+ }
114
+ if (shape === "line") {
115
+ return /* @__PURE__ */ jsx("path", { d: "M 1 6 H 11", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" });
116
+ }
117
+ return /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "4.5" });
118
+ }
119
+ function SterlingInlineLegend({
120
+ items,
121
+ locale
122
+ }) {
123
+ const parts = new Intl.ListFormat(locale, {
124
+ style: "long",
125
+ type: "conjunction"
126
+ }).formatToParts(items.map((item) => item.label));
127
+ let itemIndex = 0;
128
+ return /* @__PURE__ */ jsx("span", { className: "sterling-inline-legend", children: parts.map((part, partIndex) => {
129
+ if (part.type !== "element") {
130
+ return /* @__PURE__ */ jsx("span", { children: part.value }, `literal-${partIndex}`);
131
+ }
132
+ const item = items[itemIndex++];
133
+ const colorIndex = Math.max(0, Math.min(sterlingChartColors.length - 1, item.colorIndex ?? 0));
134
+ const style = {
135
+ "--sterling-legend-mark": item.color ?? sterlingChartColors[colorIndex],
136
+ "--sterling-legend-text": item.textColor ?? sterlingLegendColors[colorIndex]
137
+ };
138
+ return /* @__PURE__ */ jsxs("span", { className: "sterling-inline-legend__item", style, children: [
139
+ /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx(LegendMark, { shape: item.shape }) }),
140
+ /* @__PURE__ */ jsx("span", { children: item.label })
141
+ ] }, `${item.label}-${partIndex}`);
142
+ }) });
143
+ }
144
+
145
+ // src/charts.tsx
146
+ import { chord as d3Chord, ribbon as d3Ribbon } from "d3-chord";
147
+ import { sankey as d3Sankey, sankeyLinkHorizontal } from "d3-sankey";
148
+ import { arc as d3Arc } from "d3-shape";
149
+
150
+ // src/plot.tsx
151
+ import { scaleLinear, scaleTime } from "d3-scale";
152
+
153
+ // src/visualStyle.ts
154
+ var sterlingVisualStyle = {
155
+ stroke: {
156
+ grid: 1,
157
+ detail: 1.5,
158
+ candle: 1.75,
159
+ mark: 2,
160
+ series: 2.25,
161
+ emphasis: 2.5,
162
+ interval: 7,
163
+ halo: 3,
164
+ ring: 44,
165
+ flowMinimum: 1
166
+ },
167
+ opacity: {
168
+ ghost: 0.04,
169
+ contour: 0.08,
170
+ surface: 0.1,
171
+ area: 0.24,
172
+ ridge: 0.34,
173
+ interval: 0.28,
174
+ relationship: 0.42,
175
+ secondaryMark: 0.66,
176
+ guide: 0.7,
177
+ signal: 0.84,
178
+ mutedMark: 0.34
179
+ }
180
+ };
181
+
182
+ // src/plot.tsx
183
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
184
+ var axisText = "var(--sterling-text)";
185
+ var axisMuted = "var(--sterling-muted)";
186
+ var axisGrid = "var(--sterling-grid)";
187
+ var axisLine = "var(--sterling-edge)";
188
+ var MONO = "var(--font-mono)";
189
+ var TICK = 5;
190
+ var TICK_LABEL = 11;
191
+ var AXIS_TITLE = 12;
192
+ var defaultMargin = { top: 26, right: 26, bottom: 56, left: 70 };
193
+ function frame(width, height, margin = defaultMargin) {
194
+ return {
195
+ width,
196
+ height,
197
+ x0: margin.left,
198
+ x1: width - margin.right,
199
+ y0: margin.top,
200
+ y1: height - margin.bottom
201
+ };
202
+ }
203
+ function linearScale(values, range, { zero = false, padFraction = 0.05 } = {}) {
204
+ let min = Math.min(...values);
205
+ let max = Math.max(...values);
206
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
207
+ min = 0;
208
+ max = 1;
209
+ }
210
+ if (min === max) {
211
+ const bump = Math.abs(min) || 1;
212
+ min -= bump;
213
+ max += bump;
214
+ }
215
+ if (zero) {
216
+ min = Math.min(0, min);
217
+ max = Math.max(0, max);
218
+ } else {
219
+ const pad = (max - min) * padFraction;
220
+ min -= pad;
221
+ max += pad;
222
+ }
223
+ return scaleLinear().domain([min, max]).nice().range(range);
224
+ }
225
+ function timeScale(domain, range) {
226
+ return scaleTime().domain(domain).range(range).nice();
227
+ }
228
+ function tickValues(scale, count) {
229
+ return scale.ticks(count);
230
+ }
231
+ function Gridlines({
232
+ scale,
233
+ x0,
234
+ x1,
235
+ count = 5
236
+ }) {
237
+ return /* @__PURE__ */ jsx2("g", { "aria-hidden": "true", children: tickValues(scale, count).map((value) => /* @__PURE__ */ jsx2("line", { x1: x0, x2: x1, y1: scale(value), y2: scale(value), stroke: axisGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)) });
238
+ }
239
+ function AxisLeft({
240
+ scale,
241
+ x,
242
+ gridX1,
243
+ count = 5,
244
+ title,
245
+ format
246
+ }) {
247
+ const values = tickValues(scale, count);
248
+ const fmt = format ?? ((value) => scale.tickFormat(count)(value));
249
+ const [yBottom, yTop] = scale.range();
250
+ return /* @__PURE__ */ jsxs2("g", { children: [
251
+ gridX1 !== void 0 ? values.map((value) => /* @__PURE__ */ jsx2("line", { x1: x, x2: gridX1, y1: scale(value), y2: scale(value), stroke: axisGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, `g${value}`)) : null,
252
+ /* @__PURE__ */ jsx2("line", { x1: x, x2: x, y1: yBottom, y2: yTop, stroke: axisLine }),
253
+ values.map((value) => /* @__PURE__ */ jsxs2("g", { children: [
254
+ /* @__PURE__ */ jsx2("line", { x1: x - TICK, x2: x, y1: scale(value), y2: scale(value), stroke: axisLine }),
255
+ /* @__PURE__ */ jsx2("text", { x: x - TICK - 4, y: scale(value) + 3.6, textAnchor: "end", fill: axisMuted, fontSize: TICK_LABEL, fontFamily: MONO, children: fmt(value) })
256
+ ] }, value)),
257
+ title ? /* @__PURE__ */ jsx2(
258
+ "text",
259
+ {
260
+ transform: `translate(${x - 48} ${(yBottom + yTop) / 2}) rotate(-90)`,
261
+ textAnchor: "middle",
262
+ fill: axisMuted,
263
+ fontSize: AXIS_TITLE,
264
+ fontFamily: MONO,
265
+ children: title
266
+ }
267
+ ) : null
268
+ ] });
269
+ }
270
+ function AxisBottom({
271
+ scale,
272
+ y,
273
+ count = 6,
274
+ title,
275
+ format,
276
+ titleGap = 42
277
+ }) {
278
+ const values = tickValues(scale, count);
279
+ const fmt = format ?? ((value) => scale.tickFormat(count)(value));
280
+ const [x0, x1] = scale.range();
281
+ return /* @__PURE__ */ jsxs2("g", { children: [
282
+ /* @__PURE__ */ jsx2("line", { x1: x0, x2: x1, y1: y, y2: y, stroke: axisLine }),
283
+ values.map((value) => /* @__PURE__ */ jsxs2("g", { children: [
284
+ /* @__PURE__ */ jsx2("line", { x1: scale(value), x2: scale(value), y1: y, y2: y + TICK, stroke: axisLine }),
285
+ /* @__PURE__ */ jsx2("text", { x: scale(value), y: y + TICK + 13, textAnchor: "middle", fill: axisMuted, fontSize: TICK_LABEL, fontFamily: MONO, children: fmt(value) })
286
+ ] }, value)),
287
+ title ? /* @__PURE__ */ jsx2("text", { x: (x0 + x1) / 2, y: y + titleGap, textAnchor: "middle", fill: axisMuted, fontSize: AXIS_TITLE, fontFamily: MONO, children: title }) : null
288
+ ] });
289
+ }
290
+ function TimeAxisBottom({
291
+ scale,
292
+ y,
293
+ title,
294
+ targetPx = 96,
295
+ titleGap = 42
296
+ }) {
297
+ const [x0, x1] = scale.range();
298
+ const count = Math.max(2, Math.round((x1 - x0) / targetPx));
299
+ const values = scale.ticks(count);
300
+ const fmt = scale.tickFormat(count);
301
+ return /* @__PURE__ */ jsxs2("g", { children: [
302
+ /* @__PURE__ */ jsx2("line", { x1: x0, x2: x1, y1: y, y2: y, stroke: axisLine }),
303
+ values.map((value) => /* @__PURE__ */ jsxs2("g", { children: [
304
+ /* @__PURE__ */ jsx2("line", { x1: scale(value), x2: scale(value), y1: y, y2: y + TICK, stroke: axisLine }),
305
+ /* @__PURE__ */ jsx2("text", { x: scale(value), y: y + TICK + 13, textAnchor: "middle", fill: axisMuted, fontSize: TICK_LABEL, fontFamily: MONO, children: fmt(value) })
306
+ ] }, +value)),
307
+ title ? /* @__PURE__ */ jsx2("text", { x: (x0 + x1) / 2, y: y + titleGap, textAnchor: "middle", fill: axisMuted, fontSize: AXIS_TITLE, fontFamily: MONO, children: title }) : null
308
+ ] });
309
+ }
310
+ function bandCenters(count, x0, x1) {
311
+ const step = (x1 - x0) / Math.max(count, 1);
312
+ const centers = Array.from({ length: count }, (_, index) => x0 + step * (index + 0.5));
313
+ return { centers, step };
314
+ }
315
+ function divergentSignedColor(value, maxAbs) {
316
+ const stops = sterlingDivergentColors.length - 1;
317
+ const t = Math.max(0, Math.min(1, (value + maxAbs) / (2 * maxAbs)));
318
+ return sterlingDivergentColors[Math.round((1 - t) * stops)];
319
+ }
320
+ var divergentSignedRamp = [...sterlingDivergentColors].reverse();
321
+ function tukeySummary(values) {
322
+ const sorted = [...values].sort((left, right) => left - right);
323
+ const q = (p) => {
324
+ if (sorted.length === 0) return 0;
325
+ const position = (sorted.length - 1) * p;
326
+ const lower = Math.floor(position);
327
+ const upper = Math.ceil(position);
328
+ if (lower === upper) return sorted[lower];
329
+ return sorted[lower] + (sorted[upper] - sorted[lower]) * (position - lower);
330
+ };
331
+ const q1 = q(0.25);
332
+ const median = q(0.5);
333
+ const q3 = q(0.75);
334
+ const iqr = q3 - q1;
335
+ const lowerFence = q1 - 1.5 * iqr;
336
+ const upperFence = q3 + 1.5 * iqr;
337
+ const inside = sorted.filter((value) => value >= lowerFence && value <= upperFence);
338
+ const whiskerLow = inside.length ? inside[0] : q1;
339
+ const whiskerHigh = inside.length ? inside[inside.length - 1] : q3;
340
+ const outliers = sorted.filter((value) => value < lowerFence || value > upperFence);
341
+ return { q1, median, q3, iqr, whiskerLow, whiskerHigh, outliers, min: sorted[0], max: sorted[sorted.length - 1] };
342
+ }
343
+
344
+ // src/charts.tsx
345
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
346
+ var chartText = "var(--sterling-text)";
347
+ var chartMuted = "var(--sterling-muted)";
348
+ var chartGrid = "var(--sterling-grid)";
349
+ function SterlingBarChart({
350
+ data,
351
+ ariaLabel,
352
+ unit = "",
353
+ xLabel
354
+ }) {
355
+ const rowHeight = 46;
356
+ const top = 12;
357
+ const barHeight = 28;
358
+ const axisBottom = xLabel ? 50 : 34;
359
+ const x0 = 150;
360
+ const x1 = 684;
361
+ const height = top + data.length * rowHeight + axisBottom;
362
+ const baseline = top + data.length * rowHeight;
363
+ const x = linearScale(data.map((datum) => datum.value), [x0, x1], { zero: true });
364
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 720 ${height}`, role: "img", "aria-label": ariaLabel, children: [
365
+ x.ticks(6).map((value) => /* @__PURE__ */ jsx3("line", { x1: x(value), x2: x(value), y1: top, y2: baseline, stroke: chartGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)),
366
+ data.map((datum, index) => {
367
+ const y = top + index * rowHeight + (rowHeight - barHeight) / 2 - 6;
368
+ const width = x(datum.value) - x0;
369
+ return /* @__PURE__ */ jsxs3("g", { children: [
370
+ /* @__PURE__ */ jsx3("text", { x: x0 - 12, y: y + barHeight / 2 + 4, textAnchor: "end", fill: chartText, fontSize: "12", fontFamily: "var(--font-mono)", children: datum.label }),
371
+ /* @__PURE__ */ jsx3(
372
+ "rect",
373
+ {
374
+ x: x0,
375
+ y,
376
+ width: Math.max(width, 2),
377
+ height: barHeight,
378
+ rx: "3",
379
+ fill: sterlingChartColors[datum.colorIndex ?? index % sterlingChartColors.length],
380
+ children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}: ${datum.value}${unit}` })
381
+ }
382
+ ),
383
+ /* @__PURE__ */ jsxs3("text", { x: x(datum.value) + 8, y: y + barHeight / 2 + 4, fill: chartMuted, fontSize: "12", fontFamily: "var(--font-mono)", children: [
384
+ datum.value,
385
+ unit
386
+ ] })
387
+ ] }, datum.label);
388
+ }),
389
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: baseline, count: 6, title: xLabel, format: (value) => `${value}${unit}` })
390
+ ] });
391
+ }
392
+ function scatterMark(shape, x, y, color, key, title) {
393
+ if (shape % 3 === 1) {
394
+ return /* @__PURE__ */ jsx3("rect", { x: x - 4.5, y: y - 4.5, width: "9", height: "9", rx: "1", fill: color, children: /* @__PURE__ */ jsx3("title", { children: title }) }, key);
395
+ }
396
+ if (shape % 3 === 2) {
397
+ return /* @__PURE__ */ jsx3("path", { d: `M ${x} ${y - 5.5} L ${x + 5.2} ${y + 4.5} L ${x - 5.2} ${y + 4.5} Z`, fill: color, children: /* @__PURE__ */ jsx3("title", { children: title }) }, key);
398
+ }
399
+ return /* @__PURE__ */ jsx3("circle", { cx: x, cy: y, r: "4.8", fill: color, children: /* @__PURE__ */ jsx3("title", { children: title }) }, key);
400
+ }
401
+ function SterlingScatterPlot({
402
+ data,
403
+ ariaLabel,
404
+ xLabel,
405
+ yLabel,
406
+ showLegend = false,
407
+ zeroX = false,
408
+ zeroY = false
409
+ }) {
410
+ const groups = [...new Set(data.map((datum) => datum.group))];
411
+ const f = frame(720, 380);
412
+ const x = linearScale(data.map((datum) => datum.x), [f.x0, f.x1], { zero: zeroX });
413
+ const y = linearScale(data.map((datum) => datum.y), [f.y1, f.y0], { zero: zeroY });
414
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
415
+ /* @__PURE__ */ jsx3(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
416
+ data.map((datum, index) => {
417
+ const groupIndex = groups.indexOf(datum.group);
418
+ return scatterMark(
419
+ groupIndex,
420
+ x(datum.x),
421
+ y(datum.y),
422
+ sterlingChartColors[groupIndex],
423
+ `${datum.group}-${index}`,
424
+ datum.label ?? `${datum.group}: ${datum.x}, ${datum.y}`
425
+ );
426
+ }),
427
+ /* @__PURE__ */ jsx3(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
428
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: f.y1, count: 6, title: xLabel }),
429
+ showLegend ? groups.map((group, index) => /* @__PURE__ */ jsxs3("g", { transform: `translate(${f.x1 - 150 + index % 2 * 92} ${f.y0 + 2 + Math.floor(index / 2) * 20})`, children: [
430
+ scatterMark(index, 0, 0, sterlingChartColors[index], `legend-${group}`, group),
431
+ /* @__PURE__ */ jsx3("text", { x: "11", y: "4", fill: chartMuted, fontSize: "10.5", fontFamily: "var(--font-mono)", children: group })
432
+ ] }, group)) : null
433
+ ] });
434
+ }
435
+ function SterlingLineChart({
436
+ labels,
437
+ series,
438
+ ariaLabel,
439
+ yLabel,
440
+ xLabel,
441
+ times,
442
+ markers,
443
+ showLegend = false
444
+ }) {
445
+ const f = frame(720, 380);
446
+ const values = series.flatMap((item) => item.values);
447
+ const y = linearScale(values, [f.y1, f.y0], { zero: true });
448
+ const isTime = Array.isArray(times) && times.length === labels.length && labels.length > 1;
449
+ const time = isTime ? timeScale([times[0], times[times.length - 1]], [f.x0, f.x1]) : null;
450
+ const xAt = (index) => time ? time(new Date(times[index])) : f.x0 + index / Math.max(labels.length - 1, 1) * (f.x1 - f.x0);
451
+ const showMarkers = markers ?? labels.length <= 40;
452
+ const labelStep = Math.max(1, Math.ceil(labels.length / 8));
453
+ const lastIndex = labels.length - 1;
454
+ const showCatTick = (index) => {
455
+ if (index === lastIndex) return true;
456
+ if (index % labelStep !== 0) return false;
457
+ return lastIndex - index >= labelStep * 0.55;
458
+ };
459
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
460
+ /* @__PURE__ */ jsx3(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
461
+ series.map((item, seriesIndex) => {
462
+ const path = item.values.map((value, index) => `${index === 0 ? "M" : "L"} ${xAt(index)} ${y(value)}`).join(" ");
463
+ return /* @__PURE__ */ jsxs3("g", { children: [
464
+ /* @__PURE__ */ jsx3("path", { d: path, fill: "none", stroke: sterlingChartColors[seriesIndex], strokeWidth: sterlingVisualStyle.stroke.series, strokeLinecap: "round", strokeLinejoin: "round" }),
465
+ showMarkers ? item.values.map((value, index) => /* @__PURE__ */ jsx3("circle", { cx: xAt(index), cy: y(value), r: "3.4", fill: sterlingChartColors[seriesIndex], children: /* @__PURE__ */ jsx3("title", { children: `${item.label}, ${labels[index]}: ${value}` }) }, index)) : null
466
+ ] }, item.label);
467
+ }),
468
+ /* @__PURE__ */ jsx3(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
469
+ time ? /* @__PURE__ */ jsx3(TimeAxisBottom, { scale: time, y: f.y1, title: xLabel }) : /* @__PURE__ */ jsxs3("g", { children: [
470
+ /* @__PURE__ */ jsx3("line", { x1: f.x0, x2: f.x1, y1: f.y1, y2: f.y1, stroke: "var(--sterling-edge)" }),
471
+ labels.map(
472
+ (label, index) => showCatTick(index) ? /* @__PURE__ */ jsxs3("g", { children: [
473
+ /* @__PURE__ */ jsx3("line", { x1: xAt(index), x2: xAt(index), y1: f.y1, y2: f.y1 + 5, stroke: "var(--sterling-edge)" }),
474
+ /* @__PURE__ */ jsx3("text", { x: xAt(index), y: f.y1 + 18, textAnchor: "middle", fill: chartMuted, fontSize: "11", fontFamily: "var(--font-mono)", children: label })
475
+ ] }, `${label}-${index}`) : null
476
+ ),
477
+ xLabel ? /* @__PURE__ */ jsx3("text", { x: (f.x0 + f.x1) / 2, y: f.y1 + 42, textAnchor: "middle", fill: chartMuted, fontSize: "12", fontFamily: "var(--font-mono)", children: xLabel }) : null
478
+ ] }),
479
+ showLegend ? series.map((item, index) => /* @__PURE__ */ jsxs3("g", { transform: `translate(${f.x0 + 28 + index * 176} ${f.y0 - 2})`, children: [
480
+ /* @__PURE__ */ jsx3("line", { x1: "0", x2: "22", stroke: sterlingChartColors[index], strokeWidth: sterlingVisualStyle.stroke.series }),
481
+ /* @__PURE__ */ jsx3("text", { x: "30", y: "4", fill: chartMuted, fontSize: "11", fontFamily: "var(--font-mono)", children: item.label })
482
+ ] }, item.label)) : null
483
+ ] });
484
+ }
485
+ function SterlingHeatmap({
486
+ values,
487
+ rowLabels,
488
+ columnLabels,
489
+ ariaLabel,
490
+ domain,
491
+ legendTitle,
492
+ showValues = false
493
+ }) {
494
+ const flat = values.flat();
495
+ const maxAbs = domain ?? Math.max(1, Math.ceil(Math.max(...flat.map((value) => Math.abs(value))) * 10) / 10);
496
+ const width = 720;
497
+ const startX = 168;
498
+ const startY = 46;
499
+ const rightPad = 24;
500
+ const gridWidth = width - startX - rightPad;
501
+ const cellW = gridWidth / Math.max(columnLabels.length, 1);
502
+ const cellH = Math.min(cellW * 0.5, 46);
503
+ const gap = 3;
504
+ const gridHeight = cellH * rowLabels.length;
505
+ const height = startY + gridHeight + 60;
506
+ const legendWidth = Math.min(gridWidth, 340);
507
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${width} ${height}`, role: "img", "aria-label": ariaLabel, children: [
508
+ columnLabels.map((label, index) => /* @__PURE__ */ jsx3("text", { x: startX + index * cellW + cellW / 2, y: startY - 12, textAnchor: "middle", fill: chartText, fontSize: "11", fontFamily: "var(--font-mono)", children: label }, label)),
509
+ rowLabels.map((label, row) => /* @__PURE__ */ jsxs3("g", { children: [
510
+ /* @__PURE__ */ jsx3("text", { x: startX - 12, y: startY + row * cellH + cellH / 2 + 4, textAnchor: "end", fill: chartText, fontSize: "11", fontFamily: "var(--font-mono)", children: label }),
511
+ columnLabels.map((column, columnIndex) => {
512
+ const value = values[row]?.[columnIndex] ?? 0;
513
+ return /* @__PURE__ */ jsxs3("g", { children: [
514
+ /* @__PURE__ */ jsx3(
515
+ "rect",
516
+ {
517
+ x: startX + columnIndex * cellW,
518
+ y: startY + row * cellH,
519
+ width: cellW - gap,
520
+ height: cellH - gap,
521
+ rx: "3",
522
+ fill: divergentSignedColor(value, maxAbs),
523
+ children: /* @__PURE__ */ jsx3("title", { children: `${label}, ${column}: ${value.toFixed(2)}` })
524
+ }
525
+ ),
526
+ showValues ? /* @__PURE__ */ jsx3(
527
+ "text",
528
+ {
529
+ x: startX + columnIndex * cellW + (cellW - gap) / 2,
530
+ y: startY + row * cellH + (cellH - gap) / 2 + 4,
531
+ textAnchor: "middle",
532
+ fill: Math.abs(value) > maxAbs * 0.55 ? "var(--sterling-surface)" : chartText,
533
+ fontSize: "10.5",
534
+ fontFamily: "var(--font-mono)",
535
+ children: value.toFixed(1)
536
+ }
537
+ ) : null
538
+ ] }, column);
539
+ })
540
+ ] }, label)),
541
+ legendTitle ? /* @__PURE__ */ jsx3("text", { x: startX, y: height - 38, fill: chartMuted, fontSize: "10.5", fontFamily: "var(--font-mono)", children: legendTitle }) : null,
542
+ divergentSignedRamp.map((color, index) => /* @__PURE__ */ jsx3("rect", { x: startX + index * legendWidth / divergentSignedRamp.length, y: height - 28, width: legendWidth / divergentSignedRamp.length + 0.5, height: "13", fill: color }, `${color}-${index}`)),
543
+ /* @__PURE__ */ jsx3("text", { x: startX, y: height - 5, fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: -maxAbs }),
544
+ /* @__PURE__ */ jsx3("text", { x: startX + legendWidth / 2, y: height - 5, textAnchor: "middle", fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: "0" }),
545
+ /* @__PURE__ */ jsx3("text", { x: startX + legendWidth, y: height - 5, textAnchor: "end", fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: `+${maxAbs}` })
546
+ ] });
547
+ }
548
+ function SterlingSequentialSurface({
549
+ values: suppliedValues,
550
+ ariaLabel,
551
+ lowLabel = "low / bajo",
552
+ highLabel = "high / alto"
553
+ }) {
554
+ const defaultRows = 10;
555
+ const defaultColumns = 18;
556
+ const generatedValues = Array.from({ length: defaultRows }, (_, row) => Array.from({ length: defaultColumns }, (_2, column) => {
557
+ const x = column / (defaultColumns - 1);
558
+ const y = row / (defaultRows - 1);
559
+ const firstPeak = Math.exp(-(((x - 0.3) / 0.19) ** 2 + ((y - 0.34) / 0.25) ** 2));
560
+ const secondPeak = 0.76 * Math.exp(-(((x - 0.72) / 0.23) ** 2 + ((y - 0.67) / 0.2) ** 2));
561
+ const saddle = 0.22 * Math.sin(x * Math.PI * 2.4) * Math.cos(y * Math.PI * 1.7);
562
+ return firstPeak + secondPeak + saddle;
563
+ }));
564
+ const values = suppliedValues?.length && suppliedValues.some((row) => row.length) ? suppliedValues : generatedValues;
565
+ const rows = values.length;
566
+ const columns = Math.max(1, ...values.map((row) => row.length));
567
+ const flat = values.flat();
568
+ const min = Math.min(...flat);
569
+ const max = Math.max(...flat);
570
+ const cellWidth = 558 / columns;
571
+ const cellHeight = 240 / Math.max(rows, 1);
572
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: "0 0 720 340", role: "img", "aria-label": ariaLabel, children: [
573
+ /* @__PURE__ */ jsx3("g", { transform: "translate(82 34)", children: values.flatMap((rowValues, row) => rowValues.map((value, column) => {
574
+ const index = Math.max(0, Math.min(sterlingHeatColors.length - 1, Math.round((value - min) / Math.max(max - min, 1) * (sterlingHeatColors.length - 1))));
575
+ return /* @__PURE__ */ jsx3("rect", { x: column * cellWidth, y: row * cellHeight, width: cellWidth + 0.35, height: cellHeight + 0.35, fill: sterlingHeatColors[index], children: /* @__PURE__ */ jsx3("title", { children: `x ${column + 1}, y ${row + 1}: ${value.toFixed(2)}` }) }, `${row}-${column}`);
576
+ })) }),
577
+ /* @__PURE__ */ jsx3("text", { x: "82", y: "302", fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: lowLabel }),
578
+ sterlingHeatColors.map((color, index) => /* @__PURE__ */ jsx3("rect", { x: 152 + index * 34, y: "289", width: "34", height: "15", fill: color }, color)),
579
+ /* @__PURE__ */ jsx3("text", { x: "540", y: "302", fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: highLabel })
580
+ ] });
581
+ }
582
+ function SterlingCorrelogram({
583
+ values,
584
+ labels,
585
+ ariaLabel
586
+ }) {
587
+ const cell = 67;
588
+ const startX = 112;
589
+ const startY = 34;
590
+ const size = labels.length * cell;
591
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${startX + size + 54} ${startY + size + 72}`, role: "img", "aria-label": ariaLabel, children: [
592
+ labels.flatMap((rowLabel, row) => labels.map((columnLabel, column) => {
593
+ const value = values[row]?.[column] ?? 0;
594
+ const color = divergentSignedColor(value, 1);
595
+ const centerX = startX + column * cell + cell / 2;
596
+ const centerY = startY + row * cell + cell / 2;
597
+ return /* @__PURE__ */ jsxs3("g", { children: [
598
+ /* @__PURE__ */ jsx3("rect", { x: startX + column * cell, y: startY + row * cell, width: cell, height: cell, fill: "none", stroke: chartGrid }),
599
+ row === column ? /* @__PURE__ */ jsx3("text", { x: centerX, y: centerY + 4, textAnchor: "middle", fill: chartText, fontSize: "10.5", fontFamily: "var(--font-mono)", children: rowLabel }) : row > column ? /* @__PURE__ */ jsx3(
600
+ "ellipse",
601
+ {
602
+ cx: centerX,
603
+ cy: centerY,
604
+ rx: "25",
605
+ ry: Math.max(2.5, 25 * (1 - Math.abs(value))),
606
+ transform: `rotate(${value >= 0 ? -45 : 45} ${centerX} ${centerY})`,
607
+ fill: color,
608
+ fillOpacity: sterlingVisualStyle.opacity.secondaryMark,
609
+ stroke: color,
610
+ children: /* @__PURE__ */ jsx3("title", { children: `${rowLabel}, ${columnLabel}: ${value.toFixed(2)}` })
611
+ }
612
+ ) : /* @__PURE__ */ jsx3("text", { x: centerX, y: centerY + 5, textAnchor: "middle", fill: Math.abs(value) >= 0.3 ? color : chartMuted, fontSize: "15", fontFamily: "var(--font-mono)", fontWeight: "700", children: value.toFixed(2) })
613
+ ] }, `${rowLabel}-${columnLabel}`);
614
+ })),
615
+ /* @__PURE__ */ jsx3("text", { x: startX, y: startY + size + 41, fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: "-1" }),
616
+ divergentSignedRamp.map((color, index) => /* @__PURE__ */ jsx3("rect", { x: startX + 28 + index * 27, y: startY + size + 27, width: "27", height: "16", fill: color }, `${color}-${index}`)),
617
+ /* @__PURE__ */ jsx3("text", { x: startX + 340, y: startY + size + 41, fill: chartMuted, fontSize: "10", fontFamily: "var(--font-mono)", children: "+1" })
618
+ ] });
619
+ }
620
+ function SterlingHistogram({
621
+ values,
622
+ bins = 16,
623
+ ariaLabel,
624
+ xLabel,
625
+ yLabel
626
+ }) {
627
+ const min = Math.min(...values);
628
+ const max = Math.max(...values);
629
+ const step = Math.max((max - min) / bins, Number.EPSILON);
630
+ const counts = Array.from({ length: bins }, () => 0);
631
+ values.forEach((value) => {
632
+ counts[Math.min(bins - 1, Math.floor((value - min) / step))] += 1;
633
+ });
634
+ const top = Math.max(...counts, 1);
635
+ const f = frame(720, 380);
636
+ const x = linearScale([min, max], [f.x0, f.x1]);
637
+ const y = linearScale([0, top], [f.y1, f.y0], { zero: true });
638
+ const barWidth = x(min + step) - x(min);
639
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
640
+ /* @__PURE__ */ jsx3(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
641
+ counts.map((count, index) => {
642
+ const lower = min + index * step;
643
+ const upper = lower + step;
644
+ return /* @__PURE__ */ jsx3(
645
+ "rect",
646
+ {
647
+ x: x(lower) + 1,
648
+ y: y(count),
649
+ width: Math.max(barWidth - 2, 1),
650
+ height: f.y1 - y(count),
651
+ fill: sterlingChartColors[0],
652
+ children: /* @__PURE__ */ jsx3("title", { children: `${lower.toFixed(1)}-${upper.toFixed(1)}: ${count}` })
653
+ },
654
+ index
655
+ );
656
+ }),
657
+ /* @__PURE__ */ jsx3(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel, format: (value) => `${Math.round(value)}` }),
658
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: f.y1, count: 7, title: xLabel })
659
+ ] });
660
+ }
661
+ function SterlingBoxPlot({ groups, ariaLabel, yLabel }) {
662
+ const all = groups.flatMap((group) => group.values);
663
+ const top = 24;
664
+ const rowH = 80;
665
+ const axisBottom = 48;
666
+ const height = top + groups.length * rowH + axisBottom;
667
+ const baseline = top + groups.length * rowH + 6;
668
+ const x0 = 168;
669
+ const x1 = 690;
670
+ const x = linearScale(all, [x0, x1]);
671
+ const boxHalf = 24;
672
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 720 ${height}`, role: "img", "aria-label": ariaLabel, children: [
673
+ x.ticks(6).map((value) => /* @__PURE__ */ jsx3("line", { x1: x(value), x2: x(value), y1: top, y2: baseline, stroke: chartGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)),
674
+ groups.map((group, index) => {
675
+ const summary = tukeySummary(group.values);
676
+ const center = top + index * rowH + rowH / 2 - 4;
677
+ const color = sterlingChartColors[index];
678
+ return /* @__PURE__ */ jsxs3("g", { children: [
679
+ /* @__PURE__ */ jsx3("text", { x: x0 - 12, y: center + 4, textAnchor: "end", fill: chartText, fontSize: "12", fontFamily: "var(--font-mono)", children: group.label }),
680
+ /* @__PURE__ */ jsx3("line", { x1: x(summary.whiskerLow), x2: x(summary.q1), y1: center, y2: center, stroke: color, strokeWidth: sterlingVisualStyle.stroke.mark }),
681
+ /* @__PURE__ */ jsx3("line", { x1: x(summary.q3), x2: x(summary.whiskerHigh), y1: center, y2: center, stroke: color, strokeWidth: sterlingVisualStyle.stroke.mark }),
682
+ /* @__PURE__ */ jsx3("line", { x1: x(summary.whiskerLow), x2: x(summary.whiskerLow), y1: center - 12, y2: center + 12, stroke: color, strokeWidth: sterlingVisualStyle.stroke.mark }),
683
+ /* @__PURE__ */ jsx3("line", { x1: x(summary.whiskerHigh), x2: x(summary.whiskerHigh), y1: center - 12, y2: center + 12, stroke: color, strokeWidth: sterlingVisualStyle.stroke.mark }),
684
+ /* @__PURE__ */ jsx3("rect", { x: x(summary.q1), y: center - boxHalf, width: Math.max(x(summary.q3) - x(summary.q1), 2), height: boxHalf * 2, rx: "3", fill: color, fillOpacity: sterlingVisualStyle.opacity.interval, stroke: color, strokeWidth: sterlingVisualStyle.stroke.mark, children: /* @__PURE__ */ jsx3("title", { children: `${group.label}: n=${group.values.length}, median ${summary.median.toFixed(2)}, IQR ${summary.q1.toFixed(2)}-${summary.q3.toFixed(2)}` }) }),
685
+ /* @__PURE__ */ jsx3("line", { x1: x(summary.median), x2: x(summary.median), y1: center - boxHalf, y2: center + boxHalf, stroke: color, strokeWidth: sterlingVisualStyle.stroke.emphasis }),
686
+ summary.outliers.map((value, outlierIndex) => /* @__PURE__ */ jsx3("circle", { cx: x(value), cy: center, r: "3.4", fill: "none", stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail, children: /* @__PURE__ */ jsx3("title", { children: `${group.label} outlier: ${value.toFixed(2)}` }) }, outlierIndex))
687
+ ] }, group.label);
688
+ }),
689
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: baseline, count: 6, title: yLabel })
690
+ ] });
691
+ }
692
+ function SterlingDumbbellChart({
693
+ data,
694
+ ariaLabel,
695
+ leftLabel,
696
+ rightLabel,
697
+ xLabel
698
+ }) {
699
+ const top = 56;
700
+ const rowH = 66;
701
+ const axisBottom = xLabel ? 50 : 34;
702
+ const x0 = 150;
703
+ const x1 = 660;
704
+ const height = top + data.length * rowH + axisBottom;
705
+ const baseline = top + data.length * rowH;
706
+ const x = linearScale(data.flatMap((datum) => [datum.left, datum.right]), [x0, x1], { zero: true });
707
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 720 ${height}`, role: "img", "aria-label": ariaLabel, children: [
708
+ x.ticks(6).map((value) => /* @__PURE__ */ jsx3("line", { x1: x(value), x2: x(value), y1: top - 20, y2: baseline, stroke: chartGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)),
709
+ data.map((datum, index) => {
710
+ const y = top + index * rowH + rowH / 2 - 4;
711
+ return /* @__PURE__ */ jsxs3("g", { children: [
712
+ /* @__PURE__ */ jsx3("text", { x: x0 - 14, y: y + 4, textAnchor: "end", fill: chartText, fontSize: "12", fontFamily: "var(--font-mono)", children: datum.label }),
713
+ /* @__PURE__ */ jsx3("line", { x1: x(datum.left), x2: x(datum.right), y1: y, y2: y, stroke: chartGrid, strokeWidth: sterlingVisualStyle.stroke.series, strokeLinecap: "round" }),
714
+ /* @__PURE__ */ jsx3("circle", { cx: x(datum.left), cy: y, r: "8", fill: sterlingChartColors[0], children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}, ${leftLabel}: ${datum.left.toFixed(2)}` }) }),
715
+ /* @__PURE__ */ jsx3("circle", { cx: x(datum.right), cy: y, r: "8", fill: sterlingChartColors[3], children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}, ${rightLabel}: ${datum.right.toFixed(2)}` }) })
716
+ ] }, datum.label);
717
+ }),
718
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: baseline, count: 6, title: xLabel })
719
+ ] });
720
+ }
721
+ function kernelDensity(values, steps = 64, domain) {
722
+ const min = domain?.[0] ?? Math.min(...values);
723
+ const max = domain?.[1] ?? Math.max(...values);
724
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
725
+ const spread = Math.sqrt(values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(values.length - 1, 1));
726
+ const bandwidth = Math.max(1.06 * spread * values.length ** -0.2, (max - min) / 100, 1e-3);
727
+ return Array.from({ length: steps }, (_, index) => {
728
+ const value = min + index / (steps - 1) * (max - min);
729
+ const density = values.reduce((sum, observation) => {
730
+ const z = (value - observation) / bandwidth;
731
+ return sum + Math.exp(-0.5 * z * z) / Math.sqrt(2 * Math.PI);
732
+ }, 0) / (values.length * bandwidth);
733
+ return { value, density };
734
+ });
735
+ }
736
+ function SterlingDensityChart({ values, ariaLabel, xLabel, yLabel }) {
737
+ const density = kernelDensity(values);
738
+ const maxDensity = Math.max(...density.map((point) => point.density), Number.EPSILON);
739
+ const f = frame(720, 380);
740
+ const x = linearScale([density[0].value, density[density.length - 1].value], [f.x0, f.x1], { padFraction: 0 });
741
+ const y = linearScale([0, maxDensity], [f.y1, f.y0], { zero: true });
742
+ const line = density.map((point, index) => `${index === 0 ? "M" : "L"} ${x(point.value)} ${y(point.density)}`).join(" ");
743
+ const area = `${line} L ${x(density[density.length - 1].value)} ${f.y1} L ${x(density[0].value)} ${f.y1} Z`;
744
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
745
+ /* @__PURE__ */ jsx3(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
746
+ /* @__PURE__ */ jsx3("path", { d: area, fill: sterlingSequentialColors[4], fillOpacity: sterlingVisualStyle.opacity.area }),
747
+ /* @__PURE__ */ jsx3("path", { d: line, fill: "none", stroke: sterlingSequentialColors[7], strokeWidth: sterlingVisualStyle.stroke.series, strokeLinecap: "round", strokeLinejoin: "round" }),
748
+ /* @__PURE__ */ jsx3(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
749
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: f.y1, count: 7, title: xLabel })
750
+ ] });
751
+ }
752
+ function SterlingViolinPlot({ groups, ariaLabel, yLabel }) {
753
+ const all = groups.flatMap((group) => group.values);
754
+ const observedMin = Math.min(...all);
755
+ const observedMax = Math.max(...all);
756
+ const bandwidthOf = (values) => {
757
+ const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
758
+ const spread = Math.sqrt(values.reduce((sum, value) => sum + (value - mean) ** 2, 0) / Math.max(values.length - 1, 1));
759
+ return Math.max(1.06 * spread * values.length ** -0.2, 1e-6);
760
+ };
761
+ const maxBandwidth = Math.max(...groups.map((group) => bandwidthOf(group.values)));
762
+ const margin = Math.max((observedMax - observedMin) * 0.05, maxBandwidth * 3);
763
+ const domain = [observedMin - margin, observedMax + margin];
764
+ const f = frame(720, 390, { top: 26, right: 26, bottom: 44, left: 70 });
765
+ const y = linearScale(domain, [f.y1, f.y0], { padFraction: 0 });
766
+ const { centers } = bandCenters(groups.length, f.x0, f.x1);
767
+ const halfWidth = Math.min(46, (f.x1 - f.x0) / groups.length * 0.42);
768
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
769
+ /* @__PURE__ */ jsx3(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
770
+ groups.map((group, groupIndex) => {
771
+ const estimate = kernelDensity(group.values, 96, domain);
772
+ const peak = Math.max(...estimate.map((point) => point.density), Number.EPSILON);
773
+ const cutoff = peak * 0.01;
774
+ const firstIndex = estimate.findIndex((point) => point.density >= cutoff);
775
+ const lastIndex = estimate.length - 1 - [...estimate].reverse().findIndex((point) => point.density >= cutoff);
776
+ const density = estimate.slice(Math.max(0, firstIndex - 1), Math.min(estimate.length - 1, lastIndex + 1) + 1);
777
+ const center = centers[groupIndex];
778
+ const right = density.map((point) => `${center + point.density / peak * halfWidth} ${y(point.value)}`);
779
+ const left = [...density].reverse().map((point) => `${center - point.density / peak * halfWidth} ${y(point.value)}`);
780
+ const path = `M ${right.join(" L ")} L ${left.join(" L ")} Z`;
781
+ const summary = tukeySummary(group.values);
782
+ const color = sterlingChartColors[groupIndex];
783
+ return /* @__PURE__ */ jsxs3("g", { children: [
784
+ /* @__PURE__ */ jsx3("path", { d: path, fill: color, fillOpacity: sterlingVisualStyle.opacity.area, stroke: color, strokeWidth: sterlingVisualStyle.stroke.series, children: /* @__PURE__ */ jsx3("title", { children: `${group.label}: n=${group.values.length}, median ${summary.median.toFixed(1)}, IQR ${summary.q1.toFixed(1)}-${summary.q3.toFixed(1)}` }) }),
785
+ /* @__PURE__ */ jsx3("line", { x1: center, x2: center, y1: y(summary.whiskerLow), y2: y(summary.whiskerHigh), stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail }),
786
+ /* @__PURE__ */ jsx3("line", { x1: center - 5, x2: center + 5, y1: y(summary.whiskerLow), y2: y(summary.whiskerLow), stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail }),
787
+ /* @__PURE__ */ jsx3("line", { x1: center - 5, x2: center + 5, y1: y(summary.whiskerHigh), y2: y(summary.whiskerHigh), stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail }),
788
+ /* @__PURE__ */ jsx3("line", { x1: center, x2: center, y1: y(summary.q3), y2: y(summary.q1), stroke: color, strokeWidth: sterlingVisualStyle.stroke.interval, strokeLinecap: "round" }),
789
+ /* @__PURE__ */ jsx3("circle", { cx: center, cy: y(summary.median), r: "4.5", fill: "var(--sterling-surface)", stroke: color, strokeWidth: sterlingVisualStyle.stroke.emphasis }),
790
+ summary.outliers.map((value, outlierIndex) => /* @__PURE__ */ jsx3("circle", { cx: center, cy: y(value), r: "3", fill: "none", stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail, children: /* @__PURE__ */ jsx3("title", { children: `${group.label} outlier: ${value.toFixed(1)}` }) }, outlierIndex)),
791
+ /* @__PURE__ */ jsx3("text", { x: center, y: f.y1 + 18, textAnchor: "middle", fill: chartMuted, fontSize: "10.5", fontFamily: "var(--font-mono)", children: group.label })
792
+ ] }, group.label);
793
+ }),
794
+ /* @__PURE__ */ jsx3(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
795
+ /* @__PURE__ */ jsx3("line", { x1: f.x0, x2: f.x1, y1: f.y1, y2: f.y1, stroke: "var(--sterling-edge)" })
796
+ ] });
797
+ }
798
+ function SterlingDonutChart({ data, ariaLabel, centerLabel, centerValue }) {
799
+ const total = data.reduce((sum, datum) => sum + datum.value, 0);
800
+ const radius = 96;
801
+ const circumference = 2 * Math.PI * radius;
802
+ let offset = 0;
803
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: "0 0 720 350", role: "img", "aria-label": ariaLabel, children: [
804
+ /* @__PURE__ */ jsx3("g", { transform: "translate(360 174) rotate(-90)", children: data.map((datum, index) => {
805
+ const length = datum.value / total * circumference;
806
+ const currentOffset = offset;
807
+ offset += length;
808
+ return /* @__PURE__ */ jsx3(
809
+ "circle",
810
+ {
811
+ cx: "0",
812
+ cy: "0",
813
+ r: radius,
814
+ fill: "none",
815
+ stroke: sterlingChartColors[index],
816
+ strokeWidth: sterlingVisualStyle.stroke.ring,
817
+ strokeDasharray: `${length} ${circumference - length}`,
818
+ strokeDashoffset: -currentOffset,
819
+ children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}: ${datum.value} (${(datum.value / total * 100).toFixed(1)}%)` })
820
+ },
821
+ datum.label
822
+ );
823
+ }) }),
824
+ /* @__PURE__ */ jsx3("text", { x: "360", y: "171", textAnchor: "middle", fill: chartText, fontSize: "30", fontFamily: "var(--font-display)", fontWeight: "600", children: centerValue ?? total.toLocaleString() }),
825
+ /* @__PURE__ */ jsx3("text", { x: "360", y: "195", textAnchor: "middle", fill: chartMuted, fontSize: "11", fontFamily: "var(--font-mono)", children: centerLabel })
826
+ ] });
827
+ }
828
+ function SterlingLollipopChart({ data, ariaLabel, unit = "", xLabel }) {
829
+ const top = 30;
830
+ const rowH = 56;
831
+ const axisBottom = xLabel ? 50 : 34;
832
+ const x0 = 200;
833
+ const x1 = 660;
834
+ const height = top + data.length * rowH + axisBottom;
835
+ const baseline = top + data.length * rowH;
836
+ const x = linearScale(data.map((datum) => datum.value), [x0, x1], { zero: true });
837
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: `0 0 720 ${height}`, role: "img", "aria-label": ariaLabel, children: [
838
+ x.ticks(6).map((value) => /* @__PURE__ */ jsx3("line", { x1: x(value), x2: x(value), y1: top, y2: baseline, stroke: chartGrid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)),
839
+ data.map((datum, index) => {
840
+ const y = top + index * rowH + rowH / 2 - 4;
841
+ const color = sterlingChartColors[index];
842
+ return /* @__PURE__ */ jsxs3("g", { children: [
843
+ /* @__PURE__ */ jsx3("text", { x: x0 - 14, y: y + 4, textAnchor: "end", fill: chartText, fontSize: "12", fontFamily: "var(--font-mono)", children: datum.label }),
844
+ /* @__PURE__ */ jsx3("line", { x1: x(0), x2: x(datum.value), y1: y, y2: y, stroke: color, strokeOpacity: sterlingVisualStyle.opacity.secondaryMark, strokeWidth: sterlingVisualStyle.stroke.series }),
845
+ /* @__PURE__ */ jsx3("circle", { cx: x(datum.value), cy: y, r: "8", fill: color, children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}: ${datum.value}${unit}` }) }),
846
+ /* @__PURE__ */ jsxs3("text", { x: x(datum.value) + 15, y: y + 4, fill: chartMuted, fontSize: "11", fontFamily: "var(--font-mono)", children: [
847
+ datum.value,
848
+ unit
849
+ ] })
850
+ ] }, datum.label);
851
+ }),
852
+ /* @__PURE__ */ jsx3(AxisBottom, { scale: x, y: baseline, count: 6, title: xLabel, format: (value) => `${value}${unit}` })
853
+ ] });
854
+ }
855
+ function polarPoint(centerX, centerY, radius, angle) {
856
+ const radians = (angle - 90) * Math.PI / 180;
857
+ return { x: centerX + radius * Math.cos(radians), y: centerY + radius * Math.sin(radians) };
858
+ }
859
+ function pieArc(centerX, centerY, radius, startAngle, endAngle) {
860
+ const start = polarPoint(centerX, centerY, radius, endAngle);
861
+ const end = polarPoint(centerX, centerY, radius, startAngle);
862
+ return `M ${centerX} ${centerY} L ${start.x} ${start.y} A ${radius} ${radius} 0 ${endAngle - startAngle > 180 ? 1 : 0} 0 ${end.x} ${end.y} Z`;
863
+ }
864
+ function SterlingPieChart({ data, ariaLabel }) {
865
+ const total = data.reduce((sum, datum) => sum + datum.value, 0);
866
+ let angle = 0;
867
+ return /* @__PURE__ */ jsx3("svg", { className: "sterling-chart", viewBox: "0 0 720 390", role: "img", "aria-label": ariaLabel, children: data.map((datum, index) => {
868
+ const start = angle;
869
+ const end = angle + datum.value / total * 360;
870
+ angle = end;
871
+ return /* @__PURE__ */ jsx3("path", { d: pieArc(360, 194, 138, start, end), fill: sterlingChartColors[index], stroke: "var(--sterling-surface)", strokeWidth: sterlingVisualStyle.stroke.mark, children: /* @__PURE__ */ jsx3("title", { children: `${datum.label}: ${datum.value.toLocaleString()} (${(datum.value / total * 100).toFixed(1)}%)` }) }, datum.label);
872
+ }) });
873
+ }
874
+ function SterlingChordChart({
875
+ rowLabels,
876
+ columnLabels,
877
+ values,
878
+ ariaLabel
879
+ }) {
880
+ const labels = [...rowLabels, ...columnLabels];
881
+ const matrix = Array.from({ length: labels.length }, () => Array(labels.length).fill(0));
882
+ values.forEach((row, rowIndex) => row.forEach((value, columnIndex) => {
883
+ matrix[rowIndex][rowLabels.length + columnIndex] = value;
884
+ matrix[rowLabels.length + columnIndex][rowIndex] = value;
885
+ }));
886
+ const chords = d3Chord().padAngle(0.055).sortSubgroups((left, right) => right - left)(matrix);
887
+ const arcPath = d3Arc().innerRadius(126).outerRadius(145).cornerRadius(3).startAngle((group) => group.startAngle).endAngle((group) => group.endAngle);
888
+ const ribbonPath = d3Ribbon().radius(122);
889
+ return /* @__PURE__ */ jsx3("svg", { className: "sterling-chart", viewBox: "0 0 720 420", role: "img", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxs3("g", { transform: "translate(360 204)", children: [
890
+ chords.map((item, index) => /* @__PURE__ */ jsx3("path", { d: ribbonPath(item) ?? void 0, fill: sterlingChartColors[item.source.index], fillOpacity: sterlingVisualStyle.opacity.relationship, children: /* @__PURE__ */ jsx3("title", { children: `${labels[item.source.index]} + ${labels[item.target.index]}: ${item.source.value}` }) }, `${item.source.index}-${item.target.index}-${index}`)),
891
+ chords.groups.map((group) => /* @__PURE__ */ jsx3("path", { d: arcPath(group) ?? void 0, fill: sterlingChartColors[group.index], stroke: "var(--sterling-surface)", strokeWidth: sterlingVisualStyle.stroke.mark }, group.index)),
892
+ chords.groups.map((group) => {
893
+ const angle = (group.startAngle + group.endAngle) / 2;
894
+ const x = Math.sin(angle) * 170;
895
+ const y = -Math.cos(angle) * 170;
896
+ return /* @__PURE__ */ jsx3("text", { x, y: y + 4, textAnchor: x < -8 ? "end" : x > 8 ? "start" : "middle", fill: chartText, fontSize: "10", fontFamily: "var(--font-mono)", children: labels[group.index] }, `label-${group.index}`);
897
+ })
898
+ ] }) });
899
+ }
900
+ function SterlingSankeyChart({ links, ariaLabel }) {
901
+ const sources = [...new Set(links.map((link) => link.source))];
902
+ const targets = [...new Set(links.map((link) => link.target))];
903
+ const labels = [...sources, ...targets];
904
+ const graph = d3Sankey().nodeWidth(14).nodePadding(12).extent([[112, 36], [608, 360]])({
905
+ nodes: labels.map((name, index) => ({ name, colorIndex: index })),
906
+ links: links.map((link) => ({
907
+ source: labels.indexOf(link.source),
908
+ target: labels.indexOf(link.target),
909
+ value: link.value,
910
+ sourceName: link.source,
911
+ targetName: link.target,
912
+ colorIndex: sources.indexOf(link.source)
913
+ }))
914
+ });
915
+ const linkPath = sankeyLinkHorizontal();
916
+ return /* @__PURE__ */ jsxs3("svg", { className: "sterling-chart", viewBox: "0 0 720 420", role: "img", "aria-label": ariaLabel, children: [
917
+ graph.links.map((link, index) => /* @__PURE__ */ jsx3(
918
+ "path",
919
+ {
920
+ d: linkPath(link) ?? void 0,
921
+ fill: "none",
922
+ stroke: sterlingChartColors[link.colorIndex],
923
+ strokeOpacity: sterlingVisualStyle.opacity.relationship,
924
+ strokeWidth: Math.max(sterlingVisualStyle.stroke.flowMinimum, link.width ?? sterlingVisualStyle.stroke.flowMinimum),
925
+ children: /* @__PURE__ */ jsx3("title", { children: `${link.sourceName} \u2192 ${link.targetName}: ${link.value}` })
926
+ },
927
+ `${link.sourceName}-${link.targetName}-${index}`
928
+ )),
929
+ graph.nodes.map((node) => {
930
+ const x0 = node.x0 ?? 0;
931
+ const x1 = node.x1 ?? x0;
932
+ const y0 = node.y0 ?? 0;
933
+ const y1 = node.y1 ?? y0;
934
+ const sourceSide = (node.depth ?? 0) === 0;
935
+ return /* @__PURE__ */ jsxs3("g", { children: [
936
+ /* @__PURE__ */ jsx3("rect", { x: x0, y: y0, width: Math.max(1, x1 - x0), height: Math.max(1, y1 - y0), rx: "2", fill: sterlingChartColors[node.colorIndex] }),
937
+ /* @__PURE__ */ jsx3("text", { x: sourceSide ? x0 - 10 : x1 + 10, y: (y0 + y1) / 2 + 4, textAnchor: sourceSide ? "end" : "start", fill: chartText, fontSize: "11", fontFamily: "var(--font-mono)", children: node.name })
938
+ ] }, node.name);
939
+ })
940
+ ] });
941
+ }
942
+
943
+ // src/canonicalCharts.tsx
944
+ import { geoAlbersUsa, geoPath } from "d3-geo";
945
+ import { hierarchy, treemap, treemapSquarify } from "d3-hierarchy";
946
+ import { feature } from "topojson-client";
947
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
948
+ var muted = "var(--sterling-muted)";
949
+ var grid = "var(--sterling-grid)";
950
+ var surface = "var(--sterling-surface)";
951
+ var text = "var(--sterling-text)";
952
+ function SterlingVerticalBarChart({ data, ariaLabel, yLabel, xLabel }) {
953
+ const f = frame(720, 380, { top: 26, right: 26, bottom: 56, left: 70 });
954
+ const y = linearScale([0, Math.max(...data.map(([, value]) => value), 1)], [f.y1, f.y0], { zero: true });
955
+ const { centers, step } = bandCenters(data.length, f.x0, f.x1);
956
+ const width = Math.min(70, step * 0.62);
957
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
958
+ /* @__PURE__ */ jsx4(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
959
+ data.map(([label, value], index) => {
960
+ const cx = centers[index];
961
+ return /* @__PURE__ */ jsxs4("g", { children: [
962
+ /* @__PURE__ */ jsx4("rect", { x: cx - width / 2, y: y(value), width, height: f.y1 - y(value), rx: "6", fill: sterlingChartColors[index], children: /* @__PURE__ */ jsx4("title", { children: `${label}: ${value.toFixed(1)}` }) }),
963
+ /* @__PURE__ */ jsx4("text", { x: cx, y: y(value) - 8, textAnchor: "middle", fill: muted, fontSize: "11", fontFamily: "var(--font-mono)", children: value.toFixed(1) }),
964
+ /* @__PURE__ */ jsx4("text", { x: cx, y: f.y1 + 18, textAnchor: "middle", fill: text, fontSize: "12", fontFamily: "var(--font-mono)", children: label })
965
+ ] }, label);
966
+ }),
967
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
968
+ /* @__PURE__ */ jsx4("line", { x1: f.x0, x2: f.x1, y1: f.y1, y2: f.y1, stroke: "var(--sterling-edge)" }),
969
+ xLabel ? /* @__PURE__ */ jsx4("text", { x: (f.x0 + f.x1) / 2, y: f.y1 + 42, textAnchor: "middle", fill: muted, fontSize: "12", fontFamily: "var(--font-mono)", children: xLabel }) : null
970
+ ] });
971
+ }
972
+ function SterlingCandlestickChart({ rows, ariaLabel, yLabel, xLabel }) {
973
+ const values = rows.flatMap(([, open, high, low, close]) => [open, high, low, close]);
974
+ const f = frame(720, 380, { top: 26, right: 26, bottom: 56, left: 70 });
975
+ const y = linearScale(values, [f.y1, f.y0], { padFraction: 0.06 });
976
+ const { centers, step } = bandCenters(rows.length, f.x0, f.x1);
977
+ const bodyWidth = Math.min(15, step * 0.62);
978
+ const rising = sterlingDivergentColors[2];
979
+ const falling = sterlingDivergentColors[8];
980
+ const labelStep = Math.max(1, Math.ceil(rows.length / 8));
981
+ const lastIndex = rows.length - 1;
982
+ const showDate = (index) => index === lastIndex || index % labelStep === 0 && lastIndex - index >= labelStep * 0.55;
983
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
984
+ /* @__PURE__ */ jsx4(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
985
+ rows.map(([date, open, high, low, close], index) => {
986
+ const x = centers[index];
987
+ const up = close >= open;
988
+ const color = up ? rising : falling;
989
+ const top = y(Math.max(open, close));
990
+ const bottom = y(Math.min(open, close));
991
+ return /* @__PURE__ */ jsxs4("g", { children: [
992
+ /* @__PURE__ */ jsx4("title", { children: `${date}: open ${open}, high ${high}, low ${low}, close ${close}` }),
993
+ /* @__PURE__ */ jsx4("line", { x1: x, x2: x, y1: y(high), y2: y(low), stroke: color, strokeWidth: sterlingVisualStyle.stroke.candle }),
994
+ /* @__PURE__ */ jsx4("rect", { x: x - bodyWidth / 2, y: top, width: bodyWidth, height: Math.max(2, bottom - top), rx: "1.5", fill: up ? color : surface, stroke: color, strokeWidth: sterlingVisualStyle.stroke.candle }),
995
+ showDate(index) ? /* @__PURE__ */ jsx4("text", { x, y: f.y1 + 18, textAnchor: "middle", fill: muted, fontSize: "10", fontFamily: "var(--font-mono)", children: date }) : null
996
+ ] }, date);
997
+ }),
998
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel, format: (value) => value.toFixed(0) }),
999
+ /* @__PURE__ */ jsx4("line", { x1: f.x0, x2: f.x1, y1: f.y1, y2: f.y1, stroke: "var(--sterling-edge)" }),
1000
+ xLabel ? /* @__PURE__ */ jsx4("text", { x: (f.x0 + f.x1) / 2, y: f.y1 + 42, textAnchor: "middle", fill: muted, fontSize: "12", fontFamily: "var(--font-mono)", children: xLabel }) : null
1001
+ ] });
1002
+ }
1003
+ function polar(cx, cy, radius, index, count) {
1004
+ const angle = -Math.PI / 2 + index * Math.PI * 2 / count;
1005
+ return [cx + Math.cos(angle) * radius, cy + Math.sin(angle) * radius];
1006
+ }
1007
+ function SterlingRadarChart({ labels, series, domain, ariaLabel, unit = "" }) {
1008
+ const cx = 360, cy = 196, radius = 130;
1009
+ const scale = (value) => (value - domain[0]) / Math.max(domain[1] - domain[0], 1) * radius;
1010
+ const levels = [0.2, 0.4, 0.6, 0.8, 1];
1011
+ const ringValue = (level) => domain[0] + level * (domain[1] - domain[0]);
1012
+ const format = (value) => `${Number.isInteger(value) ? value : value.toFixed(1)}${unit}`;
1013
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 720 390", role: "img", "aria-label": ariaLabel, children: [
1014
+ levels.map((level) => /* @__PURE__ */ jsx4("polygon", { points: labels.map((_, index) => polar(cx, cy, radius * level, index, labels.length).join(",")).join(" "), fill: "none", stroke: grid }, level)),
1015
+ labels.map((label, index) => {
1016
+ const [x, y] = polar(cx, cy, radius, index, labels.length);
1017
+ const [lx, ly] = polar(cx, cy, radius + 24, index, labels.length);
1018
+ return /* @__PURE__ */ jsxs4("g", { children: [
1019
+ /* @__PURE__ */ jsx4("line", { x1: cx, y1: cy, x2: x, y2: y, stroke: grid }),
1020
+ /* @__PURE__ */ jsx4("text", { x: lx, y: ly + 4, textAnchor: "middle", fill: muted, fontSize: "10", fontFamily: "var(--font-mono)", children: label })
1021
+ ] }, label);
1022
+ }),
1023
+ series.map(([name, ...values], index) => {
1024
+ const color = sterlingSequentialColors[Math.min(9, index + 2)];
1025
+ const latest = index === series.length - 1;
1026
+ return /* @__PURE__ */ jsx4("polygon", { points: values.map((value, axis) => polar(cx, cy, scale(value), axis, labels.length).join(",")).join(" "), fill: latest ? color : "none", fillOpacity: sterlingVisualStyle.opacity.surface, stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail, strokeOpacity: latest ? 1 : sterlingVisualStyle.opacity.guide, children: /* @__PURE__ */ jsx4("title", { children: `${name}: ${values.join(", ")}` }) }, name);
1027
+ }),
1028
+ [0, ...levels].map((level) => /* @__PURE__ */ jsx4(
1029
+ "text",
1030
+ {
1031
+ x: cx + 6,
1032
+ y: cy - radius * level + 3,
1033
+ fill: muted,
1034
+ fontSize: "9",
1035
+ fontFamily: "var(--font-mono)",
1036
+ stroke: surface,
1037
+ strokeWidth: sterlingVisualStyle.stroke.halo,
1038
+ paintOrder: "stroke",
1039
+ children: format(ringValue(level))
1040
+ },
1041
+ `r-${level}`
1042
+ ))
1043
+ ] });
1044
+ }
1045
+ function SterlingRidgelineChart({ groups, ariaLabel, xLabel, unit = "" }) {
1046
+ const all = groups.flatMap((group) => group.values);
1047
+ const observedMin = Math.min(...all);
1048
+ const observedMax = Math.max(...all);
1049
+ const margin = (observedMax - observedMin) * 0.08;
1050
+ const domain = [observedMin - margin, observedMax + margin];
1051
+ const x0 = 118, x1 = 664;
1052
+ const baseline = 338;
1053
+ const rowStep = (baseline - 60) / Math.max(groups.length, 1);
1054
+ const amplitude = rowStep * 1.9;
1055
+ const x = linearScale(domain, [x0, x1], { padFraction: 0 });
1056
+ const peak = Math.max(
1057
+ ...groups.map((group) => Math.max(...kernelDensity(group.values, 96, domain).map((point) => point.density))),
1058
+ Number.EPSILON
1059
+ );
1060
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 720 390", role: "img", "aria-label": ariaLabel, children: [
1061
+ x.ticks(6).map((value) => /* @__PURE__ */ jsx4("line", { x1: x(value), x2: x(value), y1: 26, y2: baseline, stroke: grid, strokeWidth: sterlingVisualStyle.stroke.grid }, value)),
1062
+ groups.map((source, index) => {
1063
+ const base = 60 + index * rowStep;
1064
+ const density = kernelDensity(source.values, 96, domain);
1065
+ const points = density.map((point) => `${x(point.value)} ${base - point.density / peak * amplitude}`);
1066
+ const color = sterlingChartColors[index % sterlingChartColors.length];
1067
+ return /* @__PURE__ */ jsxs4("g", { children: [
1068
+ /* @__PURE__ */ jsx4("text", { x: x0 - 12, y: base + 3, textAnchor: "end", fill: text, fontSize: "10", fontFamily: "var(--font-mono)", children: source.label }),
1069
+ /* @__PURE__ */ jsx4("path", { d: `M ${x(domain[0])} ${base} L ${points.join(" L ")} L ${x(domain[1])} ${base} Z`, fill: color, fillOpacity: sterlingVisualStyle.opacity.ridge, stroke: color, strokeWidth: sterlingVisualStyle.stroke.series, strokeLinejoin: "round" })
1070
+ ] }, source.label);
1071
+ }),
1072
+ /* @__PURE__ */ jsx4(AxisBottom, { scale: x, y: baseline, count: 6, title: xLabel, format: (value) => `${value}${unit}` })
1073
+ ] });
1074
+ }
1075
+ function SterlingDensity2DChart({ points, regionLabels, ariaLabel, xLabel, yLabel }) {
1076
+ const f = frame(720, 380, { top: 26, right: 26, bottom: 56, left: 74 });
1077
+ const x = linearScale(points.map((point) => point[0]), [f.x0, f.x1]);
1078
+ const y = linearScale(points.map((point) => point[1]), [f.y1, f.y0]);
1079
+ const pxX = Math.abs(x(1e3) - x(0)) / 1e3;
1080
+ const pxY = Math.abs(y(1) - y(0));
1081
+ const specs = [[4570, 71.26, 559, 0.74, 0.36], [4012, 69.71, 605, 1.02, 0.46], [4611, 71.77, 283, 1.04, -0.03], [4703, 71.23, 664, 1.35, -0.29]];
1082
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
1083
+ /* @__PURE__ */ jsx4(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
1084
+ specs.flatMap(([meanX, meanY, sdX, sdY, correlation2], index) => [1, 0.68, 0.38].map((level) => /* @__PURE__ */ jsx4("ellipse", { cx: x(meanX), cy: y(meanY), rx: sdX * pxX * 1.7 * level, ry: sdY * pxY * 1.7 * level, transform: `rotate(${-correlation2 * 35} ${x(meanX)} ${y(meanY)})`, fill: sterlingChartColors[index], fillOpacity: sterlingVisualStyle.opacity.contour, stroke: sterlingChartColors[index], strokeWidth: sterlingVisualStyle.stroke.detail }, `${index}-${level}`))),
1085
+ points.map(([income, life, group], index) => /* @__PURE__ */ jsx4("circle", { cx: x(income), cy: y(life), r: "4", fill: sterlingChartColors[group], fillOpacity: sterlingVisualStyle.opacity.secondaryMark, children: /* @__PURE__ */ jsx4("title", { children: `${regionLabels[group]}: ${income}, ${life}` }) }, index)),
1086
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
1087
+ /* @__PURE__ */ jsx4(AxisBottom, { scale: x, y: f.y1, count: 6, title: xLabel, format: (value) => `${(value / 1e3).toFixed(1)}k` })
1088
+ ] });
1089
+ }
1090
+ function SterlingTreemapChart({ rows, ariaLabel }) {
1091
+ const continents = [...new Set(rows.map(([continent]) => continent))];
1092
+ const rootData = {
1093
+ name: "world",
1094
+ children: continents.map((continent) => ({
1095
+ name: continent,
1096
+ continent,
1097
+ children: rows.filter(([name]) => name === continent).map(([, , country, value]) => ({ name: country, continent, value }))
1098
+ }))
1099
+ };
1100
+ const rankByCountry = /* @__PURE__ */ new Map();
1101
+ continents.forEach((continent) => {
1102
+ const list = rows.filter(([name]) => name === continent).sort((left, right) => right[3] - left[3]);
1103
+ list.forEach(([, , country], index) => rankByCountry.set(country, { rank: index, total: list.length }));
1104
+ });
1105
+ const stopFor = (country) => {
1106
+ const entry = rankByCountry.get(country);
1107
+ if (!entry || entry.total < 2) return sterlingRampStops;
1108
+ return Math.round(sterlingRampStops - entry.rank * (sterlingRampStops - 1) / (entry.total - 1));
1109
+ };
1110
+ const treeRoot = hierarchy(rootData).sum((datum) => datum.value ?? 0).sort((left, right) => (right.value ?? 0) - (left.value ?? 0));
1111
+ const root = treemap().tile(treemapSquarify).size([680, 330]).paddingInner(3).paddingOuter(4).paddingTop((node) => node.depth === 1 ? 21 : 0).round(true)(treeRoot);
1112
+ return /* @__PURE__ */ jsx4("svg", { className: "sterling-chart", viewBox: "0 0 720 370", role: "img", "aria-label": ariaLabel, children: /* @__PURE__ */ jsxs4("g", { transform: "translate(20 20)", children: [
1113
+ root.descendants().filter((node) => node.depth === 1).map((node) => {
1114
+ const color = sterlingChartColors[continents.indexOf(node.data.name)];
1115
+ return /* @__PURE__ */ jsxs4("g", { children: [
1116
+ /* @__PURE__ */ jsx4("rect", { x: node.x0, y: node.y0, width: node.x1 - node.x0, height: node.y1 - node.y0, rx: "3", fill: "none", stroke: color, strokeWidth: sterlingVisualStyle.stroke.detail }),
1117
+ /* @__PURE__ */ jsx4("text", { x: node.x0 + 6, y: node.y0 + 13, fill: color, fontSize: "9", fontFamily: "var(--font-mono)", fontWeight: "700", children: node.data.name })
1118
+ ] }, `group-${node.data.name}`);
1119
+ }),
1120
+ root.leaves().map((leaf) => {
1121
+ const continent = leaf.data.continent ?? "";
1122
+ const width = leaf.x1 - leaf.x0;
1123
+ const height = leaf.y1 - leaf.y0;
1124
+ const fontSize = width > 120 ? 10 : 8;
1125
+ const stop = stopFor(leaf.data.name);
1126
+ const fits = width > leaf.data.name.length * fontSize * 0.62 + 10 && height > fontSize * 2.4;
1127
+ return /* @__PURE__ */ jsxs4("g", { children: [
1128
+ /* @__PURE__ */ jsx4("rect", { x: leaf.x0, y: leaf.y0, width, height, rx: "2", fill: sterlingRamp(continents.indexOf(continent), stop), children: /* @__PURE__ */ jsx4("title", { children: `${leaf.data.name}: ${(leaf.value ?? 0).toLocaleString()}` }) }),
1129
+ fits ? /* @__PURE__ */ jsx4("text", { x: leaf.x0 + 6, y: leaf.y0 + fontSize + 5, fill: stop > sterlingRampStops / 2 ? surface : text, fontSize, fontFamily: "var(--font-mono)", children: leaf.data.name }) : null
1130
+ ] }, leaf.data.name);
1131
+ })
1132
+ ] }) });
1133
+ }
1134
+ function SterlingNetworkChart({ nodes, edges, ariaLabel }) {
1135
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 560 300", role: "img", "aria-label": ariaLabel, children: [
1136
+ edges.map(([source, target], index) => /* @__PURE__ */ jsx4("line", { x1: nodes[source][1] + 42, y1: nodes[source][2], x2: nodes[target][1] + 42, y2: nodes[target][2], stroke: grid, strokeWidth: sterlingVisualStyle.stroke.detail }, index)),
1137
+ nodes.map(([name, x, y, degree, community]) => {
1138
+ const radius = 5 + (degree - 10) * 0.45;
1139
+ return /* @__PURE__ */ jsxs4("g", { children: [
1140
+ /* @__PURE__ */ jsx4("circle", { cx: x + 42, cy: y, r: radius, fill: sterlingChartColors[community], stroke: surface, strokeWidth: sterlingVisualStyle.stroke.mark, children: /* @__PURE__ */ jsx4("title", { children: `${name}: ${degree}` }) }),
1141
+ degree >= 19 || name === "Y Holtz" ? /* @__PURE__ */ jsx4("text", { x: x + 42, y: y - radius - 7, textAnchor: "middle", fill: muted, fontSize: "7.5", fontFamily: "var(--font-mono)", children: name }) : null
1142
+ ] }, name);
1143
+ })
1144
+ ] });
1145
+ }
1146
+ function SterlingDendrogramChart({ labels, merge, height, order, groups, ariaLabel, yLabel, cutLabel }) {
1147
+ const leafY = 270, maximum = Math.max(...height), axisX = 78, step = (666 - axisX - 24) / (order.length - 1);
1148
+ const leafX = new Map(order.map((leaf, position) => [leaf, axisX + 12 + position * step]));
1149
+ const groupByLeaf = /* @__PURE__ */ new Map();
1150
+ groups.forEach((members, group) => members.forEach((leaf) => groupByLeaf.set(leaf, group)));
1151
+ const dist = linearScale([0, maximum], [leafY, leafY - 206], { zero: true });
1152
+ const clusters = [];
1153
+ const child = (reference) => reference < 0 ? { x: leafX.get(-reference) ?? axisX, y: leafY, members: [-reference], group: groupByLeaf.get(-reference) ?? null } : clusters[reference - 1];
1154
+ const branches = merge.map(([leftRef, rightRef], index) => {
1155
+ const left = child(leftRef), right = child(rightRef), nodeY = dist(height[index]), members = [...left.members, ...right.members], memberships = [...new Set(members.map((leaf) => groupByLeaf.get(leaf)))], group = memberships.length === 1 ? memberships[0] ?? null : null;
1156
+ clusters.push({ x: (left.x + right.x) / 2, y: nodeY, members, group });
1157
+ return { left, right, y: nodeY, group };
1158
+ });
1159
+ const cut = 0.388, cutY = dist(cut);
1160
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 720 390", role: "img", "aria-label": ariaLabel, children: [
1161
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: dist, x: axisX, gridX1: 666, count: 5, title: yLabel }),
1162
+ /* @__PURE__ */ jsx4("line", { x1: axisX, x2: "666", y1: cutY, y2: cutY, stroke: muted, strokeDasharray: "5 5" }),
1163
+ cutLabel ? /* @__PURE__ */ jsx4("text", { x: "666", y: cutY - 6, textAnchor: "end", fill: muted, fontSize: "9", fontFamily: "var(--font-mono)", children: `${cutLabel} ${cut}` }) : null,
1164
+ groups.map((members, index) => {
1165
+ const positions = members.map((leaf) => leafX.get(leaf) ?? 0);
1166
+ const x0 = Math.min(...positions) - 9, x1 = Math.max(...positions) + 9;
1167
+ return /* @__PURE__ */ jsx4("rect", { x: x0, y: cutY, width: x1 - x0, height: leafY - cutY + 50, rx: "6", fill: sterlingChartColors[index], fillOpacity: sterlingVisualStyle.opacity.ghost, stroke: sterlingChartColors[index], strokeWidth: sterlingVisualStyle.stroke.detail }, index);
1168
+ }),
1169
+ branches.map(({ left, right, y, group }, index) => /* @__PURE__ */ jsxs4("g", { children: [
1170
+ /* @__PURE__ */ jsx4("path", { d: `M ${left.x} ${left.y} V ${y}`, stroke: left.group === null ? muted : sterlingChartColors[left.group], fill: "none", strokeWidth: sterlingVisualStyle.stroke.detail }),
1171
+ /* @__PURE__ */ jsx4("path", { d: `M ${right.x} ${right.y} V ${y}`, stroke: right.group === null ? muted : sterlingChartColors[right.group], fill: "none", strokeWidth: sterlingVisualStyle.stroke.detail }),
1172
+ /* @__PURE__ */ jsx4("path", { d: `M ${left.x} ${y} H ${right.x}`, stroke: group === null ? muted : sterlingChartColors[group], fill: "none", strokeWidth: sterlingVisualStyle.stroke.detail })
1173
+ ] }, index)),
1174
+ order.map((leaf) => {
1175
+ const x = leafX.get(leaf) ?? 0, group = groupByLeaf.get(leaf) ?? 0;
1176
+ return /* @__PURE__ */ jsxs4("g", { children: [
1177
+ /* @__PURE__ */ jsx4("circle", { cx: x, cy: leafY, r: "3.5", fill: sterlingChartColors[group] }),
1178
+ /* @__PURE__ */ jsx4("text", { x: x + 3, y: leafY + 12, transform: `rotate(50 ${x + 3} ${leafY + 12})`, fill: muted, fontSize: "7.5", fontFamily: "var(--font-mono)", children: labels[leaf - 1] })
1179
+ ] }, leaf);
1180
+ })
1181
+ ] });
1182
+ }
1183
+ function SterlingVolcanoChart({ hex, labels, ariaLabel, xLabel, yLabel }) {
1184
+ const genes = Array.from({ length: hex.length / 4 }, (_, index) => {
1185
+ const offset = index * 4;
1186
+ return [parseInt(hex.slice(offset, offset + 2), 16) / 255 * 12 - 6, parseInt(hex.slice(offset + 2, offset + 4), 16) / 255 * 5];
1187
+ });
1188
+ const f = frame(720, 380, { top: 26, right: 26, bottom: 56, left: 70 });
1189
+ const x = linearScale([-6, 6], [f.x0, f.x1], { padFraction: 0 });
1190
+ const y = linearScale([0, 5], [f.y1, f.y0], { zero: true });
1191
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
1192
+ /* @__PURE__ */ jsx4(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
1193
+ /* @__PURE__ */ jsx4("line", { x1: x(0), x2: x(0), y1: f.y0, y2: f.y1, stroke: grid, strokeWidth: sterlingVisualStyle.stroke.grid }),
1194
+ [-1, 1].map((v) => /* @__PURE__ */ jsx4("line", { x1: x(v), x2: x(v), y1: f.y0, y2: f.y1, stroke: sterlingChartColors[7], strokeDasharray: "5 5", strokeOpacity: sterlingVisualStyle.opacity.guide, strokeWidth: sterlingVisualStyle.stroke.grid }, v)),
1195
+ /* @__PURE__ */ jsx4("line", { x1: f.x0, x2: f.x1, y1: y(1.3), y2: y(1.3), stroke: sterlingChartColors[7], strokeDasharray: "5 5", strokeOpacity: sterlingVisualStyle.opacity.guide, strokeWidth: sterlingVisualStyle.stroke.grid }),
1196
+ genes.map(([effect, evidence], index) => {
1197
+ const significant = Math.abs(effect) >= 1 && evidence >= 1.3;
1198
+ const color = significant ? effect < 0 ? sterlingChartColors[2] : sterlingChartColors[1] : sterlingChartColors[7];
1199
+ return /* @__PURE__ */ jsx4("circle", { cx: x(effect), cy: y(evidence), r: significant ? 2.5 : 1.6, fill: color, fillOpacity: significant ? sterlingVisualStyle.opacity.signal : sterlingVisualStyle.opacity.mutedMark }, index);
1200
+ }),
1201
+ labels.map(([gene, effect, evidence]) => /* @__PURE__ */ jsxs4("g", { children: [
1202
+ /* @__PURE__ */ jsx4("circle", { cx: x(effect), cy: y(evidence), r: "4", fill: effect < 0 ? sterlingChartColors[2] : sterlingChartColors[1], stroke: surface }),
1203
+ /* @__PURE__ */ jsx4("text", { x: x(effect), y: y(evidence) - 8, textAnchor: "middle", fill: text, fontSize: "8", fontFamily: "var(--font-mono)", children: gene })
1204
+ ] }, gene)),
1205
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
1206
+ /* @__PURE__ */ jsx4(AxisBottom, { scale: x, y: f.y1, count: 7, title: xLabel })
1207
+ ] });
1208
+ }
1209
+ function SterlingManhattanChart({ hex, labels, chromosomeCenters, ariaLabel, xLabel, yLabel }) {
1210
+ const points = Array.from({ length: hex.length / 8 }, (_, index) => {
1211
+ const offset = index * 8;
1212
+ return [parseInt(hex.slice(offset, offset + 4), 16) / 65535, parseInt(hex.slice(offset + 4, offset + 6), 16) / 255 * 9, parseInt(hex.slice(offset + 6, offset + 8), 16)];
1213
+ });
1214
+ const f = frame(720, 380, { top: 26, right: 26, bottom: 56, left: 70 });
1215
+ const x = (v) => f.x0 + v * (f.x1 - f.x0);
1216
+ const y = linearScale([0, 9], [f.y1, f.y0], { zero: true });
1217
+ const threshold = -Math.log10(5e-8);
1218
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: `0 0 ${f.width} ${f.height}`, role: "img", "aria-label": ariaLabel, children: [
1219
+ /* @__PURE__ */ jsx4(Gridlines, { scale: y, x0: f.x0, x1: f.x1, count: 5 }),
1220
+ /* @__PURE__ */ jsx4("line", { x1: f.x0, x2: f.x1, y1: y(threshold), y2: y(threshold), stroke: sterlingChartColors[5], strokeDasharray: "5 5" }),
1221
+ points.map(([position, evidence, chromosome], index) => /* @__PURE__ */ jsx4("circle", { cx: x(position), cy: y(evidence), r: evidence >= threshold ? 3 : 1.5, fill: sterlingChartColors[chromosome % 2 === 0 ? 4 : 0], fillOpacity: evidence >= threshold ? 1 : sterlingVisualStyle.opacity.secondaryMark }, index)),
1222
+ labels.slice(0, 1).map(([name, chromosome, position, evidence]) => /* @__PURE__ */ jsxs4("g", { children: [
1223
+ /* @__PURE__ */ jsx4("circle", { cx: x(position), cy: y(evidence), r: "4", fill: sterlingChartColors[chromosome % 2 === 0 ? 4 : 0], stroke: surface }),
1224
+ /* @__PURE__ */ jsx4("text", { x: x(position) + 8, y: y(evidence) - 8, fill: text, fontSize: "8", fontFamily: "var(--font-mono)", children: `chr${chromosome} \xB7 ${name}` })
1225
+ ] }, name)),
1226
+ /* @__PURE__ */ jsx4(AxisLeft, { scale: y, x: f.x0, count: 5, title: yLabel }),
1227
+ /* @__PURE__ */ jsx4("line", { x1: f.x0, x2: f.x1, y1: f.y1, y2: f.y1, stroke: "var(--sterling-edge)" }),
1228
+ chromosomeCenters.map((position, index) => /* @__PURE__ */ jsx4("text", { x: x(position), y: f.y1 + 16, textAnchor: "middle", fill: muted, fontSize: "8", fontFamily: "var(--font-mono)", children: index + 1 }, index)),
1229
+ xLabel ? /* @__PURE__ */ jsx4("text", { x: (f.x0 + f.x1) / 2, y: f.y1 + 42, textAnchor: "middle", fill: muted, fontSize: "12", fontFamily: "var(--font-mono)", children: xLabel }) : null
1230
+ ] });
1231
+ }
1232
+ function correlation(left, right) {
1233
+ const lm = left.reduce((a, b) => a + b, 0) / left.length, rm = right.reduce((a, b) => a + b, 0) / right.length;
1234
+ let n = 0, ls = 0, rs = 0;
1235
+ left.forEach((value, index) => {
1236
+ const l = value - lm, r = right[index] - rm;
1237
+ n += l * r;
1238
+ ls += l * l;
1239
+ rs += r * r;
1240
+ });
1241
+ return n / Math.sqrt(ls * rs);
1242
+ }
1243
+ function clusterVectors(vectors, memberships) {
1244
+ const distances = vectors.map((left, li) => vectors.map((right, ri) => li === ri ? 0 : 1 - correlation(left, right)));
1245
+ let clusters = vectors.map((_, i) => ({ members: [i], left: null, right: null, height: 0, group: memberships[i] }));
1246
+ const meanMembership = (c) => c.members.reduce((s, m) => s + memberships[m], 0) / c.members.length;
1247
+ while (clusters.length > 1) {
1248
+ let bestLeft = 0, bestRight = 1, bestDistance = Number.POSITIVE_INFINITY;
1249
+ for (let i = 0; i < clusters.length; i += 1) {
1250
+ for (let j = i + 1; j < clusters.length; j += 1) {
1251
+ const L2 = clusters[i], R2 = clusters[j];
1252
+ const d = L2.members.reduce((sum, lm) => sum + R2.members.reduce((inner, rm) => inner + distances[lm][rm], 0), 0) / (L2.members.length * R2.members.length);
1253
+ if (d < bestDistance) {
1254
+ bestDistance = d;
1255
+ bestLeft = i;
1256
+ bestRight = j;
1257
+ }
1258
+ }
1259
+ }
1260
+ let L = clusters[bestLeft], R = clusters[bestRight];
1261
+ if (meanMembership(L) > meanMembership(R)) {
1262
+ [L, R] = [R, L];
1263
+ }
1264
+ const members = [...L.members, ...R.members];
1265
+ const groupSet = [...new Set(members.map((m) => memberships[m]))];
1266
+ const merged = { members, left: L, right: R, height: bestDistance, group: groupSet.length === 1 ? groupSet[0] : null };
1267
+ clusters = clusters.filter((_, index) => index !== bestLeft && index !== bestRight);
1268
+ clusters.push(merged);
1269
+ }
1270
+ return clusters[0];
1271
+ }
1272
+ function leafOrder(node) {
1273
+ return node.left ? [...leafOrder(node.left), ...leafOrder(node.right)] : node.members;
1274
+ }
1275
+ function SterlingExpressionChart({ hex, groups, types, ariaLabel }) {
1276
+ const columns = groups.length;
1277
+ const raw = Array.from({ length: hex.length / 2 }, (_, index) => parseInt(hex.slice(index * 2, index * 2 + 2), 16) / 255 * 5 - 2.5);
1278
+ const genes = raw.length / columns;
1279
+ const matrix = Array.from({ length: genes }, (_, row) => raw.slice(row * columns, (row + 1) * columns));
1280
+ const columnVectors = Array.from({ length: columns }, (_, column) => matrix.map((row) => row[column]));
1281
+ const tree = clusterVectors(columnVectors, groups);
1282
+ const order = leafOrder(tree);
1283
+ const cell = 9.25;
1284
+ const startX = 132;
1285
+ const startY = 86;
1286
+ const matrixSize = columns * cell;
1287
+ const columnCenter = (visible) => startX + visible * cell + cell / 2;
1288
+ const rowCenter = (visible) => startY + visible * cell + cell / 2;
1289
+ const branchColor = (node) => node.group === null ? muted : sterlingChartColors[node.group];
1290
+ const maxHeight = Math.max(tree.height, 1e-4);
1291
+ const visibleIndex = new Map(order.map((original, visible) => [original, visible]));
1292
+ const cells = order.flatMap(
1293
+ (row, visibleRow) => order.map((column, visibleColumn) => {
1294
+ const value = correlation(columnVectors[row], columnVectors[column]);
1295
+ return /* @__PURE__ */ jsx4("rect", { x: startX + visibleColumn * cell, y: startY + visibleRow * cell, width: cell + 0.1, height: cell + 0.1, fill: divergentSignedColor(value, 1), children: /* @__PURE__ */ jsx4("title", { children: `${types[groups[row]]} \xD7 ${types[groups[column]]}: r ${value.toFixed(2)}` }) }, `${visibleRow}-${visibleColumn}`);
1296
+ })
1297
+ );
1298
+ const topAnnotations = order.map((column, visible) => /* @__PURE__ */ jsx4("rect", { x: startX + visible * cell, y: "78", width: cell + 0.1, height: "5", fill: sterlingChartColors[groups[column]] }, `ta-${visible}`));
1299
+ const leftAnnotations = order.map((row, visible) => /* @__PURE__ */ jsx4("rect", { x: "124", y: startY + visible * cell, width: "5", height: cell + 0.1, fill: sterlingChartColors[groups[row]] }, `la-${visible}`));
1300
+ const runs = [];
1301
+ order.forEach((column, index) => {
1302
+ const group = groups[column];
1303
+ const previous = runs[runs.length - 1];
1304
+ if (previous && previous.group === group) previous.length += 1;
1305
+ else runs.push({ group, start: index, length: 1 });
1306
+ });
1307
+ const regionFrames = runs.map(({ group, start, length }, index) => /* @__PURE__ */ jsx4("rect", { x: startX + start * cell + 0.7, y: startY + start * cell + 0.7, width: length * cell - 1.4, height: length * cell - 1.4, fill: "none", stroke: sterlingChartColors[group], strokeWidth: sterlingVisualStyle.stroke.series }, `rf-${index}`));
1308
+ const topMarks = [];
1309
+ let topKey = 0;
1310
+ const renderTop = (node) => {
1311
+ if (!node.left) return { x: columnCenter(visibleIndex.get(node.members[0])), y: 75 };
1312
+ const l = renderTop(node.left);
1313
+ const r = renderTop(node.right);
1314
+ const y = 75 - node.height / maxHeight * 55;
1315
+ const x = (l.x + r.x) / 2;
1316
+ topMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${l.x} ${l.y} V${y}`, fill: "none", stroke: branchColor(node.left), strokeWidth: sterlingVisualStyle.stroke.grid }, `tm-${topKey++}`));
1317
+ topMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${r.x} ${r.y} V${y}`, fill: "none", stroke: branchColor(node.right), strokeWidth: sterlingVisualStyle.stroke.grid }, `tm-${topKey++}`));
1318
+ topMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${l.x} ${y} H${r.x}`, fill: "none", stroke: branchColor(node), strokeWidth: sterlingVisualStyle.stroke.grid }, `tm-${topKey++}`));
1319
+ return { x, y };
1320
+ };
1321
+ renderTop(tree);
1322
+ const leftMarks = [];
1323
+ let leftKey = 0;
1324
+ const renderLeft = (node) => {
1325
+ if (!node.left) return { x: 121, y: rowCenter(visibleIndex.get(node.members[0])) };
1326
+ const l = renderLeft(node.left);
1327
+ const r = renderLeft(node.right);
1328
+ const x = 121 - node.height / maxHeight * 78;
1329
+ const y = (l.y + r.y) / 2;
1330
+ leftMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${l.x} ${l.y} H${x}`, fill: "none", stroke: branchColor(node.left), strokeWidth: sterlingVisualStyle.stroke.grid }, `lm-${leftKey++}`));
1331
+ leftMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${r.x} ${r.y} H${x}`, fill: "none", stroke: branchColor(node.right), strokeWidth: sterlingVisualStyle.stroke.grid }, `lm-${leftKey++}`));
1332
+ leftMarks.push(/* @__PURE__ */ jsx4("path", { d: `M${x} ${l.y} V${r.y}`, fill: "none", stroke: branchColor(node), strokeWidth: sterlingVisualStyle.stroke.grid }, `lm-${leftKey++}`));
1333
+ return { x, y };
1334
+ };
1335
+ renderLeft(tree);
1336
+ const rowLabels = order.map((row, visible) => /* @__PURE__ */ jsx4("text", { x: startX + matrixSize + 7, y: startY + visible * cell + 6.3, fill: muted, fontSize: "6", fontFamily: "var(--font-mono)", children: `${types[groups[row]]} ${row % 4 + 1}` }, `rl-${visible}`));
1337
+ const legendStops = Array.from({ length: 21 }, (_, index) => {
1338
+ const value = -1 + index / 20 * 2;
1339
+ return /* @__PURE__ */ jsx4("rect", { x: 132 + index * 5, y: "394", width: "5.2", height: "8", fill: divergentSignedColor(value, 1) }, `ls-${index}`);
1340
+ });
1341
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 600 416", role: "img", "aria-label": ariaLabel, children: [
1342
+ topMarks,
1343
+ leftMarks,
1344
+ topAnnotations,
1345
+ leftAnnotations,
1346
+ cells,
1347
+ regionFrames,
1348
+ rowLabels,
1349
+ legendStops,
1350
+ /* @__PURE__ */ jsx4("text", { x: "126", y: "401", textAnchor: "end", fill: muted, fontSize: "6.4", fontFamily: "var(--font-mono)", children: "-1" }),
1351
+ /* @__PURE__ */ jsx4("text", { x: "242", y: "401", fill: muted, fontSize: "6.4", fontFamily: "var(--font-mono)", children: "+1 r" })
1352
+ ] });
1353
+ }
1354
+ function SterlingGeoMapChart({ atlas, rows, ariaLabel }) {
1355
+ const topology = atlas;
1356
+ const collection = feature(atlas, topology.objects.states);
1357
+ const projection = geoAlbersUsa().fitSize([620, 286], collection);
1358
+ const path = geoPath(projection);
1359
+ const valueById = new Map(rows.map((row) => [row.id, row]));
1360
+ const maximum = Math.max(...rows.map((row) => row.engineers));
1361
+ return /* @__PURE__ */ jsxs4("svg", { className: "sterling-chart", viewBox: "0 0 720 390", role: "img", "aria-label": ariaLabel, children: [
1362
+ /* @__PURE__ */ jsx4("g", { transform: "translate(50 18)", children: collection.features.map((state, index) => {
1363
+ const id = Number(state.id), row = valueById.get(id), value = row?.engineers ?? 0, colorIndex = Math.min(9, Math.max(0, Math.round(value / maximum * 9)));
1364
+ return /* @__PURE__ */ jsx4("path", { d: path(state) ?? void 0, fill: sterlingSequentialColors[colorIndex], stroke: surface, strokeWidth: sterlingVisualStyle.stroke.grid, children: /* @__PURE__ */ jsx4("title", { children: `${row?.state ?? `State ${id}`}: ${(value * 100).toFixed(2)}%` }) }, id || index);
1365
+ }) }),
1366
+ /* @__PURE__ */ jsx4("text", { x: "132", y: "342", textAnchor: "end", fill: muted, fontSize: "9", fontFamily: "var(--font-mono)", children: "0%" }),
1367
+ sterlingSequentialColors.map((color, index) => /* @__PURE__ */ jsx4("rect", { x: 142 + index * 40, y: "330", width: "40", height: "14", fill: color }, color)),
1368
+ /* @__PURE__ */ jsxs4("text", { x: "552", y: "342", fill: muted, fontSize: "9", fontFamily: "var(--font-mono)", children: [
1369
+ (maximum * 100).toFixed(2),
1370
+ "%"
1371
+ ] }),
1372
+ /* @__PURE__ */ jsx4("text", { x: "360", y: "370", textAnchor: "middle", fill: muted, fontSize: "10", fontFamily: "var(--font-mono)", children: "engineers as share of population / proporci\xF3n de ingenieros" })
1373
+ ] });
1374
+ }
1375
+
1376
+ // src/dataExport.ts
1377
+ function csvCell(value) {
1378
+ if (value === null || value === void 0) return "";
1379
+ if (value instanceof Date) return value.toISOString();
1380
+ if (typeof value === "object") return JSON.stringify(value);
1381
+ return String(value);
1382
+ }
1383
+ function escapeCsvCell(value) {
1384
+ const cell = csvCell(value);
1385
+ return /[\",\n\r]/.test(cell) ? `"${cell.replace(/"/g, '""')}"` : cell;
1386
+ }
1387
+ function sterlingRowsToCsv(rows) {
1388
+ const columns = [...new Set(rows.flatMap((row) => Object.keys(row)))];
1389
+ return [
1390
+ columns.map(escapeCsvCell).join(","),
1391
+ ...rows.map((row) => columns.map((column) => escapeCsvCell(row[column])).join(","))
1392
+ ].join("\r\n");
1393
+ }
1394
+ function rowsFromArray(values) {
1395
+ return values.map((value) => {
1396
+ if (Array.isArray(value)) {
1397
+ return Object.fromEntries(value.map((cell, index) => [`value_${index + 1}`, cell]));
1398
+ }
1399
+ if (value && typeof value === "object") return value;
1400
+ return { value };
1401
+ });
1402
+ }
1403
+ function inferSterlingDataExport(props) {
1404
+ if (Array.isArray(props.data)) return { rows: rowsFromArray(props.data) };
1405
+ if (Array.isArray(props.rows)) return { rows: rowsFromArray(props.rows) };
1406
+ if (Array.isArray(props.links)) return { rows: rowsFromArray(props.links) };
1407
+ if (Array.isArray(props.points)) return { rows: rowsFromArray(props.points) };
1408
+ if (Array.isArray(props.groups)) {
1409
+ const groups = props.groups;
1410
+ if (groups.every((group) => Array.isArray(group.values))) {
1411
+ return {
1412
+ rows: groups.flatMap((group) => group.values.map((value) => ({ group: group.label, value })))
1413
+ };
1414
+ }
1415
+ }
1416
+ if (Array.isArray(props.values)) {
1417
+ const values = props.values;
1418
+ if (values.every((value) => typeof value === "number")) return { rows: values.map((value) => ({ value })) };
1419
+ if (values.every(Array.isArray)) {
1420
+ const rowLabels = Array.isArray(props.rowLabels) ? props.rowLabels : [];
1421
+ const columnLabels = Array.isArray(props.columnLabels) ? props.columnLabels : [];
1422
+ return {
1423
+ rows: values.flatMap((row, rowIndex) => row.map((value, columnIndex) => ({
1424
+ row: rowLabels[rowIndex] ?? rowIndex + 1,
1425
+ column: columnLabels[columnIndex] ?? columnIndex + 1,
1426
+ value
1427
+ })))
1428
+ };
1429
+ }
1430
+ }
1431
+ if (Array.isArray(props.series) && Array.isArray(props.labels)) {
1432
+ const labels = props.labels;
1433
+ const series = props.series;
1434
+ if (series.every((item) => Array.isArray(item.values))) {
1435
+ return {
1436
+ rows: labels.map((label, index) => Object.fromEntries([
1437
+ ["label", label],
1438
+ ...series.map((item) => [String(item.label ?? "value"), item.values[index]])
1439
+ ]))
1440
+ };
1441
+ }
1442
+ }
1443
+ if (Array.isArray(props.nodes)) return { rows: rowsFromArray(props.nodes) };
1444
+ return void 0;
1445
+ }
1446
+
1447
+ // src/editorial.tsx
1448
+ import { Fragment, jsxs as jsxs5 } from "react/jsx-runtime";
1449
+ function sterlingCredit({
1450
+ author,
1451
+ productName = "Sterling",
1452
+ linkToSterling = true,
1453
+ sterlingUrl = "https://www.lamatemaga.com/sterling"
1454
+ }, locale = "en") {
1455
+ const product = linkToSterling ? /* @__PURE__ */ jsxs5("a", { className: "sterling-figure__credit-link", href: sterlingUrl, children: [
1456
+ productName,
1457
+ " \u2726"
1458
+ ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1459
+ productName,
1460
+ " \u2726"
1461
+ ] });
1462
+ if (locale === "es") {
1463
+ return author ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1464
+ "Hecho por ",
1465
+ author,
1466
+ " con ",
1467
+ product
1468
+ ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1469
+ "Hecho con ",
1470
+ product
1471
+ ] });
1472
+ }
1473
+ return author ? /* @__PURE__ */ jsxs5(Fragment, { children: [
1474
+ "Made by ",
1475
+ author,
1476
+ " with ",
1477
+ product
1478
+ ] }) : /* @__PURE__ */ jsxs5(Fragment, { children: [
1479
+ "Made with ",
1480
+ product
1481
+ ] });
1482
+ }
1483
+
1484
+ // src/tailwind.ts
1485
+ var orderedStops = [100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
1486
+ var rampStops = [200, 300, 400, 500, 600, 700, 800];
1487
+ function at(scale, stop, fallback) {
1488
+ return scale[stop] ?? fallback;
1489
+ }
1490
+ function createTailwindSterlingPalette({
1491
+ categorical,
1492
+ surface: surface2,
1493
+ divergent,
1494
+ heat
1495
+ }) {
1496
+ const first = categorical[0] ?? {};
1497
+ const categoricalValues = categorical.map((scale) => at(scale, 500, "currentColor"));
1498
+ return defineSterlingPalette({
1499
+ surface: surface2,
1500
+ categorical: categoricalValues,
1501
+ legend: categorical.map((scale) => at(scale, 700, at(scale, 500, "currentColor"))),
1502
+ sequential: orderedStops.map((stop) => at(first, stop, at(first, 500, "currentColor"))),
1503
+ divergent: orderedStops.map((stop) => at(divergent ?? first, stop, at(first, 500, "currentColor"))),
1504
+ heat: orderedStops.concat(950).map((stop) => at(heat ?? first, stop, at(first, 500, "currentColor"))).slice(0, 11),
1505
+ ramps: categorical.map((scale) => rampStops.map((stop) => at(scale, stop, at(scale, 500, "currentColor"))))
1506
+ });
1507
+ }
1508
+ export {
1509
+ AXIS_TITLE,
1510
+ AxisBottom,
1511
+ AxisLeft,
1512
+ Gridlines,
1513
+ SterlingBarChart,
1514
+ SterlingBoxPlot,
1515
+ SterlingCandlestickChart,
1516
+ SterlingChordChart,
1517
+ SterlingCorrelogram,
1518
+ SterlingDendrogramChart,
1519
+ SterlingDensity2DChart,
1520
+ SterlingDensityChart,
1521
+ SterlingDonutChart,
1522
+ SterlingDumbbellChart,
1523
+ SterlingExpressionChart,
1524
+ SterlingGeoMapChart,
1525
+ SterlingHeatmap,
1526
+ SterlingHistogram,
1527
+ SterlingInlineLegend,
1528
+ SterlingLineChart,
1529
+ SterlingLollipopChart,
1530
+ SterlingManhattanChart,
1531
+ SterlingNetworkChart,
1532
+ SterlingPieChart,
1533
+ SterlingRadarChart,
1534
+ SterlingRidgelineChart,
1535
+ SterlingSankeyChart,
1536
+ SterlingScatterPlot,
1537
+ SterlingSequentialSurface,
1538
+ SterlingTreemapChart,
1539
+ SterlingVerticalBarChart,
1540
+ SterlingViolinPlot,
1541
+ SterlingVolcanoChart,
1542
+ TICK,
1543
+ TICK_LABEL,
1544
+ TimeAxisBottom,
1545
+ axisGrid,
1546
+ axisLine,
1547
+ axisMuted,
1548
+ axisText,
1549
+ bandCenters,
1550
+ createTailwindSterlingPalette,
1551
+ defaultMargin,
1552
+ defineSterlingPalette,
1553
+ divergentSignedColor,
1554
+ divergentSignedRamp,
1555
+ frame,
1556
+ inferSterlingDataExport,
1557
+ kernelDensity,
1558
+ linearScale,
1559
+ sterlingCategorical,
1560
+ sterlingChartColors,
1561
+ sterlingColorNames,
1562
+ sterlingCredit,
1563
+ sterlingDivergentColors,
1564
+ sterlingHeatColors,
1565
+ sterlingLegendColors,
1566
+ sterlingPaletteStyle,
1567
+ sterlingRamp,
1568
+ sterlingRampStops,
1569
+ sterlingRowsToCsv,
1570
+ sterlingSequentialColors,
1571
+ sterlingVisualStyle,
1572
+ timeScale,
1573
+ tukeySummary
1574
+ };
1575
+ //# sourceMappingURL=server.mjs.map