@ggterm/core 0.2.5 → 0.2.9

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.
package/dist/index.js CHANGED
@@ -29,423 +29,102 @@ var __export = (target, all) => {
29
29
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
30
30
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
31
31
 
32
- // src/pipeline/scales.ts
33
- var exports_scales = {};
34
- __export(exports_scales, {
35
- niceDomain: () => niceDomain,
36
- inferDiscreteDomain: () => inferDiscreteDomain,
37
- inferContinuousDomain: () => inferContinuousDomain,
38
- getTransformFunctions: () => getTransformFunctions,
39
- expandDomain: () => expandDomain,
40
- createResolvedSizeScale: () => createResolvedSizeScale,
41
- createResolvedDiscreteScale: () => createResolvedDiscreteScale,
42
- createResolvedDiscreteColorScale: () => createResolvedDiscreteColorScale,
43
- createResolvedContinuousScale: () => createResolvedContinuousScale,
44
- createResolvedContinuousColorScale: () => createResolvedContinuousColorScale,
45
- buildScaleContext: () => buildScaleContext,
46
- DEFAULT_POINT_COLOR: () => DEFAULT_POINT_COLOR
47
- });
48
- function inferContinuousDomain(data, field) {
49
- let min = Infinity;
50
- let max = -Infinity;
51
- for (const row of data) {
52
- const value = row[field];
53
- if (typeof value === "number" && !isNaN(value)) {
54
- if (value < min)
55
- min = value;
56
- if (value > max)
57
- max = value;
58
- }
59
- }
60
- if (min === Infinity)
61
- min = 0;
62
- if (max === -Infinity)
63
- max = 1;
64
- if (min === max) {
65
- min = min - 1;
66
- max = max + 1;
67
- }
68
- return [min, max];
69
- }
70
- function inferDiscreteDomain(data, field, options = {}) {
71
- const { limits, order = "alphabetical", reverse = false, exclude, drop = true } = options;
72
- const seen = new Map;
73
- let index = 0;
74
- for (const row of data) {
75
- const value = row[field];
76
- if (value !== null && value !== undefined) {
77
- const key = String(value);
78
- if (!seen.has(key)) {
79
- seen.set(key, { firstIndex: index, count: 1 });
80
- } else {
81
- seen.get(key).count++;
82
- }
83
- }
84
- index++;
85
- }
86
- let result;
87
- if (limits) {
88
- if (drop) {
89
- result = limits.filter((v) => seen.has(v));
90
- } else {
91
- result = [...limits];
92
- }
93
- } else {
94
- const values = Array.from(seen.keys());
95
- switch (order) {
96
- case "data":
97
- result = values.sort((a, b) => seen.get(a).firstIndex - seen.get(b).firstIndex);
98
- break;
99
- case "frequency":
100
- result = values.sort((a, b) => seen.get(b).count - seen.get(a).count);
101
- break;
102
- case "reverse":
103
- result = values.sort().reverse();
104
- break;
105
- case "alphabetical":
106
- default:
107
- result = values.sort();
108
- break;
109
- }
110
- }
111
- if (exclude && exclude.length > 0) {
112
- const excludeSet = new Set(exclude);
113
- result = result.filter((v) => !excludeSet.has(v));
114
- }
115
- if (reverse) {
116
- result = result.reverse();
117
- }
118
- return result;
119
- }
120
- function expandDomain(domain, expand = 0.05) {
121
- const range = domain[1] - domain[0];
122
- const padding = range * expand;
123
- return [domain[0] - padding, domain[1] + padding];
124
- }
125
- function niceStep(range, targetTicks = 5) {
126
- const rawStep = range / Math.max(1, targetTicks - 1);
127
- const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
128
- const normalized = rawStep / magnitude;
129
- let nice;
130
- if (normalized <= 1.5)
131
- nice = 1;
132
- else if (normalized <= 3)
133
- nice = 2;
134
- else if (normalized <= 7)
135
- nice = 5;
136
- else
137
- nice = 10;
138
- return nice * magnitude;
139
- }
140
- function niceDomain(domain, targetTicks = 5) {
141
- const [min, max] = domain;
142
- const range = max - min;
143
- if (range === 0) {
144
- if (min === 0)
145
- return [-1, 1];
146
- const magnitude = Math.pow(10, Math.floor(Math.log10(Math.abs(min))));
147
- return [min - magnitude, min + magnitude];
148
- }
149
- const step = niceStep(range, targetTicks);
150
- const niceMin = Math.floor(min / step) * step;
151
- const niceMax = Math.ceil(max / step) * step;
152
- return [niceMin, niceMax];
153
- }
154
- function getTransformFunctions(trans = "identity") {
155
- switch (trans) {
156
- case "log10":
157
- return {
158
- type: "log10",
159
- transform: (v) => v > 0 ? Math.log10(v) : -Infinity,
160
- invert: (v) => Math.pow(10, v)
161
- };
162
- case "sqrt":
163
- return {
164
- type: "sqrt",
165
- transform: (v) => v >= 0 ? Math.sqrt(v) : 0,
166
- invert: (v) => v * v
167
- };
168
- case "reverse":
169
- return {
170
- type: "reverse",
171
- transform: (v) => -v,
172
- invert: (v) => -v
173
- };
174
- default:
175
- return {
176
- type: "identity",
177
- transform: (v) => v,
178
- invert: (v) => v
179
- };
180
- }
181
- }
182
- function createResolvedContinuousScale(aesthetic, domain, range, trans = "identity") {
183
- const [domainMin, domainMax] = domain;
184
- const [rangeMin, rangeMax] = range;
185
- const rangeSpan = rangeMax - rangeMin;
186
- const { transform, invert } = getTransformFunctions(trans);
32
+ // src/themes/default.ts
33
+ function defaultTheme() {
187
34
  return {
188
- aesthetic,
189
- type: "continuous",
190
- domain,
191
- range,
192
- trans,
193
- transform,
194
- invert,
195
- normalize(value) {
196
- const num = Number(value);
197
- if (isNaN(num))
198
- return 0;
199
- const transformed = transform(num);
200
- const transformedMin = transform(domainMin);
201
- const transformedMax = transform(domainMax);
202
- if (transformedMax === transformedMin)
203
- return 0.5;
204
- return (transformed - transformedMin) / (transformedMax - transformedMin);
35
+ panel: {
36
+ background: "",
37
+ border: "single",
38
+ grid: { major: "·", minor: null }
205
39
  },
206
- toCanvas(normalized) {
207
- return rangeMin + normalized * rangeSpan;
40
+ axis: {
41
+ text: { color: "" },
42
+ ticks: { char: "┼", length: 1 },
43
+ title: { color: "", bold: false }
208
44
  },
209
- map(value) {
210
- return this.toCanvas(this.normalize(value));
45
+ legend: {
46
+ position: "right",
47
+ title: { bold: true }
48
+ },
49
+ title: {
50
+ align: "center",
51
+ bold: true
52
+ },
53
+ facet: {
54
+ strip: {
55
+ text: "#c8c8c8",
56
+ background: ""
57
+ }
211
58
  }
212
59
  };
213
60
  }
214
- function createResolvedDiscreteScale(aesthetic, domain, range) {
215
- const [rangeMin, rangeMax] = range;
216
- const rangeSpan = rangeMax - rangeMin;
61
+ function themeMinimal() {
217
62
  return {
218
- aesthetic,
219
- type: "discrete",
220
- domain,
221
- range,
222
- normalize(value) {
223
- const str = String(value);
224
- const index = domain.indexOf(str);
225
- if (index < 0)
226
- return 0;
227
- return domain.length > 1 ? index / (domain.length - 1) : 0.5;
63
+ panel: {
64
+ background: "",
65
+ border: "none",
66
+ grid: { major: null, minor: null }
228
67
  },
229
- toCanvas(normalized) {
230
- return rangeMin + normalized * rangeSpan;
68
+ axis: {
69
+ text: { color: "" },
70
+ ticks: { char: "│", length: 1 },
71
+ title: { color: "", bold: false }
231
72
  },
232
- map(value) {
233
- return this.toCanvas(this.normalize(value));
73
+ legend: {
74
+ position: "right",
75
+ title: { bold: false }
76
+ },
77
+ title: {
78
+ align: "left",
79
+ bold: false
80
+ },
81
+ facet: {
82
+ strip: {
83
+ text: "#999999",
84
+ background: ""
85
+ }
234
86
  }
235
87
  };
236
88
  }
237
- function interpolateColor(color1, color2, t) {
238
- return {
239
- r: Math.round(color1.r + (color2.r - color1.r) * t),
240
- g: Math.round(color1.g + (color2.g - color1.g) * t),
241
- b: Math.round(color1.b + (color2.b - color1.b) * t),
242
- a: color1.a + (color2.a - color1.a) * t
243
- };
244
- }
245
- function createResolvedDiscreteColorScale(domain, palette = CATEGORY_COLORS) {
89
+ function themeDark() {
246
90
  return {
247
- aesthetic: "color",
248
- type: "discrete",
249
- domain,
250
- map(value) {
251
- const str = String(value);
252
- const index = domain.indexOf(str);
253
- if (index < 0)
254
- return palette[0];
255
- return palette[index % palette.length];
256
- }
257
- };
258
- }
259
- function createResolvedContinuousColorScale(domain, lowColor = { r: 68, g: 1, b: 84, a: 1 }, highColor = { r: 253, g: 231, b: 37, a: 1 }) {
260
- const [min, max] = domain;
261
- const span = max - min;
262
- return {
263
- aesthetic: "color",
264
- type: "continuous",
265
- domain,
266
- map(value) {
267
- const num = Number(value);
268
- if (isNaN(num))
269
- return lowColor;
270
- const t = Math.max(0, Math.min(1, (num - min) / span));
271
- return interpolateColor(lowColor, highColor, t);
272
- }
273
- };
274
- }
275
- function isCategoricalField(data, field) {
276
- for (const row of data) {
277
- const value = row[field];
278
- if (value !== null && value !== undefined) {
279
- if (typeof value === "string" && isNaN(Number(value))) {
280
- return true;
91
+ panel: {
92
+ background: "#1e1e1e",
93
+ border: "rounded",
94
+ grid: { major: "·", minor: null }
95
+ },
96
+ axis: {
97
+ text: { color: "#ccc" },
98
+ ticks: { char: "┼", length: 1 },
99
+ title: { color: "#fff", bold: true }
100
+ },
101
+ legend: {
102
+ position: "right",
103
+ title: { bold: true }
104
+ },
105
+ title: {
106
+ align: "center",
107
+ bold: true
108
+ },
109
+ facet: {
110
+ strip: {
111
+ text: "#ffffff",
112
+ background: "#333333"
281
113
  }
282
114
  }
283
- }
284
- return false;
285
- }
286
- function createResolvedSizeScale(domain) {
287
- const [min, max] = domain;
288
- const span = max - min;
289
- return {
290
- aesthetic: "size",
291
- type: "continuous",
292
- domain,
293
- map(value) {
294
- const num = Number(value);
295
- if (isNaN(num))
296
- return 1;
297
- const t = Math.max(0, Math.min(1, (num - min) / span));
298
- return Math.floor(t * 3.99);
299
- }
300
115
  };
301
116
  }
302
- function computeDomain(data, field, trans = "identity") {
303
- const rawDomain = inferContinuousDomain(data, field);
304
- if (trans === "log10") {
305
- const [min, max] = rawDomain;
306
- const safeMin = min > 0 ? min : 0.001;
307
- const safeMax = max > 0 ? max : 1;
308
- const minPow = Math.floor(Math.log10(safeMin));
309
- const maxPow = Math.ceil(Math.log10(safeMax));
310
- return [Math.pow(10, minPow), Math.pow(10, maxPow)];
311
- }
312
- return niceDomain(rawDomain);
313
- }
314
- function buildScaleContext(data, aes, plotArea, userScales = [], coordLimits) {
315
- const userXScale = userScales.find((s) => s.aesthetic === "x");
316
- const userYScale = userScales.find((s) => s.aesthetic === "y");
317
- const userColorScale = userScales.find((s) => s.aesthetic === "color" || s.aesthetic === "fill");
318
- const xIsCategorical = isCategoricalField(data, aes.x);
319
- let x;
320
- if (xIsCategorical) {
321
- const xOrderOptions = {};
322
- if (userXScale) {
323
- if (userXScale.domain && Array.isArray(userXScale.domain)) {
324
- xOrderOptions.limits = userXScale.domain;
325
- }
326
- const orderOpts = userXScale.orderOptions;
327
- if (orderOpts) {
328
- if (orderOpts.order)
329
- xOrderOptions.order = orderOpts.order;
330
- if (orderOpts.reverse)
331
- xOrderOptions.reverse = orderOpts.reverse;
332
- if (orderOpts.exclude)
333
- xOrderOptions.exclude = orderOpts.exclude;
334
- if (orderOpts.drop !== undefined)
335
- xOrderOptions.drop = orderOpts.drop;
336
- }
337
- }
338
- const xDomain = inferDiscreteDomain(data, aes.x, xOrderOptions);
339
- x = createResolvedDiscreteScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1]);
340
- if (userXScale?.labels) {
341
- x.labels = userXScale.labels;
342
- }
343
- } else {
344
- const xTrans = userXScale?.trans ?? "identity";
345
- const xDomain = coordLimits?.xlim ?? userXScale?.domain ?? computeDomain(data, aes.x, xTrans);
346
- x = createResolvedContinuousScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1], xTrans);
347
- if (userXScale?.breaks) {
348
- x.breaks = userXScale.breaks;
349
- }
350
- if (userXScale?.labels) {
351
- x.labels = userXScale.labels;
352
- }
353
- }
354
- const yTrans = userYScale?.trans ?? "identity";
355
- const yDomain = coordLimits?.ylim ?? userYScale?.domain ?? computeDomain(data, aes.y, yTrans);
356
- const y = createResolvedContinuousScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y], yTrans);
357
- if (userYScale?.breaks) {
358
- y.breaks = userYScale.breaks;
359
- }
360
- if (userYScale?.labels) {
361
- y.labels = userYScale.labels;
362
- }
363
- const context = { x, y };
364
- if (aes.y2) {
365
- const userY2Scale = userScales.find((s) => s.aesthetic === "y2");
366
- const y2Trans = userY2Scale?.trans ?? "identity";
367
- const y2Domain = userY2Scale?.domain ?? computeDomain(data, aes.y2, y2Trans);
368
- const y2 = createResolvedContinuousScale("y2", y2Domain, [plotArea.y + plotArea.height - 1, plotArea.y], y2Trans);
369
- if (userY2Scale?.breaks) {
370
- y2.breaks = userY2Scale.breaks;
371
- }
372
- if (userY2Scale?.labels) {
373
- y2.labels = userY2Scale.labels;
374
- }
375
- context.y2 = y2;
376
- }
377
- const colorAesField = aes.color || aes.fill;
378
- if (colorAesField) {
379
- const colorOrderOptions = {};
380
- if (userColorScale) {
381
- if (userColorScale.domain && Array.isArray(userColorScale.domain)) {
382
- colorOrderOptions.limits = userColorScale.domain;
383
- }
384
- const orderOpts = userColorScale.orderOptions;
385
- if (orderOpts) {
386
- if (orderOpts.order)
387
- colorOrderOptions.order = orderOpts.order;
388
- if (orderOpts.reverse)
389
- colorOrderOptions.reverse = orderOpts.reverse;
390
- if (orderOpts.exclude)
391
- colorOrderOptions.exclude = orderOpts.exclude;
392
- if (orderOpts.drop !== undefined)
393
- colorOrderOptions.drop = orderOpts.drop;
394
- }
395
- }
396
- const colorDomain = inferDiscreteDomain(data, colorAesField, colorOrderOptions);
397
- if (userColorScale && userColorScale.map) {
398
- context.color = {
399
- aesthetic: userColorScale.aesthetic || "color",
400
- type: userColorScale.type === "continuous" ? "continuous" : "discrete",
401
- domain: userColorScale.type === "continuous" ? userColorScale.domain ?? inferContinuousDomain(data, colorAesField) : colorDomain,
402
- map: (value) => {
403
- const result = userColorScale.map(value);
404
- if (typeof result === "object" && "r" in result) {
405
- return result;
406
- }
407
- return { r: 128, g: 128, b: 128, a: 1 };
408
- }
409
- };
410
- } else {
411
- context.color = createResolvedDiscreteColorScale(colorDomain);
412
- }
413
- }
414
- if (aes.size) {
415
- const sizeDomain = inferContinuousDomain(data, aes.size);
416
- context.size = createResolvedSizeScale(sizeDomain);
417
- }
418
- return context;
419
- }
420
- var CATEGORY_COLORS, DEFAULT_POINT_COLOR;
421
- var init_scales = __esm(() => {
422
- CATEGORY_COLORS = [
423
- { r: 31, g: 119, b: 180, a: 1 },
424
- { r: 255, g: 127, b: 14, a: 1 },
425
- { r: 44, g: 160, b: 44, a: 1 },
426
- { r: 214, g: 39, b: 40, a: 1 },
427
- { r: 148, g: 103, b: 189, a: 1 },
428
- { r: 140, g: 86, b: 75, a: 1 },
429
- { r: 227, g: 119, b: 194, a: 1 },
430
- { r: 127, g: 127, b: 127, a: 1 },
431
- { r: 188, g: 189, b: 34, a: 1 },
432
- { r: 23, g: 190, b: 207, a: 1 }
433
- ];
434
- DEFAULT_POINT_COLOR = { r: 79, g: 169, b: 238, a: 1 };
435
- });
436
-
437
- // src/themes/default.ts
438
- function defaultTheme() {
117
+ function themeClassic() {
439
118
  return {
440
119
  panel: {
441
120
  background: "",
442
121
  border: "single",
443
- grid: { major: "·", minor: null }
122
+ grid: { major: null, minor: null }
444
123
  },
445
124
  axis: {
446
125
  text: { color: "" },
447
- ticks: { char: "", length: 1 },
448
- title: { color: "", bold: false }
126
+ ticks: { char: "", length: 1 },
127
+ title: { color: "", bold: true }
449
128
  },
450
129
  legend: {
451
130
  position: "right",
@@ -463,7 +142,7 @@ function defaultTheme() {
463
142
  }
464
143
  };
465
144
  }
466
- function themeMinimal() {
145
+ function themeVoid() {
467
146
  return {
468
147
  panel: {
469
148
  background: "",
@@ -472,11 +151,11 @@ function themeMinimal() {
472
151
  },
473
152
  axis: {
474
153
  text: { color: "" },
475
- ticks: { char: "", length: 1 },
154
+ ticks: { char: "", length: 0 },
476
155
  title: { color: "", bold: false }
477
156
  },
478
157
  legend: {
479
- position: "right",
158
+ position: "none",
480
159
  title: { bold: false }
481
160
  },
482
161
  title: {
@@ -485,332 +164,677 @@ function themeMinimal() {
485
164
  },
486
165
  facet: {
487
166
  strip: {
488
- text: "#999999",
167
+ text: "#888888",
489
168
  background: ""
490
169
  }
491
170
  }
492
171
  };
493
172
  }
494
- function themeDark() {
173
+
174
+ // src/coords/cartesian.ts
175
+ function coordCartesian(options = {}) {
495
176
  return {
496
- panel: {
497
- background: "#1e1e1e",
498
- border: "rounded",
499
- grid: { major: "·", minor: null }
500
- },
501
- axis: {
502
- text: { color: "#ccc" },
503
- ticks: { char: "┼", length: 1 },
504
- title: { color: "#fff", bold: true }
505
- },
506
- legend: {
507
- position: "right",
508
- title: { bold: true }
509
- },
510
- title: {
511
- align: "center",
512
- bold: true
513
- },
514
- facet: {
515
- strip: {
516
- text: "#ffffff",
517
- background: "#333333"
518
- }
177
+ type: "cartesian",
178
+ xlim: options.xlim,
179
+ ylim: options.ylim,
180
+ clip: options.clip ?? true,
181
+ transform(x, y) {
182
+ return { x, y };
183
+ }
184
+ };
185
+ }
186
+ function coordFlip() {
187
+ return {
188
+ type: "flip",
189
+ transform(x, y) {
190
+ return { x: y, y: x };
519
191
  }
520
192
  };
521
193
  }
522
- function themeClassic() {
194
+ function coordPolar(options = {}) {
195
+ const theta = options.theta ?? "x";
196
+ return {
197
+ type: "polar",
198
+ transform(x, y) {
199
+ const angle = theta === "x" ? x : y;
200
+ const radius = theta === "x" ? y : x;
201
+ return {
202
+ x: radius * Math.cos(angle),
203
+ y: radius * Math.sin(angle)
204
+ };
205
+ }
206
+ };
207
+ }
208
+ function coordFixed(options = {}) {
209
+ const ratio = options.ratio ?? 1;
210
+ return {
211
+ type: "fixed",
212
+ xlim: options.xlim,
213
+ ylim: options.ylim,
214
+ clip: options.clip ?? true,
215
+ ratio,
216
+ transform(x, y) {
217
+ return { x, y };
218
+ }
219
+ };
220
+ }
221
+ function coordEqual(options = {}) {
222
+ return coordFixed({ ...options, ratio: 1 });
223
+ }
224
+ function getTransform(type) {
225
+ switch (type) {
226
+ case "log10":
227
+ return (v) => v > 0 ? Math.log10(v) : -Infinity;
228
+ case "sqrt":
229
+ return (v) => v >= 0 ? Math.sqrt(v) : 0;
230
+ case "reverse":
231
+ return (v) => -v;
232
+ default:
233
+ return (v) => v;
234
+ }
235
+ }
236
+ function coordTrans(options = {}) {
237
+ const xTrans = getTransform(options.x ?? "identity");
238
+ const yTrans = getTransform(options.y ?? "identity");
239
+ return {
240
+ type: "trans",
241
+ xlim: options.xlim,
242
+ ylim: options.ylim,
243
+ clip: options.clip ?? true,
244
+ xTransType: options.x ?? "identity",
245
+ yTransType: options.y ?? "identity",
246
+ transform(x, y) {
247
+ return {
248
+ x: xTrans(x),
249
+ y: yTrans(y)
250
+ };
251
+ }
252
+ };
253
+ }
254
+ function coordFlipWithLimits(options = {}) {
255
+ return {
256
+ type: "flip",
257
+ xlim: options.xlim,
258
+ ylim: options.ylim,
259
+ clip: options.clip ?? true,
260
+ transform(x, y) {
261
+ return { x: y, y: x };
262
+ }
263
+ };
264
+ }
265
+
266
+ // src/canvas/canvas.ts
267
+ function createEmptyCell() {
268
+ return {
269
+ char: " ",
270
+ fg: { ...DEFAULT_FG },
271
+ bg: { ...DEFAULT_BG }
272
+ };
273
+ }
274
+
275
+ class TerminalCanvas {
276
+ width;
277
+ height;
278
+ cells;
279
+ constructor(width, height) {
280
+ this.width = width;
281
+ this.height = height;
282
+ this.cells = [];
283
+ this.clear();
284
+ }
285
+ setCell(x, y, cell) {
286
+ if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || x >= this.width || y < 0 || y >= this.height) {
287
+ return;
288
+ }
289
+ const ix = Math.floor(x);
290
+ const iy = Math.floor(y);
291
+ const existing = this.cells[iy][ix];
292
+ this.cells[iy][ix] = {
293
+ char: cell.char ?? existing.char,
294
+ fg: cell.fg ?? existing.fg,
295
+ bg: cell.bg ?? existing.bg,
296
+ bold: cell.bold ?? existing.bold,
297
+ italic: cell.italic ?? existing.italic,
298
+ underline: cell.underline ?? existing.underline
299
+ };
300
+ }
301
+ getCell(x, y) {
302
+ if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || x >= this.width || y < 0 || y >= this.height) {
303
+ return createEmptyCell();
304
+ }
305
+ return this.cells[Math.floor(y)][Math.floor(x)];
306
+ }
307
+ clear() {
308
+ this.cells = [];
309
+ for (let y = 0;y < this.height; y++) {
310
+ const row = [];
311
+ for (let x = 0;x < this.width; x++) {
312
+ row.push(createEmptyCell());
313
+ }
314
+ this.cells.push(row);
315
+ }
316
+ }
317
+ drawChar(x, y, char, fg) {
318
+ this.setCell(x, y, { char, fg });
319
+ }
320
+ drawString(x, y, str, fg) {
321
+ for (let i = 0;i < str.length; i++) {
322
+ this.drawChar(x + i, y, str[i], fg);
323
+ }
324
+ }
325
+ drawHLine(x, y, length, char = "─", fg) {
326
+ for (let i = 0;i < length; i++) {
327
+ this.drawChar(x + i, y, char, fg);
328
+ }
329
+ }
330
+ drawVLine(x, y, length, char = "│", fg) {
331
+ for (let i = 0;i < length; i++) {
332
+ this.drawChar(x, y + i, char, fg);
333
+ }
334
+ }
335
+ drawPoint(x, y, fg, shape = "●") {
336
+ this.drawChar(x, y, shape, fg);
337
+ }
338
+ fillRect(x, y, width, height, char = " ", fg, bg) {
339
+ for (let dy = 0;dy < height; dy++) {
340
+ for (let dx = 0;dx < width; dx++) {
341
+ this.setCell(x + dx, y + dy, { char, fg, bg });
342
+ }
343
+ }
344
+ }
345
+ drawBox(x, y, width, height, style = "single", fg) {
346
+ const chars = style === "double" ? { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" } : style === "rounded" ? { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" } : { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
347
+ this.drawChar(x, y, chars.tl, fg);
348
+ this.drawChar(x + width - 1, y, chars.tr, fg);
349
+ this.drawChar(x, y + height - 1, chars.bl, fg);
350
+ this.drawChar(x + width - 1, y + height - 1, chars.br, fg);
351
+ this.drawHLine(x + 1, y, width - 2, chars.h, fg);
352
+ this.drawHLine(x + 1, y + height - 1, width - 2, chars.h, fg);
353
+ this.drawVLine(x, y + 1, height - 2, chars.v, fg);
354
+ this.drawVLine(x + width - 1, y + 1, height - 2, chars.v, fg);
355
+ }
356
+ toString() {
357
+ return this.cells.map((row) => row.map((cell) => cell.char).join("")).join(`
358
+ `);
359
+ }
360
+ toAnsiString() {
361
+ const lines = [];
362
+ for (const row of this.cells) {
363
+ let line = "";
364
+ let currentFg = null;
365
+ let currentBg = null;
366
+ for (const cell of row) {
367
+ const fgChanged = !currentFg || currentFg.r !== cell.fg.r || currentFg.g !== cell.fg.g || currentFg.b !== cell.fg.b;
368
+ const bgChanged = cell.bg.a > 0 && (!currentBg || currentBg.r !== cell.bg.r || currentBg.g !== cell.bg.g || currentBg.b !== cell.bg.b);
369
+ if (fgChanged) {
370
+ line += `\x1B[38;2;${cell.fg.r};${cell.fg.g};${cell.fg.b}m`;
371
+ currentFg = cell.fg;
372
+ }
373
+ if (bgChanged) {
374
+ line += `\x1B[48;2;${cell.bg.r};${cell.bg.g};${cell.bg.b}m`;
375
+ currentBg = cell.bg;
376
+ }
377
+ if (cell.bold)
378
+ line += "\x1B[1m";
379
+ if (cell.italic)
380
+ line += "\x1B[3m";
381
+ if (cell.underline)
382
+ line += "\x1B[4m";
383
+ line += cell.char;
384
+ if (cell.bold || cell.italic || cell.underline) {
385
+ line += "\x1B[22;23;24m";
386
+ if (currentFg) {
387
+ line += `\x1B[38;2;${currentFg.r};${currentFg.g};${currentFg.b}m`;
388
+ }
389
+ }
390
+ }
391
+ line += "\x1B[0m";
392
+ lines.push(line);
393
+ }
394
+ return lines.join(`
395
+ `);
396
+ }
397
+ }
398
+ function createCanvas(width, height) {
399
+ return new TerminalCanvas(width, height);
400
+ }
401
+ var DEFAULT_FG, DEFAULT_BG;
402
+ var init_canvas = __esm(() => {
403
+ DEFAULT_FG = { r: 255, g: 255, b: 255, a: 1 };
404
+ DEFAULT_BG = { r: 0, g: 0, b: 0, a: 0 };
405
+ });
406
+
407
+ // src/pipeline/scales.ts
408
+ var exports_scales = {};
409
+ __export(exports_scales, {
410
+ niceDomain: () => niceDomain,
411
+ inferDiscreteDomain: () => inferDiscreteDomain,
412
+ inferContinuousDomain: () => inferContinuousDomain,
413
+ getTransformFunctions: () => getTransformFunctions,
414
+ expandDomain: () => expandDomain,
415
+ createResolvedSizeScale: () => createResolvedSizeScale,
416
+ createResolvedDiscreteScale: () => createResolvedDiscreteScale,
417
+ createResolvedDiscreteColorScale: () => createResolvedDiscreteColorScale,
418
+ createResolvedContinuousScale: () => createResolvedContinuousScale,
419
+ createResolvedContinuousColorScale: () => createResolvedContinuousColorScale,
420
+ buildScaleContext: () => buildScaleContext,
421
+ DEFAULT_POINT_COLOR: () => DEFAULT_POINT_COLOR
422
+ });
423
+ function inferContinuousDomain(data, field) {
424
+ let min = Infinity;
425
+ let max = -Infinity;
426
+ for (const row of data) {
427
+ const value = row[field];
428
+ if (typeof value === "number" && !isNaN(value)) {
429
+ if (value < min)
430
+ min = value;
431
+ if (value > max)
432
+ max = value;
433
+ }
434
+ }
435
+ if (min === Infinity)
436
+ min = 0;
437
+ if (max === -Infinity)
438
+ max = 1;
439
+ if (min === max) {
440
+ min = min - 1;
441
+ max = max + 1;
442
+ }
443
+ return [min, max];
444
+ }
445
+ function inferDiscreteDomain(data, field, options = {}) {
446
+ const { limits, order = "alphabetical", reverse = false, exclude, drop = true } = options;
447
+ const seen = new Map;
448
+ let index = 0;
449
+ for (const row of data) {
450
+ const value = row[field];
451
+ if (value !== null && value !== undefined) {
452
+ const key = String(value);
453
+ if (!seen.has(key)) {
454
+ seen.set(key, { firstIndex: index, count: 1 });
455
+ } else {
456
+ seen.get(key).count++;
457
+ }
458
+ }
459
+ index++;
460
+ }
461
+ let result;
462
+ if (limits) {
463
+ if (drop) {
464
+ result = limits.filter((v) => seen.has(v));
465
+ } else {
466
+ result = [...limits];
467
+ }
468
+ } else {
469
+ const values = Array.from(seen.keys());
470
+ switch (order) {
471
+ case "data":
472
+ result = values.sort((a, b) => seen.get(a).firstIndex - seen.get(b).firstIndex);
473
+ break;
474
+ case "frequency":
475
+ result = values.sort((a, b) => seen.get(b).count - seen.get(a).count);
476
+ break;
477
+ case "reverse":
478
+ result = values.sort().reverse();
479
+ break;
480
+ case "alphabetical":
481
+ default:
482
+ result = values.sort();
483
+ break;
484
+ }
485
+ }
486
+ if (exclude && exclude.length > 0) {
487
+ const excludeSet = new Set(exclude);
488
+ result = result.filter((v) => !excludeSet.has(v));
489
+ }
490
+ if (reverse) {
491
+ result = result.reverse();
492
+ }
493
+ return result;
494
+ }
495
+ function expandDomain(domain, expand = 0.05) {
496
+ const range = domain[1] - domain[0];
497
+ const padding = range * expand;
498
+ return [domain[0] - padding, domain[1] + padding];
499
+ }
500
+ function niceStep(range, targetTicks = 5) {
501
+ const rawStep = range / Math.max(1, targetTicks - 1);
502
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
503
+ const normalized = rawStep / magnitude;
504
+ let nice;
505
+ if (normalized <= 1.5)
506
+ nice = 1;
507
+ else if (normalized <= 3)
508
+ nice = 2;
509
+ else if (normalized <= 7)
510
+ nice = 5;
511
+ else
512
+ nice = 10;
513
+ return nice * magnitude;
514
+ }
515
+ function niceDomain(domain, targetTicks = 5) {
516
+ const [min, max] = domain;
517
+ const range = max - min;
518
+ if (range === 0) {
519
+ if (min === 0)
520
+ return [-1, 1];
521
+ const magnitude = Math.pow(10, Math.floor(Math.log10(Math.abs(min))));
522
+ return [min - magnitude, min + magnitude];
523
+ }
524
+ const step = niceStep(range, targetTicks);
525
+ const niceMin = Math.floor(min / step) * step;
526
+ const niceMax = Math.ceil(max / step) * step;
527
+ return [niceMin, niceMax];
528
+ }
529
+ function getTransformFunctions(trans = "identity") {
530
+ switch (trans) {
531
+ case "log10":
532
+ return {
533
+ type: "log10",
534
+ transform: (v) => v > 0 ? Math.log10(v) : -Infinity,
535
+ invert: (v) => Math.pow(10, v)
536
+ };
537
+ case "sqrt":
538
+ return {
539
+ type: "sqrt",
540
+ transform: (v) => v >= 0 ? Math.sqrt(v) : 0,
541
+ invert: (v) => v * v
542
+ };
543
+ case "reverse":
544
+ return {
545
+ type: "reverse",
546
+ transform: (v) => -v,
547
+ invert: (v) => -v
548
+ };
549
+ default:
550
+ return {
551
+ type: "identity",
552
+ transform: (v) => v,
553
+ invert: (v) => v
554
+ };
555
+ }
556
+ }
557
+ function createResolvedContinuousScale(aesthetic, domain, range, trans = "identity") {
558
+ const [domainMin, domainMax] = domain;
559
+ const [rangeMin, rangeMax] = range;
560
+ const rangeSpan = rangeMax - rangeMin;
561
+ const { transform, invert } = getTransformFunctions(trans);
523
562
  return {
524
- panel: {
525
- background: "",
526
- border: "single",
527
- grid: { major: null, minor: null }
528
- },
529
- axis: {
530
- text: { color: "" },
531
- ticks: { char: "─", length: 1 },
532
- title: { color: "", bold: true }
533
- },
534
- legend: {
535
- position: "right",
536
- title: { bold: true }
563
+ aesthetic,
564
+ type: "continuous",
565
+ domain,
566
+ range,
567
+ trans,
568
+ transform,
569
+ invert,
570
+ normalize(value) {
571
+ const num = Number(value);
572
+ if (isNaN(num))
573
+ return 0;
574
+ const transformed = transform(num);
575
+ const transformedMin = transform(domainMin);
576
+ const transformedMax = transform(domainMax);
577
+ if (transformedMax === transformedMin)
578
+ return 0.5;
579
+ return (transformed - transformedMin) / (transformedMax - transformedMin);
537
580
  },
538
- title: {
539
- align: "center",
540
- bold: true
581
+ toCanvas(normalized) {
582
+ return rangeMin + normalized * rangeSpan;
541
583
  },
542
- facet: {
543
- strip: {
544
- text: "#c8c8c8",
545
- background: ""
546
- }
584
+ map(value) {
585
+ return this.toCanvas(this.normalize(value));
547
586
  }
548
587
  };
549
588
  }
550
- function themeVoid() {
589
+ function createResolvedDiscreteScale(aesthetic, domain, range) {
590
+ const [rangeMin, rangeMax] = range;
591
+ const rangeSpan = rangeMax - rangeMin;
551
592
  return {
552
- panel: {
553
- background: "",
554
- border: "none",
555
- grid: { major: null, minor: null }
556
- },
557
- axis: {
558
- text: { color: "" },
559
- ticks: { char: "", length: 0 },
560
- title: { color: "", bold: false }
561
- },
562
- legend: {
563
- position: "none",
564
- title: { bold: false }
593
+ aesthetic,
594
+ type: "discrete",
595
+ domain,
596
+ range,
597
+ normalize(value) {
598
+ const str = String(value);
599
+ const index = domain.indexOf(str);
600
+ if (index < 0)
601
+ return 0;
602
+ return domain.length > 1 ? index / (domain.length - 1) : 0.5;
565
603
  },
566
- title: {
567
- align: "left",
568
- bold: false
604
+ toCanvas(normalized) {
605
+ return rangeMin + normalized * rangeSpan;
569
606
  },
570
- facet: {
571
- strip: {
572
- text: "#888888",
573
- background: ""
574
- }
607
+ map(value) {
608
+ return this.toCanvas(this.normalize(value));
575
609
  }
576
610
  };
577
611
  }
578
-
579
- // src/coords/cartesian.ts
580
- function coordCartesian(options = {}) {
612
+ function interpolateColor(color1, color2, t) {
581
613
  return {
582
- type: "cartesian",
583
- xlim: options.xlim,
584
- ylim: options.ylim,
585
- clip: options.clip ?? true,
586
- transform(x, y) {
587
- return { x, y };
588
- }
614
+ r: Math.round(color1.r + (color2.r - color1.r) * t),
615
+ g: Math.round(color1.g + (color2.g - color1.g) * t),
616
+ b: Math.round(color1.b + (color2.b - color1.b) * t),
617
+ a: color1.a + (color2.a - color1.a) * t
589
618
  };
590
619
  }
591
- function coordFlip() {
620
+ function createResolvedDiscreteColorScale(domain, palette = CATEGORY_COLORS) {
592
621
  return {
593
- type: "flip",
594
- transform(x, y) {
595
- return { x: y, y: x };
622
+ aesthetic: "color",
623
+ type: "discrete",
624
+ domain,
625
+ map(value) {
626
+ const str = String(value);
627
+ const index = domain.indexOf(str);
628
+ if (index < 0)
629
+ return palette[0];
630
+ return palette[index % palette.length];
596
631
  }
597
632
  };
598
633
  }
599
- function coordPolar(options = {}) {
600
- const theta = options.theta ?? "x";
634
+ function createResolvedContinuousColorScale(domain, lowColor = { r: 68, g: 1, b: 84, a: 1 }, highColor = { r: 253, g: 231, b: 37, a: 1 }) {
635
+ const [min, max] = domain;
636
+ const span = max - min;
601
637
  return {
602
- type: "polar",
603
- transform(x, y) {
604
- const angle = theta === "x" ? x : y;
605
- const radius = theta === "x" ? y : x;
606
- return {
607
- x: radius * Math.cos(angle),
608
- y: radius * Math.sin(angle)
609
- };
638
+ aesthetic: "color",
639
+ type: "continuous",
640
+ domain,
641
+ map(value) {
642
+ const num = Number(value);
643
+ if (isNaN(num))
644
+ return lowColor;
645
+ const t = Math.max(0, Math.min(1, (num - min) / span));
646
+ return interpolateColor(lowColor, highColor, t);
610
647
  }
611
648
  };
612
649
  }
613
- function coordFixed(options = {}) {
614
- const ratio = options.ratio ?? 1;
615
- return {
616
- type: "fixed",
617
- xlim: options.xlim,
618
- ylim: options.ylim,
619
- clip: options.clip ?? true,
620
- ratio,
621
- transform(x, y) {
622
- return { x, y };
650
+ function isCategoricalField(data, field) {
651
+ for (const row of data) {
652
+ const value = row[field];
653
+ if (value !== null && value !== undefined) {
654
+ if (typeof value === "string") {
655
+ return true;
656
+ }
623
657
  }
624
- };
625
- }
626
- function coordEqual(options = {}) {
627
- return coordFixed({ ...options, ratio: 1 });
628
- }
629
- function getTransform(type) {
630
- switch (type) {
631
- case "log10":
632
- return (v) => v > 0 ? Math.log10(v) : -Infinity;
633
- case "sqrt":
634
- return (v) => v >= 0 ? Math.sqrt(v) : 0;
635
- case "reverse":
636
- return (v) => -v;
637
- default:
638
- return (v) => v;
639
658
  }
659
+ return false;
640
660
  }
641
- function coordTrans(options = {}) {
642
- const xTrans = getTransform(options.x ?? "identity");
643
- const yTrans = getTransform(options.y ?? "identity");
644
- return {
645
- type: "trans",
646
- xlim: options.xlim,
647
- ylim: options.ylim,
648
- clip: options.clip ?? true,
649
- xTransType: options.x ?? "identity",
650
- yTransType: options.y ?? "identity",
651
- transform(x, y) {
652
- return {
653
- x: xTrans(x),
654
- y: yTrans(y)
655
- };
656
- }
657
- };
658
- }
659
- function coordFlipWithLimits(options = {}) {
660
- return {
661
- type: "flip",
662
- xlim: options.xlim,
663
- ylim: options.ylim,
664
- clip: options.clip ?? true,
665
- transform(x, y) {
666
- return { x: y, y: x };
667
- }
668
- };
669
- }
670
-
671
- // src/canvas/canvas.ts
672
- var DEFAULT_FG = { r: 255, g: 255, b: 255, a: 1 };
673
- var DEFAULT_BG = { r: 0, g: 0, b: 0, a: 0 };
674
- function createEmptyCell() {
661
+ function createResolvedSizeScale(domain) {
662
+ const [min, max] = domain;
663
+ const span = max - min;
675
664
  return {
676
- char: " ",
677
- fg: { ...DEFAULT_FG },
678
- bg: { ...DEFAULT_BG }
665
+ aesthetic: "size",
666
+ type: "continuous",
667
+ domain,
668
+ map(value) {
669
+ const num = Number(value);
670
+ if (isNaN(num))
671
+ return 1;
672
+ const t = Math.max(0, Math.min(1, (num - min) / span));
673
+ return Math.floor(t * 3.99);
674
+ }
679
675
  };
680
676
  }
681
-
682
- class TerminalCanvas {
683
- width;
684
- height;
685
- cells;
686
- constructor(width, height) {
687
- this.width = width;
688
- this.height = height;
689
- this.cells = [];
690
- this.clear();
677
+ function computeDomain(data, field, trans = "identity") {
678
+ const rawDomain = inferContinuousDomain(data, field);
679
+ if (trans === "log10") {
680
+ const [min, max] = rawDomain;
681
+ const safeMin = min > 0 ? min : 0.001;
682
+ const safeMax = max > 0 ? max : 1;
683
+ const minPow = Math.floor(Math.log10(safeMin));
684
+ const maxPow = Math.ceil(Math.log10(safeMax));
685
+ return [Math.pow(10, minPow), Math.pow(10, maxPow)];
691
686
  }
692
- setCell(x, y, cell) {
693
- if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
694
- return;
687
+ return niceDomain(rawDomain);
688
+ }
689
+ function buildScaleContext(data, aes, plotArea, userScales = [], coordLimits) {
690
+ const userXScale = userScales.find((s) => s.aesthetic === "x");
691
+ const userYScale = userScales.find((s) => s.aesthetic === "y");
692
+ const userColorScale = userScales.find((s) => s.aesthetic === "color" || s.aesthetic === "fill");
693
+ const xIsCategorical = isCategoricalField(data, aes.x);
694
+ let x;
695
+ if (xIsCategorical) {
696
+ const xOrderOptions = {};
697
+ if (userXScale) {
698
+ if (userXScale.domain && Array.isArray(userXScale.domain)) {
699
+ xOrderOptions.limits = userXScale.domain;
700
+ }
701
+ const orderOpts = userXScale.orderOptions;
702
+ if (orderOpts) {
703
+ if (orderOpts.order)
704
+ xOrderOptions.order = orderOpts.order;
705
+ if (orderOpts.reverse)
706
+ xOrderOptions.reverse = orderOpts.reverse;
707
+ if (orderOpts.exclude)
708
+ xOrderOptions.exclude = orderOpts.exclude;
709
+ if (orderOpts.drop !== undefined)
710
+ xOrderOptions.drop = orderOpts.drop;
711
+ }
695
712
  }
696
- const ix = Math.floor(x);
697
- const iy = Math.floor(y);
698
- const existing = this.cells[iy][ix];
699
- this.cells[iy][ix] = {
700
- char: cell.char ?? existing.char,
701
- fg: cell.fg ?? existing.fg,
702
- bg: cell.bg ?? existing.bg,
703
- bold: cell.bold ?? existing.bold,
704
- italic: cell.italic ?? existing.italic,
705
- underline: cell.underline ?? existing.underline
706
- };
707
- }
708
- getCell(x, y) {
709
- if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
710
- return createEmptyCell();
713
+ const xDomain = inferDiscreteDomain(data, aes.x, xOrderOptions);
714
+ x = createResolvedDiscreteScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1]);
715
+ if (userXScale?.labels) {
716
+ x.labels = userXScale.labels;
717
+ }
718
+ } else {
719
+ const xTrans = userXScale?.trans ?? "identity";
720
+ const xDomain = coordLimits?.xlim ?? userXScale?.domain ?? computeDomain(data, aes.x, xTrans);
721
+ x = createResolvedContinuousScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1], xTrans);
722
+ if (userXScale?.breaks) {
723
+ x.breaks = userXScale.breaks;
724
+ }
725
+ if (userXScale?.labels) {
726
+ x.labels = userXScale.labels;
711
727
  }
712
- return this.cells[Math.floor(y)][Math.floor(x)];
713
728
  }
714
- clear() {
715
- this.cells = [];
716
- for (let y = 0;y < this.height; y++) {
717
- const row = [];
718
- for (let x = 0;x < this.width; x++) {
719
- row.push(createEmptyCell());
729
+ const yIsCategorical = isCategoricalField(data, aes.y);
730
+ let y;
731
+ if (yIsCategorical) {
732
+ const yOrderOptions = {};
733
+ if (userYScale) {
734
+ if (userYScale.domain && Array.isArray(userYScale.domain)) {
735
+ yOrderOptions.limits = userYScale.domain;
736
+ }
737
+ const orderOpts = userYScale.orderOptions;
738
+ if (orderOpts) {
739
+ if (orderOpts.order)
740
+ yOrderOptions.order = orderOpts.order;
741
+ if (orderOpts.reverse)
742
+ yOrderOptions.reverse = orderOpts.reverse;
743
+ if (orderOpts.exclude)
744
+ yOrderOptions.exclude = orderOpts.exclude;
745
+ if (orderOpts.drop !== undefined)
746
+ yOrderOptions.drop = orderOpts.drop;
720
747
  }
721
- this.cells.push(row);
722
748
  }
723
- }
724
- drawChar(x, y, char, fg) {
725
- this.setCell(x, y, { char, fg });
726
- }
727
- drawString(x, y, str, fg) {
728
- for (let i = 0;i < str.length; i++) {
729
- this.drawChar(x + i, y, str[i], fg);
749
+ const yDomain = inferDiscreteDomain(data, aes.y, yOrderOptions);
750
+ y = createResolvedDiscreteScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y]);
751
+ if (userYScale?.labels) {
752
+ y.labels = userYScale.labels;
730
753
  }
731
- }
732
- drawHLine(x, y, length, char = "", fg) {
733
- for (let i = 0;i < length; i++) {
734
- this.drawChar(x + i, y, char, fg);
754
+ } else {
755
+ const yTrans = userYScale?.trans ?? "identity";
756
+ const yDomain = coordLimits?.ylim ?? userYScale?.domain ?? computeDomain(data, aes.y, yTrans);
757
+ y = createResolvedContinuousScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y], yTrans);
758
+ if (userYScale?.breaks) {
759
+ y.breaks = userYScale.breaks;
735
760
  }
736
- }
737
- drawVLine(x, y, length, char = "│", fg) {
738
- for (let i = 0;i < length; i++) {
739
- this.drawChar(x, y + i, char, fg);
761
+ if (userYScale?.labels) {
762
+ y.labels = userYScale.labels;
740
763
  }
741
764
  }
742
- drawPoint(x, y, fg, shape = "●") {
743
- this.drawChar(x, y, shape, fg);
765
+ const context = { x, y };
766
+ if (aes.y2) {
767
+ const userY2Scale = userScales.find((s) => s.aesthetic === "y2");
768
+ const y2Trans = userY2Scale?.trans ?? "identity";
769
+ const y2Domain = userY2Scale?.domain ?? computeDomain(data, aes.y2, y2Trans);
770
+ const y2 = createResolvedContinuousScale("y2", y2Domain, [plotArea.y + plotArea.height - 1, plotArea.y], y2Trans);
771
+ if (userY2Scale?.breaks) {
772
+ y2.breaks = userY2Scale.breaks;
773
+ }
774
+ if (userY2Scale?.labels) {
775
+ y2.labels = userY2Scale.labels;
776
+ }
777
+ context.y2 = y2;
744
778
  }
745
- fillRect(x, y, width, height, char = " ", fg, bg) {
746
- for (let dy = 0;dy < height; dy++) {
747
- for (let dx = 0;dx < width; dx++) {
748
- this.setCell(x + dx, y + dy, { char, fg, bg });
779
+ const colorAesField = aes.color || aes.fill;
780
+ if (colorAesField) {
781
+ const colorOrderOptions = {};
782
+ if (userColorScale) {
783
+ if (userColorScale.domain && Array.isArray(userColorScale.domain)) {
784
+ colorOrderOptions.limits = userColorScale.domain;
785
+ }
786
+ const orderOpts = userColorScale.orderOptions;
787
+ if (orderOpts) {
788
+ if (orderOpts.order)
789
+ colorOrderOptions.order = orderOpts.order;
790
+ if (orderOpts.reverse)
791
+ colorOrderOptions.reverse = orderOpts.reverse;
792
+ if (orderOpts.exclude)
793
+ colorOrderOptions.exclude = orderOpts.exclude;
794
+ if (orderOpts.drop !== undefined)
795
+ colorOrderOptions.drop = orderOpts.drop;
749
796
  }
750
797
  }
751
- }
752
- drawBox(x, y, width, height, style = "single", fg) {
753
- const chars = style === "double" ? { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" } : style === "rounded" ? { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" } : { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
754
- this.drawChar(x, y, chars.tl, fg);
755
- this.drawChar(x + width - 1, y, chars.tr, fg);
756
- this.drawChar(x, y + height - 1, chars.bl, fg);
757
- this.drawChar(x + width - 1, y + height - 1, chars.br, fg);
758
- this.drawHLine(x + 1, y, width - 2, chars.h, fg);
759
- this.drawHLine(x + 1, y + height - 1, width - 2, chars.h, fg);
760
- this.drawVLine(x, y + 1, height - 2, chars.v, fg);
761
- this.drawVLine(x + width - 1, y + 1, height - 2, chars.v, fg);
762
- }
763
- toString() {
764
- return this.cells.map((row) => row.map((cell) => cell.char).join("")).join(`
765
- `);
766
- }
767
- toAnsiString() {
768
- const lines = [];
769
- for (const row of this.cells) {
770
- let line = "";
771
- let currentFg = null;
772
- let currentBg = null;
773
- for (const cell of row) {
774
- const fgChanged = !currentFg || currentFg.r !== cell.fg.r || currentFg.g !== cell.fg.g || currentFg.b !== cell.fg.b;
775
- const bgChanged = cell.bg.a > 0 && (!currentBg || currentBg.r !== cell.bg.r || currentBg.g !== cell.bg.g || currentBg.b !== cell.bg.b);
776
- if (fgChanged) {
777
- line += `\x1B[38;2;${cell.fg.r};${cell.fg.g};${cell.fg.b}m`;
778
- currentFg = cell.fg;
779
- }
780
- if (bgChanged) {
781
- line += `\x1B[48;2;${cell.bg.r};${cell.bg.g};${cell.bg.b}m`;
782
- currentBg = cell.bg;
783
- }
784
- if (cell.bold)
785
- line += "\x1B[1m";
786
- if (cell.italic)
787
- line += "\x1B[3m";
788
- if (cell.underline)
789
- line += "\x1B[4m";
790
- line += cell.char;
791
- if (cell.bold || cell.italic || cell.underline) {
792
- line += "\x1B[22;23;24m";
793
- if (currentFg) {
794
- line += `\x1B[38;2;${currentFg.r};${currentFg.g};${currentFg.b}m`;
798
+ const colorDomain = inferDiscreteDomain(data, colorAesField, colorOrderOptions);
799
+ if (userColorScale && userColorScale.map) {
800
+ context.color = {
801
+ aesthetic: userColorScale.aesthetic || "color",
802
+ type: userColorScale.type === "continuous" ? "continuous" : "discrete",
803
+ domain: userColorScale.type === "continuous" ? userColorScale.domain ?? inferContinuousDomain(data, colorAesField) : colorDomain,
804
+ map: (value) => {
805
+ const result = userColorScale.map(value);
806
+ if (typeof result === "object" && "r" in result) {
807
+ return result;
795
808
  }
809
+ return { r: 128, g: 128, b: 128, a: 1 };
796
810
  }
797
- }
798
- line += "\x1B[0m";
799
- lines.push(line);
811
+ };
812
+ } else {
813
+ context.color = createResolvedDiscreteColorScale(colorDomain);
800
814
  }
801
- return lines.join(`
802
- `);
803
815
  }
816
+ if (aes.size) {
817
+ const sizeDomain = inferContinuousDomain(data, aes.size);
818
+ context.size = createResolvedSizeScale(sizeDomain);
819
+ }
820
+ return context;
804
821
  }
805
- function createCanvas(width, height) {
806
- return new TerminalCanvas(width, height);
807
- }
808
-
809
- // src/pipeline/pipeline.ts
810
- init_scales();
811
-
812
- // src/pipeline/render-geoms.ts
813
- init_scales();
822
+ var CATEGORY_COLORS, DEFAULT_POINT_COLOR;
823
+ var init_scales = __esm(() => {
824
+ CATEGORY_COLORS = [
825
+ { r: 31, g: 119, b: 180, a: 1 },
826
+ { r: 255, g: 127, b: 14, a: 1 },
827
+ { r: 44, g: 160, b: 44, a: 1 },
828
+ { r: 214, g: 39, b: 40, a: 1 },
829
+ { r: 148, g: 103, b: 189, a: 1 },
830
+ { r: 140, g: 86, b: 75, a: 1 },
831
+ { r: 227, g: 119, b: 194, a: 1 },
832
+ { r: 127, g: 127, b: 127, a: 1 },
833
+ { r: 188, g: 189, b: 34, a: 1 },
834
+ { r: 23, g: 190, b: 207, a: 1 }
835
+ ];
836
+ DEFAULT_POINT_COLOR = { r: 79, g: 169, b: 238, a: 1 };
837
+ });
814
838
 
815
839
  // src/positions/index.ts
816
840
  function position_identity() {
@@ -1012,22 +1036,6 @@ function getPositionType(position) {
1012
1036
  }
1013
1037
 
1014
1038
  // src/pipeline/render-geoms.ts
1015
- var POINT_SHAPES = {
1016
- circle: "●",
1017
- filled_circle: "●",
1018
- open_circle: "○",
1019
- square: "■",
1020
- open_square: "□",
1021
- diamond: "◆",
1022
- open_diamond: "◇",
1023
- triangle: "▲",
1024
- open_triangle: "△",
1025
- cross: "✕",
1026
- plus: "+",
1027
- star: "★",
1028
- dot: "•"
1029
- };
1030
- var SIZE_CHARS = ["·", "•", "●", "⬤"];
1031
1039
  function getPointShape(shape) {
1032
1040
  if (!shape)
1033
1041
  return POINT_SHAPES.circle;
@@ -1038,7 +1046,45 @@ function getPointColor(row, aes, colorScale) {
1038
1046
  const value = row[aes.color];
1039
1047
  return colorScale.map(value);
1040
1048
  }
1041
- return DEFAULT_POINT_COLOR;
1049
+ return DEFAULT_POINT_COLOR;
1050
+ }
1051
+ function parseColorToRgba(color, fallback = { r: 128, g: 128, b: 128, a: 1 }) {
1052
+ if (!color)
1053
+ return fallback;
1054
+ if (typeof color === "object" && color !== null && "r" in color) {
1055
+ return color;
1056
+ }
1057
+ if (typeof color === "string") {
1058
+ if (color.startsWith("#")) {
1059
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
1060
+ if (result) {
1061
+ return {
1062
+ r: parseInt(result[1], 16),
1063
+ g: parseInt(result[2], 16),
1064
+ b: parseInt(result[3], 16),
1065
+ a: 1
1066
+ };
1067
+ }
1068
+ }
1069
+ const namedColors = {
1070
+ red: { r: 255, g: 0, b: 0, a: 1 },
1071
+ blue: { r: 0, g: 0, b: 255, a: 1 },
1072
+ green: { r: 0, g: 128, b: 0, a: 1 },
1073
+ black: { r: 0, g: 0, b: 0, a: 1 },
1074
+ white: { r: 255, g: 255, b: 255, a: 1 },
1075
+ gray: { r: 128, g: 128, b: 128, a: 1 },
1076
+ grey: { r: 128, g: 128, b: 128, a: 1 },
1077
+ yellow: { r: 255, g: 255, b: 0, a: 1 },
1078
+ orange: { r: 255, g: 165, b: 0, a: 1 },
1079
+ purple: { r: 128, g: 0, b: 128, a: 1 },
1080
+ cyan: { r: 0, g: 255, b: 255, a: 1 },
1081
+ magenta: { r: 255, g: 0, b: 255, a: 1 }
1082
+ };
1083
+ const named = namedColors[color.toLowerCase()];
1084
+ if (named)
1085
+ return named;
1086
+ }
1087
+ return fallback;
1042
1088
  }
1043
1089
  function renderGeomPoint(data, geom, aes, scales, canvas) {
1044
1090
  const defaultShape = getPointShape(geom.params.shape);
@@ -1438,7 +1484,7 @@ function renderGeomHLine(_data, geom, _aes, scales, canvas) {
1438
1484
  if (yintercept === undefined)
1439
1485
  return;
1440
1486
  const cy = Math.round(scales.y.map(yintercept));
1441
- const color = geom.params.color ?? { r: 128, g: 128, b: 128, a: 1 };
1487
+ const color = parseColorToRgba(geom.params.color);
1442
1488
  const startX = Math.round(scales.x.range[0]);
1443
1489
  const endX = Math.round(scales.x.range[1]);
1444
1490
  canvas.drawHLine(startX, cy, endX - startX + 1, "─", color);
@@ -1448,7 +1494,7 @@ function renderGeomVLine(_data, geom, _aes, scales, canvas) {
1448
1494
  if (xintercept === undefined)
1449
1495
  return;
1450
1496
  const cx = Math.round(scales.x.map(xintercept));
1451
- const color = geom.params.color ?? { r: 128, g: 128, b: 128, a: 1 };
1497
+ const color = parseColorToRgba(geom.params.color);
1452
1498
  const startY = Math.round(Math.min(scales.y.range[0], scales.y.range[1]));
1453
1499
  const endY = Math.round(Math.max(scales.y.range[0], scales.y.range[1]));
1454
1500
  canvas.drawVLine(cx, startY, endY - startY + 1, "│", color);
@@ -1765,20 +1811,52 @@ function renderGeomTile(data, geom, aes, scales, canvas) {
1765
1811
  const plotRight = Math.round(scales.x.range[1]);
1766
1812
  const plotTop = Math.round(Math.min(scales.y.range[0], scales.y.range[1]));
1767
1813
  const plotBottom = Math.round(Math.max(scales.y.range[0], scales.y.range[1]));
1768
- let tileWidth = geom.params.width;
1769
- let tileHeight = geom.params.height;
1770
- if (!tileWidth || !tileHeight) {
1771
- const xVals = [...new Set(data.map((r) => Number(r[aes.x]) || 0))].sort((a, b) => a - b);
1772
- const yVals = [...new Set(data.map((r) => Number(r[aes.y]) || 0))].sort((a, b) => a - b);
1773
- if (xVals.length > 1) {
1774
- tileWidth = tileWidth ?? xVals[1] - xVals[0];
1814
+ let halfW;
1815
+ let halfH;
1816
+ const xIsDiscrete = scales.x.type === "discrete";
1817
+ const yIsDiscrete = scales.y.type === "discrete";
1818
+ if (xIsDiscrete) {
1819
+ const xDomain = scales.x.domain;
1820
+ const canvasWidth = Math.abs(scales.x.range[1] - scales.x.range[0]);
1821
+ halfW = Math.max(1, Math.floor(canvasWidth / (xDomain.length * 2)));
1822
+ } else {
1823
+ let tileWidth = data[0]?.width ?? geom.params.width;
1824
+ if (!tileWidth) {
1825
+ const xVals = [...new Set(data.map((r) => Number(r[aes.x])).filter((v) => !isNaN(v)))].sort((a, b) => a - b);
1826
+ if (xVals.length > 1) {
1827
+ tileWidth = xVals[1] - xVals[0];
1828
+ }
1829
+ }
1830
+ tileWidth = tileWidth ?? 1;
1831
+ const sampleX = data.find((r) => r[aes.x] !== null && r[aes.x] !== undefined)?.[aes.x];
1832
+ if (sampleX !== undefined) {
1833
+ const cx = scales.x.map(sampleX);
1834
+ halfW = Math.max(1, Math.floor(Math.abs(scales.x.map(Number(sampleX) + tileWidth / 2) - cx)));
1835
+ } else {
1836
+ halfW = 1;
1775
1837
  }
1776
- if (yVals.length > 1) {
1777
- tileHeight = tileHeight ?? yVals[1] - yVals[0];
1838
+ }
1839
+ if (yIsDiscrete) {
1840
+ const yDomain = scales.y.domain;
1841
+ const canvasHeight = Math.abs(scales.y.range[1] - scales.y.range[0]);
1842
+ halfH = Math.max(1, Math.floor(canvasHeight / (yDomain.length * 2)));
1843
+ } else {
1844
+ let tileHeight = data[0]?.height ?? geom.params.height;
1845
+ if (!tileHeight) {
1846
+ const yVals = [...new Set(data.map((r) => Number(r[aes.y])).filter((v) => !isNaN(v)))].sort((a, b) => a - b);
1847
+ if (yVals.length > 1) {
1848
+ tileHeight = yVals[1] - yVals[0];
1849
+ }
1850
+ }
1851
+ tileHeight = tileHeight ?? 1;
1852
+ const sampleY = data.find((r) => r[aes.y] !== null && r[aes.y] !== undefined)?.[aes.y];
1853
+ if (sampleY !== undefined) {
1854
+ const cy = scales.y.map(sampleY);
1855
+ halfH = Math.max(1, Math.floor(Math.abs(scales.y.map(Number(sampleY) + tileHeight / 2) - cy)));
1856
+ } else {
1857
+ halfH = 1;
1778
1858
  }
1779
1859
  }
1780
- tileWidth = tileWidth ?? 1;
1781
- tileHeight = tileHeight ?? 1;
1782
1860
  for (const row of data) {
1783
1861
  const xVal = row[aes.x];
1784
1862
  const yVal = row[aes.y];
@@ -1788,8 +1866,6 @@ function renderGeomTile(data, geom, aes, scales, canvas) {
1788
1866
  }
1789
1867
  const cx = Math.round(scales.x.map(xVal));
1790
1868
  const cy = Math.round(scales.y.map(yVal));
1791
- const halfW = Math.max(1, Math.floor(Math.abs(scales.x.map(Number(xVal) + tileWidth / 2) - cx)));
1792
- const halfH = Math.max(1, Math.floor(Math.abs(scales.y.map(Number(yVal) + tileHeight / 2) - cy)));
1793
1869
  let color;
1794
1870
  if (scales.color && typeof fillVal === "number") {
1795
1871
  color = scales.color.map(fillVal);
@@ -1977,7 +2053,7 @@ function renderGeomAbline(_data, geom, _aes, scales, canvas) {
1977
2053
  const intercept = geom.params.intercept ?? 0;
1978
2054
  const linetype = geom.params.linetype ?? "solid";
1979
2055
  const lineChar = linetype === "dotted" ? "·" : linetype === "dashed" ? "╌" : "─";
1980
- const color = geom.params.color ?? { r: 128, g: 128, b: 128, a: 1 };
2056
+ const color = parseColorToRgba(geom.params.color);
1981
2057
  const plotLeft = Math.round(scales.x.range[0]);
1982
2058
  const plotRight = Math.round(scales.x.range[1]);
1983
2059
  const plotTop = Math.round(Math.min(scales.y.range[0], scales.y.range[1]));
@@ -2169,6 +2245,7 @@ function renderGeom(data, geom, aes, scales, canvas, coordType) {
2169
2245
  break;
2170
2246
  case "tile":
2171
2247
  case "raster":
2248
+ case "bin2d":
2172
2249
  renderGeomTile(data, geom, aes, scales, canvas);
2173
2250
  break;
2174
2251
  case "contour":
@@ -2198,6 +2275,26 @@ function renderGeom(data, geom, aes, scales, canvas, coordType) {
2198
2275
  break;
2199
2276
  }
2200
2277
  }
2278
+ var POINT_SHAPES, SIZE_CHARS;
2279
+ var init_render_geoms = __esm(() => {
2280
+ init_scales();
2281
+ POINT_SHAPES = {
2282
+ circle: "●",
2283
+ filled_circle: "●",
2284
+ open_circle: "○",
2285
+ square: "■",
2286
+ open_square: "□",
2287
+ diamond: "◆",
2288
+ open_diamond: "◇",
2289
+ triangle: "▲",
2290
+ open_triangle: "△",
2291
+ cross: "✕",
2292
+ plus: "+",
2293
+ star: "★",
2294
+ dot: "•"
2295
+ };
2296
+ SIZE_CHARS = ["·", "•", "●", "⬤"];
2297
+ });
2201
2298
 
2202
2299
  // src/pipeline/render-axes.ts
2203
2300
  function calculateTicks(domain, targetTicks = 5, transform, invert) {
@@ -2505,7 +2602,6 @@ function renderTitle(canvas, title, width, theme) {
2505
2602
  }
2506
2603
  canvas.drawString(x, 0, title, titleColor);
2507
2604
  }
2508
- var SIZE_SYMBOLS = ["·", "•", "●", "⬤"];
2509
2605
  function renderMultiLegend(canvas, entries, x, y, theme, width) {
2510
2606
  if (theme.legend.position === "none" || entries.length === 0)
2511
2607
  return;
@@ -2633,6 +2729,10 @@ function formatContinuousLegendValue(value) {
2633
2729
  }
2634
2730
  return value.toFixed(1);
2635
2731
  }
2732
+ var SIZE_SYMBOLS;
2733
+ var init_render_axes = __esm(() => {
2734
+ SIZE_SYMBOLS = ["·", "•", "●", "⬤"];
2735
+ });
2636
2736
 
2637
2737
  // src/stats/bin.ts
2638
2738
  function computeBins(data, field, params = {}) {
@@ -2678,71 +2778,313 @@ function computeBins(data, field, params = {}) {
2678
2778
  } else {
2679
2779
  binStart = min;
2680
2780
  }
2681
- const binCounts = new Map;
2682
- for (const val of values) {
2683
- const binIndex = Math.floor((val - binStart) / binWidth);
2684
- binCounts.set(binIndex, (binCounts.get(binIndex) ?? 0) + 1);
2781
+ const binCounts = new Map;
2782
+ for (const val of values) {
2783
+ const binIndex = Math.floor((val - binStart) / binWidth);
2784
+ binCounts.set(binIndex, (binCounts.get(binIndex) ?? 0) + 1);
2785
+ }
2786
+ const bins = [];
2787
+ const maxBinIndex = Math.ceil((max - binStart) / binWidth);
2788
+ for (let i = 0;i <= maxBinIndex; i++) {
2789
+ const count = binCounts.get(i) ?? 0;
2790
+ const xmin = binStart + i * binWidth;
2791
+ const xmax = xmin + binWidth;
2792
+ const x = (xmin + xmax) / 2;
2793
+ bins.push({
2794
+ x,
2795
+ xmin,
2796
+ xmax,
2797
+ count,
2798
+ density: count / (values.length * binWidth)
2799
+ });
2800
+ }
2801
+ return { bins, binWidth };
2802
+ }
2803
+ function stat_bin(params = {}) {
2804
+ return {
2805
+ type: "bin",
2806
+ compute(data, aes) {
2807
+ const groupField = aes.color || aes.fill || aes.group;
2808
+ if (groupField) {
2809
+ const groups = new Map;
2810
+ for (const row of data) {
2811
+ const groupVal = String(row[groupField] ?? "default");
2812
+ if (!groups.has(groupVal)) {
2813
+ groups.set(groupVal, []);
2814
+ }
2815
+ groups.get(groupVal).push(row);
2816
+ }
2817
+ const results = [];
2818
+ for (const [groupVal, groupData] of groups) {
2819
+ const { bins: bins2 } = computeBins(groupData, aes.x, params);
2820
+ for (const bin of bins2) {
2821
+ results.push({
2822
+ x: bin.x,
2823
+ xmin: bin.xmin,
2824
+ xmax: bin.xmax,
2825
+ y: bin.count,
2826
+ count: bin.count,
2827
+ density: bin.density,
2828
+ [groupField]: groupVal
2829
+ });
2830
+ }
2831
+ }
2832
+ return results;
2833
+ }
2834
+ const { bins } = computeBins(data, aes.x, params);
2835
+ return bins.map((bin) => ({
2836
+ x: bin.x,
2837
+ xmin: bin.xmin,
2838
+ xmax: bin.xmax,
2839
+ y: bin.count,
2840
+ count: bin.count,
2841
+ density: bin.density
2842
+ }));
2843
+ }
2844
+ };
2845
+ }
2846
+
2847
+ // src/performance/binning.ts
2848
+ function computeDomain2(data, field) {
2849
+ let min = Infinity;
2850
+ let max = -Infinity;
2851
+ for (const d of data) {
2852
+ const v = d[field];
2853
+ if (typeof v === "number" && !isNaN(v)) {
2854
+ if (v < min)
2855
+ min = v;
2856
+ if (v > max)
2857
+ max = v;
2858
+ }
2859
+ }
2860
+ if (min === Infinity)
2861
+ return [0, 1];
2862
+ if (min === max)
2863
+ return [min - 0.5, max + 0.5];
2864
+ return [min, max];
2865
+ }
2866
+ function aggregateValues(values, method) {
2867
+ if (values.length === 0)
2868
+ return 0;
2869
+ switch (method) {
2870
+ case "count":
2871
+ return values.length;
2872
+ case "sum":
2873
+ return values.reduce((a, b) => a + b, 0);
2874
+ case "mean":
2875
+ return values.reduce((a, b) => a + b, 0) / values.length;
2876
+ case "median":
2877
+ const sorted = [...values].sort((a, b) => a - b);
2878
+ const mid = Math.floor(sorted.length / 2);
2879
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
2880
+ case "min":
2881
+ return Math.min(...values);
2882
+ case "max":
2883
+ return Math.max(...values);
2884
+ default:
2885
+ return values.length;
2886
+ }
2887
+ }
2888
+ function rectbin(data, options) {
2889
+ const {
2890
+ xField,
2891
+ yField,
2892
+ xBins = 20,
2893
+ yBins = 20,
2894
+ aggregate = "count",
2895
+ valueField
2896
+ } = options;
2897
+ if (data.length === 0)
2898
+ return [];
2899
+ const xDomain = options.xDomain ?? computeDomain2(data, xField);
2900
+ const yDomain = options.yDomain ?? computeDomain2(data, yField);
2901
+ const xRange = xDomain[1] - xDomain[0];
2902
+ const yRange = yDomain[1] - yDomain[0];
2903
+ const binWidth = xRange / xBins;
2904
+ const binHeight = yRange / yBins;
2905
+ const bins = new Map;
2906
+ for (const point of data) {
2907
+ const x = point[xField];
2908
+ const y = point[yField];
2909
+ if (typeof x !== "number" || typeof y !== "number")
2910
+ continue;
2911
+ const bx = Math.min(xBins - 1, Math.max(0, Math.floor((x - xDomain[0]) / binWidth)));
2912
+ const by = Math.min(yBins - 1, Math.max(0, Math.floor((y - yDomain[0]) / binHeight)));
2913
+ const key = `${bx},${by}`;
2914
+ if (!bins.has(key)) {
2915
+ bins.set(key, { points: [], values: [] });
2916
+ }
2917
+ const bin = bins.get(key);
2918
+ bin.points.push(point);
2919
+ if (valueField && typeof point[valueField] === "number") {
2920
+ bin.values.push(point[valueField]);
2921
+ }
2922
+ }
2923
+ const result = [];
2924
+ for (const [key, bin] of bins) {
2925
+ const [bx, by] = key.split(",").map(Number);
2926
+ const centerX = xDomain[0] + (bx + 0.5) * binWidth;
2927
+ const centerY = yDomain[0] + (by + 0.5) * binHeight;
2928
+ result.push({
2929
+ x: centerX,
2930
+ y: centerY,
2931
+ count: bin.points.length,
2932
+ value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
2933
+ width: binWidth,
2934
+ height: binHeight,
2935
+ points: bin.points
2936
+ });
2937
+ }
2938
+ return result;
2939
+ }
2940
+ function hexbin(data, options) {
2941
+ const { xField, yField, aggregate = "count", valueField, radius = 10 } = options;
2942
+ if (data.length === 0)
2943
+ return [];
2944
+ const xDomain = options.xDomain ?? computeDomain2(data, xField);
2945
+ const yDomain = options.yDomain ?? computeDomain2(data, yField);
2946
+ const hexWidth = radius * 2;
2947
+ const hexHeight = radius * Math.sqrt(3);
2948
+ const bins = new Map;
2949
+ for (const point of data) {
2950
+ const x = point[xField];
2951
+ const y = point[yField];
2952
+ if (typeof x !== "number" || typeof y !== "number")
2953
+ continue;
2954
+ const col = Math.round((x - xDomain[0]) / (hexWidth * 0.75));
2955
+ const row = Math.round((y - yDomain[0]) / hexHeight - col % 2 * 0.5);
2956
+ const key = `${col},${row}`;
2957
+ if (!bins.has(key)) {
2958
+ bins.set(key, { points: [], values: [], col, row });
2959
+ }
2960
+ const bin = bins.get(key);
2961
+ bin.points.push(point);
2962
+ if (valueField && typeof point[valueField] === "number") {
2963
+ bin.values.push(point[valueField]);
2964
+ }
2965
+ }
2966
+ function hexVertices(cx, cy, r) {
2967
+ const vertices = [];
2968
+ for (let i = 0;i < 6; i++) {
2969
+ const angle = Math.PI / 3 * i + Math.PI / 6;
2970
+ vertices.push({
2971
+ x: cx + r * Math.cos(angle),
2972
+ y: cy + r * Math.sin(angle)
2973
+ });
2974
+ }
2975
+ return vertices;
2976
+ }
2977
+ const result = [];
2978
+ for (const [, bin] of bins) {
2979
+ const centerX = xDomain[0] + bin.col * hexWidth * 0.75;
2980
+ const centerY = yDomain[0] + (bin.row + bin.col % 2 * 0.5) * hexHeight;
2981
+ result.push({
2982
+ x: centerX,
2983
+ y: centerY,
2984
+ count: bin.points.length,
2985
+ value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
2986
+ width: hexWidth,
2987
+ height: hexHeight,
2988
+ points: bin.points,
2989
+ vertices: hexVertices(centerX, centerY, radius),
2990
+ col: bin.col,
2991
+ row: bin.row
2992
+ });
2993
+ }
2994
+ return result;
2995
+ }
2996
+
2997
+ class Binner {
2998
+ options;
2999
+ type;
3000
+ hexRadius;
3001
+ constructor(options) {
3002
+ this.options = options;
3003
+ this.type = options.type ?? "rect";
3004
+ this.hexRadius = options.hexRadius ?? 10;
3005
+ }
3006
+ bin(data) {
3007
+ if (this.type === "hex") {
3008
+ return hexbin(data, { ...this.options, radius: this.hexRadius });
3009
+ }
3010
+ return rectbin(data, this.options);
3011
+ }
3012
+ toPlotData(data) {
3013
+ const bins = this.bin(data);
3014
+ const maxCount = Math.max(...bins.map((b) => b.count));
3015
+ const minSize = 1;
3016
+ const maxSize = 5;
3017
+ return bins.map((bin) => ({
3018
+ x: bin.x,
3019
+ y: bin.y,
3020
+ count: bin.count,
3021
+ value: bin.value,
3022
+ size: minSize + bin.count / maxCount * (maxSize - minSize)
3023
+ }));
3024
+ }
3025
+ getDensityColors(bins, colorScale) {
3026
+ const maxCount = Math.max(...bins.map((b) => b.count));
3027
+ const colors = new Map;
3028
+ for (const bin of bins) {
3029
+ const t = bin.count / maxCount;
3030
+ colors.set(bin, colorScale(t));
3031
+ }
3032
+ return colors;
2685
3033
  }
2686
- const bins = [];
2687
- const maxBinIndex = Math.ceil((max - binStart) / binWidth);
2688
- for (let i = 0;i <= maxBinIndex; i++) {
2689
- const count = binCounts.get(i) ?? 0;
2690
- const xmin = binStart + i * binWidth;
2691
- const xmax = xmin + binWidth;
2692
- const x = (xmin + xmax) / 2;
2693
- bins.push({
2694
- x,
2695
- xmin,
2696
- xmax,
2697
- count,
2698
- density: count / (values.length * binWidth)
2699
- });
3034
+ }
3035
+ function createBinner(options) {
3036
+ return new Binner(options);
3037
+ }
3038
+
3039
+ // src/stats/bin2d.ts
3040
+ function computeBins2d(data, xField, yField, params = {}) {
3041
+ const {
3042
+ bins = 30,
3043
+ binsx,
3044
+ binsy,
3045
+ drop = true
3046
+ } = params;
3047
+ const xBins = binsx ?? bins;
3048
+ const yBins = binsy ?? bins;
3049
+ const binned = rectbin(data, {
3050
+ xField,
3051
+ yField,
3052
+ xBins,
3053
+ yBins,
3054
+ aggregate: "count"
3055
+ });
3056
+ const total = data.length;
3057
+ const results = binned.map((bin) => ({
3058
+ x: bin.x,
3059
+ y: bin.y,
3060
+ count: bin.count,
3061
+ density: total > 0 ? bin.count / total : 0,
3062
+ width: bin.width,
3063
+ height: bin.height
3064
+ }));
3065
+ if (drop) {
3066
+ return results.filter((r) => r.count > 0);
2700
3067
  }
2701
- return { bins, binWidth };
3068
+ return results;
2702
3069
  }
2703
- function stat_bin(params = {}) {
3070
+ function stat_bin2d(params = {}) {
2704
3071
  return {
2705
- type: "bin",
3072
+ type: "bin2d",
2706
3073
  compute(data, aes) {
2707
- const groupField = aes.color || aes.fill || aes.group;
2708
- if (groupField) {
2709
- const groups = new Map;
2710
- for (const row of data) {
2711
- const groupVal = String(row[groupField] ?? "default");
2712
- if (!groups.has(groupVal)) {
2713
- groups.set(groupVal, []);
2714
- }
2715
- groups.get(groupVal).push(row);
2716
- }
2717
- const results = [];
2718
- for (const [groupVal, groupData] of groups) {
2719
- const { bins: bins2 } = computeBins(groupData, aes.x, params);
2720
- for (const bin of bins2) {
2721
- results.push({
2722
- x: bin.x,
2723
- xmin: bin.xmin,
2724
- xmax: bin.xmax,
2725
- y: bin.count,
2726
- count: bin.count,
2727
- density: bin.density,
2728
- [groupField]: groupVal
2729
- });
2730
- }
2731
- }
2732
- return results;
2733
- }
2734
- const { bins } = computeBins(data, aes.x, params);
3074
+ const bins = computeBins2d(data, aes.x, aes.y, params);
2735
3075
  return bins.map((bin) => ({
2736
3076
  x: bin.x,
2737
- xmin: bin.xmin,
2738
- xmax: bin.xmax,
2739
- y: bin.count,
3077
+ y: bin.y,
2740
3078
  count: bin.count,
2741
- density: bin.density
3079
+ density: bin.density,
3080
+ fill: bin.count,
3081
+ width: bin.width,
3082
+ height: bin.height
2742
3083
  }));
2743
3084
  }
2744
3085
  };
2745
3086
  }
3087
+ var init_bin2d = () => {};
2746
3088
 
2747
3089
  // src/stats/boxplot.ts
2748
3090
  function quantile(sorted, p) {
@@ -3159,17 +3501,6 @@ function stat_smooth(params = {}) {
3159
3501
  }
3160
3502
 
3161
3503
  // src/stats/summary.ts
3162
- var summaryFunctions = {
3163
- mean: (values) => values.reduce((a, b) => a + b, 0) / values.length,
3164
- median: (values) => {
3165
- const sorted = [...values].sort((a, b) => a - b);
3166
- const mid = Math.floor(sorted.length / 2);
3167
- return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
3168
- },
3169
- min: (values) => Math.min(...values),
3170
- max: (values) => Math.max(...values),
3171
- sum: (values) => values.reduce((a, b) => a + b, 0)
3172
- };
3173
3504
  function sd(values) {
3174
3505
  const n = values.length;
3175
3506
  if (n < 2)
@@ -3301,6 +3632,20 @@ function stat_summary(params = {}) {
3301
3632
  }
3302
3633
  };
3303
3634
  }
3635
+ var summaryFunctions;
3636
+ var init_summary = __esm(() => {
3637
+ summaryFunctions = {
3638
+ mean: (values) => values.reduce((a, b) => a + b, 0) / values.length,
3639
+ median: (values) => {
3640
+ const sorted = [...values].sort((a, b) => a - b);
3641
+ const mid = Math.floor(sorted.length / 2);
3642
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
3643
+ },
3644
+ min: (values) => Math.min(...values),
3645
+ max: (values) => Math.max(...values),
3646
+ sum: (values) => values.reduce((a, b) => a + b, 0)
3647
+ };
3648
+ });
3304
3649
 
3305
3650
  // src/stats/qq.ts
3306
3651
  function qnorm(p, mean = 0, sd2 = 1) {
@@ -3483,15 +3828,125 @@ function stat_qq_line(params = {}) {
3483
3828
  };
3484
3829
  }
3485
3830
 
3831
+ // src/stats/density2d.ts
3832
+ function gaussian2d(dx, dy, hx, hy) {
3833
+ const ux = dx / hx;
3834
+ const uy = dy / hy;
3835
+ return Math.exp(-0.5 * (ux * ux + uy * uy)) / (2 * Math.PI * hx * hy);
3836
+ }
3837
+ function scottBandwidth2d(values) {
3838
+ const n = values.length;
3839
+ if (n < 2)
3840
+ return 1;
3841
+ const mean = values.reduce((a, b) => a + b, 0) / n;
3842
+ const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / (n - 1);
3843
+ const std = Math.sqrt(variance);
3844
+ return std * Math.pow(n, -1 / 6);
3845
+ }
3846
+ function computeDensity2d(data, xField, yField, params = {}) {
3847
+ const points = [];
3848
+ const xValues = [];
3849
+ const yValues = [];
3850
+ for (const row of data) {
3851
+ const xVal = row[xField];
3852
+ const yVal = row[yField];
3853
+ if (xVal === null || xVal === undefined || yVal === null || yVal === undefined)
3854
+ continue;
3855
+ const x = Number(xVal);
3856
+ const y = Number(yVal);
3857
+ if (isNaN(x) || isNaN(y))
3858
+ continue;
3859
+ points.push({ x, y });
3860
+ xValues.push(x);
3861
+ yValues.push(y);
3862
+ }
3863
+ if (points.length < 3) {
3864
+ return [];
3865
+ }
3866
+ const n = params.n ?? 50;
3867
+ const nx = params.nx ?? n;
3868
+ const ny = params.ny ?? n;
3869
+ const adjust = params.adjust ?? 1;
3870
+ let hx, hy;
3871
+ if (Array.isArray(params.h)) {
3872
+ hx = params.h[0] * adjust;
3873
+ hy = params.h[1] * adjust;
3874
+ } else if (params.h !== undefined) {
3875
+ hx = params.h * adjust;
3876
+ hy = params.h * adjust;
3877
+ } else {
3878
+ hx = scottBandwidth2d(xValues) * adjust;
3879
+ hy = scottBandwidth2d(yValues) * adjust;
3880
+ }
3881
+ if (hx <= 0)
3882
+ hx = 1;
3883
+ if (hy <= 0)
3884
+ hy = 1;
3885
+ const xMin = Math.min(...xValues);
3886
+ const xMax = Math.max(...xValues);
3887
+ const yMin = Math.min(...yValues);
3888
+ const yMax = Math.max(...yValues);
3889
+ const xPad = 3 * hx;
3890
+ const yPad = 3 * hy;
3891
+ const gridXMin = xMin - xPad;
3892
+ const gridXMax = xMax + xPad;
3893
+ const gridYMin = yMin - yPad;
3894
+ const gridYMax = yMax + yPad;
3895
+ const xStep = (gridXMax - gridXMin) / (nx - 1);
3896
+ const yStep = (gridYMax - gridYMin) / (ny - 1);
3897
+ const results = [];
3898
+ const nPoints = points.length;
3899
+ for (let i = 0;i < nx; i++) {
3900
+ const gx = gridXMin + i * xStep;
3901
+ for (let j = 0;j < ny; j++) {
3902
+ const gy = gridYMin + j * yStep;
3903
+ let density = 0;
3904
+ for (const pt of points) {
3905
+ density += gaussian2d(gx - pt.x, gy - pt.y, hx, hy);
3906
+ }
3907
+ density /= nPoints;
3908
+ results.push({
3909
+ x: gx,
3910
+ y: gy,
3911
+ z: density,
3912
+ density,
3913
+ level: density
3914
+ });
3915
+ }
3916
+ }
3917
+ return results;
3918
+ }
3919
+ function stat_density_2d(params = {}) {
3920
+ return {
3921
+ type: "density_2d",
3922
+ compute(data, aes) {
3923
+ if (aes.color) {
3924
+ const groups = new Map;
3925
+ for (const row of data) {
3926
+ const group = String(row[aes.color] ?? "default");
3927
+ if (!groups.has(group)) {
3928
+ groups.set(group, []);
3929
+ }
3930
+ groups.get(group).push(row);
3931
+ }
3932
+ const result = [];
3933
+ for (const [group, groupData] of groups) {
3934
+ const density = computeDensity2d(groupData, aes.x, aes.y, params);
3935
+ for (const d of density) {
3936
+ result.push({
3937
+ ...d,
3938
+ [aes.color]: group
3939
+ });
3940
+ }
3941
+ }
3942
+ return result;
3943
+ }
3944
+ return computeDensity2d(data, aes.x, aes.y, params);
3945
+ }
3946
+ };
3947
+ }
3948
+
3486
3949
  // src/facets/index.ts
3487
- var label_value = (value) => value;
3488
- var label_both = (value, variable) => variable ? `${variable}: ${value}` : value;
3489
- var label_parsed = (value) => value.replace(/_/g, " ");
3490
- var label_wrap = (width) => (value) => {
3491
- if (value.length <= width)
3492
- return value;
3493
- return value.substring(0, width - 1) + "…";
3494
- };
3495
3950
  function as_labeller(labels) {
3496
3951
  return (value) => labels[value] ?? value;
3497
3952
  }
@@ -3684,6 +4139,11 @@ function calculateGridStripLayout(totalWidth, totalHeight, nrow, ncol, hasTitle,
3684
4139
  rowStripWidth: rowStripWidth - 1
3685
4140
  };
3686
4141
  }
4142
+ var label_value = (value) => value, label_both = (value, variable) => variable ? `${variable}: ${value}` : value, label_parsed = (value) => value.replace(/_/g, " "), label_wrap = (width) => (value) => {
4143
+ if (value.length <= width)
4144
+ return value;
4145
+ return value.substring(0, width - 1) + "…";
4146
+ };
3687
4147
 
3688
4148
  // src/pipeline/pipeline.ts
3689
4149
  function calculateLayout(spec, options) {
@@ -3796,6 +4256,23 @@ function applyStatTransform(data, geom, aes) {
3796
4256
  dparams: geom.params.dparams
3797
4257
  });
3798
4258
  return qqLineStat.compute(data, aes);
4259
+ } else if (geom.stat === "bin2d") {
4260
+ const bin2dStat = stat_bin2d({
4261
+ bins: geom.params.bins,
4262
+ binsx: geom.params.binsx,
4263
+ binsy: geom.params.binsy,
4264
+ drop: geom.params.drop
4265
+ });
4266
+ return bin2dStat.compute(data, aes);
4267
+ } else if (geom.stat === "density_2d") {
4268
+ const density2dStat = stat_density_2d({
4269
+ h: geom.params.bandwidth,
4270
+ n: geom.params.n,
4271
+ nx: geom.params.nx,
4272
+ ny: geom.params.ny,
4273
+ adjust: geom.params.adjust
4274
+ });
4275
+ return density2dStat.compute(data, aes);
3799
4276
  }
3800
4277
  return data;
3801
4278
  }
@@ -3860,6 +4337,14 @@ function renderToCanvas(spec, options) {
3860
4337
  scaleAes = { ...spec.aes, x: "x", y: "y" };
3861
4338
  }
3862
4339
  break;
4340
+ } else if (geom.stat === "bin2d") {
4341
+ scaleData = applyStatTransform(spec.data, geom, spec.aes);
4342
+ scaleAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
4343
+ break;
4344
+ } else if (geom.stat === "density_2d") {
4345
+ scaleData = applyStatTransform(spec.data, geom, spec.aes);
4346
+ scaleAes = { ...spec.aes, x: "x", y: "y" };
4347
+ break;
3863
4348
  }
3864
4349
  }
3865
4350
  scaleData = applyCoordTransform(scaleData, scaleAes, spec.coord);
@@ -3894,6 +4379,10 @@ function renderToCanvas(spec, options) {
3894
4379
  geomAes = { ...spec.aes, x: "x", y: "y" };
3895
4380
  } else if (geom.stat === "qq_line") {
3896
4381
  geomAes = { ...spec.aes, x: "x", y: "y", xend: "xend", yend: "yend" };
4382
+ } else if (geom.stat === "bin2d") {
4383
+ geomAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
4384
+ } else if (geom.stat === "density_2d") {
4385
+ geomAes = { ...spec.aes, x: "x", y: "y" };
3897
4386
  }
3898
4387
  geomData = applyCoordTransform(geomData, geomAes, spec.coord);
3899
4388
  }
@@ -4144,8 +4633,14 @@ function renderPanel(canvas, panel, layout, spec, facet, sharedScales, nrow = 1,
4144
4633
  renderPanelAxes(canvas, scales, plotArea, panel.row, panel.col, nrow, ncol, spec.theme);
4145
4634
  for (const geom of spec.geoms) {
4146
4635
  let geomData = applyStatTransform(panel.data, geom, spec.aes);
4147
- geomData = applyCoordTransform(geomData, spec.aes, spec.coord);
4148
- renderGeom(geomData, geom, spec.aes, scales, canvas, spec.coord.type);
4636
+ let geomAes = spec.aes;
4637
+ if (geom.stat === "bin" || geom.stat === "boxplot" || geom.stat === "count" || geom.stat === "qq") {
4638
+ geomAes = { ...spec.aes, x: "x", y: "y" };
4639
+ } else if (geom.stat === "bin2d") {
4640
+ geomAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
4641
+ }
4642
+ geomData = applyCoordTransform(geomData, geomAes, spec.coord);
4643
+ renderGeom(geomData, geom, geomAes, scales, canvas, spec.coord.type);
4149
4644
  }
4150
4645
  }
4151
4646
  function renderPanelAxes(canvas, scales, plotArea, row, col, nrow, _ncol, _theme) {
@@ -4193,9 +4688,22 @@ function renderToString(spec, options) {
4193
4688
  }
4194
4689
  return canvas.toAnsiString();
4195
4690
  }
4691
+ var init_pipeline = __esm(() => {
4692
+ init_canvas();
4693
+ init_scales();
4694
+ init_render_geoms();
4695
+ init_render_axes();
4696
+ init_bin2d();
4697
+ init_summary();
4698
+ });
4196
4699
 
4197
4700
  // src/pipeline/index.ts
4198
- init_scales();
4701
+ var init_pipeline2 = __esm(() => {
4702
+ init_pipeline();
4703
+ init_scales();
4704
+ init_render_geoms();
4705
+ init_render_axes();
4706
+ });
4199
4707
 
4200
4708
  // src/grammar.ts
4201
4709
  class GGPlot {
@@ -4286,6 +4794,15 @@ class GGPlot {
4286
4794
  function gg(data = []) {
4287
4795
  return new GGPlot(data);
4288
4796
  }
4797
+ var init_grammar = __esm(() => {
4798
+ init_pipeline2();
4799
+ });
4800
+
4801
+ // src/canvas/index.ts
4802
+ var init_canvas2 = __esm(() => {
4803
+ init_canvas();
4804
+ });
4805
+
4289
4806
  // src/geoms/point.ts
4290
4807
  function geom_point(options = {}) {
4291
4808
  return {
@@ -4300,6 +4817,7 @@ function geom_point(options = {}) {
4300
4817
  }
4301
4818
  };
4302
4819
  }
4820
+
4303
4821
  // src/geoms/line.ts
4304
4822
  function geom_line(options = {}) {
4305
4823
  return {
@@ -4338,6 +4856,7 @@ function geom_vline(options) {
4338
4856
  }
4339
4857
  };
4340
4858
  }
4859
+
4341
4860
  // src/geoms/path.ts
4342
4861
  function geom_path(options = {}) {
4343
4862
  return {
@@ -4354,6 +4873,7 @@ function geom_path(options = {}) {
4354
4873
  }
4355
4874
  };
4356
4875
  }
4876
+
4357
4877
  // src/geoms/bar.ts
4358
4878
  function geom_bar(options = {}) {
4359
4879
  return {
@@ -4371,6 +4891,7 @@ function geom_bar(options = {}) {
4371
4891
  function geom_col(options = {}) {
4372
4892
  return geom_bar({ ...options, stat: "identity" });
4373
4893
  }
4894
+
4374
4895
  // src/geoms/text.ts
4375
4896
  function geom_text(options = {}) {
4376
4897
  return {
@@ -4403,6 +4924,7 @@ function geom_label(options = {}) {
4403
4924
  }
4404
4925
  };
4405
4926
  }
4927
+
4406
4928
  // src/geoms/area.ts
4407
4929
  function geom_area(options = {}) {
4408
4930
  return {
@@ -4428,6 +4950,7 @@ function geom_ribbon(options = {}) {
4428
4950
  }
4429
4951
  };
4430
4952
  }
4953
+
4431
4954
  // src/geoms/histogram.ts
4432
4955
  function geom_histogram(options = {}) {
4433
4956
  return {
@@ -4459,6 +4982,7 @@ function geom_freqpoly(options = {}) {
4459
4982
  }
4460
4983
  };
4461
4984
  }
4985
+
4462
4986
  // src/geoms/boxplot.ts
4463
4987
  function geom_boxplot(options = {}) {
4464
4988
  return {
@@ -4475,6 +4999,7 @@ function geom_boxplot(options = {}) {
4475
4999
  }
4476
5000
  };
4477
5001
  }
5002
+
4478
5003
  // src/geoms/segment.ts
4479
5004
  function geom_segment(options = {}) {
4480
5005
  return {
@@ -4507,6 +5032,7 @@ function geom_curve(options = {}) {
4507
5032
  }
4508
5033
  };
4509
5034
  }
5035
+
4510
5036
  // src/geoms/smooth.ts
4511
5037
  function geom_smooth(options = {}) {
4512
5038
  return {
@@ -4526,6 +5052,7 @@ function geom_smooth(options = {}) {
4526
5052
  }
4527
5053
  };
4528
5054
  }
5055
+
4529
5056
  // src/geoms/step.ts
4530
5057
  function geom_step(options = {}) {
4531
5058
  return {
@@ -4541,6 +5068,7 @@ function geom_step(options = {}) {
4541
5068
  }
4542
5069
  };
4543
5070
  }
5071
+
4544
5072
  // src/geoms/rug.ts
4545
5073
  function geom_rug(options = {}) {
4546
5074
  return {
@@ -4556,6 +5084,7 @@ function geom_rug(options = {}) {
4556
5084
  }
4557
5085
  };
4558
5086
  }
5087
+
4559
5088
  // src/geoms/violin.ts
4560
5089
  function geom_violin(options = {}) {
4561
5090
  return {
@@ -4573,6 +5102,7 @@ function geom_violin(options = {}) {
4573
5102
  }
4574
5103
  };
4575
5104
  }
5105
+
4576
5106
  // src/geoms/tile.ts
4577
5107
  function geom_tile(options = {}) {
4578
5108
  return {
@@ -4591,6 +5121,22 @@ function geom_tile(options = {}) {
4591
5121
  function geom_raster(options = {}) {
4592
5122
  return geom_tile(options);
4593
5123
  }
5124
+
5125
+ // src/geoms/bin2d.ts
5126
+ function geom_bin2d(options = {}) {
5127
+ return {
5128
+ type: "bin2d",
5129
+ stat: "bin2d",
5130
+ params: {
5131
+ bins: options.bins ?? 30,
5132
+ binsx: options.binsx,
5133
+ binsy: options.binsy,
5134
+ alpha: options.alpha ?? 1,
5135
+ drop: options.drop ?? true
5136
+ }
5137
+ };
5138
+ }
5139
+
4594
5140
  // src/geoms/contour.ts
4595
5141
  function geom_contour(options = {}) {
4596
5142
  return {
@@ -4633,6 +5179,7 @@ function geom_density_2d(options = {}) {
4633
5179
  }
4634
5180
  };
4635
5181
  }
5182
+
4636
5183
  // src/geoms/errorbar.ts
4637
5184
  function geom_errorbar(options = {}) {
4638
5185
  return {
@@ -4699,6 +5246,7 @@ function geom_pointrange(options = {}) {
4699
5246
  }
4700
5247
  };
4701
5248
  }
5249
+
4702
5250
  // src/geoms/rect.ts
4703
5251
  function geom_rect(options = {}) {
4704
5252
  return {
@@ -4727,6 +5275,7 @@ function geom_abline(options = {}) {
4727
5275
  }
4728
5276
  };
4729
5277
  }
5278
+
4730
5279
  // src/geoms/qq.ts
4731
5280
  function geom_qq(options = {}) {
4732
5281
  return {
@@ -4755,6 +5304,16 @@ function geom_qq_line(options = {}) {
4755
5304
  }
4756
5305
  };
4757
5306
  }
5307
+
5308
+ // src/geoms/index.ts
5309
+ var init_geoms = () => {};
5310
+
5311
+ // src/stats/index.ts
5312
+ var init_stats = __esm(() => {
5313
+ init_bin2d();
5314
+ init_summary();
5315
+ });
5316
+
4758
5317
  // src/scales/continuous.ts
4759
5318
  function createContinuousScale(aesthetic, options = {}) {
4760
5319
  const trans = options.trans ?? "identity";
@@ -4833,6 +5392,7 @@ function scale_y2_sqrt(options = {}) {
4833
5392
  function scale_y2_reverse(options = {}) {
4834
5393
  return createContinuousScale("y2", { ...options, trans: "reverse" });
4835
5394
  }
5395
+
4836
5396
  // src/scales/discrete.ts
4837
5397
  function createDiscreteScale(aesthetic, options = {}) {
4838
5398
  const valueToPosition = new Map;
@@ -4882,123 +5442,8 @@ function scale_x_discrete(options = {}) {
4882
5442
  function scale_y_discrete(options = {}) {
4883
5443
  return createDiscreteScale("y", options);
4884
5444
  }
5445
+
4885
5446
  // src/scales/color.ts
4886
- var PALETTES = {
4887
- viridis: ["#440154", "#414487", "#2a788e", "#22a884", "#7ad151", "#fde725"],
4888
- plasma: ["#0d0887", "#6a00a8", "#b12a90", "#e16462", "#fca636", "#f0f921"],
4889
- inferno: ["#000004", "#420a68", "#932667", "#dd513a", "#fca50a", "#fcffa4"],
4890
- magma: ["#000004", "#3b0f70", "#8c2981", "#de4968", "#fe9f6d", "#fcfdbf"],
4891
- cividis: ["#002051", "#1d3f6e", "#52596a", "#7b7b78", "#a89f68", "#d9c84a", "#fdea45"],
4892
- turbo: ["#30123b", "#4662d7", "#35aaf8", "#1ae4b6", "#72fe5e", "#c8ef34", "#faba39", "#f66b19", "#ca2a04"],
4893
- Blues: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"],
4894
- Greens: ["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"],
4895
- Greys: ["#ffffff", "#f0f0f0", "#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252", "#252525", "#000000"],
4896
- Oranges: ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"],
4897
- Purples: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"],
4898
- Reds: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"],
4899
- BuGn: ["#f7fcfd", "#e5f5f9", "#ccece6", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#006d2c", "#00441b"],
4900
- BuPu: ["#f7fcfd", "#e0ecf4", "#bfd3e6", "#9ebcda", "#8c96c6", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"],
4901
- GnBu: ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"],
4902
- OrRd: ["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"],
4903
- PuBu: ["#fff7fb", "#ece7f2", "#d0d1e6", "#a6bddb", "#74a9cf", "#3690c0", "#0570b0", "#045a8d", "#023858"],
4904
- PuBuGn: ["#fff7fb", "#ece2f0", "#d0d1e6", "#a6bddb", "#67a9cf", "#3690c0", "#02818a", "#016c59", "#014636"],
4905
- PuRd: ["#f7f4f9", "#e7e1ef", "#d4b9da", "#c994c7", "#df65b0", "#e7298a", "#ce1256", "#980043", "#67001f"],
4906
- RdPu: ["#fff7f3", "#fde0dd", "#fcc5c0", "#fa9fb5", "#f768a1", "#dd3497", "#ae017e", "#7a0177", "#49006a"],
4907
- YlGn: ["#ffffe5", "#f7fcb9", "#d9f0a3", "#addd8e", "#78c679", "#41ab5d", "#238b45", "#006837", "#004529"],
4908
- YlGnBu: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"],
4909
- YlOrBr: ["#ffffe5", "#fff7bc", "#fee391", "#fec44f", "#fe9929", "#ec7014", "#cc4c02", "#993404", "#662506"],
4910
- YlOrRd: ["#ffffcc", "#ffeda0", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026"],
4911
- BrBG: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e", "#003c30"],
4912
- PiYG: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#4d9221", "#276419"],
4913
- PRGn: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837", "#00441b"],
4914
- PuOr: ["#7f3b08", "#b35806", "#e08214", "#fdb863", "#fee0b6", "#f7f7f7", "#d8daeb", "#b2abd2", "#8073ac", "#542788", "#2d004b"],
4915
- RdBu: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#f7f7f7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"],
4916
- RdGy: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#ffffff", "#e0e0e0", "#bababa", "#878787", "#4d4d4d", "#1a1a1a"],
4917
- RdYlBu: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee090", "#ffffbf", "#e0f3f8", "#abd9e9", "#74add1", "#4575b4", "#313695"],
4918
- RdYlGn: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"],
4919
- Spectral: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"],
4920
- category10: [
4921
- "#1f77b4",
4922
- "#ff7f0e",
4923
- "#2ca02c",
4924
- "#d62728",
4925
- "#9467bd",
4926
- "#8c564b",
4927
- "#e377c2",
4928
- "#7f7f7f",
4929
- "#bcbd22",
4930
- "#17becf"
4931
- ],
4932
- category20: [
4933
- "#1f77b4",
4934
- "#aec7e8",
4935
- "#ff7f0e",
4936
- "#ffbb78",
4937
- "#2ca02c",
4938
- "#98df8a",
4939
- "#d62728",
4940
- "#ff9896",
4941
- "#9467bd",
4942
- "#c5b0d5",
4943
- "#8c564b",
4944
- "#c49c94",
4945
- "#e377c2",
4946
- "#f7b6d2",
4947
- "#7f7f7f",
4948
- "#c7c7c7",
4949
- "#bcbd22",
4950
- "#dbdb8d",
4951
- "#17becf",
4952
- "#9edae5"
4953
- ],
4954
- Accent: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"],
4955
- Dark2: ["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"],
4956
- Paired: ["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6", "#6a3d9a", "#ffff99", "#b15928"],
4957
- Pastel1: ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec", "#f2f2f2"],
4958
- Pastel2: ["#b3e2cd", "#fdcdac", "#cbd5e8", "#f4cae4", "#e6f5c9", "#fff2ae", "#f1e2cc", "#cccccc"],
4959
- Set1: ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf", "#999999"],
4960
- Set2: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"],
4961
- Set3: ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"],
4962
- Tab10: [
4963
- "#4e79a7",
4964
- "#f28e2c",
4965
- "#e15759",
4966
- "#76b7b2",
4967
- "#59a14f",
4968
- "#edc949",
4969
- "#af7aa1",
4970
- "#ff9da7",
4971
- "#9c755f",
4972
- "#bab0ab"
4973
- ],
4974
- Tab20: [
4975
- "#4e79a7",
4976
- "#a0cbe8",
4977
- "#f28e2c",
4978
- "#ffbe7d",
4979
- "#59a14f",
4980
- "#8cd17d",
4981
- "#b6992d",
4982
- "#f1ce63",
4983
- "#499894",
4984
- "#86bcb6",
4985
- "#e15759",
4986
- "#ff9d9a",
4987
- "#79706e",
4988
- "#bab0ac",
4989
- "#d37295",
4990
- "#fabfd2",
4991
- "#b07aa1",
4992
- "#d4a6c8",
4993
- "#9d7660",
4994
- "#d7b5a6"
4995
- ],
4996
- thermal: ["#042333", "#2c3e50", "#0b5345", "#1e8449", "#f39c12", "#e74c3c", "#fadbd8"],
4997
- haline: ["#2c3e50", "#1a5276", "#2980b9", "#5dade2", "#aed6f1", "#d5f5e3"],
4998
- terrain: ["#333399", "#0099ff", "#00cc00", "#ffff00", "#ff9900", "#cc6600", "#996633", "#ffffff"],
4999
- rainbow: ["#ff0000", "#ff8000", "#ffff00", "#80ff00", "#00ff00", "#00ff80", "#00ffff", "#0080ff", "#0000ff", "#8000ff"],
5000
- cubehelix: ["#000000", "#1a1530", "#30304d", "#4d5366", "#6d826e", "#8ab17d", "#add38a", "#dae8a2", "#ffffff"]
5001
- };
5002
5447
  function hexToRgba(hex) {
5003
5448
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
5004
5449
  if (!result)
@@ -5219,6 +5664,126 @@ function getAvailablePalettes() {
5219
5664
  function getPaletteColors(name) {
5220
5665
  return PALETTES[name];
5221
5666
  }
5667
+ var PALETTES;
5668
+ var init_color = __esm(() => {
5669
+ PALETTES = {
5670
+ viridis: ["#440154", "#414487", "#2a788e", "#22a884", "#7ad151", "#fde725"],
5671
+ plasma: ["#0d0887", "#6a00a8", "#b12a90", "#e16462", "#fca636", "#f0f921"],
5672
+ inferno: ["#000004", "#420a68", "#932667", "#dd513a", "#fca50a", "#fcffa4"],
5673
+ magma: ["#000004", "#3b0f70", "#8c2981", "#de4968", "#fe9f6d", "#fcfdbf"],
5674
+ cividis: ["#002051", "#1d3f6e", "#52596a", "#7b7b78", "#a89f68", "#d9c84a", "#fdea45"],
5675
+ turbo: ["#30123b", "#4662d7", "#35aaf8", "#1ae4b6", "#72fe5e", "#c8ef34", "#faba39", "#f66b19", "#ca2a04"],
5676
+ Blues: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"],
5677
+ Greens: ["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"],
5678
+ Greys: ["#ffffff", "#f0f0f0", "#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252", "#252525", "#000000"],
5679
+ Oranges: ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"],
5680
+ Purples: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"],
5681
+ Reds: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"],
5682
+ BuGn: ["#f7fcfd", "#e5f5f9", "#ccece6", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#006d2c", "#00441b"],
5683
+ BuPu: ["#f7fcfd", "#e0ecf4", "#bfd3e6", "#9ebcda", "#8c96c6", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"],
5684
+ GnBu: ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"],
5685
+ OrRd: ["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"],
5686
+ PuBu: ["#fff7fb", "#ece7f2", "#d0d1e6", "#a6bddb", "#74a9cf", "#3690c0", "#0570b0", "#045a8d", "#023858"],
5687
+ PuBuGn: ["#fff7fb", "#ece2f0", "#d0d1e6", "#a6bddb", "#67a9cf", "#3690c0", "#02818a", "#016c59", "#014636"],
5688
+ PuRd: ["#f7f4f9", "#e7e1ef", "#d4b9da", "#c994c7", "#df65b0", "#e7298a", "#ce1256", "#980043", "#67001f"],
5689
+ RdPu: ["#fff7f3", "#fde0dd", "#fcc5c0", "#fa9fb5", "#f768a1", "#dd3497", "#ae017e", "#7a0177", "#49006a"],
5690
+ YlGn: ["#ffffe5", "#f7fcb9", "#d9f0a3", "#addd8e", "#78c679", "#41ab5d", "#238b45", "#006837", "#004529"],
5691
+ YlGnBu: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"],
5692
+ YlOrBr: ["#ffffe5", "#fff7bc", "#fee391", "#fec44f", "#fe9929", "#ec7014", "#cc4c02", "#993404", "#662506"],
5693
+ YlOrRd: ["#ffffcc", "#ffeda0", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026"],
5694
+ BrBG: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e", "#003c30"],
5695
+ PiYG: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#4d9221", "#276419"],
5696
+ PRGn: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837", "#00441b"],
5697
+ PuOr: ["#7f3b08", "#b35806", "#e08214", "#fdb863", "#fee0b6", "#f7f7f7", "#d8daeb", "#b2abd2", "#8073ac", "#542788", "#2d004b"],
5698
+ RdBu: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#f7f7f7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"],
5699
+ RdGy: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#ffffff", "#e0e0e0", "#bababa", "#878787", "#4d4d4d", "#1a1a1a"],
5700
+ RdYlBu: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee090", "#ffffbf", "#e0f3f8", "#abd9e9", "#74add1", "#4575b4", "#313695"],
5701
+ RdYlGn: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"],
5702
+ Spectral: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"],
5703
+ category10: [
5704
+ "#1f77b4",
5705
+ "#ff7f0e",
5706
+ "#2ca02c",
5707
+ "#d62728",
5708
+ "#9467bd",
5709
+ "#8c564b",
5710
+ "#e377c2",
5711
+ "#7f7f7f",
5712
+ "#bcbd22",
5713
+ "#17becf"
5714
+ ],
5715
+ category20: [
5716
+ "#1f77b4",
5717
+ "#aec7e8",
5718
+ "#ff7f0e",
5719
+ "#ffbb78",
5720
+ "#2ca02c",
5721
+ "#98df8a",
5722
+ "#d62728",
5723
+ "#ff9896",
5724
+ "#9467bd",
5725
+ "#c5b0d5",
5726
+ "#8c564b",
5727
+ "#c49c94",
5728
+ "#e377c2",
5729
+ "#f7b6d2",
5730
+ "#7f7f7f",
5731
+ "#c7c7c7",
5732
+ "#bcbd22",
5733
+ "#dbdb8d",
5734
+ "#17becf",
5735
+ "#9edae5"
5736
+ ],
5737
+ Accent: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"],
5738
+ Dark2: ["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"],
5739
+ Paired: ["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6", "#6a3d9a", "#ffff99", "#b15928"],
5740
+ Pastel1: ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec", "#f2f2f2"],
5741
+ Pastel2: ["#b3e2cd", "#fdcdac", "#cbd5e8", "#f4cae4", "#e6f5c9", "#fff2ae", "#f1e2cc", "#cccccc"],
5742
+ Set1: ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf", "#999999"],
5743
+ Set2: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"],
5744
+ Set3: ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"],
5745
+ Tab10: [
5746
+ "#4e79a7",
5747
+ "#f28e2c",
5748
+ "#e15759",
5749
+ "#76b7b2",
5750
+ "#59a14f",
5751
+ "#edc949",
5752
+ "#af7aa1",
5753
+ "#ff9da7",
5754
+ "#9c755f",
5755
+ "#bab0ab"
5756
+ ],
5757
+ Tab20: [
5758
+ "#4e79a7",
5759
+ "#a0cbe8",
5760
+ "#f28e2c",
5761
+ "#ffbe7d",
5762
+ "#59a14f",
5763
+ "#8cd17d",
5764
+ "#b6992d",
5765
+ "#f1ce63",
5766
+ "#499894",
5767
+ "#86bcb6",
5768
+ "#e15759",
5769
+ "#ff9d9a",
5770
+ "#79706e",
5771
+ "#bab0ac",
5772
+ "#d37295",
5773
+ "#fabfd2",
5774
+ "#b07aa1",
5775
+ "#d4a6c8",
5776
+ "#9d7660",
5777
+ "#d7b5a6"
5778
+ ],
5779
+ thermal: ["#042333", "#2c3e50", "#0b5345", "#1e8449", "#f39c12", "#e74c3c", "#fadbd8"],
5780
+ haline: ["#2c3e50", "#1a5276", "#2980b9", "#5dade2", "#aed6f1", "#d5f5e3"],
5781
+ terrain: ["#333399", "#0099ff", "#00cc00", "#ffff00", "#ff9900", "#cc6600", "#996633", "#ffffff"],
5782
+ rainbow: ["#ff0000", "#ff8000", "#ffff00", "#80ff00", "#00ff00", "#00ff80", "#00ffff", "#0080ff", "#0000ff", "#8000ff"],
5783
+ cubehelix: ["#000000", "#1a1530", "#30304d", "#4d5366", "#6d826e", "#8ab17d", "#add38a", "#dae8a2", "#ffffff"]
5784
+ };
5785
+ });
5786
+
5222
5787
  // src/scales/size.ts
5223
5788
  function scale_size_continuous(options = {}) {
5224
5789
  const range = options.range ?? [1, 6];
@@ -5287,45 +5852,8 @@ function scale_size_binned(options = {}) {
5287
5852
  }
5288
5853
  };
5289
5854
  }
5855
+
5290
5856
  // src/scales/shape.ts
5291
- var DEFAULT_SHAPES = [
5292
- "circle",
5293
- "square",
5294
- "triangle",
5295
- "diamond",
5296
- "cross",
5297
- "plus",
5298
- "star",
5299
- "open_circle",
5300
- "open_square",
5301
- "open_triangle",
5302
- "open_diamond",
5303
- "dot"
5304
- ];
5305
- var SHAPE_CHARS = {
5306
- circle: "●",
5307
- filled_circle: "●",
5308
- open_circle: "○",
5309
- square: "■",
5310
- filled_square: "■",
5311
- open_square: "□",
5312
- triangle: "▲",
5313
- filled_triangle: "▲",
5314
- open_triangle: "△",
5315
- triangle_down: "▼",
5316
- diamond: "◆",
5317
- filled_diamond: "◆",
5318
- open_diamond: "◇",
5319
- cross: "✕",
5320
- plus: "+",
5321
- star: "★",
5322
- open_star: "☆",
5323
- dot: "•",
5324
- bullet: "•",
5325
- asterisk: "*",
5326
- hash: "#",
5327
- at: "@"
5328
- };
5329
5857
  function scale_shape_discrete(options = {}) {
5330
5858
  const shapes = options.values ?? DEFAULT_SHAPES;
5331
5859
  return {
@@ -5384,6 +5912,48 @@ function scale_shape_ordinal(options = {}) {
5384
5912
  }
5385
5913
  };
5386
5914
  }
5915
+ var DEFAULT_SHAPES, SHAPE_CHARS;
5916
+ var init_shape = __esm(() => {
5917
+ DEFAULT_SHAPES = [
5918
+ "circle",
5919
+ "square",
5920
+ "triangle",
5921
+ "diamond",
5922
+ "cross",
5923
+ "plus",
5924
+ "star",
5925
+ "open_circle",
5926
+ "open_square",
5927
+ "open_triangle",
5928
+ "open_diamond",
5929
+ "dot"
5930
+ ];
5931
+ SHAPE_CHARS = {
5932
+ circle: "●",
5933
+ filled_circle: "●",
5934
+ open_circle: "○",
5935
+ square: "■",
5936
+ filled_square: "■",
5937
+ open_square: "□",
5938
+ triangle: "▲",
5939
+ filled_triangle: "▲",
5940
+ open_triangle: "△",
5941
+ triangle_down: "▼",
5942
+ diamond: "◆",
5943
+ filled_diamond: "◆",
5944
+ open_diamond: "◇",
5945
+ cross: "✕",
5946
+ plus: "+",
5947
+ star: "★",
5948
+ open_star: "☆",
5949
+ dot: "•",
5950
+ bullet: "•",
5951
+ asterisk: "*",
5952
+ hash: "#",
5953
+ at: "@"
5954
+ };
5955
+ });
5956
+
5387
5957
  // src/scales/alpha.ts
5388
5958
  function scale_alpha_continuous(options = {}) {
5389
5959
  const range = options.range ?? [0.1, 1];
@@ -5480,17 +6050,8 @@ function scale_alpha_binned(options = {}) {
5480
6050
  }
5481
6051
  };
5482
6052
  }
6053
+
5483
6054
  // src/scales/datetime.ts
5484
- var TIME_INTERVALS = [
5485
- { name: "millisecond", ms: 1 },
5486
- { name: "second", ms: 1000 },
5487
- { name: "minute", ms: 60 * 1000 },
5488
- { name: "hour", ms: 60 * 60 * 1000 },
5489
- { name: "day", ms: 24 * 60 * 60 * 1000 },
5490
- { name: "week", ms: 7 * 24 * 60 * 60 * 1000 },
5491
- { name: "month", ms: 30 * 24 * 60 * 60 * 1000 },
5492
- { name: "year", ms: 365 * 24 * 60 * 60 * 1000 }
5493
- ];
5494
6055
  function parseDateTime(value) {
5495
6056
  if (value === null || value === undefined)
5496
6057
  return null;
@@ -5672,6 +6233,27 @@ function scale_y_duration(options = {}) {
5672
6233
  scale.aesthetic = "y";
5673
6234
  return scale;
5674
6235
  }
6236
+ var TIME_INTERVALS;
6237
+ var init_datetime = __esm(() => {
6238
+ TIME_INTERVALS = [
6239
+ { name: "millisecond", ms: 1 },
6240
+ { name: "second", ms: 1000 },
6241
+ { name: "minute", ms: 60 * 1000 },
6242
+ { name: "hour", ms: 60 * 60 * 1000 },
6243
+ { name: "day", ms: 24 * 60 * 60 * 1000 },
6244
+ { name: "week", ms: 7 * 24 * 60 * 60 * 1000 },
6245
+ { name: "month", ms: 30 * 24 * 60 * 60 * 1000 },
6246
+ { name: "year", ms: 365 * 24 * 60 * 60 * 1000 }
6247
+ ];
6248
+ });
6249
+
6250
+ // src/scales/index.ts
6251
+ var init_scales2 = __esm(() => {
6252
+ init_color();
6253
+ init_shape();
6254
+ init_datetime();
6255
+ });
6256
+
5675
6257
  // src/annotations.ts
5676
6258
  function annotate(geomType, options = {}) {
5677
6259
  const parseColor2 = (c) => {
@@ -5825,6 +6407,7 @@ function annotate_hline(yintercept, options = {}) {
5825
6407
  function annotate_vline(xintercept, options = {}) {
5826
6408
  return annotate("vline", { ...options, x: xintercept });
5827
6409
  }
6410
+
5828
6411
  // src/terminal/capabilities.ts
5829
6412
  function detectColorCapability() {
5830
6413
  const colorTerm = process.env.COLORTERM ?? "";
@@ -5937,7 +6520,6 @@ function getRecommendedRenderer(caps) {
5937
6520
  return "block";
5938
6521
  return "ascii";
5939
6522
  }
5940
- var cachedCapabilities = null;
5941
6523
  function getCapabilities() {
5942
6524
  if (!cachedCapabilities) {
5943
6525
  cachedCapabilities = detectCapabilities();
@@ -5947,25 +6529,9 @@ function getCapabilities() {
5947
6529
  function clearCapabilityCache() {
5948
6530
  cachedCapabilities = null;
5949
6531
  }
6532
+ var cachedCapabilities = null;
6533
+
5950
6534
  // src/terminal/colors.ts
5951
- var ANSI_16_COLORS = [
5952
- { r: 0, g: 0, b: 0, a: 255 },
5953
- { r: 128, g: 0, b: 0, a: 255 },
5954
- { r: 0, g: 128, b: 0, a: 255 },
5955
- { r: 128, g: 128, b: 0, a: 255 },
5956
- { r: 0, g: 0, b: 128, a: 255 },
5957
- { r: 128, g: 0, b: 128, a: 255 },
5958
- { r: 0, g: 128, b: 128, a: 255 },
5959
- { r: 192, g: 192, b: 192, a: 255 },
5960
- { r: 128, g: 128, b: 128, a: 255 },
5961
- { r: 255, g: 0, b: 0, a: 255 },
5962
- { r: 0, g: 255, b: 0, a: 255 },
5963
- { r: 255, g: 255, b: 0, a: 255 },
5964
- { r: 0, g: 0, b: 255, a: 255 },
5965
- { r: 255, g: 0, b: 255, a: 255 },
5966
- { r: 0, g: 255, b: 255, a: 255 },
5967
- { r: 255, g: 255, b: 255, a: 255 }
5968
- ];
5969
6535
  function generate256Palette() {
5970
6536
  const palette = [];
5971
6537
  palette.push(...ANSI_16_COLORS);
@@ -5988,7 +6554,6 @@ function generate256Palette() {
5988
6554
  }
5989
6555
  return palette;
5990
6556
  }
5991
- var _palette256 = null;
5992
6557
  function getPalette256() {
5993
6558
  if (!_palette256) {
5994
6559
  _palette256 = generate256Palette();
@@ -6225,28 +6790,29 @@ function getColorEscape(color, mode, type) {
6225
6790
  }
6226
6791
  return bgEscape(color, mode);
6227
6792
  }
6228
- var RESET = "\x1B[0m";
6229
- var RESET_FG = "\x1B[39m";
6230
- var RESET_BG = "\x1B[49m";
6793
+ var ANSI_16_COLORS, _palette256 = null, RESET = "\x1B[0m", RESET_FG = "\x1B[39m", RESET_BG = "\x1B[49m";
6794
+ var init_colors = __esm(() => {
6795
+ ANSI_16_COLORS = [
6796
+ { r: 0, g: 0, b: 0, a: 255 },
6797
+ { r: 128, g: 0, b: 0, a: 255 },
6798
+ { r: 0, g: 128, b: 0, a: 255 },
6799
+ { r: 128, g: 128, b: 0, a: 255 },
6800
+ { r: 0, g: 0, b: 128, a: 255 },
6801
+ { r: 128, g: 0, b: 128, a: 255 },
6802
+ { r: 0, g: 128, b: 128, a: 255 },
6803
+ { r: 192, g: 192, b: 192, a: 255 },
6804
+ { r: 128, g: 128, b: 128, a: 255 },
6805
+ { r: 255, g: 0, b: 0, a: 255 },
6806
+ { r: 0, g: 255, b: 0, a: 255 },
6807
+ { r: 255, g: 255, b: 0, a: 255 },
6808
+ { r: 0, g: 0, b: 255, a: 255 },
6809
+ { r: 255, g: 0, b: 255, a: 255 },
6810
+ { r: 0, g: 255, b: 255, a: 255 },
6811
+ { r: 255, g: 255, b: 255, a: 255 }
6812
+ ];
6813
+ });
6814
+
6231
6815
  // src/terminal/renderer-chain.ts
6232
- var RENDERER_REQUIREMENTS = {
6233
- kitty: { graphics: "kitty" },
6234
- iterm2: { graphics: "iterm2" },
6235
- sixel: { graphics: "sixel" },
6236
- braille: { unicode: true, braille: true },
6237
- "block-subpixel": { unicode: true },
6238
- block: { unicode: true },
6239
- ascii: {}
6240
- };
6241
- var FALLBACK_ORDER = [
6242
- "kitty",
6243
- "iterm2",
6244
- "sixel",
6245
- "braille",
6246
- "block-subpixel",
6247
- "block",
6248
- "ascii"
6249
- ];
6250
6816
  function isRendererAvailable(type, caps) {
6251
6817
  const reqs = RENDERER_REQUIREMENTS[type];
6252
6818
  if (reqs.graphics) {
@@ -6395,194 +6961,226 @@ function getTerminalInfo() {
6395
6961
  isTTY: caps.isTTY
6396
6962
  };
6397
6963
  }
6964
+ var RENDERER_REQUIREMENTS, FALLBACK_ORDER;
6965
+ var init_renderer_chain = __esm(() => {
6966
+ init_colors();
6967
+ RENDERER_REQUIREMENTS = {
6968
+ kitty: { graphics: "kitty" },
6969
+ iterm2: { graphics: "iterm2" },
6970
+ sixel: { graphics: "sixel" },
6971
+ braille: { unicode: true, braille: true },
6972
+ "block-subpixel": { unicode: true },
6973
+ block: { unicode: true },
6974
+ ascii: {}
6975
+ };
6976
+ FALLBACK_ORDER = [
6977
+ "kitty",
6978
+ "iterm2",
6979
+ "sixel",
6980
+ "braille",
6981
+ "block-subpixel",
6982
+ "block",
6983
+ "ascii"
6984
+ ];
6985
+ });
6986
+
6987
+ // src/terminal/index.ts
6988
+ var init_terminal = __esm(() => {
6989
+ init_colors();
6990
+ init_renderer_chain();
6991
+ });
6992
+
6398
6993
  // src/streaming/data-buffer.ts
6399
- class DataBuffer {
6400
- buffer;
6401
- head = 0;
6402
- tail = 0;
6403
- _size = 0;
6404
- options;
6405
- lastCleanup = 0;
6406
- cleanupInterval = 1000;
6407
- constructor(options) {
6408
- this.options = {
6409
- maxSize: options.maxSize,
6410
- overwrite: options.overwrite ?? true,
6411
- timeField: options.timeField ?? "time",
6412
- maxAge: options.maxAge ?? 0
6413
- };
6414
- this.buffer = new Array(options.maxSize);
6415
- }
6416
- push(record) {
6417
- if (this.options.maxAge > 0) {
6418
- this.cleanupOldData();
6994
+ function createDataBuffer(options) {
6995
+ return new DataBuffer(options);
6996
+ }
6997
+ var DataBuffer;
6998
+ var init_data_buffer = __esm(() => {
6999
+ DataBuffer = class DataBuffer {
7000
+ buffer;
7001
+ head = 0;
7002
+ tail = 0;
7003
+ _size = 0;
7004
+ options;
7005
+ lastCleanup = 0;
7006
+ cleanupInterval = 1000;
7007
+ constructor(options) {
7008
+ this.options = {
7009
+ maxSize: options.maxSize,
7010
+ overwrite: options.overwrite ?? true,
7011
+ timeField: options.timeField ?? "time",
7012
+ maxAge: options.maxAge ?? 0
7013
+ };
7014
+ this.buffer = new Array(options.maxSize);
6419
7015
  }
6420
- if (this._size === this.options.maxSize) {
6421
- if (!this.options.overwrite) {
6422
- return false;
7016
+ push(record) {
7017
+ if (this.options.maxAge > 0) {
7018
+ this.cleanupOldData();
6423
7019
  }
6424
- this.head = (this.head + 1) % this.options.maxSize;
6425
- } else {
6426
- this._size++;
7020
+ if (this._size === this.options.maxSize) {
7021
+ if (!this.options.overwrite) {
7022
+ return false;
7023
+ }
7024
+ this.head = (this.head + 1) % this.options.maxSize;
7025
+ } else {
7026
+ this._size++;
7027
+ }
7028
+ this.buffer[this.tail] = record;
7029
+ this.tail = (this.tail + 1) % this.options.maxSize;
7030
+ return true;
6427
7031
  }
6428
- this.buffer[this.tail] = record;
6429
- this.tail = (this.tail + 1) % this.options.maxSize;
6430
- return true;
6431
- }
6432
- pushMany(records) {
6433
- let added = 0;
6434
- for (const record of records) {
6435
- if (this.push(record)) {
6436
- added++;
7032
+ pushMany(records) {
7033
+ let added = 0;
7034
+ for (const record of records) {
7035
+ if (this.push(record)) {
7036
+ added++;
7037
+ }
7038
+ }
7039
+ return added;
7040
+ }
7041
+ shift() {
7042
+ if (this._size === 0) {
7043
+ return;
6437
7044
  }
7045
+ const record = this.buffer[this.head];
7046
+ this.head = (this.head + 1) % this.options.maxSize;
7047
+ this._size--;
7048
+ return record;
6438
7049
  }
6439
- return added;
6440
- }
6441
- shift() {
6442
- if (this._size === 0) {
6443
- return;
7050
+ get(index) {
7051
+ if (index < 0 || index >= this._size) {
7052
+ return;
7053
+ }
7054
+ const actualIndex = (this.head + index) % this.options.maxSize;
7055
+ return this.buffer[actualIndex];
6444
7056
  }
6445
- const record = this.buffer[this.head];
6446
- this.head = (this.head + 1) % this.options.maxSize;
6447
- this._size--;
6448
- return record;
6449
- }
6450
- get(index) {
6451
- if (index < 0 || index >= this._size) {
6452
- return;
7057
+ latest() {
7058
+ if (this._size === 0) {
7059
+ return;
7060
+ }
7061
+ const index = (this.tail - 1 + this.options.maxSize) % this.options.maxSize;
7062
+ return this.buffer[index];
6453
7063
  }
6454
- const actualIndex = (this.head + index) % this.options.maxSize;
6455
- return this.buffer[actualIndex];
6456
- }
6457
- latest() {
6458
- if (this._size === 0) {
6459
- return;
7064
+ oldest() {
7065
+ if (this._size === 0) {
7066
+ return;
7067
+ }
7068
+ return this.buffer[this.head];
6460
7069
  }
6461
- const index = (this.tail - 1 + this.options.maxSize) % this.options.maxSize;
6462
- return this.buffer[index];
6463
- }
6464
- oldest() {
6465
- if (this._size === 0) {
6466
- return;
7070
+ toArray() {
7071
+ const result = [];
7072
+ for (let i = 0;i < this._size; i++) {
7073
+ const index = (this.head + i) % this.options.maxSize;
7074
+ result.push(this.buffer[index]);
7075
+ }
7076
+ return result;
6467
7077
  }
6468
- return this.buffer[this.head];
6469
- }
6470
- toArray() {
6471
- const result = [];
6472
- for (let i = 0;i < this._size; i++) {
6473
- const index = (this.head + i) % this.options.maxSize;
6474
- result.push(this.buffer[index]);
7078
+ getTimeRange(startTime, endTime) {
7079
+ const timeField = this.options.timeField;
7080
+ const result = [];
7081
+ for (let i = 0;i < this._size; i++) {
7082
+ const index = (this.head + i) % this.options.maxSize;
7083
+ const record = this.buffer[index];
7084
+ const time = record[timeField];
7085
+ if (time >= startTime && time <= endTime) {
7086
+ result.push(record);
7087
+ }
7088
+ }
7089
+ return result;
6475
7090
  }
6476
- return result;
6477
- }
6478
- getTimeRange(startTime, endTime) {
6479
- const timeField = this.options.timeField;
6480
- const result = [];
6481
- for (let i = 0;i < this._size; i++) {
6482
- const index = (this.head + i) % this.options.maxSize;
6483
- const record = this.buffer[index];
6484
- const time = record[timeField];
6485
- if (time >= startTime && time <= endTime) {
6486
- result.push(record);
7091
+ getLast(n) {
7092
+ const count = Math.min(n, this._size);
7093
+ const result = [];
7094
+ for (let i = this._size - count;i < this._size; i++) {
7095
+ const index = (this.head + i) % this.options.maxSize;
7096
+ result.push(this.buffer[index]);
6487
7097
  }
7098
+ return result;
6488
7099
  }
6489
- return result;
6490
- }
6491
- getLast(n) {
6492
- const count = Math.min(n, this._size);
6493
- const result = [];
6494
- for (let i = this._size - count;i < this._size; i++) {
6495
- const index = (this.head + i) % this.options.maxSize;
6496
- result.push(this.buffer[index]);
7100
+ clear() {
7101
+ this.head = 0;
7102
+ this.tail = 0;
7103
+ this._size = 0;
6497
7104
  }
6498
- return result;
6499
- }
6500
- clear() {
6501
- this.head = 0;
6502
- this.tail = 0;
6503
- this._size = 0;
6504
- }
6505
- get size() {
6506
- return this._size;
6507
- }
6508
- get capacity() {
6509
- return this.options.maxSize;
6510
- }
6511
- get isFull() {
6512
- return this._size === this.options.maxSize;
6513
- }
6514
- get isEmpty() {
6515
- return this._size === 0;
6516
- }
6517
- getTimeExtent() {
6518
- if (this._size === 0) {
6519
- return null;
7105
+ get size() {
7106
+ return this._size;
6520
7107
  }
6521
- const timeField = this.options.timeField;
6522
- let min = Infinity;
6523
- let max = -Infinity;
6524
- for (let i = 0;i < this._size; i++) {
6525
- const index = (this.head + i) % this.options.maxSize;
6526
- const time = this.buffer[index][timeField];
6527
- if (time < min)
6528
- min = time;
6529
- if (time > max)
6530
- max = time;
7108
+ get capacity() {
7109
+ return this.options.maxSize;
6531
7110
  }
6532
- return { min, max };
6533
- }
6534
- cleanupOldData() {
6535
- const now = Date.now();
6536
- if (now - this.lastCleanup < this.cleanupInterval) {
6537
- return;
7111
+ get isFull() {
7112
+ return this._size === this.options.maxSize;
6538
7113
  }
6539
- this.lastCleanup = now;
6540
- const cutoff = now - this.options.maxAge;
6541
- const timeField = this.options.timeField;
6542
- while (this._size > 0) {
6543
- const oldest = this.buffer[this.head];
6544
- const time = oldest[timeField];
6545
- if (time >= cutoff) {
6546
- break;
7114
+ get isEmpty() {
7115
+ return this._size === 0;
7116
+ }
7117
+ getTimeExtent() {
7118
+ if (this._size === 0) {
7119
+ return null;
6547
7120
  }
6548
- this.head = (this.head + 1) % this.options.maxSize;
6549
- this._size--;
7121
+ const timeField = this.options.timeField;
7122
+ let min = Infinity;
7123
+ let max = -Infinity;
7124
+ for (let i = 0;i < this._size; i++) {
7125
+ const index = (this.head + i) % this.options.maxSize;
7126
+ const time = this.buffer[index][timeField];
7127
+ if (time < min)
7128
+ min = time;
7129
+ if (time > max)
7130
+ max = time;
7131
+ }
7132
+ return { min, max };
6550
7133
  }
6551
- }
6552
- *[Symbol.iterator]() {
6553
- for (let i = 0;i < this._size; i++) {
6554
- const index = (this.head + i) % this.options.maxSize;
6555
- yield this.buffer[index];
7134
+ cleanupOldData() {
7135
+ const now = Date.now();
7136
+ if (now - this.lastCleanup < this.cleanupInterval) {
7137
+ return;
7138
+ }
7139
+ this.lastCleanup = now;
7140
+ const cutoff = now - this.options.maxAge;
7141
+ const timeField = this.options.timeField;
7142
+ while (this._size > 0) {
7143
+ const oldest = this.buffer[this.head];
7144
+ const time = oldest[timeField];
7145
+ if (time >= cutoff) {
7146
+ break;
7147
+ }
7148
+ this.head = (this.head + 1) % this.options.maxSize;
7149
+ this._size--;
7150
+ }
6556
7151
  }
6557
- }
6558
- map(fn) {
6559
- const result = [];
6560
- let i = 0;
6561
- for (const record of this) {
6562
- result.push(fn(record, i++));
7152
+ *[Symbol.iterator]() {
7153
+ for (let i = 0;i < this._size; i++) {
7154
+ const index = (this.head + i) % this.options.maxSize;
7155
+ yield this.buffer[index];
7156
+ }
6563
7157
  }
6564
- return result;
6565
- }
6566
- filter(fn) {
6567
- const result = [];
6568
- for (const record of this) {
6569
- if (fn(record)) {
6570
- result.push(record);
7158
+ map(fn) {
7159
+ const result = [];
7160
+ let i = 0;
7161
+ for (const record of this) {
7162
+ result.push(fn(record, i++));
6571
7163
  }
7164
+ return result;
6572
7165
  }
6573
- return result;
6574
- }
6575
- reduce(fn, initial) {
6576
- let acc = initial;
6577
- for (const record of this) {
6578
- acc = fn(acc, record);
7166
+ filter(fn) {
7167
+ const result = [];
7168
+ for (const record of this) {
7169
+ if (fn(record)) {
7170
+ result.push(record);
7171
+ }
7172
+ }
7173
+ return result;
6579
7174
  }
6580
- return acc;
6581
- }
6582
- }
6583
- function createDataBuffer(options) {
6584
- return new DataBuffer(options);
6585
- }
7175
+ reduce(fn, initial) {
7176
+ let acc = initial;
7177
+ for (const record of this) {
7178
+ acc = fn(acc, record);
7179
+ }
7180
+ return acc;
7181
+ }
7182
+ };
7183
+ });
6586
7184
 
6587
7185
  // src/streaming/data-window.ts
6588
7186
  class DataWindow {
@@ -6757,6 +7355,9 @@ class DataWindow {
6757
7355
  function createDataWindow(options) {
6758
7356
  return new DataWindow(options);
6759
7357
  }
7358
+ var init_data_window = __esm(() => {
7359
+ init_data_buffer();
7360
+ });
6760
7361
 
6761
7362
  // src/streaming/rolling-aggregator.ts
6762
7363
  class RollingAggregator {
@@ -7217,6 +7818,19 @@ function createTimeSeriesPlot(options) {
7217
7818
  labels: { title: options.title ?? "Time Series" }
7218
7819
  });
7219
7820
  }
7821
+ var init_streaming_plot = __esm(() => {
7822
+ init_grammar();
7823
+ init_data_buffer();
7824
+ init_data_window();
7825
+ });
7826
+
7827
+ // src/streaming/index.ts
7828
+ var init_streaming = __esm(() => {
7829
+ init_streaming_plot();
7830
+ init_data_window();
7831
+ init_data_buffer();
7832
+ });
7833
+
7220
7834
  // src/performance/sampling.ts
7221
7835
  class SeededRandom {
7222
7836
  seed;
@@ -7382,14 +7996,8 @@ function autoSample(data, targetSize, options = {}) {
7382
7996
  }
7383
7997
  return systematicSample(data, targetSize);
7384
7998
  }
7999
+
7385
8000
  // src/performance/level-of-detail.ts
7386
- var DEFAULT_LOD_LEVELS = [
7387
- { name: "full", maxPoints: 500, threshold: 0 },
7388
- { name: "medium", maxPoints: 1000, threshold: 1000, samplingMethod: "lttb" },
7389
- { name: "low", maxPoints: 500, threshold: 5000, samplingMethod: "lttb" },
7390
- { name: "veryLow", maxPoints: 200, threshold: 20000, samplingMethod: "systematic" },
7391
- { name: "minimal", maxPoints: 100, threshold: 1e5, samplingMethod: "binned", binResolution: 50 }
7392
- ];
7393
8001
  function binData(data, resolution, xField, yField) {
7394
8002
  if (data.length === 0)
7395
8003
  return [];
@@ -7487,252 +8095,72 @@ class LevelOfDetail {
7487
8095
  switch (method) {
7488
8096
  case "lttb":
7489
8097
  return lttbSample(data, level.maxPoints, this.options.xField, this.options.yField);
7490
- case "binned":
7491
- return binData(data, level.binResolution || 50, this.options.xField, this.options.yField);
7492
- case "systematic":
7493
- default:
7494
- return systematicSample(data, level.maxPoints);
7495
- }
7496
- }
7497
- updateRenderTime(renderMs) {
7498
- this.lastRenderMs = renderMs;
7499
- if (renderMs > this.options.targetRenderMs * 1.5) {
7500
- this.adaptiveMaxPoints = Math.max(50, Math.floor(this.adaptiveMaxPoints * 0.8));
7501
- } else if (renderMs < this.options.targetRenderMs * 0.5) {
7502
- this.adaptiveMaxPoints = Math.min(this.currentLevel.maxPoints * 2, Math.floor(this.adaptiveMaxPoints * 1.2));
7503
- }
7504
- }
7505
- getCurrentLevel() {
7506
- return this.currentLevel;
7507
- }
7508
- getLevels() {
7509
- return [...this.options.levels];
7510
- }
7511
- setLevel(name) {
7512
- const level = this.options.levels.find((l) => l.name === name);
7513
- if (level) {
7514
- this.currentLevel = level;
7515
- this.adaptiveMaxPoints = level.maxPoints;
7516
- return true;
7517
- }
7518
- return false;
7519
- }
7520
- getStats() {
7521
- return {
7522
- currentLevel: this.currentLevel.name,
7523
- maxPoints: this.currentLevel.maxPoints,
7524
- adaptiveMaxPoints: this.adaptiveMaxPoints,
7525
- lastRenderMs: this.lastRenderMs,
7526
- targetRenderMs: this.options.targetRenderMs
7527
- };
7528
- }
7529
- processAdaptive(data) {
7530
- if (data.length <= this.adaptiveMaxPoints) {
7531
- return data;
7532
- }
7533
- return lttbSample(data, this.adaptiveMaxPoints, this.options.xField, this.options.yField);
7534
- }
7535
- }
7536
- function createLOD(options = {}) {
7537
- return new LevelOfDetail({
7538
- levels: options.levels ?? DEFAULT_LOD_LEVELS,
7539
- xField: options.xField,
7540
- yField: options.yField,
7541
- autoSelect: options.autoSelect,
7542
- targetRenderMs: options.targetRenderMs
7543
- });
7544
- }
7545
- // src/performance/binning.ts
7546
- function computeDomain2(data, field) {
7547
- let min = Infinity;
7548
- let max = -Infinity;
7549
- for (const d of data) {
7550
- const v = d[field];
7551
- if (typeof v === "number" && !isNaN(v)) {
7552
- if (v < min)
7553
- min = v;
7554
- if (v > max)
7555
- max = v;
7556
- }
7557
- }
7558
- if (min === Infinity)
7559
- return [0, 1];
7560
- if (min === max)
7561
- return [min - 0.5, max + 0.5];
7562
- return [min, max];
7563
- }
7564
- function aggregateValues(values, method) {
7565
- if (values.length === 0)
7566
- return 0;
7567
- switch (method) {
7568
- case "count":
7569
- return values.length;
7570
- case "sum":
7571
- return values.reduce((a, b) => a + b, 0);
7572
- case "mean":
7573
- return values.reduce((a, b) => a + b, 0) / values.length;
7574
- case "median":
7575
- const sorted = [...values].sort((a, b) => a - b);
7576
- const mid = Math.floor(sorted.length / 2);
7577
- return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
7578
- case "min":
7579
- return Math.min(...values);
7580
- case "max":
7581
- return Math.max(...values);
7582
- default:
7583
- return values.length;
7584
- }
7585
- }
7586
- function rectbin(data, options) {
7587
- const {
7588
- xField,
7589
- yField,
7590
- xBins = 20,
7591
- yBins = 20,
7592
- aggregate = "count",
7593
- valueField
7594
- } = options;
7595
- if (data.length === 0)
7596
- return [];
7597
- const xDomain = options.xDomain ?? computeDomain2(data, xField);
7598
- const yDomain = options.yDomain ?? computeDomain2(data, yField);
7599
- const xRange = xDomain[1] - xDomain[0];
7600
- const yRange = yDomain[1] - yDomain[0];
7601
- const binWidth = xRange / xBins;
7602
- const binHeight = yRange / yBins;
7603
- const bins = new Map;
7604
- for (const point of data) {
7605
- const x = point[xField];
7606
- const y = point[yField];
7607
- if (typeof x !== "number" || typeof y !== "number")
7608
- continue;
7609
- const bx = Math.min(xBins - 1, Math.max(0, Math.floor((x - xDomain[0]) / binWidth)));
7610
- const by = Math.min(yBins - 1, Math.max(0, Math.floor((y - yDomain[0]) / binHeight)));
7611
- const key = `${bx},${by}`;
7612
- if (!bins.has(key)) {
7613
- bins.set(key, { points: [], values: [] });
7614
- }
7615
- const bin = bins.get(key);
7616
- bin.points.push(point);
7617
- if (valueField && typeof point[valueField] === "number") {
7618
- bin.values.push(point[valueField]);
7619
- }
7620
- }
7621
- const result = [];
7622
- for (const [key, bin] of bins) {
7623
- const [bx, by] = key.split(",").map(Number);
7624
- const centerX = xDomain[0] + (bx + 0.5) * binWidth;
7625
- const centerY = yDomain[0] + (by + 0.5) * binHeight;
7626
- result.push({
7627
- x: centerX,
7628
- y: centerY,
7629
- count: bin.points.length,
7630
- value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
7631
- width: binWidth,
7632
- height: binHeight,
7633
- points: bin.points
7634
- });
7635
- }
7636
- return result;
7637
- }
7638
- function hexbin(data, options) {
7639
- const { xField, yField, aggregate = "count", valueField, radius = 10 } = options;
7640
- if (data.length === 0)
7641
- return [];
7642
- const xDomain = options.xDomain ?? computeDomain2(data, xField);
7643
- const yDomain = options.yDomain ?? computeDomain2(data, yField);
7644
- const hexWidth = radius * 2;
7645
- const hexHeight = radius * Math.sqrt(3);
7646
- const bins = new Map;
7647
- for (const point of data) {
7648
- const x = point[xField];
7649
- const y = point[yField];
7650
- if (typeof x !== "number" || typeof y !== "number")
7651
- continue;
7652
- const col = Math.round((x - xDomain[0]) / (hexWidth * 0.75));
7653
- const row = Math.round((y - yDomain[0]) / hexHeight - col % 2 * 0.5);
7654
- const key = `${col},${row}`;
7655
- if (!bins.has(key)) {
7656
- bins.set(key, { points: [], values: [], col, row });
7657
- }
7658
- const bin = bins.get(key);
7659
- bin.points.push(point);
7660
- if (valueField && typeof point[valueField] === "number") {
7661
- bin.values.push(point[valueField]);
8098
+ case "binned":
8099
+ return binData(data, level.binResolution || 50, this.options.xField, this.options.yField);
8100
+ case "systematic":
8101
+ default:
8102
+ return systematicSample(data, level.maxPoints);
7662
8103
  }
7663
8104
  }
7664
- function hexVertices(cx, cy, r) {
7665
- const vertices = [];
7666
- for (let i = 0;i < 6; i++) {
7667
- const angle = Math.PI / 3 * i + Math.PI / 6;
7668
- vertices.push({
7669
- x: cx + r * Math.cos(angle),
7670
- y: cy + r * Math.sin(angle)
7671
- });
8105
+ updateRenderTime(renderMs) {
8106
+ this.lastRenderMs = renderMs;
8107
+ if (renderMs > this.options.targetRenderMs * 1.5) {
8108
+ this.adaptiveMaxPoints = Math.max(50, Math.floor(this.adaptiveMaxPoints * 0.8));
8109
+ } else if (renderMs < this.options.targetRenderMs * 0.5) {
8110
+ this.adaptiveMaxPoints = Math.min(this.currentLevel.maxPoints * 2, Math.floor(this.adaptiveMaxPoints * 1.2));
7672
8111
  }
7673
- return vertices;
7674
8112
  }
7675
- const result = [];
7676
- for (const [, bin] of bins) {
7677
- const centerX = xDomain[0] + bin.col * hexWidth * 0.75;
7678
- const centerY = yDomain[0] + (bin.row + bin.col % 2 * 0.5) * hexHeight;
7679
- result.push({
7680
- x: centerX,
7681
- y: centerY,
7682
- count: bin.points.length,
7683
- value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
7684
- width: hexWidth,
7685
- height: hexHeight,
7686
- points: bin.points,
7687
- vertices: hexVertices(centerX, centerY, radius),
7688
- col: bin.col,
7689
- row: bin.row
7690
- });
8113
+ getCurrentLevel() {
8114
+ return this.currentLevel;
7691
8115
  }
7692
- return result;
7693
- }
7694
-
7695
- class Binner {
7696
- options;
7697
- type;
7698
- hexRadius;
7699
- constructor(options) {
7700
- this.options = options;
7701
- this.type = options.type ?? "rect";
7702
- this.hexRadius = options.hexRadius ?? 10;
8116
+ getLevels() {
8117
+ return [...this.options.levels];
7703
8118
  }
7704
- bin(data) {
7705
- if (this.type === "hex") {
7706
- return hexbin(data, { ...this.options, radius: this.hexRadius });
8119
+ setLevel(name) {
8120
+ const level = this.options.levels.find((l) => l.name === name);
8121
+ if (level) {
8122
+ this.currentLevel = level;
8123
+ this.adaptiveMaxPoints = level.maxPoints;
8124
+ return true;
7707
8125
  }
7708
- return rectbin(data, this.options);
8126
+ return false;
7709
8127
  }
7710
- toPlotData(data) {
7711
- const bins = this.bin(data);
7712
- const maxCount = Math.max(...bins.map((b) => b.count));
7713
- const minSize = 1;
7714
- const maxSize = 5;
7715
- return bins.map((bin) => ({
7716
- x: bin.x,
7717
- y: bin.y,
7718
- count: bin.count,
7719
- value: bin.value,
7720
- size: minSize + bin.count / maxCount * (maxSize - minSize)
7721
- }));
8128
+ getStats() {
8129
+ return {
8130
+ currentLevel: this.currentLevel.name,
8131
+ maxPoints: this.currentLevel.maxPoints,
8132
+ adaptiveMaxPoints: this.adaptiveMaxPoints,
8133
+ lastRenderMs: this.lastRenderMs,
8134
+ targetRenderMs: this.options.targetRenderMs
8135
+ };
7722
8136
  }
7723
- getDensityColors(bins, colorScale) {
7724
- const maxCount = Math.max(...bins.map((b) => b.count));
7725
- const colors = new Map;
7726
- for (const bin of bins) {
7727
- const t = bin.count / maxCount;
7728
- colors.set(bin, colorScale(t));
8137
+ processAdaptive(data) {
8138
+ if (data.length <= this.adaptiveMaxPoints) {
8139
+ return data;
7729
8140
  }
7730
- return colors;
8141
+ return lttbSample(data, this.adaptiveMaxPoints, this.options.xField, this.options.yField);
7731
8142
  }
7732
8143
  }
7733
- function createBinner(options) {
7734
- return new Binner(options);
8144
+ function createLOD(options = {}) {
8145
+ return new LevelOfDetail({
8146
+ levels: options.levels ?? DEFAULT_LOD_LEVELS,
8147
+ xField: options.xField,
8148
+ yField: options.yField,
8149
+ autoSelect: options.autoSelect,
8150
+ targetRenderMs: options.targetRenderMs
8151
+ });
7735
8152
  }
8153
+ var DEFAULT_LOD_LEVELS;
8154
+ var init_level_of_detail = __esm(() => {
8155
+ DEFAULT_LOD_LEVELS = [
8156
+ { name: "full", maxPoints: 500, threshold: 0 },
8157
+ { name: "medium", maxPoints: 1000, threshold: 1000, samplingMethod: "lttb" },
8158
+ { name: "low", maxPoints: 500, threshold: 5000, samplingMethod: "lttb" },
8159
+ { name: "veryLow", maxPoints: 200, threshold: 20000, samplingMethod: "systematic" },
8160
+ { name: "minimal", maxPoints: 100, threshold: 1e5, samplingMethod: "binned", binResolution: 50 }
8161
+ ];
8162
+ });
8163
+
7736
8164
  // src/performance/canvas-diff.ts
7737
8165
  function colorsEqual(a, b, tolerance = 0) {
7738
8166
  if (tolerance === 0) {
@@ -7913,8 +8341,15 @@ function quickDiff(oldCanvas, newCanvas) {
7913
8341
  }
7914
8342
  return false;
7915
8343
  }
8344
+
8345
+ // src/performance/index.ts
8346
+ var init_performance = __esm(() => {
8347
+ init_level_of_detail();
8348
+ });
8349
+
7916
8350
  // src/repl/repl.ts
7917
8351
  import * as readline from "readline";
8352
+
7918
8353
  class GGTermREPL {
7919
8354
  rl = null;
7920
8355
  state;
@@ -8549,25 +8984,18 @@ function startREPL(options) {
8549
8984
  repl.start();
8550
8985
  return repl;
8551
8986
  }
8987
+ var init_repl = __esm(() => {
8988
+ init_grammar();
8989
+ init_geoms();
8990
+ init_scales2();
8991
+ });
8992
+
8993
+ // src/repl/index.ts
8994
+ var init_repl2 = __esm(() => {
8995
+ init_repl();
8996
+ });
8997
+
8552
8998
  // src/export/vega-lite.ts
8553
- var GEOM_TO_MARK = {
8554
- point: "point",
8555
- line: "line",
8556
- bar: "bar",
8557
- area: "area",
8558
- boxplot: "boxplot",
8559
- rect: "rect",
8560
- text: "text",
8561
- rule: "rule",
8562
- histogram: "bar",
8563
- freqpoly: "line",
8564
- violin: "area",
8565
- step: "line",
8566
- path: "line",
8567
- segment: "rule",
8568
- smooth: "line",
8569
- errorbar: "errorbar"
8570
- };
8571
8999
  function inferFieldType(data, field) {
8572
9000
  const values = data.map((d) => d[field]).filter((v) => v != null);
8573
9001
  if (values.length === 0)
@@ -8587,11 +9015,12 @@ function inferFieldType(data, field) {
8587
9015
  }
8588
9016
  function buildEncoding(aes, data, geom) {
8589
9017
  const encoding = {};
9018
+ const isHeatmap = geom.type === "tile" || geom.type === "raster";
8590
9019
  if (aes.x) {
8591
9020
  const xType = inferFieldType(data, aes.x);
8592
9021
  encoding.x = {
8593
9022
  field: aes.x,
8594
- type: xType,
9023
+ type: isHeatmap && xType === "quantitative" ? "ordinal" : xType,
8595
9024
  ...xType === "temporal" ? { timeUnit: "yearmonthdate" } : {}
8596
9025
  };
8597
9026
  }
@@ -8602,18 +9031,25 @@ function buildEncoding(aes, data, geom) {
8602
9031
  const yType = inferFieldType(data, aes.y);
8603
9032
  encoding.y = {
8604
9033
  field: aes.y,
8605
- type: yType
9034
+ type: isHeatmap && yType === "quantitative" ? "ordinal" : yType
8606
9035
  };
8607
9036
  }
8608
9037
  }
8609
- if (aes.color) {
9038
+ if (isHeatmap && aes.fill) {
9039
+ const fillType = inferFieldType(data, aes.fill);
9040
+ encoding.color = {
9041
+ field: aes.fill,
9042
+ type: fillType === "nominal" ? "quantitative" : fillType,
9043
+ scale: { scheme: "viridis" }
9044
+ };
9045
+ } else if (aes.color) {
8610
9046
  const colorType = inferFieldType(data, aes.color);
8611
9047
  encoding.color = {
8612
9048
  field: aes.color,
8613
9049
  type: colorType
8614
9050
  };
8615
9051
  }
8616
- if (aes.fill && !aes.color) {
9052
+ if (aes.fill && !aes.color && !isHeatmap) {
8617
9053
  const fillType = inferFieldType(data, aes.fill);
8618
9054
  encoding.color = {
8619
9055
  field: aes.fill,
@@ -8646,16 +9082,39 @@ function buildMark(geom) {
8646
9082
  markProps.color = geom.params.color;
8647
9083
  if (geom.params.fill)
8648
9084
  markProps.fill = geom.params.fill;
9085
+ if (geom.params.linetype === "dashed")
9086
+ markProps.strokeDash = [4, 4];
9087
+ if (geom.params.linetype === "dotted")
9088
+ markProps.strokeDash = [2, 2];
8649
9089
  }
8650
9090
  if (geom.type === "step") {
8651
9091
  markProps.interpolate = "step-after";
8652
9092
  }
8653
- if (geom.type === "smooth") {
9093
+ if (geom.type === "smooth" || geom.type === "curve") {
8654
9094
  markProps.interpolate = "monotone";
8655
9095
  }
8656
9096
  if (geom.type === "histogram") {
8657
9097
  markProps.type = "bar";
8658
9098
  }
9099
+ if (geom.type === "tile" || geom.type === "raster" || geom.type === "density_2d") {
9100
+ markProps.type = "rect";
9101
+ markProps.tooltip = true;
9102
+ }
9103
+ if (geom.type === "contour") {
9104
+ markProps.type = "line";
9105
+ markProps.strokeWidth = 1;
9106
+ }
9107
+ if (geom.type === "contour_filled") {
9108
+ markProps.type = "area";
9109
+ markProps.opacity = 0.7;
9110
+ }
9111
+ if (geom.type === "qq") {
9112
+ markProps.type = "point";
9113
+ }
9114
+ if (geom.type === "qq_line") {
9115
+ markProps.type = "line";
9116
+ markProps.strokeDash = [4, 4];
9117
+ }
8659
9118
  if (Object.keys(markProps).length === 1) {
8660
9119
  return markType;
8661
9120
  }
@@ -8705,6 +9164,184 @@ function buildBoxplotSpec(data, aes) {
8705
9164
  }
8706
9165
  };
8707
9166
  }
9167
+ function buildHLineSpec(geom, _data) {
9168
+ const yintercept = geom.params?.yintercept;
9169
+ if (yintercept !== undefined) {
9170
+ return {
9171
+ mark: { type: "rule", strokeDash: geom.params?.linetype === "dashed" ? [4, 4] : undefined },
9172
+ encoding: {
9173
+ y: { datum: yintercept },
9174
+ ...geom.params?.color ? { color: { value: geom.params.color } } : {}
9175
+ }
9176
+ };
9177
+ }
9178
+ return {
9179
+ mark: "rule",
9180
+ encoding: {
9181
+ y: { field: "y", type: "quantitative" }
9182
+ }
9183
+ };
9184
+ }
9185
+ function buildVLineSpec(geom, _data) {
9186
+ const xintercept = geom.params?.xintercept;
9187
+ if (xintercept !== undefined) {
9188
+ return {
9189
+ mark: { type: "rule", strokeDash: geom.params?.linetype === "dashed" ? [4, 4] : undefined },
9190
+ encoding: {
9191
+ x: { datum: xintercept },
9192
+ ...geom.params?.color ? { color: { value: geom.params.color } } : {}
9193
+ }
9194
+ };
9195
+ }
9196
+ return {
9197
+ mark: "rule",
9198
+ encoding: {
9199
+ x: { field: "x", type: "quantitative" }
9200
+ }
9201
+ };
9202
+ }
9203
+ function buildAblineSpec(geom, data, aes) {
9204
+ const slope = geom.params?.slope ?? 1;
9205
+ const intercept = geom.params?.intercept ?? 0;
9206
+ const xValues = data.map((d) => Number(d[aes.x])).filter((x) => !isNaN(x));
9207
+ const xMin = Math.min(...xValues);
9208
+ const xMax = Math.max(...xValues);
9209
+ const yMin = slope * xMin + intercept;
9210
+ const yMax = slope * xMax + intercept;
9211
+ return {
9212
+ data: {
9213
+ values: [
9214
+ { x: xMin, y: yMin },
9215
+ { x: xMax, y: yMax }
9216
+ ]
9217
+ },
9218
+ mark: { type: "line", strokeDash: geom.params?.linetype === "dashed" ? [4, 4] : undefined },
9219
+ encoding: {
9220
+ x: { field: "x", type: "quantitative" },
9221
+ y: { field: "y", type: "quantitative" },
9222
+ ...geom.params?.color ? { color: { value: geom.params.color } } : {}
9223
+ }
9224
+ };
9225
+ }
9226
+ function buildLinerangeSpec(data, aes) {
9227
+ return {
9228
+ mark: "rule",
9229
+ encoding: {
9230
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9231
+ y: { field: aes.ymin || "ymin", type: "quantitative" },
9232
+ y2: { field: aes.ymax || "ymax" },
9233
+ ...aes.color ? { color: { field: aes.color, type: inferFieldType(data, aes.color) } } : {}
9234
+ }
9235
+ };
9236
+ }
9237
+ function buildPointrangeSpec(data, aes) {
9238
+ const colorEncoding = aes.color ? { color: { field: aes.color, type: inferFieldType(data, aes.color) } } : {};
9239
+ return [
9240
+ {
9241
+ mark: "rule",
9242
+ encoding: {
9243
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9244
+ y: { field: aes.ymin || "ymin", type: "quantitative" },
9245
+ y2: { field: aes.ymax || "ymax" },
9246
+ ...colorEncoding
9247
+ }
9248
+ },
9249
+ {
9250
+ mark: { type: "point", filled: true },
9251
+ encoding: {
9252
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9253
+ y: { field: aes.y, type: "quantitative" },
9254
+ ...colorEncoding
9255
+ }
9256
+ }
9257
+ ];
9258
+ }
9259
+ function buildCrossbarSpec(data, aes) {
9260
+ const colorEncoding = aes.color ? { color: { field: aes.color, type: inferFieldType(data, aes.color) } } : {};
9261
+ return [
9262
+ {
9263
+ mark: { type: "bar", width: 20 },
9264
+ encoding: {
9265
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9266
+ y: { field: aes.ymin || "ymin", type: "quantitative" },
9267
+ y2: { field: aes.ymax || "ymax" },
9268
+ ...colorEncoding
9269
+ }
9270
+ },
9271
+ {
9272
+ mark: { type: "tick", thickness: 2 },
9273
+ encoding: {
9274
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9275
+ y: { field: aes.y, type: "quantitative" },
9276
+ color: { value: "black" }
9277
+ }
9278
+ }
9279
+ ];
9280
+ }
9281
+ function buildErrorbarhSpec(data, aes) {
9282
+ return {
9283
+ mark: "rule",
9284
+ encoding: {
9285
+ y: { field: aes.y, type: inferFieldType(data, aes.y) },
9286
+ x: { field: aes.xmin || "xmin", type: "quantitative" },
9287
+ x2: { field: aes.xmax || "xmax" },
9288
+ ...aes.color ? { color: { field: aes.color, type: inferFieldType(data, aes.color) } } : {}
9289
+ }
9290
+ };
9291
+ }
9292
+ function buildRibbonSpec(data, aes) {
9293
+ return {
9294
+ mark: { type: "area", opacity: 0.3 },
9295
+ encoding: {
9296
+ x: { field: aes.x, type: inferFieldType(data, aes.x) },
9297
+ y: { field: aes.ymin || "ymin", type: "quantitative" },
9298
+ y2: { field: aes.ymax || "ymax" },
9299
+ ...aes.color ? { color: { field: aes.color, type: inferFieldType(data, aes.color) } } : {},
9300
+ ...aes.fill ? { fill: { field: aes.fill, type: inferFieldType(data, aes.fill) } } : {}
9301
+ }
9302
+ };
9303
+ }
9304
+ function buildRugSpec(data, aes, geom) {
9305
+ const sides = geom.params?.sides || "b";
9306
+ const encoding = {};
9307
+ if (sides.includes("b") || sides.includes("t")) {
9308
+ encoding.x = { field: aes.x, type: inferFieldType(data, aes.x) };
9309
+ }
9310
+ if (sides.includes("l") || sides.includes("r")) {
9311
+ encoding.y = { field: aes.y, type: inferFieldType(data, aes.y) };
9312
+ }
9313
+ if (Object.keys(encoding).length === 0) {
9314
+ encoding.x = { field: aes.x, type: inferFieldType(data, aes.x) };
9315
+ }
9316
+ return {
9317
+ mark: { type: "tick", thickness: 1 },
9318
+ encoding
9319
+ };
9320
+ }
9321
+ function buildBin2dSpec(_data, aes, geom) {
9322
+ const binX = geom.params?.binwidth_x || geom.params?.bins || 10;
9323
+ const binY = geom.params?.binwidth_y || geom.params?.bins || 10;
9324
+ return {
9325
+ mark: "rect",
9326
+ encoding: {
9327
+ x: {
9328
+ field: aes.x,
9329
+ bin: { maxbins: binX },
9330
+ type: "quantitative"
9331
+ },
9332
+ y: {
9333
+ field: aes.y,
9334
+ bin: { maxbins: binY },
9335
+ type: "quantitative"
9336
+ },
9337
+ color: {
9338
+ aggregate: "count",
9339
+ type: "quantitative",
9340
+ scale: { scheme: "viridis" }
9341
+ }
9342
+ }
9343
+ };
9344
+ }
8708
9345
  function getPublicationConfig() {
8709
9346
  return {
8710
9347
  font: "Arial",
@@ -8808,40 +9445,107 @@ function plotSpecToVegaLite(spec, options = {}) {
8808
9445
  vlSpec.title = spec.labels.title;
8809
9446
  }
8810
9447
  }
8811
- if (spec.geoms.length > 1) {
8812
- vlSpec.layer = spec.geoms.map((geom) => {
8813
- if (geom.type === "histogram" || geom.stat === "bin") {
8814
- const histSpec = buildHistogramSpec(spec.data, spec.aes, geom);
8815
- return {
8816
- mark: histSpec.mark,
8817
- encoding: histSpec.encoding
8818
- };
8819
- }
8820
- if (geom.type === "boxplot") {
8821
- const boxSpec = buildBoxplotSpec(spec.data, spec.aes);
8822
- return {
8823
- mark: boxSpec.mark,
8824
- encoding: boxSpec.encoding
8825
- };
8826
- }
9448
+ function buildGeomLayer(geom) {
9449
+ const data = spec.data;
9450
+ if (geom.type === "histogram" || geom.stat === "bin") {
9451
+ const histSpec = buildHistogramSpec(data, spec.aes, geom);
8827
9452
  return {
8828
- mark: buildMark(geom),
8829
- encoding: buildEncoding(spec.aes, spec.data, geom)
9453
+ mark: histSpec.mark,
9454
+ encoding: histSpec.encoding
8830
9455
  };
8831
- });
9456
+ }
9457
+ if (geom.type === "boxplot") {
9458
+ const boxSpec = buildBoxplotSpec(data, spec.aes);
9459
+ return {
9460
+ mark: boxSpec.mark,
9461
+ encoding: boxSpec.encoding
9462
+ };
9463
+ }
9464
+ if (geom.type === "hline") {
9465
+ const hlineSpec = buildHLineSpec(geom, data);
9466
+ return {
9467
+ mark: hlineSpec.mark,
9468
+ encoding: hlineSpec.encoding
9469
+ };
9470
+ }
9471
+ if (geom.type === "vline") {
9472
+ const vlineSpec = buildVLineSpec(geom, data);
9473
+ return {
9474
+ mark: vlineSpec.mark,
9475
+ encoding: vlineSpec.encoding
9476
+ };
9477
+ }
9478
+ if (geom.type === "abline") {
9479
+ const ablineSpec = buildAblineSpec(geom, data, spec.aes);
9480
+ return {
9481
+ mark: ablineSpec.mark,
9482
+ encoding: ablineSpec.encoding
9483
+ };
9484
+ }
9485
+ if (geom.type === "linerange") {
9486
+ const linerangeSpec = buildLinerangeSpec(data, spec.aes);
9487
+ return {
9488
+ mark: linerangeSpec.mark,
9489
+ encoding: linerangeSpec.encoding
9490
+ };
9491
+ }
9492
+ if (geom.type === "pointrange") {
9493
+ return buildPointrangeSpec(data, spec.aes);
9494
+ }
9495
+ if (geom.type === "crossbar") {
9496
+ return buildCrossbarSpec(data, spec.aes);
9497
+ }
9498
+ if (geom.type === "errorbarh") {
9499
+ const errorhSpec = buildErrorbarhSpec(data, spec.aes);
9500
+ return {
9501
+ mark: errorhSpec.mark,
9502
+ encoding: errorhSpec.encoding
9503
+ };
9504
+ }
9505
+ if (geom.type === "ribbon") {
9506
+ const ribbonSpec = buildRibbonSpec(data, spec.aes);
9507
+ return {
9508
+ mark: ribbonSpec.mark,
9509
+ encoding: ribbonSpec.encoding
9510
+ };
9511
+ }
9512
+ if (geom.type === "rug") {
9513
+ const rugSpec = buildRugSpec(data, spec.aes, geom);
9514
+ return {
9515
+ mark: rugSpec.mark,
9516
+ encoding: rugSpec.encoding
9517
+ };
9518
+ }
9519
+ if (geom.type === "bin2d") {
9520
+ const bin2dSpec = buildBin2dSpec(data, spec.aes, geom);
9521
+ return {
9522
+ mark: bin2dSpec.mark,
9523
+ encoding: bin2dSpec.encoding
9524
+ };
9525
+ }
9526
+ return {
9527
+ mark: buildMark(geom),
9528
+ encoding: buildEncoding(spec.aes, data, geom)
9529
+ };
9530
+ }
9531
+ if (spec.geoms.length > 1) {
9532
+ vlSpec.layer = [];
9533
+ for (const geom of spec.geoms) {
9534
+ const layerResult = buildGeomLayer(geom);
9535
+ if (Array.isArray(layerResult)) {
9536
+ vlSpec.layer.push(...layerResult);
9537
+ } else {
9538
+ vlSpec.layer.push(layerResult);
9539
+ }
9540
+ }
8832
9541
  } else if (spec.geoms.length === 1) {
8833
9542
  const geom = spec.geoms[0];
8834
- if (geom.type === "histogram" || geom.stat === "bin") {
8835
- const histSpec = buildHistogramSpec(spec.data, spec.aes, geom);
8836
- vlSpec.mark = histSpec.mark;
8837
- vlSpec.encoding = histSpec.encoding;
8838
- } else if (geom.type === "boxplot") {
8839
- const boxSpec = buildBoxplotSpec(spec.data, spec.aes);
8840
- vlSpec.mark = boxSpec.mark;
8841
- vlSpec.encoding = boxSpec.encoding;
9543
+ const layerResult = buildGeomLayer(geom);
9544
+ if (Array.isArray(layerResult)) {
9545
+ vlSpec.layer = layerResult;
8842
9546
  } else {
8843
- vlSpec.mark = buildMark(geom);
8844
- vlSpec.encoding = buildEncoding(spec.aes, spec.data, geom);
9547
+ vlSpec.mark = layerResult.mark;
9548
+ vlSpec.encoding = layerResult.encoding;
8845
9549
  }
8846
9550
  } else {
8847
9551
  vlSpec.mark = "point";
@@ -8938,6 +9642,306 @@ function exportToVegaLiteJSON(spec, options = {}) {
8938
9642
  const vlSpec = plotSpecToVegaLite(spec, options);
8939
9643
  return JSON.stringify(vlSpec, null, 2);
8940
9644
  }
9645
+ var GEOM_TO_MARK;
9646
+ var init_vega_lite = __esm(() => {
9647
+ GEOM_TO_MARK = {
9648
+ point: "point",
9649
+ line: "line",
9650
+ bar: "bar",
9651
+ col: "bar",
9652
+ area: "area",
9653
+ rect: "rect",
9654
+ text: "text",
9655
+ label: "text",
9656
+ rule: "rule",
9657
+ boxplot: "boxplot",
9658
+ histogram: "bar",
9659
+ freqpoly: "line",
9660
+ violin: "area",
9661
+ tile: "rect",
9662
+ raster: "rect",
9663
+ bin2d: "rect",
9664
+ density_2d: "rect",
9665
+ contour: "line",
9666
+ contour_filled: "area",
9667
+ step: "line",
9668
+ path: "line",
9669
+ smooth: "line",
9670
+ curve: "line",
9671
+ segment: "rule",
9672
+ linerange: "rule",
9673
+ pointrange: "rule",
9674
+ errorbar: "errorbar",
9675
+ errorbarh: "rule",
9676
+ crossbar: "rule",
9677
+ ribbon: "area",
9678
+ hline: "rule",
9679
+ vline: "rule",
9680
+ abline: "line",
9681
+ qq: "point",
9682
+ qq_line: "line",
9683
+ rug: "tick"
9684
+ };
9685
+ });
9686
+
9687
+ // src/export/index.ts
9688
+ var exports_export = {};
9689
+ __export(exports_export, {
9690
+ plotSpecToVegaLite: () => plotSpecToVegaLite,
9691
+ exportToVegaLiteJSON: () => exportToVegaLiteJSON
9692
+ });
9693
+ var init_export = __esm(() => {
9694
+ init_vega_lite();
9695
+ });
9696
+
9697
+ // src/index.ts
9698
+ var exports_src = {};
9699
+ __export(exports_src, {
9700
+ themeVoid: () => themeVoid,
9701
+ themeMinimal: () => themeMinimal,
9702
+ themeDark: () => themeDark,
9703
+ themeClassic: () => themeClassic,
9704
+ systematicSample: () => systematicSample,
9705
+ stratifiedSample: () => stratifiedSample,
9706
+ stat_summary: () => stat_summary,
9707
+ stat_smooth: () => stat_smooth,
9708
+ stat_qq_line: () => stat_qq_line,
9709
+ stat_qq: () => stat_qq,
9710
+ stat_density: () => stat_density,
9711
+ stat_boxplot: () => stat_boxplot,
9712
+ stat_bin2d: () => stat_bin2d,
9713
+ stat_bin: () => stat_bin,
9714
+ startREPL: () => startREPL,
9715
+ selectRenderer: () => selectRenderer,
9716
+ selectColorMode: () => selectColorMode,
9717
+ scale_y_time: () => scale_y_time,
9718
+ scale_y_sqrt: () => scale_y_sqrt,
9719
+ scale_y_reverse: () => scale_y_reverse,
9720
+ scale_y_log10: () => scale_y_log10,
9721
+ scale_y_duration: () => scale_y_duration,
9722
+ scale_y_discrete: () => scale_y_discrete,
9723
+ scale_y_datetime: () => scale_y_datetime,
9724
+ scale_y_date: () => scale_y_date,
9725
+ scale_y_continuous: () => scale_y_continuous,
9726
+ scale_y2_sqrt: () => scale_y2_sqrt,
9727
+ scale_y2_reverse: () => scale_y2_reverse,
9728
+ scale_y2_log10: () => scale_y2_log10,
9729
+ scale_y2_continuous: () => scale_y2_continuous,
9730
+ scale_x_time: () => scale_x_time,
9731
+ scale_x_sqrt: () => scale_x_sqrt,
9732
+ scale_x_reverse: () => scale_x_reverse,
9733
+ scale_x_log10: () => scale_x_log10,
9734
+ scale_x_duration: () => scale_x_duration,
9735
+ scale_x_discrete: () => scale_x_discrete,
9736
+ scale_x_datetime: () => scale_x_datetime,
9737
+ scale_x_date: () => scale_x_date,
9738
+ scale_x_continuous: () => scale_x_continuous,
9739
+ scale_size_radius: () => scale_size_radius,
9740
+ scale_size_identity: () => scale_size_identity,
9741
+ scale_size_continuous: () => scale_size_continuous,
9742
+ scale_size_binned: () => scale_size_binned,
9743
+ scale_size_area: () => scale_size_area,
9744
+ scale_shape_ordinal: () => scale_shape_ordinal,
9745
+ scale_shape_manual: () => scale_shape_manual,
9746
+ scale_shape_identity: () => scale_shape_identity,
9747
+ scale_shape_discrete: () => scale_shape_discrete,
9748
+ scale_fill_viridis: () => scale_fill_viridis,
9749
+ scale_fill_manual: () => scale_fill_manual,
9750
+ scale_fill_gradientn: () => scale_fill_gradientn,
9751
+ scale_fill_gradient2: () => scale_fill_gradient2,
9752
+ scale_fill_gradient: () => scale_fill_gradient,
9753
+ scale_fill_distiller: () => scale_fill_distiller,
9754
+ scale_fill_discrete: () => scale_fill_discrete,
9755
+ scale_fill_continuous: () => scale_fill_continuous,
9756
+ scale_fill_brewer: () => scale_fill_brewer,
9757
+ scale_color_viridis: () => scale_color_viridis,
9758
+ scale_color_manual: () => scale_color_manual,
9759
+ scale_color_gradientn: () => scale_color_gradientn,
9760
+ scale_color_gradient2: () => scale_color_gradient2,
9761
+ scale_color_gradient: () => scale_color_gradient,
9762
+ scale_color_distiller: () => scale_color_distiller,
9763
+ scale_color_discrete: () => scale_color_discrete,
9764
+ scale_color_continuous: () => scale_color_continuous,
9765
+ scale_color_brewer: () => scale_color_brewer,
9766
+ scale_alpha_manual: () => scale_alpha_manual,
9767
+ scale_alpha_identity: () => scale_alpha_identity,
9768
+ scale_alpha_discrete: () => scale_alpha_discrete,
9769
+ scale_alpha_continuous: () => scale_alpha_continuous,
9770
+ scale_alpha_binned: () => scale_alpha_binned,
9771
+ scale_alpha: () => scale_alpha,
9772
+ rgbToAnsi256: () => rgbToAnsi256,
9773
+ rgbToAnsi16: () => rgbToAnsi16,
9774
+ reservoirSample: () => reservoirSample,
9775
+ renderToString: () => renderToString,
9776
+ renderToCanvas: () => renderToCanvas,
9777
+ rectbin: () => rectbin,
9778
+ randomSample: () => randomSample,
9779
+ quickDiff: () => quickDiff,
9780
+ querySixelSupport: () => querySixelSupport,
9781
+ quantizeColor: () => quantizeColor,
9782
+ position_stack: () => position_stack,
9783
+ position_jitter: () => position_jitter,
9784
+ position_identity: () => position_identity,
9785
+ position_fill: () => position_fill,
9786
+ position_dodge: () => position_dodge,
9787
+ plotSpecToVegaLite: () => plotSpecToVegaLite,
9788
+ lttbSample: () => lttbSample,
9789
+ label_wrap: () => label_wrap,
9790
+ label_value: () => label_value,
9791
+ label_parsed: () => label_parsed,
9792
+ label_both: () => label_both,
9793
+ isStackPosition: () => isStackPosition,
9794
+ isRendererAvailable: () => isRendererAvailable,
9795
+ isDodgePosition: () => isDodgePosition,
9796
+ isCI: () => isCI,
9797
+ inferDiscreteDomain: () => inferDiscreteDomain,
9798
+ inferContinuousDomain: () => inferContinuousDomain,
9799
+ hexbin: () => hexbin,
9800
+ gg: () => gg,
9801
+ getTerminalName: () => getTerminalName,
9802
+ getTerminalInfo: () => getTerminalInfo,
9803
+ getRecommendedRenderer: () => getRecommendedRenderer,
9804
+ getPositionType: () => getPositionType,
9805
+ getPaletteColors: () => getPaletteColors,
9806
+ getPalette256: () => getPalette256,
9807
+ getColorEscape: () => getColorEscape,
9808
+ getCapabilities: () => getCapabilities,
9809
+ getAvailablePalettes: () => getAvailablePalettes,
9810
+ geom_vline: () => geom_vline,
9811
+ geom_violin: () => geom_violin,
9812
+ geom_tile: () => geom_tile,
9813
+ geom_text: () => geom_text,
9814
+ geom_step: () => geom_step,
9815
+ geom_smooth: () => geom_smooth,
9816
+ geom_segment: () => geom_segment,
9817
+ geom_rug: () => geom_rug,
9818
+ geom_ribbon: () => geom_ribbon,
9819
+ geom_rect: () => geom_rect,
9820
+ geom_raster: () => geom_raster,
9821
+ geom_qq_line: () => geom_qq_line,
9822
+ geom_qq: () => geom_qq,
9823
+ geom_pointrange: () => geom_pointrange,
9824
+ geom_point: () => geom_point,
9825
+ geom_path: () => geom_path,
9826
+ geom_linerange: () => geom_linerange,
9827
+ geom_line: () => geom_line,
9828
+ geom_label: () => geom_label,
9829
+ geom_hline: () => geom_hline,
9830
+ geom_histogram: () => geom_histogram,
9831
+ geom_freqpoly: () => geom_freqpoly,
9832
+ geom_errorbarh: () => geom_errorbarh,
9833
+ geom_errorbar: () => geom_errorbar,
9834
+ geom_density_2d: () => geom_density_2d,
9835
+ geom_curve: () => geom_curve,
9836
+ geom_crossbar: () => geom_crossbar,
9837
+ geom_contour_filled: () => geom_contour_filled,
9838
+ geom_contour: () => geom_contour,
9839
+ geom_col: () => geom_col,
9840
+ geom_boxplot: () => geom_boxplot,
9841
+ geom_bin2d: () => geom_bin2d,
9842
+ geom_bar: () => geom_bar,
9843
+ geom_area: () => geom_area,
9844
+ geom_abline: () => geom_abline,
9845
+ generate256Palette: () => generate256Palette,
9846
+ formatDateTime: () => formatDateTime,
9847
+ findClosestPaletteColor: () => findClosestPaletteColor,
9848
+ fgEscape: () => fgEscape,
9849
+ facet_wrap: () => facet_wrap,
9850
+ facet_grid: () => facet_grid,
9851
+ exportToVegaLiteJSON: () => exportToVegaLiteJSON,
9852
+ ditherPixels: () => ditherPixels,
9853
+ detectUnicodeSupport: () => detectUnicodeSupport,
9854
+ detectTerminalSize: () => detectTerminalSize,
9855
+ detectGraphicsProtocol: () => detectGraphicsProtocol,
9856
+ detectColorCapability: () => detectColorCapability,
9857
+ detectCapabilities: () => detectCapabilities,
9858
+ defaultTheme: () => defaultTheme,
9859
+ createTimeSeriesPlot: () => createTimeSeriesPlot,
9860
+ createStreamingPlot: () => createStreamingPlot,
9861
+ createSampler: () => createSampler,
9862
+ createRollingAggregator: () => createRollingAggregator,
9863
+ createRendererChain: () => createRendererChain,
9864
+ createOptimizedPalette: () => createOptimizedPalette,
9865
+ createMultiAggregator: () => createMultiAggregator,
9866
+ createLOD: () => createLOD,
9867
+ createDataWindow: () => createDataWindow,
9868
+ createDataBuffer: () => createDataBuffer,
9869
+ createCanvasDiff: () => createCanvasDiff,
9870
+ createCanvas: () => createCanvas,
9871
+ createBinner: () => createBinner,
9872
+ coordTrans: () => coordTrans,
9873
+ coordPolar: () => coordPolar,
9874
+ coordFlipWithLimits: () => coordFlipWithLimits,
9875
+ coordFlip: () => coordFlip,
9876
+ coordFixed: () => coordFixed,
9877
+ coordEqual: () => coordEqual,
9878
+ coordCartesian: () => coordCartesian,
9879
+ computeSummary: () => computeSummary,
9880
+ computeSmooth: () => computeSmooth,
9881
+ computeQQLine: () => computeQQLine,
9882
+ computeQQ: () => computeQQ,
9883
+ computeFacetPanels: () => computeFacetPanels,
9884
+ computeDensity: () => computeDensity,
9885
+ computeBoxplotStats: () => computeBoxplotStats,
9886
+ computeBins2d: () => computeBins2d,
9887
+ computeBins: () => computeBins,
9888
+ colorDistance: () => colorDistance,
9889
+ clearCapabilityCache: () => clearCapabilityCache,
9890
+ calculatePanelLayouts: () => calculatePanelLayouts,
9891
+ calculateLayout: () => calculateLayout,
9892
+ calculateGridStripLayout: () => calculateGridStripLayout,
9893
+ calculateDateTimeTicks: () => calculateDateTimeTicks,
9894
+ buildScaleContext: () => buildScaleContext,
9895
+ bgEscape: () => bgEscape,
9896
+ autoSample: () => autoSample,
9897
+ autoRenderer: () => autoRenderer,
9898
+ as_labeller: () => as_labeller,
9899
+ applyPositionAdjustment: () => applyPositionAdjustment,
9900
+ annotate_vline: () => annotate_vline,
9901
+ annotate_text: () => annotate_text,
9902
+ annotate_segment: () => annotate_segment,
9903
+ annotate_rect: () => annotate_rect,
9904
+ annotate_label: () => annotate_label,
9905
+ annotate_hline: () => annotate_hline,
9906
+ annotate: () => annotate,
9907
+ TerminalCanvas: () => TerminalCanvas,
9908
+ StreamingPlot: () => StreamingPlot,
9909
+ SHAPE_CHARS: () => SHAPE_CHARS,
9910
+ RollingAggregator: () => RollingAggregator,
9911
+ RendererChain: () => RendererChain,
9912
+ RESET_FG: () => RESET_FG,
9913
+ RESET_BG: () => RESET_BG,
9914
+ RESET: () => RESET,
9915
+ LevelOfDetail: () => LevelOfDetail,
9916
+ GGTermREPL: () => GGTermREPL,
9917
+ GGPlot: () => GGPlot,
9918
+ ExponentialMovingAverage: () => ExponentialMovingAverage,
9919
+ DataWindow: () => DataWindow,
9920
+ DataSampler: () => DataSampler,
9921
+ DataBuffer: () => DataBuffer,
9922
+ DEFAULT_SHAPES: () => DEFAULT_SHAPES,
9923
+ DEFAULT_LOD_LEVELS: () => DEFAULT_LOD_LEVELS,
9924
+ DEFAULT_FG: () => DEFAULT_FG,
9925
+ DEFAULT_BG: () => DEFAULT_BG,
9926
+ CanvasDiff: () => CanvasDiff,
9927
+ Binner: () => Binner,
9928
+ ANSI_16_COLORS: () => ANSI_16_COLORS
9929
+ });
9930
+ var init_src = __esm(() => {
9931
+ init_grammar();
9932
+ init_canvas2();
9933
+ init_pipeline2();
9934
+ init_geoms();
9935
+ init_stats();
9936
+ init_scales2();
9937
+ init_terminal();
9938
+ init_streaming();
9939
+ init_performance();
9940
+ init_repl2();
9941
+ init_export();
9942
+ });
9943
+ init_src();
9944
+
8941
9945
  export {
8942
9946
  themeVoid,
8943
9947
  themeMinimal,
@@ -8951,6 +9955,7 @@ export {
8951
9955
  stat_qq,
8952
9956
  stat_density,
8953
9957
  stat_boxplot,
9958
+ stat_bin2d,
8954
9959
  stat_bin,
8955
9960
  startREPL,
8956
9961
  selectRenderer,
@@ -9079,6 +10084,7 @@ export {
9079
10084
  geom_contour,
9080
10085
  geom_col,
9081
10086
  geom_boxplot,
10087
+ geom_bin2d,
9082
10088
  geom_bar,
9083
10089
  geom_area,
9084
10090
  geom_abline,
@@ -9123,6 +10129,7 @@ export {
9123
10129
  computeFacetPanels,
9124
10130
  computeDensity,
9125
10131
  computeBoxplotStats,
10132
+ computeBins2d,
9126
10133
  computeBins,
9127
10134
  colorDistance,
9128
10135
  clearCapabilityCache,