@ggterm/core 0.2.0 → 0.2.7

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/cli.js CHANGED
@@ -30,472 +30,64 @@ var __export = (target, all) => {
30
30
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
31
31
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
32
32
 
33
- // src/pipeline/scales.ts
34
- var exports_scales = {};
35
- __export(exports_scales, {
36
- niceDomain: () => niceDomain,
37
- inferDiscreteDomain: () => inferDiscreteDomain,
38
- inferContinuousDomain: () => inferContinuousDomain,
39
- getTransformFunctions: () => getTransformFunctions,
40
- expandDomain: () => expandDomain,
41
- createResolvedSizeScale: () => createResolvedSizeScale,
42
- createResolvedDiscreteScale: () => createResolvedDiscreteScale,
43
- createResolvedDiscreteColorScale: () => createResolvedDiscreteColorScale,
44
- createResolvedContinuousScale: () => createResolvedContinuousScale,
45
- createResolvedContinuousColorScale: () => createResolvedContinuousColorScale,
46
- buildScaleContext: () => buildScaleContext,
47
- DEFAULT_POINT_COLOR: () => DEFAULT_POINT_COLOR
48
- });
49
- function inferContinuousDomain(data, field) {
50
- let min = Infinity;
51
- let max = -Infinity;
52
- for (const row of data) {
53
- const value = row[field];
54
- if (typeof value === "number" && !isNaN(value)) {
55
- if (value < min)
56
- min = value;
57
- if (value > max)
58
- max = value;
59
- }
60
- }
61
- if (min === Infinity)
62
- min = 0;
63
- if (max === -Infinity)
64
- max = 1;
65
- if (min === max) {
66
- min = min - 1;
67
- max = max + 1;
68
- }
69
- return [min, max];
70
- }
71
- function inferDiscreteDomain(data, field, options = {}) {
72
- const { limits, order = "alphabetical", reverse = false, exclude, drop = true } = options;
73
- const seen = new Map;
74
- let index = 0;
75
- for (const row of data) {
76
- const value = row[field];
77
- if (value !== null && value !== undefined) {
78
- const key = String(value);
79
- if (!seen.has(key)) {
80
- seen.set(key, { firstIndex: index, count: 1 });
81
- } else {
82
- seen.get(key).count++;
83
- }
84
- }
85
- index++;
86
- }
87
- let result;
88
- if (limits) {
89
- if (drop) {
90
- result = limits.filter((v) => seen.has(v));
91
- } else {
92
- result = [...limits];
93
- }
94
- } else {
95
- const values = Array.from(seen.keys());
96
- switch (order) {
97
- case "data":
98
- result = values.sort((a, b) => seen.get(a).firstIndex - seen.get(b).firstIndex);
99
- break;
100
- case "frequency":
101
- result = values.sort((a, b) => seen.get(b).count - seen.get(a).count);
102
- break;
103
- case "reverse":
104
- result = values.sort().reverse();
105
- break;
106
- case "alphabetical":
107
- default:
108
- result = values.sort();
109
- break;
110
- }
111
- }
112
- if (exclude && exclude.length > 0) {
113
- const excludeSet = new Set(exclude);
114
- result = result.filter((v) => !excludeSet.has(v));
115
- }
116
- if (reverse) {
117
- result = result.reverse();
118
- }
119
- return result;
120
- }
121
- function expandDomain(domain, expand = 0.05) {
122
- const range = domain[1] - domain[0];
123
- const padding = range * expand;
124
- return [domain[0] - padding, domain[1] + padding];
125
- }
126
- function niceStep(range, targetTicks = 5) {
127
- const rawStep = range / Math.max(1, targetTicks - 1);
128
- const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
129
- const normalized = rawStep / magnitude;
130
- let nice;
131
- if (normalized <= 1.5)
132
- nice = 1;
133
- else if (normalized <= 3)
134
- nice = 2;
135
- else if (normalized <= 7)
136
- nice = 5;
137
- else
138
- nice = 10;
139
- return nice * magnitude;
140
- }
141
- function niceDomain(domain, targetTicks = 5) {
142
- const [min, max] = domain;
143
- const range = max - min;
144
- if (range === 0) {
145
- if (min === 0)
146
- return [-1, 1];
147
- const magnitude = Math.pow(10, Math.floor(Math.log10(Math.abs(min))));
148
- return [min - magnitude, min + magnitude];
149
- }
150
- const step = niceStep(range, targetTicks);
151
- const niceMin = Math.floor(min / step) * step;
152
- const niceMax = Math.ceil(max / step) * step;
153
- return [niceMin, niceMax];
154
- }
155
- function getTransformFunctions(trans = "identity") {
156
- switch (trans) {
157
- case "log10":
158
- return {
159
- type: "log10",
160
- transform: (v) => v > 0 ? Math.log10(v) : -Infinity,
161
- invert: (v) => Math.pow(10, v)
162
- };
163
- case "sqrt":
164
- return {
165
- type: "sqrt",
166
- transform: (v) => v >= 0 ? Math.sqrt(v) : 0,
167
- invert: (v) => v * v
168
- };
169
- case "reverse":
170
- return {
171
- type: "reverse",
172
- transform: (v) => -v,
173
- invert: (v) => -v
174
- };
175
- default:
176
- return {
177
- type: "identity",
178
- transform: (v) => v,
179
- invert: (v) => v
180
- };
181
- }
182
- }
183
- function createResolvedContinuousScale(aesthetic, domain, range, trans = "identity") {
184
- const [domainMin, domainMax] = domain;
185
- const [rangeMin, rangeMax] = range;
186
- const rangeSpan = rangeMax - rangeMin;
187
- const { transform, invert } = getTransformFunctions(trans);
33
+ // src/themes/default.ts
34
+ function defaultTheme() {
188
35
  return {
189
- aesthetic,
190
- type: "continuous",
191
- domain,
192
- range,
193
- trans,
194
- transform,
195
- invert,
196
- normalize(value) {
197
- const num = Number(value);
198
- if (isNaN(num))
199
- return 0;
200
- const transformed = transform(num);
201
- const transformedMin = transform(domainMin);
202
- const transformedMax = transform(domainMax);
203
- if (transformedMax === transformedMin)
204
- return 0.5;
205
- return (transformed - transformedMin) / (transformedMax - transformedMin);
36
+ panel: {
37
+ background: "",
38
+ border: "single",
39
+ grid: { major: "·", minor: null }
206
40
  },
207
- toCanvas(normalized) {
208
- return rangeMin + normalized * rangeSpan;
41
+ axis: {
42
+ text: { color: "" },
43
+ ticks: { char: "┼", length: 1 },
44
+ title: { color: "", bold: false }
209
45
  },
210
- map(value) {
211
- return this.toCanvas(this.normalize(value));
46
+ legend: {
47
+ position: "right",
48
+ title: { bold: true }
49
+ },
50
+ title: {
51
+ align: "center",
52
+ bold: true
53
+ },
54
+ facet: {
55
+ strip: {
56
+ text: "#c8c8c8",
57
+ background: ""
58
+ }
212
59
  }
213
60
  };
214
61
  }
215
- function createResolvedDiscreteScale(aesthetic, domain, range) {
216
- const [rangeMin, rangeMax] = range;
217
- const rangeSpan = rangeMax - rangeMin;
62
+ function themeMinimal() {
218
63
  return {
219
- aesthetic,
220
- type: "discrete",
221
- domain,
222
- range,
223
- normalize(value) {
224
- const str = String(value);
225
- const index = domain.indexOf(str);
226
- if (index < 0)
227
- return 0;
228
- return domain.length > 1 ? index / (domain.length - 1) : 0.5;
64
+ panel: {
65
+ background: "",
66
+ border: "none",
67
+ grid: { major: null, minor: null }
229
68
  },
230
- toCanvas(normalized) {
231
- return rangeMin + normalized * rangeSpan;
69
+ axis: {
70
+ text: { color: "" },
71
+ ticks: { char: "│", length: 1 },
72
+ title: { color: "", bold: false }
232
73
  },
233
- map(value) {
234
- return this.toCanvas(this.normalize(value));
74
+ legend: {
75
+ position: "right",
76
+ title: { bold: false }
77
+ },
78
+ title: {
79
+ align: "left",
80
+ bold: false
81
+ },
82
+ facet: {
83
+ strip: {
84
+ text: "#999999",
85
+ background: ""
86
+ }
235
87
  }
236
88
  };
237
89
  }
238
- function interpolateColor(color1, color2, t) {
239
- return {
240
- r: Math.round(color1.r + (color2.r - color1.r) * t),
241
- g: Math.round(color1.g + (color2.g - color1.g) * t),
242
- b: Math.round(color1.b + (color2.b - color1.b) * t),
243
- a: color1.a + (color2.a - color1.a) * t
244
- };
245
- }
246
- function createResolvedDiscreteColorScale(domain, palette = CATEGORY_COLORS) {
247
- return {
248
- aesthetic: "color",
249
- type: "discrete",
250
- domain,
251
- map(value) {
252
- const str = String(value);
253
- const index = domain.indexOf(str);
254
- if (index < 0)
255
- return palette[0];
256
- return palette[index % palette.length];
257
- }
258
- };
259
- }
260
- function createResolvedContinuousColorScale(domain, lowColor = { r: 68, g: 1, b: 84, a: 1 }, highColor = { r: 253, g: 231, b: 37, a: 1 }) {
261
- const [min, max] = domain;
262
- const span = max - min;
263
- return {
264
- aesthetic: "color",
265
- type: "continuous",
266
- domain,
267
- map(value) {
268
- const num = Number(value);
269
- if (isNaN(num))
270
- return lowColor;
271
- const t = Math.max(0, Math.min(1, (num - min) / span));
272
- return interpolateColor(lowColor, highColor, t);
273
- }
274
- };
275
- }
276
- function isCategoricalField(data, field) {
277
- for (const row of data) {
278
- const value = row[field];
279
- if (value !== null && value !== undefined) {
280
- if (typeof value === "string" && isNaN(Number(value))) {
281
- return true;
282
- }
283
- }
284
- }
285
- return false;
286
- }
287
- function createResolvedSizeScale(domain) {
288
- const [min, max] = domain;
289
- const span = max - min;
290
- return {
291
- aesthetic: "size",
292
- type: "continuous",
293
- domain,
294
- map(value) {
295
- const num = Number(value);
296
- if (isNaN(num))
297
- return 1;
298
- const t = Math.max(0, Math.min(1, (num - min) / span));
299
- return Math.floor(t * 3.99);
300
- }
301
- };
302
- }
303
- function computeDomain(data, field, trans = "identity") {
304
- const rawDomain = inferContinuousDomain(data, field);
305
- if (trans === "log10") {
306
- const [min, max] = rawDomain;
307
- const safeMin = min > 0 ? min : 0.001;
308
- const safeMax = max > 0 ? max : 1;
309
- const minPow = Math.floor(Math.log10(safeMin));
310
- const maxPow = Math.ceil(Math.log10(safeMax));
311
- return [Math.pow(10, minPow), Math.pow(10, maxPow)];
312
- }
313
- return niceDomain(rawDomain);
314
- }
315
- function buildScaleContext(data, aes, plotArea, userScales = [], coordLimits) {
316
- const userXScale = userScales.find((s) => s.aesthetic === "x");
317
- const userYScale = userScales.find((s) => s.aesthetic === "y");
318
- const userColorScale = userScales.find((s) => s.aesthetic === "color" || s.aesthetic === "fill");
319
- const xIsCategorical = isCategoricalField(data, aes.x);
320
- let x;
321
- if (xIsCategorical) {
322
- const xOrderOptions = {};
323
- if (userXScale) {
324
- if (userXScale.domain && Array.isArray(userXScale.domain)) {
325
- xOrderOptions.limits = userXScale.domain;
326
- }
327
- const orderOpts = userXScale.orderOptions;
328
- if (orderOpts) {
329
- if (orderOpts.order)
330
- xOrderOptions.order = orderOpts.order;
331
- if (orderOpts.reverse)
332
- xOrderOptions.reverse = orderOpts.reverse;
333
- if (orderOpts.exclude)
334
- xOrderOptions.exclude = orderOpts.exclude;
335
- if (orderOpts.drop !== undefined)
336
- xOrderOptions.drop = orderOpts.drop;
337
- }
338
- }
339
- const xDomain = inferDiscreteDomain(data, aes.x, xOrderOptions);
340
- x = createResolvedDiscreteScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1]);
341
- if (userXScale?.labels) {
342
- x.labels = userXScale.labels;
343
- }
344
- } else {
345
- const xTrans = userXScale?.trans ?? "identity";
346
- const xDomain = coordLimits?.xlim ?? userXScale?.domain ?? computeDomain(data, aes.x, xTrans);
347
- x = createResolvedContinuousScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1], xTrans);
348
- if (userXScale?.breaks) {
349
- x.breaks = userXScale.breaks;
350
- }
351
- if (userXScale?.labels) {
352
- x.labels = userXScale.labels;
353
- }
354
- }
355
- const yTrans = userYScale?.trans ?? "identity";
356
- const yDomain = coordLimits?.ylim ?? userYScale?.domain ?? computeDomain(data, aes.y, yTrans);
357
- const y = createResolvedContinuousScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y], yTrans);
358
- if (userYScale?.breaks) {
359
- y.breaks = userYScale.breaks;
360
- }
361
- if (userYScale?.labels) {
362
- y.labels = userYScale.labels;
363
- }
364
- const context = { x, y };
365
- if (aes.y2) {
366
- const userY2Scale = userScales.find((s) => s.aesthetic === "y2");
367
- const y2Trans = userY2Scale?.trans ?? "identity";
368
- const y2Domain = userY2Scale?.domain ?? computeDomain(data, aes.y2, y2Trans);
369
- const y2 = createResolvedContinuousScale("y2", y2Domain, [plotArea.y + plotArea.height - 1, plotArea.y], y2Trans);
370
- if (userY2Scale?.breaks) {
371
- y2.breaks = userY2Scale.breaks;
372
- }
373
- if (userY2Scale?.labels) {
374
- y2.labels = userY2Scale.labels;
375
- }
376
- context.y2 = y2;
377
- }
378
- const colorAesField = aes.color || aes.fill;
379
- if (colorAesField) {
380
- const colorOrderOptions = {};
381
- if (userColorScale) {
382
- if (userColorScale.domain && Array.isArray(userColorScale.domain)) {
383
- colorOrderOptions.limits = userColorScale.domain;
384
- }
385
- const orderOpts = userColorScale.orderOptions;
386
- if (orderOpts) {
387
- if (orderOpts.order)
388
- colorOrderOptions.order = orderOpts.order;
389
- if (orderOpts.reverse)
390
- colorOrderOptions.reverse = orderOpts.reverse;
391
- if (orderOpts.exclude)
392
- colorOrderOptions.exclude = orderOpts.exclude;
393
- if (orderOpts.drop !== undefined)
394
- colorOrderOptions.drop = orderOpts.drop;
395
- }
396
- }
397
- const colorDomain = inferDiscreteDomain(data, colorAesField, colorOrderOptions);
398
- if (userColorScale && userColorScale.map) {
399
- context.color = {
400
- aesthetic: userColorScale.aesthetic || "color",
401
- type: userColorScale.type === "continuous" ? "continuous" : "discrete",
402
- domain: userColorScale.type === "continuous" ? userColorScale.domain ?? inferContinuousDomain(data, colorAesField) : colorDomain,
403
- map: (value) => {
404
- const result = userColorScale.map(value);
405
- if (typeof result === "object" && "r" in result) {
406
- return result;
407
- }
408
- return { r: 128, g: 128, b: 128, a: 1 };
409
- }
410
- };
411
- } else {
412
- context.color = createResolvedDiscreteColorScale(colorDomain);
413
- }
414
- }
415
- if (aes.size) {
416
- const sizeDomain = inferContinuousDomain(data, aes.size);
417
- context.size = createResolvedSizeScale(sizeDomain);
418
- }
419
- return context;
420
- }
421
- var CATEGORY_COLORS, DEFAULT_POINT_COLOR;
422
- var init_scales = __esm(() => {
423
- CATEGORY_COLORS = [
424
- { r: 31, g: 119, b: 180, a: 1 },
425
- { r: 255, g: 127, b: 14, a: 1 },
426
- { r: 44, g: 160, b: 44, a: 1 },
427
- { r: 214, g: 39, b: 40, a: 1 },
428
- { r: 148, g: 103, b: 189, a: 1 },
429
- { r: 140, g: 86, b: 75, a: 1 },
430
- { r: 227, g: 119, b: 194, a: 1 },
431
- { r: 127, g: 127, b: 127, a: 1 },
432
- { r: 188, g: 189, b: 34, a: 1 },
433
- { r: 23, g: 190, b: 207, a: 1 }
434
- ];
435
- DEFAULT_POINT_COLOR = { r: 79, g: 169, b: 238, a: 1 };
436
- });
437
-
438
- // src/repl/repl.ts
439
- import * as readline from "readline";
440
-
441
- // src/themes/default.ts
442
- function defaultTheme() {
443
- return {
444
- panel: {
445
- background: "",
446
- border: "single",
447
- grid: { major: "·", minor: null }
448
- },
449
- axis: {
450
- text: { color: "" },
451
- ticks: { char: "┼", length: 1 },
452
- title: { color: "", bold: false }
453
- },
454
- legend: {
455
- position: "right",
456
- title: { bold: true }
457
- },
458
- title: {
459
- align: "center",
460
- bold: true
461
- },
462
- facet: {
463
- strip: {
464
- text: "#c8c8c8",
465
- background: ""
466
- }
467
- }
468
- };
469
- }
470
- function themeMinimal() {
471
- return {
472
- panel: {
473
- background: "",
474
- border: "none",
475
- grid: { major: null, minor: null }
476
- },
477
- axis: {
478
- text: { color: "" },
479
- ticks: { char: "│", length: 1 },
480
- title: { color: "", bold: false }
481
- },
482
- legend: {
483
- position: "right",
484
- title: { bold: false }
485
- },
486
- title: {
487
- align: "left",
488
- bold: false
489
- },
490
- facet: {
491
- strip: {
492
- text: "#999999",
493
- background: ""
494
- }
495
- }
496
- };
497
- }
498
- function themeDark() {
90
+ function themeDark() {
499
91
  return {
500
92
  panel: {
501
93
  background: "#1e1e1e",
@@ -592,229 +184,658 @@ function coordCartesian(options = {}) {
592
184
  }
593
185
  };
594
186
  }
595
- function coordFlip() {
187
+ function coordFlip() {
188
+ return {
189
+ type: "flip",
190
+ transform(x, y) {
191
+ return { x: y, y: x };
192
+ }
193
+ };
194
+ }
195
+ function coordPolar(options = {}) {
196
+ const theta = options.theta ?? "x";
197
+ return {
198
+ type: "polar",
199
+ transform(x, y) {
200
+ const angle = theta === "x" ? x : y;
201
+ const radius = theta === "x" ? y : x;
202
+ return {
203
+ x: radius * Math.cos(angle),
204
+ y: radius * Math.sin(angle)
205
+ };
206
+ }
207
+ };
208
+ }
209
+ function coordFixed(options = {}) {
210
+ const ratio = options.ratio ?? 1;
211
+ return {
212
+ type: "fixed",
213
+ xlim: options.xlim,
214
+ ylim: options.ylim,
215
+ clip: options.clip ?? true,
216
+ ratio,
217
+ transform(x, y) {
218
+ return { x, y };
219
+ }
220
+ };
221
+ }
222
+ function coordEqual(options = {}) {
223
+ return coordFixed({ ...options, ratio: 1 });
224
+ }
225
+ function getTransform(type) {
226
+ switch (type) {
227
+ case "log10":
228
+ return (v) => v > 0 ? Math.log10(v) : -Infinity;
229
+ case "sqrt":
230
+ return (v) => v >= 0 ? Math.sqrt(v) : 0;
231
+ case "reverse":
232
+ return (v) => -v;
233
+ default:
234
+ return (v) => v;
235
+ }
236
+ }
237
+ function coordTrans(options = {}) {
238
+ const xTrans = getTransform(options.x ?? "identity");
239
+ const yTrans = getTransform(options.y ?? "identity");
240
+ return {
241
+ type: "trans",
242
+ xlim: options.xlim,
243
+ ylim: options.ylim,
244
+ clip: options.clip ?? true,
245
+ xTransType: options.x ?? "identity",
246
+ yTransType: options.y ?? "identity",
247
+ transform(x, y) {
248
+ return {
249
+ x: xTrans(x),
250
+ y: yTrans(y)
251
+ };
252
+ }
253
+ };
254
+ }
255
+ function coordFlipWithLimits(options = {}) {
256
+ return {
257
+ type: "flip",
258
+ xlim: options.xlim,
259
+ ylim: options.ylim,
260
+ clip: options.clip ?? true,
261
+ transform(x, y) {
262
+ return { x: y, y: x };
263
+ }
264
+ };
265
+ }
266
+
267
+ // src/canvas/canvas.ts
268
+ function createEmptyCell() {
269
+ return {
270
+ char: " ",
271
+ fg: { ...DEFAULT_FG },
272
+ bg: { ...DEFAULT_BG }
273
+ };
274
+ }
275
+
276
+ class TerminalCanvas {
277
+ width;
278
+ height;
279
+ cells;
280
+ constructor(width, height) {
281
+ this.width = width;
282
+ this.height = height;
283
+ this.cells = [];
284
+ this.clear();
285
+ }
286
+ setCell(x, y, cell) {
287
+ if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || x >= this.width || y < 0 || y >= this.height) {
288
+ return;
289
+ }
290
+ const ix = Math.floor(x);
291
+ const iy = Math.floor(y);
292
+ const existing = this.cells[iy][ix];
293
+ this.cells[iy][ix] = {
294
+ char: cell.char ?? existing.char,
295
+ fg: cell.fg ?? existing.fg,
296
+ bg: cell.bg ?? existing.bg,
297
+ bold: cell.bold ?? existing.bold,
298
+ italic: cell.italic ?? existing.italic,
299
+ underline: cell.underline ?? existing.underline
300
+ };
301
+ }
302
+ getCell(x, y) {
303
+ if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || x >= this.width || y < 0 || y >= this.height) {
304
+ return createEmptyCell();
305
+ }
306
+ return this.cells[Math.floor(y)][Math.floor(x)];
307
+ }
308
+ clear() {
309
+ this.cells = [];
310
+ for (let y = 0;y < this.height; y++) {
311
+ const row = [];
312
+ for (let x = 0;x < this.width; x++) {
313
+ row.push(createEmptyCell());
314
+ }
315
+ this.cells.push(row);
316
+ }
317
+ }
318
+ drawChar(x, y, char, fg) {
319
+ this.setCell(x, y, { char, fg });
320
+ }
321
+ drawString(x, y, str, fg) {
322
+ for (let i = 0;i < str.length; i++) {
323
+ this.drawChar(x + i, y, str[i], fg);
324
+ }
325
+ }
326
+ drawHLine(x, y, length, char = "─", fg) {
327
+ for (let i = 0;i < length; i++) {
328
+ this.drawChar(x + i, y, char, fg);
329
+ }
330
+ }
331
+ drawVLine(x, y, length, char = "│", fg) {
332
+ for (let i = 0;i < length; i++) {
333
+ this.drawChar(x, y + i, char, fg);
334
+ }
335
+ }
336
+ drawPoint(x, y, fg, shape = "●") {
337
+ this.drawChar(x, y, shape, fg);
338
+ }
339
+ fillRect(x, y, width, height, char = " ", fg, bg) {
340
+ for (let dy = 0;dy < height; dy++) {
341
+ for (let dx = 0;dx < width; dx++) {
342
+ this.setCell(x + dx, y + dy, { char, fg, bg });
343
+ }
344
+ }
345
+ }
346
+ drawBox(x, y, width, height, style = "single", fg) {
347
+ const chars = style === "double" ? { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" } : style === "rounded" ? { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" } : { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
348
+ this.drawChar(x, y, chars.tl, fg);
349
+ this.drawChar(x + width - 1, y, chars.tr, fg);
350
+ this.drawChar(x, y + height - 1, chars.bl, fg);
351
+ this.drawChar(x + width - 1, y + height - 1, chars.br, fg);
352
+ this.drawHLine(x + 1, y, width - 2, chars.h, fg);
353
+ this.drawHLine(x + 1, y + height - 1, width - 2, chars.h, fg);
354
+ this.drawVLine(x, y + 1, height - 2, chars.v, fg);
355
+ this.drawVLine(x + width - 1, y + 1, height - 2, chars.v, fg);
356
+ }
357
+ toString() {
358
+ return this.cells.map((row) => row.map((cell) => cell.char).join("")).join(`
359
+ `);
360
+ }
361
+ toAnsiString() {
362
+ const lines = [];
363
+ for (const row of this.cells) {
364
+ let line = "";
365
+ let currentFg = null;
366
+ let currentBg = null;
367
+ for (const cell of row) {
368
+ const fgChanged = !currentFg || currentFg.r !== cell.fg.r || currentFg.g !== cell.fg.g || currentFg.b !== cell.fg.b;
369
+ const bgChanged = cell.bg.a > 0 && (!currentBg || currentBg.r !== cell.bg.r || currentBg.g !== cell.bg.g || currentBg.b !== cell.bg.b);
370
+ if (fgChanged) {
371
+ line += `\x1B[38;2;${cell.fg.r};${cell.fg.g};${cell.fg.b}m`;
372
+ currentFg = cell.fg;
373
+ }
374
+ if (bgChanged) {
375
+ line += `\x1B[48;2;${cell.bg.r};${cell.bg.g};${cell.bg.b}m`;
376
+ currentBg = cell.bg;
377
+ }
378
+ if (cell.bold)
379
+ line += "\x1B[1m";
380
+ if (cell.italic)
381
+ line += "\x1B[3m";
382
+ if (cell.underline)
383
+ line += "\x1B[4m";
384
+ line += cell.char;
385
+ if (cell.bold || cell.italic || cell.underline) {
386
+ line += "\x1B[22;23;24m";
387
+ if (currentFg) {
388
+ line += `\x1B[38;2;${currentFg.r};${currentFg.g};${currentFg.b}m`;
389
+ }
390
+ }
391
+ }
392
+ line += "\x1B[0m";
393
+ lines.push(line);
394
+ }
395
+ return lines.join(`
396
+ `);
397
+ }
398
+ }
399
+ function createCanvas(width, height) {
400
+ return new TerminalCanvas(width, height);
401
+ }
402
+ var DEFAULT_FG, DEFAULT_BG;
403
+ var init_canvas = __esm(() => {
404
+ DEFAULT_FG = { r: 255, g: 255, b: 255, a: 1 };
405
+ DEFAULT_BG = { r: 0, g: 0, b: 0, a: 0 };
406
+ });
407
+
408
+ // src/pipeline/scales.ts
409
+ var exports_scales = {};
410
+ __export(exports_scales, {
411
+ niceDomain: () => niceDomain,
412
+ inferDiscreteDomain: () => inferDiscreteDomain,
413
+ inferContinuousDomain: () => inferContinuousDomain,
414
+ getTransformFunctions: () => getTransformFunctions,
415
+ expandDomain: () => expandDomain,
416
+ createResolvedSizeScale: () => createResolvedSizeScale,
417
+ createResolvedDiscreteScale: () => createResolvedDiscreteScale,
418
+ createResolvedDiscreteColorScale: () => createResolvedDiscreteColorScale,
419
+ createResolvedContinuousScale: () => createResolvedContinuousScale,
420
+ createResolvedContinuousColorScale: () => createResolvedContinuousColorScale,
421
+ buildScaleContext: () => buildScaleContext,
422
+ DEFAULT_POINT_COLOR: () => DEFAULT_POINT_COLOR
423
+ });
424
+ function inferContinuousDomain(data, field) {
425
+ let min = Infinity;
426
+ let max = -Infinity;
427
+ for (const row of data) {
428
+ const value = row[field];
429
+ if (typeof value === "number" && !isNaN(value)) {
430
+ if (value < min)
431
+ min = value;
432
+ if (value > max)
433
+ max = value;
434
+ }
435
+ }
436
+ if (min === Infinity)
437
+ min = 0;
438
+ if (max === -Infinity)
439
+ max = 1;
440
+ if (min === max) {
441
+ min = min - 1;
442
+ max = max + 1;
443
+ }
444
+ return [min, max];
445
+ }
446
+ function inferDiscreteDomain(data, field, options = {}) {
447
+ const { limits, order = "alphabetical", reverse = false, exclude, drop = true } = options;
448
+ const seen = new Map;
449
+ let index = 0;
450
+ for (const row of data) {
451
+ const value = row[field];
452
+ if (value !== null && value !== undefined) {
453
+ const key = String(value);
454
+ if (!seen.has(key)) {
455
+ seen.set(key, { firstIndex: index, count: 1 });
456
+ } else {
457
+ seen.get(key).count++;
458
+ }
459
+ }
460
+ index++;
461
+ }
462
+ let result;
463
+ if (limits) {
464
+ if (drop) {
465
+ result = limits.filter((v) => seen.has(v));
466
+ } else {
467
+ result = [...limits];
468
+ }
469
+ } else {
470
+ const values = Array.from(seen.keys());
471
+ switch (order) {
472
+ case "data":
473
+ result = values.sort((a, b) => seen.get(a).firstIndex - seen.get(b).firstIndex);
474
+ break;
475
+ case "frequency":
476
+ result = values.sort((a, b) => seen.get(b).count - seen.get(a).count);
477
+ break;
478
+ case "reverse":
479
+ result = values.sort().reverse();
480
+ break;
481
+ case "alphabetical":
482
+ default:
483
+ result = values.sort();
484
+ break;
485
+ }
486
+ }
487
+ if (exclude && exclude.length > 0) {
488
+ const excludeSet = new Set(exclude);
489
+ result = result.filter((v) => !excludeSet.has(v));
490
+ }
491
+ if (reverse) {
492
+ result = result.reverse();
493
+ }
494
+ return result;
495
+ }
496
+ function expandDomain(domain, expand = 0.05) {
497
+ const range = domain[1] - domain[0];
498
+ const padding = range * expand;
499
+ return [domain[0] - padding, domain[1] + padding];
500
+ }
501
+ function niceStep(range, targetTicks = 5) {
502
+ const rawStep = range / Math.max(1, targetTicks - 1);
503
+ const magnitude = Math.pow(10, Math.floor(Math.log10(rawStep)));
504
+ const normalized = rawStep / magnitude;
505
+ let nice;
506
+ if (normalized <= 1.5)
507
+ nice = 1;
508
+ else if (normalized <= 3)
509
+ nice = 2;
510
+ else if (normalized <= 7)
511
+ nice = 5;
512
+ else
513
+ nice = 10;
514
+ return nice * magnitude;
515
+ }
516
+ function niceDomain(domain, targetTicks = 5) {
517
+ const [min, max] = domain;
518
+ const range = max - min;
519
+ if (range === 0) {
520
+ if (min === 0)
521
+ return [-1, 1];
522
+ const magnitude = Math.pow(10, Math.floor(Math.log10(Math.abs(min))));
523
+ return [min - magnitude, min + magnitude];
524
+ }
525
+ const step = niceStep(range, targetTicks);
526
+ const niceMin = Math.floor(min / step) * step;
527
+ const niceMax = Math.ceil(max / step) * step;
528
+ return [niceMin, niceMax];
529
+ }
530
+ function getTransformFunctions(trans = "identity") {
531
+ switch (trans) {
532
+ case "log10":
533
+ return {
534
+ type: "log10",
535
+ transform: (v) => v > 0 ? Math.log10(v) : -Infinity,
536
+ invert: (v) => Math.pow(10, v)
537
+ };
538
+ case "sqrt":
539
+ return {
540
+ type: "sqrt",
541
+ transform: (v) => v >= 0 ? Math.sqrt(v) : 0,
542
+ invert: (v) => v * v
543
+ };
544
+ case "reverse":
545
+ return {
546
+ type: "reverse",
547
+ transform: (v) => -v,
548
+ invert: (v) => -v
549
+ };
550
+ default:
551
+ return {
552
+ type: "identity",
553
+ transform: (v) => v,
554
+ invert: (v) => v
555
+ };
556
+ }
557
+ }
558
+ function createResolvedContinuousScale(aesthetic, domain, range, trans = "identity") {
559
+ const [domainMin, domainMax] = domain;
560
+ const [rangeMin, rangeMax] = range;
561
+ const rangeSpan = rangeMax - rangeMin;
562
+ const { transform, invert } = getTransformFunctions(trans);
563
+ return {
564
+ aesthetic,
565
+ type: "continuous",
566
+ domain,
567
+ range,
568
+ trans,
569
+ transform,
570
+ invert,
571
+ normalize(value) {
572
+ const num = Number(value);
573
+ if (isNaN(num))
574
+ return 0;
575
+ const transformed = transform(num);
576
+ const transformedMin = transform(domainMin);
577
+ const transformedMax = transform(domainMax);
578
+ if (transformedMax === transformedMin)
579
+ return 0.5;
580
+ return (transformed - transformedMin) / (transformedMax - transformedMin);
581
+ },
582
+ toCanvas(normalized) {
583
+ return rangeMin + normalized * rangeSpan;
584
+ },
585
+ map(value) {
586
+ return this.toCanvas(this.normalize(value));
587
+ }
588
+ };
589
+ }
590
+ function createResolvedDiscreteScale(aesthetic, domain, range) {
591
+ const [rangeMin, rangeMax] = range;
592
+ const rangeSpan = rangeMax - rangeMin;
596
593
  return {
597
- type: "flip",
598
- transform(x, y) {
599
- return { x: y, y: x };
594
+ aesthetic,
595
+ type: "discrete",
596
+ domain,
597
+ range,
598
+ normalize(value) {
599
+ const str = String(value);
600
+ const index = domain.indexOf(str);
601
+ if (index < 0)
602
+ return 0;
603
+ return domain.length > 1 ? index / (domain.length - 1) : 0.5;
604
+ },
605
+ toCanvas(normalized) {
606
+ return rangeMin + normalized * rangeSpan;
607
+ },
608
+ map(value) {
609
+ return this.toCanvas(this.normalize(value));
600
610
  }
601
611
  };
602
612
  }
603
- function coordPolar(options = {}) {
604
- const theta = options.theta ?? "x";
613
+ function interpolateColor(color1, color2, t) {
605
614
  return {
606
- type: "polar",
607
- transform(x, y) {
608
- const angle = theta === "x" ? x : y;
609
- const radius = theta === "x" ? y : x;
610
- return {
611
- x: radius * Math.cos(angle),
612
- y: radius * Math.sin(angle)
613
- };
614
- }
615
+ r: Math.round(color1.r + (color2.r - color1.r) * t),
616
+ g: Math.round(color1.g + (color2.g - color1.g) * t),
617
+ b: Math.round(color1.b + (color2.b - color1.b) * t),
618
+ a: color1.a + (color2.a - color1.a) * t
615
619
  };
616
620
  }
617
- function coordFixed(options = {}) {
618
- const ratio = options.ratio ?? 1;
621
+ function createResolvedDiscreteColorScale(domain, palette = CATEGORY_COLORS) {
619
622
  return {
620
- type: "fixed",
621
- xlim: options.xlim,
622
- ylim: options.ylim,
623
- clip: options.clip ?? true,
624
- ratio,
625
- transform(x, y) {
626
- return { x, y };
623
+ aesthetic: "color",
624
+ type: "discrete",
625
+ domain,
626
+ map(value) {
627
+ const str = String(value);
628
+ const index = domain.indexOf(str);
629
+ if (index < 0)
630
+ return palette[0];
631
+ return palette[index % palette.length];
627
632
  }
628
633
  };
629
634
  }
630
- function coordEqual(options = {}) {
631
- return coordFixed({ ...options, ratio: 1 });
632
- }
633
- function getTransform(type) {
634
- switch (type) {
635
- case "log10":
636
- return (v) => v > 0 ? Math.log10(v) : -Infinity;
637
- case "sqrt":
638
- return (v) => v >= 0 ? Math.sqrt(v) : 0;
639
- case "reverse":
640
- return (v) => -v;
641
- default:
642
- return (v) => v;
643
- }
644
- }
645
- function coordTrans(options = {}) {
646
- const xTrans = getTransform(options.x ?? "identity");
647
- const yTrans = getTransform(options.y ?? "identity");
635
+ function createResolvedContinuousColorScale(domain, lowColor = { r: 68, g: 1, b: 84, a: 1 }, highColor = { r: 253, g: 231, b: 37, a: 1 }) {
636
+ const [min, max] = domain;
637
+ const span = max - min;
648
638
  return {
649
- type: "trans",
650
- xlim: options.xlim,
651
- ylim: options.ylim,
652
- clip: options.clip ?? true,
653
- xTransType: options.x ?? "identity",
654
- yTransType: options.y ?? "identity",
655
- transform(x, y) {
656
- return {
657
- x: xTrans(x),
658
- y: yTrans(y)
659
- };
639
+ aesthetic: "color",
640
+ type: "continuous",
641
+ domain,
642
+ map(value) {
643
+ const num = Number(value);
644
+ if (isNaN(num))
645
+ return lowColor;
646
+ const t = Math.max(0, Math.min(1, (num - min) / span));
647
+ return interpolateColor(lowColor, highColor, t);
660
648
  }
661
649
  };
662
650
  }
663
- function coordFlipWithLimits(options = {}) {
664
- return {
665
- type: "flip",
666
- xlim: options.xlim,
667
- ylim: options.ylim,
668
- clip: options.clip ?? true,
669
- transform(x, y) {
670
- return { x: y, y: x };
651
+ function isCategoricalField(data, field) {
652
+ for (const row of data) {
653
+ const value = row[field];
654
+ if (value !== null && value !== undefined) {
655
+ if (typeof value === "string" && isNaN(Number(value))) {
656
+ return true;
657
+ }
671
658
  }
672
- };
659
+ }
660
+ return false;
673
661
  }
674
-
675
- // src/canvas/canvas.ts
676
- var DEFAULT_FG = { r: 255, g: 255, b: 255, a: 1 };
677
- var DEFAULT_BG = { r: 0, g: 0, b: 0, a: 0 };
678
- function createEmptyCell() {
662
+ function createResolvedSizeScale(domain) {
663
+ const [min, max] = domain;
664
+ const span = max - min;
679
665
  return {
680
- char: " ",
681
- fg: { ...DEFAULT_FG },
682
- bg: { ...DEFAULT_BG }
666
+ aesthetic: "size",
667
+ type: "continuous",
668
+ domain,
669
+ map(value) {
670
+ const num = Number(value);
671
+ if (isNaN(num))
672
+ return 1;
673
+ const t = Math.max(0, Math.min(1, (num - min) / span));
674
+ return Math.floor(t * 3.99);
675
+ }
683
676
  };
684
677
  }
685
-
686
- class TerminalCanvas {
687
- width;
688
- height;
689
- cells;
690
- constructor(width, height) {
691
- this.width = width;
692
- this.height = height;
693
- this.cells = [];
694
- this.clear();
678
+ function computeDomain(data, field, trans = "identity") {
679
+ const rawDomain = inferContinuousDomain(data, field);
680
+ if (trans === "log10") {
681
+ const [min, max] = rawDomain;
682
+ const safeMin = min > 0 ? min : 0.001;
683
+ const safeMax = max > 0 ? max : 1;
684
+ const minPow = Math.floor(Math.log10(safeMin));
685
+ const maxPow = Math.ceil(Math.log10(safeMax));
686
+ return [Math.pow(10, minPow), Math.pow(10, maxPow)];
695
687
  }
696
- setCell(x, y, cell) {
697
- if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
698
- return;
688
+ return niceDomain(rawDomain);
689
+ }
690
+ function buildScaleContext(data, aes, plotArea, userScales = [], coordLimits) {
691
+ const userXScale = userScales.find((s) => s.aesthetic === "x");
692
+ const userYScale = userScales.find((s) => s.aesthetic === "y");
693
+ const userColorScale = userScales.find((s) => s.aesthetic === "color" || s.aesthetic === "fill");
694
+ const xIsCategorical = isCategoricalField(data, aes.x);
695
+ let x;
696
+ if (xIsCategorical) {
697
+ const xOrderOptions = {};
698
+ if (userXScale) {
699
+ if (userXScale.domain && Array.isArray(userXScale.domain)) {
700
+ xOrderOptions.limits = userXScale.domain;
701
+ }
702
+ const orderOpts = userXScale.orderOptions;
703
+ if (orderOpts) {
704
+ if (orderOpts.order)
705
+ xOrderOptions.order = orderOpts.order;
706
+ if (orderOpts.reverse)
707
+ xOrderOptions.reverse = orderOpts.reverse;
708
+ if (orderOpts.exclude)
709
+ xOrderOptions.exclude = orderOpts.exclude;
710
+ if (orderOpts.drop !== undefined)
711
+ xOrderOptions.drop = orderOpts.drop;
712
+ }
699
713
  }
700
- const ix = Math.floor(x);
701
- const iy = Math.floor(y);
702
- const existing = this.cells[iy][ix];
703
- this.cells[iy][ix] = {
704
- char: cell.char ?? existing.char,
705
- fg: cell.fg ?? existing.fg,
706
- bg: cell.bg ?? existing.bg,
707
- bold: cell.bold ?? existing.bold,
708
- italic: cell.italic ?? existing.italic,
709
- underline: cell.underline ?? existing.underline
710
- };
711
- }
712
- getCell(x, y) {
713
- if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
714
- return createEmptyCell();
714
+ const xDomain = inferDiscreteDomain(data, aes.x, xOrderOptions);
715
+ x = createResolvedDiscreteScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1]);
716
+ if (userXScale?.labels) {
717
+ x.labels = userXScale.labels;
718
+ }
719
+ } else {
720
+ const xTrans = userXScale?.trans ?? "identity";
721
+ const xDomain = coordLimits?.xlim ?? userXScale?.domain ?? computeDomain(data, aes.x, xTrans);
722
+ x = createResolvedContinuousScale("x", xDomain, [plotArea.x, plotArea.x + plotArea.width - 1], xTrans);
723
+ if (userXScale?.breaks) {
724
+ x.breaks = userXScale.breaks;
725
+ }
726
+ if (userXScale?.labels) {
727
+ x.labels = userXScale.labels;
715
728
  }
716
- return this.cells[Math.floor(y)][Math.floor(x)];
717
729
  }
718
- clear() {
719
- this.cells = [];
720
- for (let y = 0;y < this.height; y++) {
721
- const row = [];
722
- for (let x = 0;x < this.width; x++) {
723
- row.push(createEmptyCell());
730
+ const yIsCategorical = isCategoricalField(data, aes.y);
731
+ let y;
732
+ if (yIsCategorical) {
733
+ const yOrderOptions = {};
734
+ if (userYScale) {
735
+ if (userYScale.domain && Array.isArray(userYScale.domain)) {
736
+ yOrderOptions.limits = userYScale.domain;
737
+ }
738
+ const orderOpts = userYScale.orderOptions;
739
+ if (orderOpts) {
740
+ if (orderOpts.order)
741
+ yOrderOptions.order = orderOpts.order;
742
+ if (orderOpts.reverse)
743
+ yOrderOptions.reverse = orderOpts.reverse;
744
+ if (orderOpts.exclude)
745
+ yOrderOptions.exclude = orderOpts.exclude;
746
+ if (orderOpts.drop !== undefined)
747
+ yOrderOptions.drop = orderOpts.drop;
724
748
  }
725
- this.cells.push(row);
726
749
  }
727
- }
728
- drawChar(x, y, char, fg) {
729
- this.setCell(x, y, { char, fg });
730
- }
731
- drawString(x, y, str, fg) {
732
- for (let i = 0;i < str.length; i++) {
733
- this.drawChar(x + i, y, str[i], fg);
750
+ const yDomain = inferDiscreteDomain(data, aes.y, yOrderOptions);
751
+ y = createResolvedDiscreteScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y]);
752
+ if (userYScale?.labels) {
753
+ y.labels = userYScale.labels;
734
754
  }
735
- }
736
- drawHLine(x, y, length, char = "", fg) {
737
- for (let i = 0;i < length; i++) {
738
- this.drawChar(x + i, y, char, fg);
755
+ } else {
756
+ const yTrans = userYScale?.trans ?? "identity";
757
+ const yDomain = coordLimits?.ylim ?? userYScale?.domain ?? computeDomain(data, aes.y, yTrans);
758
+ y = createResolvedContinuousScale("y", yDomain, [plotArea.y + plotArea.height - 1, plotArea.y], yTrans);
759
+ if (userYScale?.breaks) {
760
+ y.breaks = userYScale.breaks;
739
761
  }
740
- }
741
- drawVLine(x, y, length, char = "│", fg) {
742
- for (let i = 0;i < length; i++) {
743
- this.drawChar(x, y + i, char, fg);
762
+ if (userYScale?.labels) {
763
+ y.labels = userYScale.labels;
744
764
  }
745
765
  }
746
- drawPoint(x, y, fg, shape = "●") {
747
- this.drawChar(x, y, shape, fg);
766
+ const context = { x, y };
767
+ if (aes.y2) {
768
+ const userY2Scale = userScales.find((s) => s.aesthetic === "y2");
769
+ const y2Trans = userY2Scale?.trans ?? "identity";
770
+ const y2Domain = userY2Scale?.domain ?? computeDomain(data, aes.y2, y2Trans);
771
+ const y2 = createResolvedContinuousScale("y2", y2Domain, [plotArea.y + plotArea.height - 1, plotArea.y], y2Trans);
772
+ if (userY2Scale?.breaks) {
773
+ y2.breaks = userY2Scale.breaks;
774
+ }
775
+ if (userY2Scale?.labels) {
776
+ y2.labels = userY2Scale.labels;
777
+ }
778
+ context.y2 = y2;
748
779
  }
749
- fillRect(x, y, width, height, char = " ", fg, bg) {
750
- for (let dy = 0;dy < height; dy++) {
751
- for (let dx = 0;dx < width; dx++) {
752
- this.setCell(x + dx, y + dy, { char, fg, bg });
780
+ const colorAesField = aes.color || aes.fill;
781
+ if (colorAesField) {
782
+ const colorOrderOptions = {};
783
+ if (userColorScale) {
784
+ if (userColorScale.domain && Array.isArray(userColorScale.domain)) {
785
+ colorOrderOptions.limits = userColorScale.domain;
786
+ }
787
+ const orderOpts = userColorScale.orderOptions;
788
+ if (orderOpts) {
789
+ if (orderOpts.order)
790
+ colorOrderOptions.order = orderOpts.order;
791
+ if (orderOpts.reverse)
792
+ colorOrderOptions.reverse = orderOpts.reverse;
793
+ if (orderOpts.exclude)
794
+ colorOrderOptions.exclude = orderOpts.exclude;
795
+ if (orderOpts.drop !== undefined)
796
+ colorOrderOptions.drop = orderOpts.drop;
753
797
  }
754
798
  }
755
- }
756
- drawBox(x, y, width, height, style = "single", fg) {
757
- const chars = style === "double" ? { tl: "╔", tr: "╗", bl: "╚", br: "╝", h: "═", v: "║" } : style === "rounded" ? { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" } : { tl: "┌", tr: "┐", bl: "└", br: "┘", h: "─", v: "│" };
758
- this.drawChar(x, y, chars.tl, fg);
759
- this.drawChar(x + width - 1, y, chars.tr, fg);
760
- this.drawChar(x, y + height - 1, chars.bl, fg);
761
- this.drawChar(x + width - 1, y + height - 1, chars.br, fg);
762
- this.drawHLine(x + 1, y, width - 2, chars.h, fg);
763
- this.drawHLine(x + 1, y + height - 1, width - 2, chars.h, fg);
764
- this.drawVLine(x, y + 1, height - 2, chars.v, fg);
765
- this.drawVLine(x + width - 1, y + 1, height - 2, chars.v, fg);
766
- }
767
- toString() {
768
- return this.cells.map((row) => row.map((cell) => cell.char).join("")).join(`
769
- `);
770
- }
771
- toAnsiString() {
772
- const lines = [];
773
- for (const row of this.cells) {
774
- let line = "";
775
- let currentFg = null;
776
- let currentBg = null;
777
- for (const cell of row) {
778
- const fgChanged = !currentFg || currentFg.r !== cell.fg.r || currentFg.g !== cell.fg.g || currentFg.b !== cell.fg.b;
779
- const bgChanged = cell.bg.a > 0 && (!currentBg || currentBg.r !== cell.bg.r || currentBg.g !== cell.bg.g || currentBg.b !== cell.bg.b);
780
- if (fgChanged) {
781
- line += `\x1B[38;2;${cell.fg.r};${cell.fg.g};${cell.fg.b}m`;
782
- currentFg = cell.fg;
783
- }
784
- if (bgChanged) {
785
- line += `\x1B[48;2;${cell.bg.r};${cell.bg.g};${cell.bg.b}m`;
786
- currentBg = cell.bg;
787
- }
788
- if (cell.bold)
789
- line += "\x1B[1m";
790
- if (cell.italic)
791
- line += "\x1B[3m";
792
- if (cell.underline)
793
- line += "\x1B[4m";
794
- line += cell.char;
795
- if (cell.bold || cell.italic || cell.underline) {
796
- line += "\x1B[22;23;24m";
797
- if (currentFg) {
798
- line += `\x1B[38;2;${currentFg.r};${currentFg.g};${currentFg.b}m`;
799
+ const colorDomain = inferDiscreteDomain(data, colorAesField, colorOrderOptions);
800
+ if (userColorScale && userColorScale.map) {
801
+ context.color = {
802
+ aesthetic: userColorScale.aesthetic || "color",
803
+ type: userColorScale.type === "continuous" ? "continuous" : "discrete",
804
+ domain: userColorScale.type === "continuous" ? userColorScale.domain ?? inferContinuousDomain(data, colorAesField) : colorDomain,
805
+ map: (value) => {
806
+ const result = userColorScale.map(value);
807
+ if (typeof result === "object" && "r" in result) {
808
+ return result;
799
809
  }
810
+ return { r: 128, g: 128, b: 128, a: 1 };
800
811
  }
801
- }
802
- line += "\x1B[0m";
803
- lines.push(line);
812
+ };
813
+ } else {
814
+ context.color = createResolvedDiscreteColorScale(colorDomain);
804
815
  }
805
- return lines.join(`
806
- `);
807
816
  }
817
+ if (aes.size) {
818
+ const sizeDomain = inferContinuousDomain(data, aes.size);
819
+ context.size = createResolvedSizeScale(sizeDomain);
820
+ }
821
+ return context;
808
822
  }
809
- function createCanvas(width, height) {
810
- return new TerminalCanvas(width, height);
811
- }
812
-
813
- // src/pipeline/pipeline.ts
814
- init_scales();
815
-
816
- // src/pipeline/render-geoms.ts
817
- init_scales();
823
+ var CATEGORY_COLORS, DEFAULT_POINT_COLOR;
824
+ var init_scales = __esm(() => {
825
+ CATEGORY_COLORS = [
826
+ { r: 31, g: 119, b: 180, a: 1 },
827
+ { r: 255, g: 127, b: 14, a: 1 },
828
+ { r: 44, g: 160, b: 44, a: 1 },
829
+ { r: 214, g: 39, b: 40, a: 1 },
830
+ { r: 148, g: 103, b: 189, a: 1 },
831
+ { r: 140, g: 86, b: 75, a: 1 },
832
+ { r: 227, g: 119, b: 194, a: 1 },
833
+ { r: 127, g: 127, b: 127, a: 1 },
834
+ { r: 188, g: 189, b: 34, a: 1 },
835
+ { r: 23, g: 190, b: 207, a: 1 }
836
+ ];
837
+ DEFAULT_POINT_COLOR = { r: 79, g: 169, b: 238, a: 1 };
838
+ });
818
839
 
819
840
  // src/positions/index.ts
820
841
  function position_identity() {
@@ -1016,22 +1037,6 @@ function getPositionType(position) {
1016
1037
  }
1017
1038
 
1018
1039
  // src/pipeline/render-geoms.ts
1019
- var POINT_SHAPES = {
1020
- circle: "●",
1021
- filled_circle: "●",
1022
- open_circle: "○",
1023
- square: "■",
1024
- open_square: "□",
1025
- diamond: "◆",
1026
- open_diamond: "◇",
1027
- triangle: "▲",
1028
- open_triangle: "△",
1029
- cross: "✕",
1030
- plus: "+",
1031
- star: "★",
1032
- dot: "•"
1033
- };
1034
- var SIZE_CHARS = ["·", "•", "●", "⬤"];
1035
1040
  function getPointShape(shape) {
1036
1041
  if (!shape)
1037
1042
  return POINT_SHAPES.circle;
@@ -1769,20 +1774,52 @@ function renderGeomTile(data, geom, aes, scales, canvas) {
1769
1774
  const plotRight = Math.round(scales.x.range[1]);
1770
1775
  const plotTop = Math.round(Math.min(scales.y.range[0], scales.y.range[1]));
1771
1776
  const plotBottom = Math.round(Math.max(scales.y.range[0], scales.y.range[1]));
1772
- let tileWidth = geom.params.width;
1773
- let tileHeight = geom.params.height;
1774
- if (!tileWidth || !tileHeight) {
1775
- const xVals = [...new Set(data.map((r) => Number(r[aes.x]) || 0))].sort((a, b) => a - b);
1776
- const yVals = [...new Set(data.map((r) => Number(r[aes.y]) || 0))].sort((a, b) => a - b);
1777
- if (xVals.length > 1) {
1778
- tileWidth = tileWidth ?? xVals[1] - xVals[0];
1777
+ let halfW;
1778
+ let halfH;
1779
+ const xIsDiscrete = scales.x.type === "discrete";
1780
+ const yIsDiscrete = scales.y.type === "discrete";
1781
+ if (xIsDiscrete) {
1782
+ const xDomain = scales.x.domain;
1783
+ const canvasWidth = Math.abs(scales.x.range[1] - scales.x.range[0]);
1784
+ halfW = Math.max(1, Math.floor(canvasWidth / (xDomain.length * 2)));
1785
+ } else {
1786
+ let tileWidth = data[0]?.width ?? geom.params.width;
1787
+ if (!tileWidth) {
1788
+ const xVals = [...new Set(data.map((r) => Number(r[aes.x])).filter((v) => !isNaN(v)))].sort((a, b) => a - b);
1789
+ if (xVals.length > 1) {
1790
+ tileWidth = xVals[1] - xVals[0];
1791
+ }
1792
+ }
1793
+ tileWidth = tileWidth ?? 1;
1794
+ const sampleX = data.find((r) => r[aes.x] !== null && r[aes.x] !== undefined)?.[aes.x];
1795
+ if (sampleX !== undefined) {
1796
+ const cx = scales.x.map(sampleX);
1797
+ halfW = Math.max(1, Math.floor(Math.abs(scales.x.map(Number(sampleX) + tileWidth / 2) - cx)));
1798
+ } else {
1799
+ halfW = 1;
1800
+ }
1801
+ }
1802
+ if (yIsDiscrete) {
1803
+ const yDomain = scales.y.domain;
1804
+ const canvasHeight = Math.abs(scales.y.range[1] - scales.y.range[0]);
1805
+ halfH = Math.max(1, Math.floor(canvasHeight / (yDomain.length * 2)));
1806
+ } else {
1807
+ let tileHeight = data[0]?.height ?? geom.params.height;
1808
+ if (!tileHeight) {
1809
+ const yVals = [...new Set(data.map((r) => Number(r[aes.y])).filter((v) => !isNaN(v)))].sort((a, b) => a - b);
1810
+ if (yVals.length > 1) {
1811
+ tileHeight = yVals[1] - yVals[0];
1812
+ }
1779
1813
  }
1780
- if (yVals.length > 1) {
1781
- tileHeight = tileHeight ?? yVals[1] - yVals[0];
1814
+ tileHeight = tileHeight ?? 1;
1815
+ const sampleY = data.find((r) => r[aes.y] !== null && r[aes.y] !== undefined)?.[aes.y];
1816
+ if (sampleY !== undefined) {
1817
+ const cy = scales.y.map(sampleY);
1818
+ halfH = Math.max(1, Math.floor(Math.abs(scales.y.map(Number(sampleY) + tileHeight / 2) - cy)));
1819
+ } else {
1820
+ halfH = 1;
1782
1821
  }
1783
1822
  }
1784
- tileWidth = tileWidth ?? 1;
1785
- tileHeight = tileHeight ?? 1;
1786
1823
  for (const row of data) {
1787
1824
  const xVal = row[aes.x];
1788
1825
  const yVal = row[aes.y];
@@ -1792,8 +1829,6 @@ function renderGeomTile(data, geom, aes, scales, canvas) {
1792
1829
  }
1793
1830
  const cx = Math.round(scales.x.map(xVal));
1794
1831
  const cy = Math.round(scales.y.map(yVal));
1795
- const halfW = Math.max(1, Math.floor(Math.abs(scales.x.map(Number(xVal) + tileWidth / 2) - cx)));
1796
- const halfH = Math.max(1, Math.floor(Math.abs(scales.y.map(Number(yVal) + tileHeight / 2) - cy)));
1797
1832
  let color;
1798
1833
  if (scales.color && typeof fillVal === "number") {
1799
1834
  color = scales.color.map(fillVal);
@@ -2173,6 +2208,7 @@ function renderGeom(data, geom, aes, scales, canvas, coordType) {
2173
2208
  break;
2174
2209
  case "tile":
2175
2210
  case "raster":
2211
+ case "bin2d":
2176
2212
  renderGeomTile(data, geom, aes, scales, canvas);
2177
2213
  break;
2178
2214
  case "contour":
@@ -2202,6 +2238,26 @@ function renderGeom(data, geom, aes, scales, canvas, coordType) {
2202
2238
  break;
2203
2239
  }
2204
2240
  }
2241
+ var POINT_SHAPES, SIZE_CHARS;
2242
+ var init_render_geoms = __esm(() => {
2243
+ init_scales();
2244
+ POINT_SHAPES = {
2245
+ circle: "●",
2246
+ filled_circle: "●",
2247
+ open_circle: "○",
2248
+ square: "■",
2249
+ open_square: "□",
2250
+ diamond: "◆",
2251
+ open_diamond: "◇",
2252
+ triangle: "▲",
2253
+ open_triangle: "△",
2254
+ cross: "✕",
2255
+ plus: "+",
2256
+ star: "★",
2257
+ dot: "•"
2258
+ };
2259
+ SIZE_CHARS = ["·", "•", "●", "⬤"];
2260
+ });
2205
2261
 
2206
2262
  // src/pipeline/render-axes.ts
2207
2263
  function calculateTicks(domain, targetTicks = 5, transform, invert) {
@@ -2509,7 +2565,6 @@ function renderTitle(canvas, title, width, theme) {
2509
2565
  }
2510
2566
  canvas.drawString(x, 0, title, titleColor);
2511
2567
  }
2512
- var SIZE_SYMBOLS = ["·", "•", "●", "⬤"];
2513
2568
  function renderMultiLegend(canvas, entries, x, y, theme, width) {
2514
2569
  if (theme.legend.position === "none" || entries.length === 0)
2515
2570
  return;
@@ -2637,6 +2692,10 @@ function formatContinuousLegendValue(value) {
2637
2692
  }
2638
2693
  return value.toFixed(1);
2639
2694
  }
2695
+ var SIZE_SYMBOLS;
2696
+ var init_render_axes = __esm(() => {
2697
+ SIZE_SYMBOLS = ["·", "•", "●", "⬤"];
2698
+ });
2640
2699
 
2641
2700
  // src/stats/bin.ts
2642
2701
  function computeBins(data, field, params = {}) {
@@ -2748,6 +2807,248 @@ function stat_bin(params = {}) {
2748
2807
  };
2749
2808
  }
2750
2809
 
2810
+ // src/performance/binning.ts
2811
+ function computeDomain2(data, field) {
2812
+ let min = Infinity;
2813
+ let max = -Infinity;
2814
+ for (const d of data) {
2815
+ const v = d[field];
2816
+ if (typeof v === "number" && !isNaN(v)) {
2817
+ if (v < min)
2818
+ min = v;
2819
+ if (v > max)
2820
+ max = v;
2821
+ }
2822
+ }
2823
+ if (min === Infinity)
2824
+ return [0, 1];
2825
+ if (min === max)
2826
+ return [min - 0.5, max + 0.5];
2827
+ return [min, max];
2828
+ }
2829
+ function aggregateValues(values, method) {
2830
+ if (values.length === 0)
2831
+ return 0;
2832
+ switch (method) {
2833
+ case "count":
2834
+ return values.length;
2835
+ case "sum":
2836
+ return values.reduce((a, b) => a + b, 0);
2837
+ case "mean":
2838
+ return values.reduce((a, b) => a + b, 0) / values.length;
2839
+ case "median":
2840
+ const sorted = [...values].sort((a, b) => a - b);
2841
+ const mid = Math.floor(sorted.length / 2);
2842
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
2843
+ case "min":
2844
+ return Math.min(...values);
2845
+ case "max":
2846
+ return Math.max(...values);
2847
+ default:
2848
+ return values.length;
2849
+ }
2850
+ }
2851
+ function rectbin(data, options) {
2852
+ const {
2853
+ xField,
2854
+ yField,
2855
+ xBins = 20,
2856
+ yBins = 20,
2857
+ aggregate = "count",
2858
+ valueField
2859
+ } = options;
2860
+ if (data.length === 0)
2861
+ return [];
2862
+ const xDomain = options.xDomain ?? computeDomain2(data, xField);
2863
+ const yDomain = options.yDomain ?? computeDomain2(data, yField);
2864
+ const xRange = xDomain[1] - xDomain[0];
2865
+ const yRange = yDomain[1] - yDomain[0];
2866
+ const binWidth = xRange / xBins;
2867
+ const binHeight = yRange / yBins;
2868
+ const bins = new Map;
2869
+ for (const point of data) {
2870
+ const x = point[xField];
2871
+ const y = point[yField];
2872
+ if (typeof x !== "number" || typeof y !== "number")
2873
+ continue;
2874
+ const bx = Math.min(xBins - 1, Math.max(0, Math.floor((x - xDomain[0]) / binWidth)));
2875
+ const by = Math.min(yBins - 1, Math.max(0, Math.floor((y - yDomain[0]) / binHeight)));
2876
+ const key = `${bx},${by}`;
2877
+ if (!bins.has(key)) {
2878
+ bins.set(key, { points: [], values: [] });
2879
+ }
2880
+ const bin = bins.get(key);
2881
+ bin.points.push(point);
2882
+ if (valueField && typeof point[valueField] === "number") {
2883
+ bin.values.push(point[valueField]);
2884
+ }
2885
+ }
2886
+ const result = [];
2887
+ for (const [key, bin] of bins) {
2888
+ const [bx, by] = key.split(",").map(Number);
2889
+ const centerX = xDomain[0] + (bx + 0.5) * binWidth;
2890
+ const centerY = yDomain[0] + (by + 0.5) * binHeight;
2891
+ result.push({
2892
+ x: centerX,
2893
+ y: centerY,
2894
+ count: bin.points.length,
2895
+ value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
2896
+ width: binWidth,
2897
+ height: binHeight,
2898
+ points: bin.points
2899
+ });
2900
+ }
2901
+ return result;
2902
+ }
2903
+ function hexbin(data, options) {
2904
+ const { xField, yField, aggregate = "count", valueField, radius = 10 } = options;
2905
+ if (data.length === 0)
2906
+ return [];
2907
+ const xDomain = options.xDomain ?? computeDomain2(data, xField);
2908
+ const yDomain = options.yDomain ?? computeDomain2(data, yField);
2909
+ const hexWidth = radius * 2;
2910
+ const hexHeight = radius * Math.sqrt(3);
2911
+ const bins = new Map;
2912
+ for (const point of data) {
2913
+ const x = point[xField];
2914
+ const y = point[yField];
2915
+ if (typeof x !== "number" || typeof y !== "number")
2916
+ continue;
2917
+ const col = Math.round((x - xDomain[0]) / (hexWidth * 0.75));
2918
+ const row = Math.round((y - yDomain[0]) / hexHeight - col % 2 * 0.5);
2919
+ const key = `${col},${row}`;
2920
+ if (!bins.has(key)) {
2921
+ bins.set(key, { points: [], values: [], col, row });
2922
+ }
2923
+ const bin = bins.get(key);
2924
+ bin.points.push(point);
2925
+ if (valueField && typeof point[valueField] === "number") {
2926
+ bin.values.push(point[valueField]);
2927
+ }
2928
+ }
2929
+ function hexVertices(cx, cy, r) {
2930
+ const vertices = [];
2931
+ for (let i = 0;i < 6; i++) {
2932
+ const angle = Math.PI / 3 * i + Math.PI / 6;
2933
+ vertices.push({
2934
+ x: cx + r * Math.cos(angle),
2935
+ y: cy + r * Math.sin(angle)
2936
+ });
2937
+ }
2938
+ return vertices;
2939
+ }
2940
+ const result = [];
2941
+ for (const [, bin] of bins) {
2942
+ const centerX = xDomain[0] + bin.col * hexWidth * 0.75;
2943
+ const centerY = yDomain[0] + (bin.row + bin.col % 2 * 0.5) * hexHeight;
2944
+ result.push({
2945
+ x: centerX,
2946
+ y: centerY,
2947
+ count: bin.points.length,
2948
+ value: aggregateValues(bin.values.length > 0 ? bin.values : [bin.points.length], aggregate),
2949
+ width: hexWidth,
2950
+ height: hexHeight,
2951
+ points: bin.points,
2952
+ vertices: hexVertices(centerX, centerY, radius),
2953
+ col: bin.col,
2954
+ row: bin.row
2955
+ });
2956
+ }
2957
+ return result;
2958
+ }
2959
+
2960
+ class Binner {
2961
+ options;
2962
+ type;
2963
+ hexRadius;
2964
+ constructor(options) {
2965
+ this.options = options;
2966
+ this.type = options.type ?? "rect";
2967
+ this.hexRadius = options.hexRadius ?? 10;
2968
+ }
2969
+ bin(data) {
2970
+ if (this.type === "hex") {
2971
+ return hexbin(data, { ...this.options, radius: this.hexRadius });
2972
+ }
2973
+ return rectbin(data, this.options);
2974
+ }
2975
+ toPlotData(data) {
2976
+ const bins = this.bin(data);
2977
+ const maxCount = Math.max(...bins.map((b) => b.count));
2978
+ const minSize = 1;
2979
+ const maxSize = 5;
2980
+ return bins.map((bin) => ({
2981
+ x: bin.x,
2982
+ y: bin.y,
2983
+ count: bin.count,
2984
+ value: bin.value,
2985
+ size: minSize + bin.count / maxCount * (maxSize - minSize)
2986
+ }));
2987
+ }
2988
+ getDensityColors(bins, colorScale) {
2989
+ const maxCount = Math.max(...bins.map((b) => b.count));
2990
+ const colors = new Map;
2991
+ for (const bin of bins) {
2992
+ const t = bin.count / maxCount;
2993
+ colors.set(bin, colorScale(t));
2994
+ }
2995
+ return colors;
2996
+ }
2997
+ }
2998
+ function createBinner(options) {
2999
+ return new Binner(options);
3000
+ }
3001
+
3002
+ // src/stats/bin2d.ts
3003
+ function computeBins2d(data, xField, yField, params = {}) {
3004
+ const {
3005
+ bins = 30,
3006
+ binsx,
3007
+ binsy,
3008
+ drop = true
3009
+ } = params;
3010
+ const xBins = binsx ?? bins;
3011
+ const yBins = binsy ?? bins;
3012
+ const binned = rectbin(data, {
3013
+ xField,
3014
+ yField,
3015
+ xBins,
3016
+ yBins,
3017
+ aggregate: "count"
3018
+ });
3019
+ const total = data.length;
3020
+ const results = binned.map((bin) => ({
3021
+ x: bin.x,
3022
+ y: bin.y,
3023
+ count: bin.count,
3024
+ density: total > 0 ? bin.count / total : 0,
3025
+ width: bin.width,
3026
+ height: bin.height
3027
+ }));
3028
+ if (drop) {
3029
+ return results.filter((r) => r.count > 0);
3030
+ }
3031
+ return results;
3032
+ }
3033
+ function stat_bin2d(params = {}) {
3034
+ return {
3035
+ type: "bin2d",
3036
+ compute(data, aes) {
3037
+ const bins = computeBins2d(data, aes.x, aes.y, params);
3038
+ return bins.map((bin) => ({
3039
+ x: bin.x,
3040
+ y: bin.y,
3041
+ count: bin.count,
3042
+ density: bin.density,
3043
+ fill: bin.count,
3044
+ width: bin.width,
3045
+ height: bin.height
3046
+ }));
3047
+ }
3048
+ };
3049
+ }
3050
+ var init_bin2d = () => {};
3051
+
2751
3052
  // src/stats/boxplot.ts
2752
3053
  function quantile(sorted, p) {
2753
3054
  if (sorted.length === 0)
@@ -3163,17 +3464,6 @@ function stat_smooth(params = {}) {
3163
3464
  }
3164
3465
 
3165
3466
  // src/stats/summary.ts
3166
- var summaryFunctions = {
3167
- mean: (values) => values.reduce((a, b) => a + b, 0) / values.length,
3168
- median: (values) => {
3169
- const sorted = [...values].sort((a, b) => a - b);
3170
- const mid = Math.floor(sorted.length / 2);
3171
- return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
3172
- },
3173
- min: (values) => Math.min(...values),
3174
- max: (values) => Math.max(...values),
3175
- sum: (values) => values.reduce((a, b) => a + b, 0)
3176
- };
3177
3467
  function sd(values) {
3178
3468
  const n = values.length;
3179
3469
  if (n < 2)
@@ -3305,6 +3595,20 @@ function stat_summary(params = {}) {
3305
3595
  }
3306
3596
  };
3307
3597
  }
3598
+ var summaryFunctions;
3599
+ var init_summary = __esm(() => {
3600
+ summaryFunctions = {
3601
+ mean: (values) => values.reduce((a, b) => a + b, 0) / values.length,
3602
+ median: (values) => {
3603
+ const sorted = [...values].sort((a, b) => a - b);
3604
+ const mid = Math.floor(sorted.length / 2);
3605
+ return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
3606
+ },
3607
+ min: (values) => Math.min(...values),
3608
+ max: (values) => Math.max(...values),
3609
+ sum: (values) => values.reduce((a, b) => a + b, 0)
3610
+ };
3611
+ });
3308
3612
 
3309
3613
  // src/stats/qq.ts
3310
3614
  function qnorm(p, mean = 0, sd2 = 1) {
@@ -3488,14 +3792,6 @@ function stat_qq_line(params = {}) {
3488
3792
  }
3489
3793
 
3490
3794
  // src/facets/index.ts
3491
- var label_value = (value) => value;
3492
- var label_both = (value, variable) => variable ? `${variable}: ${value}` : value;
3493
- var label_parsed = (value) => value.replace(/_/g, " ");
3494
- var label_wrap = (width) => (value) => {
3495
- if (value.length <= width)
3496
- return value;
3497
- return value.substring(0, width - 1) + "…";
3498
- };
3499
3795
  function as_labeller(labels) {
3500
3796
  return (value) => labels[value] ?? value;
3501
3797
  }
@@ -3688,6 +3984,11 @@ function calculateGridStripLayout(totalWidth, totalHeight, nrow, ncol, hasTitle,
3688
3984
  rowStripWidth: rowStripWidth - 1
3689
3985
  };
3690
3986
  }
3987
+ var label_value = (value) => value, label_both = (value, variable) => variable ? `${variable}: ${value}` : value, label_parsed = (value) => value.replace(/_/g, " "), label_wrap = (width) => (value) => {
3988
+ if (value.length <= width)
3989
+ return value;
3990
+ return value.substring(0, width - 1) + "…";
3991
+ };
3691
3992
 
3692
3993
  // src/pipeline/pipeline.ts
3693
3994
  function calculateLayout(spec, options) {
@@ -3800,6 +4101,14 @@ function applyStatTransform(data, geom, aes) {
3800
4101
  dparams: geom.params.dparams
3801
4102
  });
3802
4103
  return qqLineStat.compute(data, aes);
4104
+ } else if (geom.stat === "bin2d") {
4105
+ const bin2dStat = stat_bin2d({
4106
+ bins: geom.params.bins,
4107
+ binsx: geom.params.binsx,
4108
+ binsy: geom.params.binsy,
4109
+ drop: geom.params.drop
4110
+ });
4111
+ return bin2dStat.compute(data, aes);
3803
4112
  }
3804
4113
  return data;
3805
4114
  }
@@ -3864,6 +4173,10 @@ function renderToCanvas(spec, options) {
3864
4173
  scaleAes = { ...spec.aes, x: "x", y: "y" };
3865
4174
  }
3866
4175
  break;
4176
+ } else if (geom.stat === "bin2d") {
4177
+ scaleData = applyStatTransform(spec.data, geom, spec.aes);
4178
+ scaleAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
4179
+ break;
3867
4180
  }
3868
4181
  }
3869
4182
  scaleData = applyCoordTransform(scaleData, scaleAes, spec.coord);
@@ -3898,6 +4211,8 @@ function renderToCanvas(spec, options) {
3898
4211
  geomAes = { ...spec.aes, x: "x", y: "y" };
3899
4212
  } else if (geom.stat === "qq_line") {
3900
4213
  geomAes = { ...spec.aes, x: "x", y: "y", xend: "xend", yend: "yend" };
4214
+ } else if (geom.stat === "bin2d") {
4215
+ geomAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
3901
4216
  }
3902
4217
  geomData = applyCoordTransform(geomData, geomAes, spec.coord);
3903
4218
  }
@@ -4148,8 +4463,14 @@ function renderPanel(canvas, panel, layout, spec, facet, sharedScales, nrow = 1,
4148
4463
  renderPanelAxes(canvas, scales, plotArea, panel.row, panel.col, nrow, ncol, spec.theme);
4149
4464
  for (const geom of spec.geoms) {
4150
4465
  let geomData = applyStatTransform(panel.data, geom, spec.aes);
4151
- geomData = applyCoordTransform(geomData, spec.aes, spec.coord);
4152
- renderGeom(geomData, geom, spec.aes, scales, canvas, spec.coord.type);
4466
+ let geomAes = spec.aes;
4467
+ if (geom.stat === "bin" || geom.stat === "boxplot" || geom.stat === "count" || geom.stat === "qq") {
4468
+ geomAes = { ...spec.aes, x: "x", y: "y" };
4469
+ } else if (geom.stat === "bin2d") {
4470
+ geomAes = { ...spec.aes, x: "x", y: "y", fill: "fill" };
4471
+ }
4472
+ geomData = applyCoordTransform(geomData, geomAes, spec.coord);
4473
+ renderGeom(geomData, geom, geomAes, scales, canvas, spec.coord.type);
4153
4474
  }
4154
4475
  }
4155
4476
  function renderPanelAxes(canvas, scales, plotArea, row, col, nrow, _ncol, _theme) {
@@ -4197,9 +4518,22 @@ function renderToString(spec, options) {
4197
4518
  }
4198
4519
  return canvas.toAnsiString();
4199
4520
  }
4521
+ var init_pipeline = __esm(() => {
4522
+ init_canvas();
4523
+ init_scales();
4524
+ init_render_geoms();
4525
+ init_render_axes();
4526
+ init_bin2d();
4527
+ init_summary();
4528
+ });
4200
4529
 
4201
4530
  // src/pipeline/index.ts
4202
- init_scales();
4531
+ var init_pipeline2 = __esm(() => {
4532
+ init_pipeline();
4533
+ init_scales();
4534
+ init_render_geoms();
4535
+ init_render_axes();
4536
+ });
4203
4537
 
4204
4538
  // src/grammar.ts
4205
4539
  class GGPlot {
@@ -4290,6 +4624,9 @@ class GGPlot {
4290
4624
  function gg(data = []) {
4291
4625
  return new GGPlot(data);
4292
4626
  }
4627
+ var init_grammar = __esm(() => {
4628
+ init_pipeline2();
4629
+ });
4293
4630
 
4294
4631
  // src/geoms/point.ts
4295
4632
  function geom_point(options = {}) {
@@ -4305,6 +4642,7 @@ function geom_point(options = {}) {
4305
4642
  }
4306
4643
  };
4307
4644
  }
4645
+
4308
4646
  // src/geoms/line.ts
4309
4647
  function geom_line(options = {}) {
4310
4648
  return {
@@ -4343,6 +4681,7 @@ function geom_vline(options) {
4343
4681
  }
4344
4682
  };
4345
4683
  }
4684
+
4346
4685
  // src/geoms/path.ts
4347
4686
  function geom_path(options = {}) {
4348
4687
  return {
@@ -4359,6 +4698,7 @@ function geom_path(options = {}) {
4359
4698
  }
4360
4699
  };
4361
4700
  }
4701
+
4362
4702
  // src/geoms/bar.ts
4363
4703
  function geom_bar(options = {}) {
4364
4704
  return {
@@ -4376,6 +4716,7 @@ function geom_bar(options = {}) {
4376
4716
  function geom_col(options = {}) {
4377
4717
  return geom_bar({ ...options, stat: "identity" });
4378
4718
  }
4719
+
4379
4720
  // src/geoms/text.ts
4380
4721
  function geom_text(options = {}) {
4381
4722
  return {
@@ -4408,6 +4749,7 @@ function geom_label(options = {}) {
4408
4749
  }
4409
4750
  };
4410
4751
  }
4752
+
4411
4753
  // src/geoms/area.ts
4412
4754
  function geom_area(options = {}) {
4413
4755
  return {
@@ -4433,6 +4775,7 @@ function geom_ribbon(options = {}) {
4433
4775
  }
4434
4776
  };
4435
4777
  }
4778
+
4436
4779
  // src/geoms/histogram.ts
4437
4780
  function geom_histogram(options = {}) {
4438
4781
  return {
@@ -4464,6 +4807,7 @@ function geom_freqpoly(options = {}) {
4464
4807
  }
4465
4808
  };
4466
4809
  }
4810
+
4467
4811
  // src/geoms/boxplot.ts
4468
4812
  function geom_boxplot(options = {}) {
4469
4813
  return {
@@ -4480,6 +4824,7 @@ function geom_boxplot(options = {}) {
4480
4824
  }
4481
4825
  };
4482
4826
  }
4827
+
4483
4828
  // src/geoms/segment.ts
4484
4829
  function geom_segment(options = {}) {
4485
4830
  return {
@@ -4512,6 +4857,7 @@ function geom_curve(options = {}) {
4512
4857
  }
4513
4858
  };
4514
4859
  }
4860
+
4515
4861
  // src/geoms/smooth.ts
4516
4862
  function geom_smooth(options = {}) {
4517
4863
  return {
@@ -4531,6 +4877,7 @@ function geom_smooth(options = {}) {
4531
4877
  }
4532
4878
  };
4533
4879
  }
4880
+
4534
4881
  // src/geoms/step.ts
4535
4882
  function geom_step(options = {}) {
4536
4883
  return {
@@ -4546,6 +4893,7 @@ function geom_step(options = {}) {
4546
4893
  }
4547
4894
  };
4548
4895
  }
4896
+
4549
4897
  // src/geoms/rug.ts
4550
4898
  function geom_rug(options = {}) {
4551
4899
  return {
@@ -4561,6 +4909,7 @@ function geom_rug(options = {}) {
4561
4909
  }
4562
4910
  };
4563
4911
  }
4912
+
4564
4913
  // src/geoms/violin.ts
4565
4914
  function geom_violin(options = {}) {
4566
4915
  return {
@@ -4578,6 +4927,7 @@ function geom_violin(options = {}) {
4578
4927
  }
4579
4928
  };
4580
4929
  }
4930
+
4581
4931
  // src/geoms/tile.ts
4582
4932
  function geom_tile(options = {}) {
4583
4933
  return {
@@ -4596,6 +4946,22 @@ function geom_tile(options = {}) {
4596
4946
  function geom_raster(options = {}) {
4597
4947
  return geom_tile(options);
4598
4948
  }
4949
+
4950
+ // src/geoms/bin2d.ts
4951
+ function geom_bin2d(options = {}) {
4952
+ return {
4953
+ type: "bin2d",
4954
+ stat: "bin2d",
4955
+ params: {
4956
+ bins: options.bins ?? 30,
4957
+ binsx: options.binsx,
4958
+ binsy: options.binsy,
4959
+ alpha: options.alpha ?? 1,
4960
+ drop: options.drop ?? true
4961
+ }
4962
+ };
4963
+ }
4964
+
4599
4965
  // src/geoms/contour.ts
4600
4966
  function geom_contour(options = {}) {
4601
4967
  return {
@@ -4638,6 +5004,7 @@ function geom_density_2d(options = {}) {
4638
5004
  }
4639
5005
  };
4640
5006
  }
5007
+
4641
5008
  // src/geoms/errorbar.ts
4642
5009
  function geom_errorbar(options = {}) {
4643
5010
  return {
@@ -4704,6 +5071,7 @@ function geom_pointrange(options = {}) {
4704
5071
  }
4705
5072
  };
4706
5073
  }
5074
+
4707
5075
  // src/geoms/rect.ts
4708
5076
  function geom_rect(options = {}) {
4709
5077
  return {
@@ -4732,6 +5100,7 @@ function geom_abline(options = {}) {
4732
5100
  }
4733
5101
  };
4734
5102
  }
5103
+
4735
5104
  // src/geoms/qq.ts
4736
5105
  function geom_qq(options = {}) {
4737
5106
  return {
@@ -4760,6 +5129,10 @@ function geom_qq_line(options = {}) {
4760
5129
  }
4761
5130
  };
4762
5131
  }
5132
+
5133
+ // src/geoms/index.ts
5134
+ var init_geoms = () => {};
5135
+
4763
5136
  // src/scales/continuous.ts
4764
5137
  function createContinuousScale(aesthetic, options = {}) {
4765
5138
  const trans = options.trans ?? "identity";
@@ -4838,6 +5211,7 @@ function scale_y2_sqrt(options = {}) {
4838
5211
  function scale_y2_reverse(options = {}) {
4839
5212
  return createContinuousScale("y2", { ...options, trans: "reverse" });
4840
5213
  }
5214
+
4841
5215
  // src/scales/discrete.ts
4842
5216
  function createDiscreteScale(aesthetic, options = {}) {
4843
5217
  const valueToPosition = new Map;
@@ -4887,123 +5261,8 @@ function scale_x_discrete(options = {}) {
4887
5261
  function scale_y_discrete(options = {}) {
4888
5262
  return createDiscreteScale("y", options);
4889
5263
  }
5264
+
4890
5265
  // src/scales/color.ts
4891
- var PALETTES = {
4892
- viridis: ["#440154", "#414487", "#2a788e", "#22a884", "#7ad151", "#fde725"],
4893
- plasma: ["#0d0887", "#6a00a8", "#b12a90", "#e16462", "#fca636", "#f0f921"],
4894
- inferno: ["#000004", "#420a68", "#932667", "#dd513a", "#fca50a", "#fcffa4"],
4895
- magma: ["#000004", "#3b0f70", "#8c2981", "#de4968", "#fe9f6d", "#fcfdbf"],
4896
- cividis: ["#002051", "#1d3f6e", "#52596a", "#7b7b78", "#a89f68", "#d9c84a", "#fdea45"],
4897
- turbo: ["#30123b", "#4662d7", "#35aaf8", "#1ae4b6", "#72fe5e", "#c8ef34", "#faba39", "#f66b19", "#ca2a04"],
4898
- Blues: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"],
4899
- Greens: ["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"],
4900
- Greys: ["#ffffff", "#f0f0f0", "#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252", "#252525", "#000000"],
4901
- Oranges: ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"],
4902
- Purples: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"],
4903
- Reds: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"],
4904
- BuGn: ["#f7fcfd", "#e5f5f9", "#ccece6", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#006d2c", "#00441b"],
4905
- BuPu: ["#f7fcfd", "#e0ecf4", "#bfd3e6", "#9ebcda", "#8c96c6", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"],
4906
- GnBu: ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"],
4907
- OrRd: ["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"],
4908
- PuBu: ["#fff7fb", "#ece7f2", "#d0d1e6", "#a6bddb", "#74a9cf", "#3690c0", "#0570b0", "#045a8d", "#023858"],
4909
- PuBuGn: ["#fff7fb", "#ece2f0", "#d0d1e6", "#a6bddb", "#67a9cf", "#3690c0", "#02818a", "#016c59", "#014636"],
4910
- PuRd: ["#f7f4f9", "#e7e1ef", "#d4b9da", "#c994c7", "#df65b0", "#e7298a", "#ce1256", "#980043", "#67001f"],
4911
- RdPu: ["#fff7f3", "#fde0dd", "#fcc5c0", "#fa9fb5", "#f768a1", "#dd3497", "#ae017e", "#7a0177", "#49006a"],
4912
- YlGn: ["#ffffe5", "#f7fcb9", "#d9f0a3", "#addd8e", "#78c679", "#41ab5d", "#238b45", "#006837", "#004529"],
4913
- YlGnBu: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"],
4914
- YlOrBr: ["#ffffe5", "#fff7bc", "#fee391", "#fec44f", "#fe9929", "#ec7014", "#cc4c02", "#993404", "#662506"],
4915
- YlOrRd: ["#ffffcc", "#ffeda0", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026"],
4916
- BrBG: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e", "#003c30"],
4917
- PiYG: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#4d9221", "#276419"],
4918
- PRGn: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837", "#00441b"],
4919
- PuOr: ["#7f3b08", "#b35806", "#e08214", "#fdb863", "#fee0b6", "#f7f7f7", "#d8daeb", "#b2abd2", "#8073ac", "#542788", "#2d004b"],
4920
- RdBu: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#f7f7f7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"],
4921
- RdGy: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#ffffff", "#e0e0e0", "#bababa", "#878787", "#4d4d4d", "#1a1a1a"],
4922
- RdYlBu: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee090", "#ffffbf", "#e0f3f8", "#abd9e9", "#74add1", "#4575b4", "#313695"],
4923
- RdYlGn: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"],
4924
- Spectral: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"],
4925
- category10: [
4926
- "#1f77b4",
4927
- "#ff7f0e",
4928
- "#2ca02c",
4929
- "#d62728",
4930
- "#9467bd",
4931
- "#8c564b",
4932
- "#e377c2",
4933
- "#7f7f7f",
4934
- "#bcbd22",
4935
- "#17becf"
4936
- ],
4937
- category20: [
4938
- "#1f77b4",
4939
- "#aec7e8",
4940
- "#ff7f0e",
4941
- "#ffbb78",
4942
- "#2ca02c",
4943
- "#98df8a",
4944
- "#d62728",
4945
- "#ff9896",
4946
- "#9467bd",
4947
- "#c5b0d5",
4948
- "#8c564b",
4949
- "#c49c94",
4950
- "#e377c2",
4951
- "#f7b6d2",
4952
- "#7f7f7f",
4953
- "#c7c7c7",
4954
- "#bcbd22",
4955
- "#dbdb8d",
4956
- "#17becf",
4957
- "#9edae5"
4958
- ],
4959
- Accent: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"],
4960
- Dark2: ["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"],
4961
- Paired: ["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6", "#6a3d9a", "#ffff99", "#b15928"],
4962
- Pastel1: ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec", "#f2f2f2"],
4963
- Pastel2: ["#b3e2cd", "#fdcdac", "#cbd5e8", "#f4cae4", "#e6f5c9", "#fff2ae", "#f1e2cc", "#cccccc"],
4964
- Set1: ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf", "#999999"],
4965
- Set2: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"],
4966
- Set3: ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"],
4967
- Tab10: [
4968
- "#4e79a7",
4969
- "#f28e2c",
4970
- "#e15759",
4971
- "#76b7b2",
4972
- "#59a14f",
4973
- "#edc949",
4974
- "#af7aa1",
4975
- "#ff9da7",
4976
- "#9c755f",
4977
- "#bab0ab"
4978
- ],
4979
- Tab20: [
4980
- "#4e79a7",
4981
- "#a0cbe8",
4982
- "#f28e2c",
4983
- "#ffbe7d",
4984
- "#59a14f",
4985
- "#8cd17d",
4986
- "#b6992d",
4987
- "#f1ce63",
4988
- "#499894",
4989
- "#86bcb6",
4990
- "#e15759",
4991
- "#ff9d9a",
4992
- "#79706e",
4993
- "#bab0ac",
4994
- "#d37295",
4995
- "#fabfd2",
4996
- "#b07aa1",
4997
- "#d4a6c8",
4998
- "#9d7660",
4999
- "#d7b5a6"
5000
- ],
5001
- thermal: ["#042333", "#2c3e50", "#0b5345", "#1e8449", "#f39c12", "#e74c3c", "#fadbd8"],
5002
- haline: ["#2c3e50", "#1a5276", "#2980b9", "#5dade2", "#aed6f1", "#d5f5e3"],
5003
- terrain: ["#333399", "#0099ff", "#00cc00", "#ffff00", "#ff9900", "#cc6600", "#996633", "#ffffff"],
5004
- rainbow: ["#ff0000", "#ff8000", "#ffff00", "#80ff00", "#00ff00", "#00ff80", "#00ffff", "#0080ff", "#0000ff", "#8000ff"],
5005
- cubehelix: ["#000000", "#1a1530", "#30304d", "#4d5366", "#6d826e", "#8ab17d", "#add38a", "#dae8a2", "#ffffff"]
5006
- };
5007
5266
  function hexToRgba(hex) {
5008
5267
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
5009
5268
  if (!result)
@@ -5224,6 +5483,126 @@ function getAvailablePalettes() {
5224
5483
  function getPaletteColors(name) {
5225
5484
  return PALETTES[name];
5226
5485
  }
5486
+ var PALETTES;
5487
+ var init_color = __esm(() => {
5488
+ PALETTES = {
5489
+ viridis: ["#440154", "#414487", "#2a788e", "#22a884", "#7ad151", "#fde725"],
5490
+ plasma: ["#0d0887", "#6a00a8", "#b12a90", "#e16462", "#fca636", "#f0f921"],
5491
+ inferno: ["#000004", "#420a68", "#932667", "#dd513a", "#fca50a", "#fcffa4"],
5492
+ magma: ["#000004", "#3b0f70", "#8c2981", "#de4968", "#fe9f6d", "#fcfdbf"],
5493
+ cividis: ["#002051", "#1d3f6e", "#52596a", "#7b7b78", "#a89f68", "#d9c84a", "#fdea45"],
5494
+ turbo: ["#30123b", "#4662d7", "#35aaf8", "#1ae4b6", "#72fe5e", "#c8ef34", "#faba39", "#f66b19", "#ca2a04"],
5495
+ Blues: ["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"],
5496
+ Greens: ["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"],
5497
+ Greys: ["#ffffff", "#f0f0f0", "#d9d9d9", "#bdbdbd", "#969696", "#737373", "#525252", "#252525", "#000000"],
5498
+ Oranges: ["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"],
5499
+ Purples: ["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"],
5500
+ Reds: ["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"],
5501
+ BuGn: ["#f7fcfd", "#e5f5f9", "#ccece6", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#006d2c", "#00441b"],
5502
+ BuPu: ["#f7fcfd", "#e0ecf4", "#bfd3e6", "#9ebcda", "#8c96c6", "#8c6bb1", "#88419d", "#810f7c", "#4d004b"],
5503
+ GnBu: ["#f7fcf0", "#e0f3db", "#ccebc5", "#a8ddb5", "#7bccc4", "#4eb3d3", "#2b8cbe", "#0868ac", "#084081"],
5504
+ OrRd: ["#fff7ec", "#fee8c8", "#fdd49e", "#fdbb84", "#fc8d59", "#ef6548", "#d7301f", "#b30000", "#7f0000"],
5505
+ PuBu: ["#fff7fb", "#ece7f2", "#d0d1e6", "#a6bddb", "#74a9cf", "#3690c0", "#0570b0", "#045a8d", "#023858"],
5506
+ PuBuGn: ["#fff7fb", "#ece2f0", "#d0d1e6", "#a6bddb", "#67a9cf", "#3690c0", "#02818a", "#016c59", "#014636"],
5507
+ PuRd: ["#f7f4f9", "#e7e1ef", "#d4b9da", "#c994c7", "#df65b0", "#e7298a", "#ce1256", "#980043", "#67001f"],
5508
+ RdPu: ["#fff7f3", "#fde0dd", "#fcc5c0", "#fa9fb5", "#f768a1", "#dd3497", "#ae017e", "#7a0177", "#49006a"],
5509
+ YlGn: ["#ffffe5", "#f7fcb9", "#d9f0a3", "#addd8e", "#78c679", "#41ab5d", "#238b45", "#006837", "#004529"],
5510
+ YlGnBu: ["#ffffd9", "#edf8b1", "#c7e9b4", "#7fcdbb", "#41b6c4", "#1d91c0", "#225ea8", "#253494", "#081d58"],
5511
+ YlOrBr: ["#ffffe5", "#fff7bc", "#fee391", "#fec44f", "#fe9929", "#ec7014", "#cc4c02", "#993404", "#662506"],
5512
+ YlOrRd: ["#ffffcc", "#ffeda0", "#fed976", "#feb24c", "#fd8d3c", "#fc4e2a", "#e31a1c", "#bd0026", "#800026"],
5513
+ BrBG: ["#543005", "#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e", "#003c30"],
5514
+ PiYG: ["#8e0152", "#c51b7d", "#de77ae", "#f1b6da", "#fde0ef", "#f7f7f7", "#e6f5d0", "#b8e186", "#7fbc41", "#4d9221", "#276419"],
5515
+ PRGn: ["#40004b", "#762a83", "#9970ab", "#c2a5cf", "#e7d4e8", "#f7f7f7", "#d9f0d3", "#a6dba0", "#5aae61", "#1b7837", "#00441b"],
5516
+ PuOr: ["#7f3b08", "#b35806", "#e08214", "#fdb863", "#fee0b6", "#f7f7f7", "#d8daeb", "#b2abd2", "#8073ac", "#542788", "#2d004b"],
5517
+ RdBu: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#f7f7f7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"],
5518
+ RdGy: ["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#ffffff", "#e0e0e0", "#bababa", "#878787", "#4d4d4d", "#1a1a1a"],
5519
+ RdYlBu: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee090", "#ffffbf", "#e0f3f8", "#abd9e9", "#74add1", "#4575b4", "#313695"],
5520
+ RdYlGn: ["#a50026", "#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850", "#006837"],
5521
+ Spectral: ["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"],
5522
+ category10: [
5523
+ "#1f77b4",
5524
+ "#ff7f0e",
5525
+ "#2ca02c",
5526
+ "#d62728",
5527
+ "#9467bd",
5528
+ "#8c564b",
5529
+ "#e377c2",
5530
+ "#7f7f7f",
5531
+ "#bcbd22",
5532
+ "#17becf"
5533
+ ],
5534
+ category20: [
5535
+ "#1f77b4",
5536
+ "#aec7e8",
5537
+ "#ff7f0e",
5538
+ "#ffbb78",
5539
+ "#2ca02c",
5540
+ "#98df8a",
5541
+ "#d62728",
5542
+ "#ff9896",
5543
+ "#9467bd",
5544
+ "#c5b0d5",
5545
+ "#8c564b",
5546
+ "#c49c94",
5547
+ "#e377c2",
5548
+ "#f7b6d2",
5549
+ "#7f7f7f",
5550
+ "#c7c7c7",
5551
+ "#bcbd22",
5552
+ "#dbdb8d",
5553
+ "#17becf",
5554
+ "#9edae5"
5555
+ ],
5556
+ Accent: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"],
5557
+ Dark2: ["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"],
5558
+ Paired: ["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00", "#cab2d6", "#6a3d9a", "#ffff99", "#b15928"],
5559
+ Pastel1: ["#fbb4ae", "#b3cde3", "#ccebc5", "#decbe4", "#fed9a6", "#ffffcc", "#e5d8bd", "#fddaec", "#f2f2f2"],
5560
+ Pastel2: ["#b3e2cd", "#fdcdac", "#cbd5e8", "#f4cae4", "#e6f5c9", "#fff2ae", "#f1e2cc", "#cccccc"],
5561
+ Set1: ["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf", "#999999"],
5562
+ Set2: ["#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854", "#ffd92f", "#e5c494", "#b3b3b3"],
5563
+ Set3: ["#8dd3c7", "#ffffb3", "#bebada", "#fb8072", "#80b1d3", "#fdb462", "#b3de69", "#fccde5", "#d9d9d9", "#bc80bd", "#ccebc5", "#ffed6f"],
5564
+ Tab10: [
5565
+ "#4e79a7",
5566
+ "#f28e2c",
5567
+ "#e15759",
5568
+ "#76b7b2",
5569
+ "#59a14f",
5570
+ "#edc949",
5571
+ "#af7aa1",
5572
+ "#ff9da7",
5573
+ "#9c755f",
5574
+ "#bab0ab"
5575
+ ],
5576
+ Tab20: [
5577
+ "#4e79a7",
5578
+ "#a0cbe8",
5579
+ "#f28e2c",
5580
+ "#ffbe7d",
5581
+ "#59a14f",
5582
+ "#8cd17d",
5583
+ "#b6992d",
5584
+ "#f1ce63",
5585
+ "#499894",
5586
+ "#86bcb6",
5587
+ "#e15759",
5588
+ "#ff9d9a",
5589
+ "#79706e",
5590
+ "#bab0ac",
5591
+ "#d37295",
5592
+ "#fabfd2",
5593
+ "#b07aa1",
5594
+ "#d4a6c8",
5595
+ "#9d7660",
5596
+ "#d7b5a6"
5597
+ ],
5598
+ thermal: ["#042333", "#2c3e50", "#0b5345", "#1e8449", "#f39c12", "#e74c3c", "#fadbd8"],
5599
+ haline: ["#2c3e50", "#1a5276", "#2980b9", "#5dade2", "#aed6f1", "#d5f5e3"],
5600
+ terrain: ["#333399", "#0099ff", "#00cc00", "#ffff00", "#ff9900", "#cc6600", "#996633", "#ffffff"],
5601
+ rainbow: ["#ff0000", "#ff8000", "#ffff00", "#80ff00", "#00ff00", "#00ff80", "#00ffff", "#0080ff", "#0000ff", "#8000ff"],
5602
+ cubehelix: ["#000000", "#1a1530", "#30304d", "#4d5366", "#6d826e", "#8ab17d", "#add38a", "#dae8a2", "#ffffff"]
5603
+ };
5604
+ });
5605
+
5227
5606
  // src/scales/size.ts
5228
5607
  function scale_size_continuous(options = {}) {
5229
5608
  const range = options.range ?? [1, 6];
@@ -5292,45 +5671,8 @@ function scale_size_binned(options = {}) {
5292
5671
  }
5293
5672
  };
5294
5673
  }
5674
+
5295
5675
  // src/scales/shape.ts
5296
- var DEFAULT_SHAPES = [
5297
- "circle",
5298
- "square",
5299
- "triangle",
5300
- "diamond",
5301
- "cross",
5302
- "plus",
5303
- "star",
5304
- "open_circle",
5305
- "open_square",
5306
- "open_triangle",
5307
- "open_diamond",
5308
- "dot"
5309
- ];
5310
- var SHAPE_CHARS = {
5311
- circle: "●",
5312
- filled_circle: "●",
5313
- open_circle: "○",
5314
- square: "■",
5315
- filled_square: "■",
5316
- open_square: "□",
5317
- triangle: "▲",
5318
- filled_triangle: "▲",
5319
- open_triangle: "△",
5320
- triangle_down: "▼",
5321
- diamond: "◆",
5322
- filled_diamond: "◆",
5323
- open_diamond: "◇",
5324
- cross: "✕",
5325
- plus: "+",
5326
- star: "★",
5327
- open_star: "☆",
5328
- dot: "•",
5329
- bullet: "•",
5330
- asterisk: "*",
5331
- hash: "#",
5332
- at: "@"
5333
- };
5334
5676
  function scale_shape_discrete(options = {}) {
5335
5677
  const shapes = options.values ?? DEFAULT_SHAPES;
5336
5678
  return {
@@ -5389,6 +5731,48 @@ function scale_shape_ordinal(options = {}) {
5389
5731
  }
5390
5732
  };
5391
5733
  }
5734
+ var DEFAULT_SHAPES, SHAPE_CHARS;
5735
+ var init_shape = __esm(() => {
5736
+ DEFAULT_SHAPES = [
5737
+ "circle",
5738
+ "square",
5739
+ "triangle",
5740
+ "diamond",
5741
+ "cross",
5742
+ "plus",
5743
+ "star",
5744
+ "open_circle",
5745
+ "open_square",
5746
+ "open_triangle",
5747
+ "open_diamond",
5748
+ "dot"
5749
+ ];
5750
+ SHAPE_CHARS = {
5751
+ circle: "●",
5752
+ filled_circle: "●",
5753
+ open_circle: "○",
5754
+ square: "■",
5755
+ filled_square: "■",
5756
+ open_square: "□",
5757
+ triangle: "▲",
5758
+ filled_triangle: "▲",
5759
+ open_triangle: "△",
5760
+ triangle_down: "▼",
5761
+ diamond: "◆",
5762
+ filled_diamond: "◆",
5763
+ open_diamond: "◇",
5764
+ cross: "✕",
5765
+ plus: "+",
5766
+ star: "★",
5767
+ open_star: "☆",
5768
+ dot: "•",
5769
+ bullet: "•",
5770
+ asterisk: "*",
5771
+ hash: "#",
5772
+ at: "@"
5773
+ };
5774
+ });
5775
+
5392
5776
  // src/scales/alpha.ts
5393
5777
  function scale_alpha_continuous(options = {}) {
5394
5778
  const range = options.range ?? [0.1, 1];
@@ -5485,17 +5869,8 @@ function scale_alpha_binned(options = {}) {
5485
5869
  }
5486
5870
  };
5487
5871
  }
5872
+
5488
5873
  // src/scales/datetime.ts
5489
- var TIME_INTERVALS = [
5490
- { name: "millisecond", ms: 1 },
5491
- { name: "second", ms: 1000 },
5492
- { name: "minute", ms: 60 * 1000 },
5493
- { name: "hour", ms: 60 * 60 * 1000 },
5494
- { name: "day", ms: 24 * 60 * 60 * 1000 },
5495
- { name: "week", ms: 7 * 24 * 60 * 60 * 1000 },
5496
- { name: "month", ms: 30 * 24 * 60 * 60 * 1000 },
5497
- { name: "year", ms: 365 * 24 * 60 * 60 * 1000 }
5498
- ];
5499
5874
  function parseDateTime(value) {
5500
5875
  if (value === null || value === undefined)
5501
5876
  return null;
@@ -5677,7 +6052,30 @@ function scale_y_duration(options = {}) {
5677
6052
  scale.aesthetic = "y";
5678
6053
  return scale;
5679
6054
  }
6055
+ var TIME_INTERVALS;
6056
+ var init_datetime = __esm(() => {
6057
+ TIME_INTERVALS = [
6058
+ { name: "millisecond", ms: 1 },
6059
+ { name: "second", ms: 1000 },
6060
+ { name: "minute", ms: 60 * 1000 },
6061
+ { name: "hour", ms: 60 * 60 * 1000 },
6062
+ { name: "day", ms: 24 * 60 * 60 * 1000 },
6063
+ { name: "week", ms: 7 * 24 * 60 * 60 * 1000 },
6064
+ { name: "month", ms: 30 * 24 * 60 * 60 * 1000 },
6065
+ { name: "year", ms: 365 * 24 * 60 * 60 * 1000 }
6066
+ ];
6067
+ });
6068
+
6069
+ // src/scales/index.ts
6070
+ var init_scales2 = __esm(() => {
6071
+ init_color();
6072
+ init_shape();
6073
+ init_datetime();
6074
+ });
6075
+
5680
6076
  // src/repl/repl.ts
6077
+ import * as readline from "readline";
6078
+
5681
6079
  class GGTermREPL {
5682
6080
  rl = null;
5683
6081
  state;
@@ -6312,7 +6710,19 @@ function startREPL(options) {
6312
6710
  repl.start();
6313
6711
  return repl;
6314
6712
  }
6713
+ var init_repl = __esm(() => {
6714
+ init_grammar();
6715
+ init_geoms();
6716
+ init_scales2();
6717
+ });
6718
+
6719
+ // src/repl/index.ts
6720
+ var init_repl2 = __esm(() => {
6721
+ init_repl();
6722
+ });
6723
+
6315
6724
  // src/cli.ts
6725
+ init_repl2();
6316
6726
  import * as fs from "fs";
6317
6727
  import * as path from "path";
6318
6728
  var VERSION = "0.0.1";