@uwdata/mosaic-plot 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -155,8 +155,8 @@ var require_interval_tree = __commonJS({
155
155
  a2.rightPoints = b.rightPoints;
156
156
  a2.count = b.count;
157
157
  }
158
- function rebuild(node, intervals) {
159
- var ntree = createIntervalTree(intervals);
158
+ function rebuild(node, intervals2) {
159
+ var ntree = createIntervalTree(intervals2);
160
160
  node.mid = ntree.mid;
161
161
  node.left = ntree.left;
162
162
  node.right = ntree.right;
@@ -165,18 +165,18 @@ var require_interval_tree = __commonJS({
165
165
  node.count = ntree.count;
166
166
  }
167
167
  function rebuildWithInterval(node, interval2) {
168
- var intervals = node.intervals([]);
169
- intervals.push(interval2);
170
- rebuild(node, intervals);
168
+ var intervals2 = node.intervals([]);
169
+ intervals2.push(interval2);
170
+ rebuild(node, intervals2);
171
171
  }
172
172
  function rebuildWithoutInterval(node, interval2) {
173
- var intervals = node.intervals([]);
174
- var idx = intervals.indexOf(interval2);
173
+ var intervals2 = node.intervals([]);
174
+ var idx = intervals2.indexOf(interval2);
175
175
  if (idx < 0) {
176
176
  return NOT_FOUND;
177
177
  }
178
- intervals.splice(idx, 1);
179
- rebuild(node, intervals);
178
+ intervals2.splice(idx, 1);
179
+ rebuild(node, intervals2);
180
180
  return SUCCESS;
181
181
  }
182
182
  proto.intervals = function(result) {
@@ -393,21 +393,21 @@ var require_interval_tree = __commonJS({
393
393
  }
394
394
  return a2[0] - b[0];
395
395
  }
396
- function createIntervalTree(intervals) {
397
- if (intervals.length === 0) {
396
+ function createIntervalTree(intervals2) {
397
+ if (intervals2.length === 0) {
398
398
  return null;
399
399
  }
400
400
  var pts = [];
401
- for (var i = 0; i < intervals.length; ++i) {
402
- pts.push(intervals[i][0], intervals[i][1]);
401
+ for (var i = 0; i < intervals2.length; ++i) {
402
+ pts.push(intervals2[i][0], intervals2[i][1]);
403
403
  }
404
404
  pts.sort(compareNumbers);
405
405
  var mid2 = pts[pts.length >> 1];
406
406
  var leftIntervals = [];
407
407
  var rightIntervals = [];
408
408
  var centerIntervals = [];
409
- for (var i = 0; i < intervals.length; ++i) {
410
- var s2 = intervals[i];
409
+ for (var i = 0; i < intervals2.length; ++i) {
410
+ var s2 = intervals2[i];
411
411
  if (s2[1] < mid2) {
412
412
  leftIntervals.push(s2);
413
413
  } else if (mid2 < s2[0]) {
@@ -475,11 +475,11 @@ var require_interval_tree = __commonJS({
475
475
  return [];
476
476
  }
477
477
  });
478
- function createWrapper(intervals) {
479
- if (!intervals || intervals.length === 0) {
478
+ function createWrapper(intervals2) {
479
+ if (!intervals2 || intervals2.length === 0) {
480
480
  return new IntervalTree2(null);
481
481
  }
482
- return new IntervalTree2(createIntervalTree(intervals));
482
+ return new IntervalTree2(createIntervalTree(intervals2));
483
483
  }
484
484
  }
485
485
  });
@@ -608,7 +608,6 @@ var MosaicClient = class {
608
608
  * @returns {this}
609
609
  */
610
610
  queryError(error) {
611
- console.error(error);
612
611
  return this;
613
612
  }
614
613
  /**
@@ -632,7 +631,7 @@ var MosaicClient = class {
632
631
  /**
633
632
  * Requests a client update.
634
633
  * For example to (re-)render an interface component.
635
- *
634
+ *
636
635
  * @returns {this | Promise<any>}
637
636
  */
638
637
  update() {
@@ -696,16 +695,24 @@ function __await(v2) {
696
695
  function __asyncGenerator(thisArg, _arguments, generator) {
697
696
  if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
698
697
  var g = generator.apply(thisArg, _arguments || []), i, q = [];
699
- return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {
698
+ return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function() {
700
699
  return this;
701
700
  }, i;
702
- function verb(n) {
703
- if (g[n]) i[n] = function(v2) {
704
- return new Promise(function(a2, b) {
705
- q.push([n, v2, a2, b]) > 1 || resume(n, v2);
706
- });
701
+ function awaitReturn(f) {
702
+ return function(v2) {
703
+ return Promise.resolve(v2).then(f, reject);
707
704
  };
708
705
  }
706
+ function verb(n, f) {
707
+ if (g[n]) {
708
+ i[n] = function(v2) {
709
+ return new Promise(function(a2, b) {
710
+ q.push([n, v2, a2, b]) > 1 || resume(n, v2);
711
+ });
712
+ };
713
+ if (f) i[n] = f(i[n]);
714
+ }
715
+ }
709
716
  function resume(n, v2) {
710
717
  try {
711
718
  step(g[n](v2));
@@ -1325,26 +1332,26 @@ var IntervalUnit;
1325
1332
  IntervalUnit2[IntervalUnit2["MONTH_DAY_NANO"] = 2] = "MONTH_DAY_NANO";
1326
1333
  })(IntervalUnit || (IntervalUnit = {}));
1327
1334
 
1328
- // ../../node_modules/flatbuffers/mjs/constants.js
1335
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/constants.js
1329
1336
  var SIZEOF_SHORT = 2;
1330
1337
  var SIZEOF_INT = 4;
1331
1338
  var FILE_IDENTIFIER_LENGTH = 4;
1332
1339
  var SIZE_PREFIX_LENGTH = 4;
1333
1340
 
1334
- // ../../node_modules/flatbuffers/mjs/utils.js
1341
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/utils.js
1335
1342
  var int32 = new Int32Array(2);
1336
1343
  var float32 = new Float32Array(int32.buffer);
1337
1344
  var float64 = new Float64Array(int32.buffer);
1338
1345
  var isLittleEndian = new Uint16Array(new Uint8Array([1, 0]).buffer)[0] === 1;
1339
1346
 
1340
- // ../../node_modules/flatbuffers/mjs/encoding.js
1347
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/encoding.js
1341
1348
  var Encoding;
1342
1349
  (function(Encoding2) {
1343
1350
  Encoding2[Encoding2["UTF8_BYTES"] = 1] = "UTF8_BYTES";
1344
1351
  Encoding2[Encoding2["UTF16_STRING"] = 2] = "UTF16_STRING";
1345
1352
  })(Encoding || (Encoding = {}));
1346
1353
 
1347
- // ../../node_modules/flatbuffers/mjs/byte-buffer.js
1354
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/byte-buffer.js
1348
1355
  var ByteBuffer = class _ByteBuffer {
1349
1356
  /**
1350
1357
  * Create a new ByteBuffer with a given array of bytes (`Uint8Array`)
@@ -1588,7 +1595,7 @@ var ByteBuffer = class _ByteBuffer {
1588
1595
  }
1589
1596
  };
1590
1597
 
1591
- // ../../node_modules/flatbuffers/mjs/builder.js
1598
+ // ../../node_modules/apache-arrow/node_modules/flatbuffers/mjs/builder.js
1592
1599
  var Builder = class _Builder {
1593
1600
  /**
1594
1601
  * Create a FlatBufferBuilder.
@@ -2028,9 +2035,22 @@ var Builder = class _Builder {
2028
2035
  this.addInt8(0);
2029
2036
  this.startVector(1, utf8.length, 1);
2030
2037
  this.bb.setPosition(this.space -= utf8.length);
2031
- for (let i = 0, offset2 = this.space, bytes = this.bb.bytes(); i < utf8.length; i++) {
2032
- bytes[offset2++] = utf8[i];
2038
+ this.bb.bytes().set(utf8, this.space);
2039
+ return this.endVector();
2040
+ }
2041
+ /**
2042
+ * Create a byte vector.
2043
+ *
2044
+ * @param v The bytes to add
2045
+ * @returns The offset in the buffer where the byte vector starts
2046
+ */
2047
+ createByteVector(v2) {
2048
+ if (v2 === null || v2 === void 0) {
2049
+ return 0;
2033
2050
  }
2051
+ this.startVector(1, v2.length, 1);
2052
+ this.bb.setPosition(this.space -= v2.length);
2053
+ this.bb.bytes().set(v2, this.space);
2034
2054
  return this.endVector();
2035
2055
  }
2036
2056
  /**
@@ -3633,9 +3653,9 @@ var BufferType;
3633
3653
  // ../../node_modules/apache-arrow/util/vector.mjs
3634
3654
  var vector_exports = {};
3635
3655
  __export(vector_exports, {
3636
- clampIndex: () => clampIndex,
3637
3656
  clampRange: () => clampRange,
3638
- createElementComparator: () => createElementComparator
3657
+ createElementComparator: () => createElementComparator,
3658
+ wrapIndex: () => wrapIndex
3639
3659
  });
3640
3660
 
3641
3661
  // ../../node_modules/apache-arrow/util/pretty.mjs
@@ -3676,9 +3696,23 @@ var bn_exports = {};
3676
3696
  __export(bn_exports, {
3677
3697
  BN: () => BN,
3678
3698
  bigNumToBigInt: () => bigNumToBigInt,
3699
+ bigNumToNumber: () => bigNumToNumber,
3679
3700
  bigNumToString: () => bigNumToString,
3680
3701
  isArrowBigNumSymbol: () => isArrowBigNumSymbol
3681
3702
  });
3703
+
3704
+ // ../../node_modules/apache-arrow/util/bigint.mjs
3705
+ function bigIntToNumber(number7) {
3706
+ if (typeof number7 === "bigint" && (number7 < Number.MIN_SAFE_INTEGER || number7 > Number.MAX_SAFE_INTEGER)) {
3707
+ throw new TypeError(`${number7} is not safe to convert to a number.`);
3708
+ }
3709
+ return Number(number7);
3710
+ }
3711
+ function divideBigInts(number7, divisor) {
3712
+ return bigIntToNumber(number7 / divisor) + bigIntToNumber(number7 % divisor) / bigIntToNumber(divisor);
3713
+ }
3714
+
3715
+ // ../../node_modules/apache-arrow/util/bn.mjs
3682
3716
  var isArrowBigNumSymbol = Symbol.for("isArrowBigNum");
3683
3717
  function BigNum(x3, ...xs) {
3684
3718
  if (xs.length === 0) {
@@ -3690,8 +3724,8 @@ BigNum.prototype[isArrowBigNumSymbol] = true;
3690
3724
  BigNum.prototype.toJSON = function() {
3691
3725
  return `"${bigNumToString(this)}"`;
3692
3726
  };
3693
- BigNum.prototype.valueOf = function() {
3694
- return bigNumToNumber(this);
3727
+ BigNum.prototype.valueOf = function(scale3) {
3728
+ return bigNumToNumber(this, scale3);
3695
3729
  };
3696
3730
  BigNum.prototype.toString = function() {
3697
3731
  return bigNumToString(this);
@@ -3722,25 +3756,34 @@ Object.setPrototypeOf(DecimalBigNum.prototype, Object.create(Uint32Array.prototy
3722
3756
  Object.assign(SignedBigNum.prototype, BigNum.prototype, { "constructor": SignedBigNum, "signed": true, "TypedArray": Int32Array, "BigIntArray": BigInt64Array });
3723
3757
  Object.assign(UnsignedBigNum.prototype, BigNum.prototype, { "constructor": UnsignedBigNum, "signed": false, "TypedArray": Uint32Array, "BigIntArray": BigUint64Array });
3724
3758
  Object.assign(DecimalBigNum.prototype, BigNum.prototype, { "constructor": DecimalBigNum, "signed": true, "TypedArray": Uint32Array, "BigIntArray": BigUint64Array });
3725
- function bigNumToNumber(bn) {
3726
- const { buffer, byteOffset, length: length4, "signed": signed } = bn;
3727
- const words = new BigUint64Array(buffer, byteOffset, length4);
3759
+ var TWO_TO_THE_64 = BigInt(4294967296) * BigInt(4294967296);
3760
+ var TWO_TO_THE_64_MINUS_1 = TWO_TO_THE_64 - BigInt(1);
3761
+ function bigNumToNumber(bn, scale3) {
3762
+ const { buffer, byteOffset, byteLength, "signed": signed } = bn;
3763
+ const words = new BigUint64Array(buffer, byteOffset, byteLength / 8);
3728
3764
  const negative2 = signed && words.at(-1) & BigInt(1) << BigInt(63);
3729
- let number7 = negative2 ? BigInt(1) : BigInt(0);
3730
- let i = BigInt(0);
3731
- if (!negative2) {
3765
+ let number7 = BigInt(0);
3766
+ let i = 0;
3767
+ if (negative2) {
3732
3768
  for (const word of words) {
3733
- number7 += word * (BigInt(1) << BigInt(32) * i++);
3769
+ number7 |= (word ^ TWO_TO_THE_64_MINUS_1) * (BigInt(1) << BigInt(64 * i++));
3734
3770
  }
3771
+ number7 *= BigInt(-1);
3772
+ number7 -= BigInt(1);
3735
3773
  } else {
3736
3774
  for (const word of words) {
3737
- number7 += ~word * (BigInt(1) << BigInt(32) * i++);
3775
+ number7 |= word * (BigInt(1) << BigInt(64 * i++));
3738
3776
  }
3739
- number7 *= BigInt(-1);
3740
3777
  }
3741
- return number7;
3778
+ if (typeof scale3 === "number") {
3779
+ const denominator = BigInt(Math.pow(10, scale3));
3780
+ const quotient = number7 / denominator;
3781
+ const remainder = number7 % denominator;
3782
+ return bigIntToNumber(quotient) + bigIntToNumber(remainder) / bigIntToNumber(denominator);
3783
+ }
3784
+ return bigIntToNumber(number7);
3742
3785
  }
3743
- var bigNumToString = (a2) => {
3786
+ function bigNumToString(a2) {
3744
3787
  if (a2.byteLength === 8) {
3745
3788
  const bigIntArray = new a2["BigIntArray"](a2.buffer, a2.byteOffset, 1);
3746
3789
  return `${bigIntArray[0]}`;
@@ -3763,15 +3806,15 @@ var bigNumToString = (a2) => {
3763
3806
  }
3764
3807
  const negated = unsignedBigNumToString(array4);
3765
3808
  return `-${negated}`;
3766
- };
3767
- var bigNumToBigInt = (a2) => {
3809
+ }
3810
+ function bigNumToBigInt(a2) {
3768
3811
  if (a2.byteLength === 8) {
3769
3812
  const bigIntArray = new a2["BigIntArray"](a2.buffer, a2.byteOffset, 1);
3770
3813
  return bigIntArray[0];
3771
3814
  } else {
3772
3815
  return bigNumToString(a2);
3773
3816
  }
3774
- };
3817
+ }
3775
3818
  function unsignedBigNumToString(a2) {
3776
3819
  let digits = "";
3777
3820
  const base64 = new Uint32Array(2);
@@ -3828,14 +3871,6 @@ var BN = class _BN {
3828
3871
  }
3829
3872
  };
3830
3873
 
3831
- // ../../node_modules/apache-arrow/util/bigint.mjs
3832
- function bigIntToNumber(number7) {
3833
- if (typeof number7 === "bigint" && (number7 < Number.MIN_SAFE_INTEGER || number7 > Number.MAX_SAFE_INTEGER)) {
3834
- throw new TypeError(`${number7} is not safe to convert to a number.`);
3835
- }
3836
- return Number(number7);
3837
- }
3838
-
3839
3874
  // ../../node_modules/apache-arrow/type.mjs
3840
3875
  var _a;
3841
3876
  var _b;
@@ -4210,11 +4245,13 @@ var Date_ = class extends DataType {
4210
4245
  toString() {
4211
4246
  return `Date${(this.unit + 1) * 32}<${DateUnit[this.unit]}>`;
4212
4247
  }
4248
+ get ArrayType() {
4249
+ return this.unit === DateUnit.DAY ? Int32Array : BigInt64Array;
4250
+ }
4213
4251
  };
4214
4252
  _l = Symbol.toStringTag;
4215
4253
  Date_[_l] = ((proto) => {
4216
4254
  proto.unit = null;
4217
- proto.ArrayType = Int32Array;
4218
4255
  return proto[Symbol.toStringTag] = "Date";
4219
4256
  })(Date_.prototype);
4220
4257
  var Time_ = class extends DataType {
@@ -4256,7 +4293,7 @@ _o = Symbol.toStringTag;
4256
4293
  Timestamp_[_o] = ((proto) => {
4257
4294
  proto.unit = null;
4258
4295
  proto.timezone = null;
4259
- proto.ArrayType = Int32Array;
4296
+ proto.ArrayType = BigInt64Array;
4260
4297
  return proto[Symbol.toStringTag] = "Timestamp";
4261
4298
  })(Timestamp_.prototype);
4262
4299
  var Interval_ = class extends DataType {
@@ -4428,9 +4465,9 @@ Map_[_w] = ((proto) => {
4428
4465
  })(Map_.prototype);
4429
4466
  var getId = /* @__PURE__ */ ((atomicDictionaryId) => () => ++atomicDictionaryId)(-1);
4430
4467
  var Dictionary = class extends DataType {
4431
- constructor(dictionary, indices, id2, isOrdered2) {
4468
+ constructor(dictionary, indices2, id2, isOrdered2) {
4432
4469
  super(Type2.Dictionary);
4433
- this.indices = indices;
4470
+ this.indices = indices2;
4434
4471
  this.dictionary = dictionary;
4435
4472
  this.isOrdered = isOrdered2 || false;
4436
4473
  this.id = id2 == null ? getId() : bigIntToNumber(id2);
@@ -4461,10 +4498,6 @@ function strideForType(type2) {
4461
4498
  switch (type2.typeId) {
4462
4499
  case Type2.Decimal:
4463
4500
  return type2.bitWidth / 32;
4464
- case Type2.Timestamp:
4465
- return 2;
4466
- case Type2.Date:
4467
- return 1 + t.unit;
4468
4501
  case Type2.Interval:
4469
4502
  return 1 + t.unit;
4470
4503
  case Type2.FixedSizeList:
@@ -4931,19 +4964,7 @@ function wrapSet(fn) {
4931
4964
  };
4932
4965
  }
4933
4966
  var setEpochMsToDays = (data, index2, epochMs) => {
4934
- data[index2] = Math.trunc(epochMs / 864e5);
4935
- };
4936
- var setEpochMsToMillisecondsLong = (data, index2, epochMs) => {
4937
- data[index2] = Math.trunc(epochMs % 4294967296);
4938
- data[index2 + 1] = Math.trunc(epochMs / 4294967296);
4939
- };
4940
- var setEpochMsToMicrosecondsLong = (data, index2, epochMs) => {
4941
- data[index2] = Math.trunc(epochMs * 1e3 % 4294967296);
4942
- data[index2 + 1] = Math.trunc(epochMs * 1e3 / 4294967296);
4943
- };
4944
- var setEpochMsToNanosecondsLong = (data, index2, epochMs) => {
4945
- data[index2] = Math.trunc(epochMs * 1e6 % 4294967296);
4946
- data[index2 + 1] = Math.trunc(epochMs * 1e6 / 4294967296);
4967
+ data[index2] = Math.floor(epochMs / 864e5);
4947
4968
  };
4948
4969
  var setVariableWidthBytes = (values2, valueOffsets, index2, value) => {
4949
4970
  if (index2 + 1 < valueOffsets.length) {
@@ -4978,7 +4999,7 @@ var setDateDay = ({ values: values2 }, index2, value) => {
4978
4999
  setEpochMsToDays(values2, index2, value.valueOf());
4979
5000
  };
4980
5001
  var setDateMillisecond = ({ values: values2 }, index2, value) => {
4981
- setEpochMsToMillisecondsLong(values2, index2 * 2, value.valueOf());
5002
+ values2[index2] = BigInt(value);
4982
5003
  };
4983
5004
  var setFixedSizeBinary = ({ stride, values: values2 }, index2, value) => {
4984
5005
  values2.set(value.subarray(0, stride), stride * index2);
@@ -4988,10 +5009,18 @@ var setUtf8 = ({ values: values2, valueOffsets }, index2, value) => setVariableW
4988
5009
  var setDate = (data, index2, value) => {
4989
5010
  data.type.unit === DateUnit.DAY ? setDateDay(data, index2, value) : setDateMillisecond(data, index2, value);
4990
5011
  };
4991
- var setTimestampSecond = ({ values: values2 }, index2, value) => setEpochMsToMillisecondsLong(values2, index2 * 2, value / 1e3);
4992
- var setTimestampMillisecond = ({ values: values2 }, index2, value) => setEpochMsToMillisecondsLong(values2, index2 * 2, value);
4993
- var setTimestampMicrosecond = ({ values: values2 }, index2, value) => setEpochMsToMicrosecondsLong(values2, index2 * 2, value);
4994
- var setTimestampNanosecond = ({ values: values2 }, index2, value) => setEpochMsToNanosecondsLong(values2, index2 * 2, value);
5012
+ var setTimestampSecond = ({ values: values2 }, index2, value) => {
5013
+ values2[index2] = BigInt(value / 1e3);
5014
+ };
5015
+ var setTimestampMillisecond = ({ values: values2 }, index2, value) => {
5016
+ values2[index2] = BigInt(value);
5017
+ };
5018
+ var setTimestampMicrosecond = ({ values: values2 }, index2, value) => {
5019
+ values2[index2] = BigInt(value * 1e3);
5020
+ };
5021
+ var setTimestampNanosecond = ({ values: values2 }, index2, value) => {
5022
+ values2[index2] = BigInt(value * 1e6);
5023
+ };
4995
5024
  var setTimestamp = (data, index2, value) => {
4996
5025
  switch (data.type.unit) {
4997
5026
  case TimeUnit.SECOND:
@@ -5296,12 +5325,6 @@ function wrapGet(fn) {
5296
5325
  return (data, _1) => data.getValid(_1) ? fn(data, _1) : null;
5297
5326
  }
5298
5327
  var epochDaysToMs = (data, index2) => 864e5 * data[index2];
5299
- var epochMillisecondsLongToMs = (data, index2) => 4294967296 * data[index2 + 1] + (data[index2] >>> 0);
5300
- var epochMicrosecondsLongToMs = (data, index2) => 4294967296 * (data[index2 + 1] / 1e3) + (data[index2] >>> 0) / 1e3;
5301
- var epochNanosecondsLongToMs = (data, index2) => 4294967296 * (data[index2 + 1] / 1e6) + (data[index2] >>> 0) / 1e6;
5302
- var epochMillisecondsToDate = (epochMs) => new Date(epochMs);
5303
- var epochDaysToDate = (data, index2) => epochMillisecondsToDate(epochDaysToMs(data, index2));
5304
- var epochMillisecondsLongToDate = (data, index2) => epochMillisecondsToDate(epochMillisecondsLongToMs(data, index2));
5305
5328
  var getNull = (_data, _index) => null;
5306
5329
  var getVariableWidthBytes = (values2, valueOffsets, index2) => {
5307
5330
  if (index2 + 1 >= valueOffsets.length) {
@@ -5316,8 +5339,8 @@ var getBool = ({ offset: offset2, values: values2 }, index2) => {
5316
5339
  const byte = values2[idx >> 3];
5317
5340
  return (byte & 1 << idx % 8) !== 0;
5318
5341
  };
5319
- var getDateDay = ({ values: values2 }, index2) => epochDaysToDate(values2, index2);
5320
- var getDateMillisecond = ({ values: values2 }, index2) => epochMillisecondsLongToDate(values2, index2 * 2);
5342
+ var getDateDay = ({ values: values2 }, index2) => epochDaysToMs(values2, index2);
5343
+ var getDateMillisecond = ({ values: values2 }, index2) => bigIntToNumber(values2[index2]);
5321
5344
  var getNumeric = ({ stride, values: values2 }, index2) => values2[stride * index2];
5322
5345
  var getFloat16 = ({ stride, values: values2 }, index2) => uint16ToFloat64(values2[stride * index2]);
5323
5346
  var getBigInts = ({ values: values2 }, index2) => values2[index2];
@@ -5330,10 +5353,10 @@ var getUtf8 = ({ values: values2, valueOffsets }, index2) => {
5330
5353
  var getInt = ({ values: values2 }, index2) => values2[index2];
5331
5354
  var getFloat = ({ type: type2, values: values2 }, index2) => type2.precision !== Precision.HALF ? values2[index2] : uint16ToFloat64(values2[index2]);
5332
5355
  var getDate = (data, index2) => data.type.unit === DateUnit.DAY ? getDateDay(data, index2) : getDateMillisecond(data, index2);
5333
- var getTimestampSecond = ({ values: values2 }, index2) => 1e3 * epochMillisecondsLongToMs(values2, index2 * 2);
5334
- var getTimestampMillisecond = ({ values: values2 }, index2) => epochMillisecondsLongToMs(values2, index2 * 2);
5335
- var getTimestampMicrosecond = ({ values: values2 }, index2) => epochMicrosecondsLongToMs(values2, index2 * 2);
5336
- var getTimestampNanosecond = ({ values: values2 }, index2) => epochNanosecondsLongToMs(values2, index2 * 2);
5356
+ var getTimestampSecond = ({ values: values2 }, index2) => 1e3 * bigIntToNumber(values2[index2]);
5357
+ var getTimestampMillisecond = ({ values: values2 }, index2) => bigIntToNumber(values2[index2]);
5358
+ var getTimestampMicrosecond = ({ values: values2 }, index2) => divideBigInts(values2[index2], BigInt(1e3));
5359
+ var getTimestampNanosecond = ({ values: values2 }, index2) => divideBigInts(values2[index2], BigInt(1e6));
5337
5360
  var getTimestamp = (data, index2) => {
5338
5361
  switch (data.type.unit) {
5339
5362
  case TimeUnit.SECOND:
@@ -5482,12 +5505,18 @@ var instance2 = new GetVisitor();
5482
5505
  // ../../node_modules/apache-arrow/row/map.mjs
5483
5506
  var kKeys = Symbol.for("keys");
5484
5507
  var kVals = Symbol.for("vals");
5508
+ var kKeysAsStrings = Symbol.for("kKeysAsStrings");
5509
+ var _kKeysAsStrings = Symbol.for("_kKeysAsStrings");
5485
5510
  var MapRow = class {
5486
5511
  constructor(slice4) {
5487
5512
  this[kKeys] = new Vector([slice4.children[0]]).memoize();
5488
5513
  this[kVals] = slice4.children[1];
5489
5514
  return new Proxy(this, new MapRowProxyHandler());
5490
5515
  }
5516
+ /** @ignore */
5517
+ get [kKeysAsStrings]() {
5518
+ return this[_kKeysAsStrings] || (this[_kKeysAsStrings] = Array.from(this[kKeys].toArray(), String));
5519
+ }
5491
5520
  [Symbol.iterator]() {
5492
5521
  return new MapRowIterator(this[kKeys], this[kVals]);
5493
5522
  }
@@ -5549,13 +5578,13 @@ var MapRowProxyHandler = class {
5549
5578
  return true;
5550
5579
  }
5551
5580
  ownKeys(row) {
5552
- return row[kKeys].toArray().map(String);
5581
+ return row[kKeysAsStrings];
5553
5582
  }
5554
5583
  has(row, key) {
5555
- return row[kKeys].includes(key);
5584
+ return row[kKeysAsStrings].includes(key);
5556
5585
  }
5557
5586
  getOwnPropertyDescriptor(row, key) {
5558
- const idx = row[kKeys].indexOf(key);
5587
+ const idx = row[kKeysAsStrings].indexOf(key);
5559
5588
  if (idx !== -1) {
5560
5589
  return { writable: true, enumerable: true, configurable: true };
5561
5590
  }
@@ -5565,7 +5594,7 @@ var MapRowProxyHandler = class {
5565
5594
  if (Reflect.has(row, key)) {
5566
5595
  return row[key];
5567
5596
  }
5568
- const idx = row[kKeys].indexOf(key);
5597
+ const idx = row[kKeysAsStrings].indexOf(key);
5569
5598
  if (idx !== -1) {
5570
5599
  const val = instance2.visit(Reflect.get(row, kVals), idx);
5571
5600
  Reflect.set(row, key, val);
@@ -5573,7 +5602,7 @@ var MapRowProxyHandler = class {
5573
5602
  }
5574
5603
  }
5575
5604
  set(row, key, val) {
5576
- const idx = row[kKeys].indexOf(key);
5605
+ const idx = row[kKeysAsStrings].indexOf(key);
5577
5606
  if (idx !== -1) {
5578
5607
  instance.visit(Reflect.get(row, kVals), idx, val);
5579
5608
  return Reflect.set(row, key, val);
@@ -5586,15 +5615,11 @@ var MapRowProxyHandler = class {
5586
5615
  Object.defineProperties(MapRow.prototype, {
5587
5616
  [Symbol.toStringTag]: { enumerable: false, configurable: false, value: "Row" },
5588
5617
  [kKeys]: { writable: true, enumerable: false, configurable: false, value: null },
5589
- [kVals]: { writable: true, enumerable: false, configurable: false, value: null }
5618
+ [kVals]: { writable: true, enumerable: false, configurable: false, value: null },
5619
+ [_kKeysAsStrings]: { writable: true, enumerable: false, configurable: false, value: null }
5590
5620
  });
5591
5621
 
5592
5622
  // ../../node_modules/apache-arrow/util/vector.mjs
5593
- function clampIndex(source, index2, then) {
5594
- const length4 = source.length;
5595
- const adjust = index2 > -1 ? index2 : length4 + index2 % length4;
5596
- return then ? then(source, adjust) : adjust;
5597
- }
5598
5623
  var tmp;
5599
5624
  function clampRange(source, begin, end, then) {
5600
5625
  const { length: len = 0 } = source;
@@ -5606,6 +5631,7 @@ function clampRange(source, begin, end, then) {
5606
5631
  rhs > len && (rhs = len);
5607
5632
  return then ? then(source, lhs, rhs) : [lhs, rhs];
5608
5633
  }
5634
+ var wrapIndex = (index2, len) => index2 < 0 ? len + index2 : index2;
5609
5635
  var isNaNFast = (value) => value !== value;
5610
5636
  function createElementComparator(search) {
5611
5637
  const typeofSearch = typeof search;
@@ -5894,7 +5920,10 @@ var Data = class _Data {
5894
5920
  let nullCount = this._nullCount;
5895
5921
  let nullBitmap;
5896
5922
  if (nullCount <= kUnknownNullCount && (nullBitmap = this.nullBitmap)) {
5897
- this._nullCount = nullCount = this.length - popcnt_bit_range(nullBitmap, this.offset, this.offset + this.length);
5923
+ this._nullCount = nullCount = nullBitmap.length === 0 ? (
5924
+ // no null bitmap, so all values are valid
5925
+ 0
5926
+ ) : this.length - popcnt_bit_range(nullBitmap, this.offset, this.offset + this.length);
5898
5927
  }
5899
5928
  return nullCount;
5900
5929
  }
@@ -5956,12 +5985,14 @@ var Data = class _Data {
5956
5985
  nullBitmap = new Uint8Array((offset2 + length4 + 63 & ~63) >> 3).fill(255);
5957
5986
  if (this.nullCount > 0) {
5958
5987
  nullBitmap.set(truncateBitmap(offset2, length4, this.nullBitmap), 0);
5988
+ Object.assign(this, { nullBitmap });
5989
+ } else {
5990
+ Object.assign(this, { nullBitmap, _nullCount: 0 });
5959
5991
  }
5960
- Object.assign(this, { nullBitmap, _nullCount: -1 });
5961
5992
  }
5962
5993
  const byte = nullBitmap[byteOffset];
5963
5994
  prev = (byte & mask) !== 0;
5964
- value ? nullBitmap[byteOffset] = byte | mask : nullBitmap[byteOffset] = byte & ~mask;
5995
+ nullBitmap[byteOffset] = value ? byte | mask : byte & ~mask;
5965
5996
  }
5966
5997
  if (prev !== !!value) {
5967
5998
  this._nullCount = this.nullCount + (value ? -1 : 1);
@@ -6402,7 +6433,9 @@ var IteratorVisitor = class extends Visitor {
6402
6433
  };
6403
6434
  function vectorIterator(vector2) {
6404
6435
  const { type: type2 } = vector2;
6405
- if (vector2.nullCount === 0 && vector2.stride === 1 && (type2.typeId === Type2.Timestamp || type2 instanceof Int_ && type2.bitWidth !== 64 || type2 instanceof Time_ && type2.bitWidth !== 64 || type2 instanceof Float && type2.precision !== Precision.HALF)) {
6436
+ if (vector2.nullCount === 0 && vector2.stride === 1 && // Don't defer to native iterator for timestamps since Numbers are expected
6437
+ // (DataType.isTimestamp(type)) && type.unit === TimeUnit.MILLISECOND ||
6438
+ (DataType.isInt(type2) && type2.bitWidth !== 64 || DataType.isTime(type2) && type2.bitWidth !== 64 || DataType.isFloat(type2) && type2.precision !== Precision.HALF)) {
6406
6439
  return new ChunkedIterator(vector2.data.length, (chunkIndex) => {
6407
6440
  const data = vector2.data[chunkIndex];
6408
6441
  return data.values.subarray(0, data.length)[Symbol.iterator]();
@@ -6576,6 +6609,13 @@ var Vector = class _Vector {
6576
6609
  get(index2) {
6577
6610
  return null;
6578
6611
  }
6612
+ /**
6613
+ * Get an element value by position.
6614
+ * @param index The index of the element to read. A negative index will count back from the last element.
6615
+ */
6616
+ at(index2) {
6617
+ return this.get(wrapIndex(index2, this.length));
6618
+ }
6579
6619
  /**
6580
6620
  * Set an element value by position.
6581
6621
  * @param index The index of the element to write.
@@ -7853,8 +7893,8 @@ var AsyncByteStreamSource = class {
7853
7893
  return (yield this.next(size, "peek")).value;
7854
7894
  });
7855
7895
  }
7856
- next(size, cmd = "read") {
7857
- return __awaiter(this, void 0, void 0, function* () {
7896
+ next(size_1) {
7897
+ return __awaiter(this, arguments, void 0, function* (size, cmd = "read") {
7858
7898
  return yield this.source.next({ cmd, size });
7859
7899
  });
7860
7900
  }
@@ -8595,9 +8635,9 @@ var DictionaryBuilder = class extends Builder2 {
8595
8635
  return this.indices.isValid(value);
8596
8636
  }
8597
8637
  setValid(index2, valid2) {
8598
- const indices = this.indices;
8599
- valid2 = indices.setValid(index2, valid2);
8600
- this.length = indices.length;
8638
+ const indices2 = this.indices;
8639
+ valid2 = indices2.setValid(index2, valid2);
8640
+ this.length = indices2.length;
8601
8641
  return valid2;
8602
8642
  }
8603
8643
  setValue(index2, value) {
@@ -9431,6 +9471,14 @@ var Table = class _Table {
9431
9471
  get(index2) {
9432
9472
  return null;
9433
9473
  }
9474
+ /**
9475
+ * Get an element value by position.
9476
+ * @param index The index of the element to read. A negative index will count back from the last element.
9477
+ */
9478
+ // @ts-ignore
9479
+ at(index2) {
9480
+ return this.get(wrapIndex(index2, this.numRows));
9481
+ }
9434
9482
  /**
9435
9483
  * Set an element value by position.
9436
9484
  *
@@ -9573,16 +9621,16 @@ var Table = class _Table {
9573
9621
  }
9574
9622
  assign(other) {
9575
9623
  const fields = this.schema.fields;
9576
- const [indices, oldToNew] = other.schema.fields.reduce((memo2, f2, newIdx) => {
9577
- const [indices2, oldToNew2] = memo2;
9624
+ const [indices2, oldToNew] = other.schema.fields.reduce((memo2, f2, newIdx) => {
9625
+ const [indices3, oldToNew2] = memo2;
9578
9626
  const i = fields.findIndex((f) => f.name === f2.name);
9579
- ~i ? oldToNew2[i] = newIdx : indices2.push(newIdx);
9627
+ ~i ? oldToNew2[i] = newIdx : indices3.push(newIdx);
9580
9628
  return memo2;
9581
9629
  }, [[], []]);
9582
9630
  const schema = this.schema.assign(other.schema);
9583
9631
  const columns = [
9584
9632
  ...fields.map((_, i) => [i, oldToNew[i]]).map(([i, j]) => j === void 0 ? this.getChildAt(i) : other.getChildAt(j)),
9585
- ...indices.map((i) => other.getChildAt(i))
9633
+ ...indices2.map((i) => other.getChildAt(i))
9586
9634
  ].filter(Boolean);
9587
9635
  return new _Table(...distributeVectorsIntoRecordBatches(schema, columns));
9588
9636
  }
@@ -9668,7 +9716,7 @@ var RecordBatch2 = class _RecordBatch {
9668
9716
  return this.data.nullCount;
9669
9717
  }
9670
9718
  /**
9671
- * Check whether an element is null.
9719
+ * Check whether an row is null.
9672
9720
  * @param index The index at which to read the validity bitmap.
9673
9721
  */
9674
9722
  isValid(index2) {
@@ -9676,14 +9724,21 @@ var RecordBatch2 = class _RecordBatch {
9676
9724
  }
9677
9725
  /**
9678
9726
  * Get a row by position.
9679
- * @param index The index of the element to read.
9727
+ * @param index The index of the row to read.
9680
9728
  */
9681
9729
  get(index2) {
9682
9730
  return instance2.visit(this.data, index2);
9683
9731
  }
9732
+ /**
9733
+ * Get a row value by position.
9734
+ * @param index The index of the row to read. A negative index will count back from the last row.
9735
+ */
9736
+ at(index2) {
9737
+ return this.get(wrapIndex(index2, this.numRows));
9738
+ }
9684
9739
  /**
9685
9740
  * Set a row by position.
9686
- * @param index The index of the element to write.
9741
+ * @param index The index of the row to write.
9687
9742
  * @param value The value to set.
9688
9743
  */
9689
9744
  set(index2, value) {
@@ -9720,7 +9775,7 @@ var RecordBatch2 = class _RecordBatch {
9720
9775
  /**
9721
9776
  * Return a zero-copy sub-section of this RecordBatch.
9722
9777
  * @param start The beginning of the specified portion of the RecordBatch.
9723
- * @param end The end of the specified portion of the RecordBatch. This is exclusive of the element at the index 'end'.
9778
+ * @param end The end of the specified portion of the RecordBatch. This is exclusive of the row at the index 'end'.
9724
9779
  */
9725
9780
  slice(begin, end) {
9726
9781
  const [slice4] = new Vector([this.data]).slice(begin, end).data;
@@ -10808,8 +10863,8 @@ var AsyncMessageReader = class {
10808
10863
  );
10809
10864
  });
10810
10865
  }
10811
- readSchema(throwIfNull = false) {
10812
- return __awaiter(this, void 0, void 0, function* () {
10866
+ readSchema() {
10867
+ return __awaiter(this, arguments, void 0, function* (throwIfNull = false) {
10813
10868
  const type2 = MessageHeader.Schema;
10814
10869
  const message = yield this.readMessage(type2);
10815
10870
  const schema = message === null || message === void 0 ? void 0 : message.header();
@@ -11057,8 +11112,8 @@ var AsyncRecordBatchStreamReader = class extends RecordBatchReader {
11057
11112
  this._impl = _impl;
11058
11113
  }
11059
11114
  readAll() {
11060
- var _a5, e_1, _b2, _c2;
11061
11115
  return __awaiter(this, void 0, void 0, function* () {
11116
+ var _a5, e_1, _b2, _c2;
11062
11117
  const batches = new Array();
11063
11118
  try {
11064
11119
  for (var _d2 = true, _e2 = __asyncValues(this), _f2; _f2 = yield _e2.next(), _a5 = _f2.done, !_a5; _d2 = true) {
@@ -11431,8 +11486,8 @@ var AsyncRecordBatchFileReaderImpl = class extends AsyncRecordBatchStreamReaderI
11431
11486
  });
11432
11487
  }
11433
11488
  readRecordBatch(index2) {
11434
- var _a5;
11435
11489
  return __awaiter(this, void 0, void 0, function* () {
11490
+ var _a5;
11436
11491
  if (this.closed) {
11437
11492
  return null;
11438
11493
  }
@@ -11453,8 +11508,8 @@ var AsyncRecordBatchFileReaderImpl = class extends AsyncRecordBatchStreamReaderI
11453
11508
  });
11454
11509
  }
11455
11510
  _readDictionaryBatch(index2) {
11456
- var _a5;
11457
11511
  return __awaiter(this, void 0, void 0, function* () {
11512
+ var _a5;
11458
11513
  const block = (_a5 = this._footer) === null || _a5 === void 0 ? void 0 : _a5.getDictionaryBatch(index2);
11459
11514
  if (block && (yield this._handle.seek(block.offset))) {
11460
11515
  const message = yield this._reader.readMessage(MessageHeader.DictionaryBatch);
@@ -11959,9 +12014,9 @@ function writeAll(writer, input) {
11959
12014
  return writer.finish();
11960
12015
  }
11961
12016
  function writeAllAsync(writer, batches) {
11962
- var _a5, batches_1, batches_1_1;
11963
- var _b2, e_1, _c2, _d2;
11964
12017
  return __awaiter(this, void 0, void 0, function* () {
12018
+ var _a5, batches_1, batches_1_1;
12019
+ var _b2, e_1, _c2, _d2;
11965
12020
  try {
11966
12021
  for (_a5 = true, batches_1 = __asyncValues(batches); batches_1_1 = yield batches_1.next(), _b2 = batches_1_1.done, !_b2; _a5 = true) {
11967
12022
  _d2 = batches_1_1.value;
@@ -12324,6 +12379,13 @@ function socketConnector(uri = "ws://localhost:3000/") {
12324
12379
  get connected() {
12325
12380
  return connected;
12326
12381
  },
12382
+ /**
12383
+ * Query the DuckDB server.
12384
+ * @param {object} query
12385
+ * @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'.
12386
+ * @param {string} query.sql A SQL query string.
12387
+ * @returns the query result
12388
+ */
12327
12389
  query(query) {
12328
12390
  return new Promise(
12329
12391
  (resolve, reject) => enqueue(query, resolve, reject)
@@ -12394,7 +12456,7 @@ function literalToSQL(value) {
12394
12456
  case "boolean":
12395
12457
  return value ? "TRUE" : "FALSE";
12396
12458
  case "string":
12397
- return `'${value}'`;
12459
+ return `'${value.replace(`'`, `''`)}'`;
12398
12460
  case "number":
12399
12461
  return Number.isFinite(value) ? String(value) : "NULL";
12400
12462
  default:
@@ -12477,7 +12539,7 @@ var SQLExpression = class {
12477
12539
  /**
12478
12540
  * Annotate this expression instance with additional properties.
12479
12541
  * @param {object[]} [props] One or more objects with properties to add.
12480
- * @returns {this} This SQL expression.
12542
+ * @returns This SQL expression.
12481
12543
  */
12482
12544
  annotate(...props) {
12483
12545
  return Object.assign(this, ...props);
@@ -12739,6 +12801,9 @@ var last_value = winf("LAST_VALUE");
12739
12801
  var nth_value = winf("NTH_VALUE");
12740
12802
 
12741
12803
  // ../sql/src/aggregates.js
12804
+ function agg(strings, ...exprs) {
12805
+ return sql(strings, ...exprs).annotate({ aggregate: true });
12806
+ }
12742
12807
  var AggregateFunction = class _AggregateFunction extends SQLExpression {
12743
12808
  /**
12744
12809
  * Create a new AggregateFunction instance.
@@ -12869,6 +12934,7 @@ var entropy = aggf("ENTROPY");
12869
12934
  var varPop = aggf("VAR_POP");
12870
12935
  var stddevPop = aggf("STDDEV_POP");
12871
12936
  var corr = aggf("CORR");
12937
+ var covariance = aggf("COVAR_SAMP");
12872
12938
  var covarPop = aggf("COVAR_POP");
12873
12939
  var regrIntercept = aggf("REGR_INTERCEPT");
12874
12940
  var regrSlope = aggf("REGR_SLOPE");
@@ -12910,6 +12976,11 @@ var castDouble = (expr) => cast(expr, "DOUBLE");
12910
12976
  var epoch_ms = (expr) => {
12911
12977
  return sql`epoch_ms(${asColumn(expr)})`;
12912
12978
  };
12979
+ function dateBin(expr, interval2, steps = 1) {
12980
+ const i = `INTERVAL ${steps} ${interval2}`;
12981
+ const d = asColumn(expr);
12982
+ return sql`TIME_BUCKET(${i}, ${d})`.annotate({ label: interval2 });
12983
+ }
12913
12984
 
12914
12985
  // ../sql/src/spatial.js
12915
12986
  var geojson = functionCall("ST_AsGeoJSON");
@@ -13031,7 +13102,8 @@ var Query = class _Query {
13031
13102
  }
13032
13103
  }
13033
13104
  }
13034
- query.select = query.select.concat(list);
13105
+ const keys = new Set(list.map((x3) => x3.as));
13106
+ query.select = query.select.filter((x3) => !keys.has(x3.as)).concat(list.filter((x3) => x3.expr));
13035
13107
  return this;
13036
13108
  }
13037
13109
  }
@@ -13504,6 +13576,7 @@ function scaleTime() {
13504
13576
  };
13505
13577
  }
13506
13578
  var scales = {
13579
+ identity: scaleLinear,
13507
13580
  linear: scaleLinear,
13508
13581
  log: scaleLog,
13509
13582
  symlog: scaleSymlog,
@@ -13526,179 +13599,97 @@ function create(name, query, {
13526
13599
  return "CREATE" + (replace ? " OR REPLACE " : " ") + (temp ? "TEMP " : "") + (view ? "VIEW" : "TABLE") + (replace ? " " : " IF NOT EXISTS ") + name + " AS " + query;
13527
13600
  }
13528
13601
 
13529
- // ../core/src/util/hash.js
13530
- function fnv_hash(v2) {
13531
- let a2 = 2166136261;
13532
- for (let i = 0, n = v2.length; i < n; ++i) {
13533
- const c4 = v2.charCodeAt(i);
13534
- const d = c4 & 65280;
13535
- if (d) a2 = fnv_multiply(a2 ^ d >> 8);
13536
- a2 = fnv_multiply(a2 ^ c4 & 255);
13537
- }
13538
- return fnv_mix(a2);
13539
- }
13540
- function fnv_multiply(a2) {
13541
- return a2 + (a2 << 1) + (a2 << 4) + (a2 << 7) + (a2 << 8) + (a2 << 24);
13542
- }
13543
- function fnv_mix(a2) {
13544
- a2 += a2 << 13;
13545
- a2 ^= a2 >>> 7;
13546
- a2 += a2 << 3;
13547
- a2 ^= a2 >>> 17;
13548
- a2 += a2 << 5;
13549
- return a2 & 4294967295;
13550
- }
13551
-
13552
- // ../core/src/DataCubeIndexer.js
13553
- var DataCubeIndexer = class {
13554
- /**
13555
- *
13556
- * @param {import('./Coordinator.js').Coordinator} mc a Mosaic coordinator
13557
- * @param {*} options Options hash to configure the data cube indexes and pass selections to the coordinator.
13558
- */
13559
- constructor(mc, { selection: selection2, temp = true }) {
13560
- this.mc = mc;
13561
- this.selection = selection2;
13562
- this.temp = temp;
13563
- this.reset();
13564
- }
13565
- reset() {
13566
- this.enabled = false;
13567
- this.clients = null;
13568
- this.indices = null;
13569
- this.activeView = null;
13570
- }
13571
- clear() {
13572
- if (this.indices) {
13573
- this.mc.cancel(Array.from(this.indices.values(), (index2) => index2.result));
13574
- this.indices = null;
13575
- }
13576
- }
13577
- index(clients, active) {
13578
- if (this.clients !== clients) {
13579
- const cols = Array.from(clients, getIndexColumns);
13580
- const from = cols[0]?.from;
13581
- this.enabled = cols.every((c4) => c4 && c4.from === from);
13582
- this.clients = clients;
13583
- this.activeView = null;
13584
- this.clear();
13585
- }
13586
- if (!this.enabled) return false;
13587
- active = active || this.selection.active;
13588
- const { source } = active;
13589
- if (source && source === this.activeView?.source) return true;
13590
- this.clear();
13591
- if (!source) return false;
13592
- const activeView = this.activeView = getActiveView(active);
13593
- if (!activeView) return false;
13594
- this.mc.logger().warn("DATA CUBE INDEX CONSTRUCTION");
13595
- const sel = this.selection.remove(source);
13596
- const indices = this.indices = /* @__PURE__ */ new Map();
13597
- const { mc, temp } = this;
13598
- for (const client of clients) {
13599
- if (sel.skip(client, active)) continue;
13600
- const index2 = getIndexColumns(client);
13601
- const query = client.query(sel.predicate(client)).select({ ...activeView.columns, ...index2.aux }).groupby(Object.keys(activeView.columns));
13602
- const [subq] = query.subqueries;
13603
- if (subq) {
13604
- const cols = Object.values(activeView.columns).map((c4) => c4.columns[0]);
13605
- subqueryPushdown(subq, cols);
13606
- }
13607
- const order = query.orderby();
13608
- query.query.orderby = [];
13609
- const sql2 = query.toString();
13610
- const id2 = (fnv_hash(sql2) >>> 0).toString(16);
13611
- const table = `cube_index_${id2}`;
13612
- const result = mc.exec(create(table, sql2, { temp }));
13613
- indices.set(client, { table, result, order, ...index2 });
13614
- }
13615
- return true;
13616
- }
13617
- async update() {
13618
- const { clients, selection: selection2, activeView } = this;
13619
- const filter3 = activeView.predicate(selection2.active.predicate);
13620
- return Promise.all(
13621
- Array.from(clients).map((client) => this.updateClient(client, filter3))
13622
- );
13623
- }
13624
- async updateClient(client, filter3) {
13625
- const index2 = this.indices.get(client);
13626
- if (!index2) return;
13627
- if (!filter3) {
13628
- filter3 = this.activeView.predicate(this.selection.active.predicate);
13629
- }
13630
- const { table, dims, aggr, order = [] } = index2;
13631
- const query = Query.select(dims, aggr).from(table).groupby(dims).where(filter3).orderby(order);
13632
- return this.mc.updateClient(client, query);
13633
- }
13634
- };
13635
- function getActiveView(clause) {
13636
- const { source, schema } = clause;
13637
- let columns = clause.predicate?.columns;
13638
- if (!schema || !columns) return null;
13639
- const { type: type2, scales: scales2, pixelSize = 1 } = schema;
13640
- let predicate;
13641
- if (type2 === "interval" && scales2) {
13642
- const bins2 = scales2.map((s2) => binInterval(s2, pixelSize));
13643
- if (bins2.some((b) => b == null)) return null;
13644
- if (bins2.length === 1) {
13645
- predicate = (p) => p ? isBetween("active0", p.range.map(bins2[0])) : [];
13646
- columns = { active0: bins2[0](clause.predicate.field) };
13647
- } else {
13648
- predicate = (p) => p ? and(p.children.map(({ range: range3 }, i) => isBetween(`active${i}`, range3.map(bins2[i])))) : [];
13649
- columns = Object.fromEntries(
13650
- clause.predicate.children.map((p, i) => [`active${i}`, bins2[i](p.field)])
13651
- );
13652
- }
13653
- } else if (type2 === "point") {
13654
- predicate = (x3) => x3;
13655
- columns = Object.fromEntries(columns.map((col) => [col.toString(), col]));
13656
- } else {
13657
- return null;
13658
- }
13659
- return { source, columns, predicate };
13660
- }
13661
- function binInterval(scale3, pixelSize) {
13662
- const { apply: apply2, sqlApply } = scaleTransform(scale3);
13663
- if (apply2) {
13664
- const { domain, range: range3 } = scale3;
13665
- const lo = apply2(Math.min(...domain));
13666
- const hi = apply2(Math.max(...domain));
13667
- const a2 = Math.abs(range3[1] - range3[0]) / (hi - lo) / pixelSize;
13668
- const s2 = pixelSize === 1 ? "" : `${pixelSize}::INTEGER * `;
13669
- return (value) => sql`${s2}FLOOR(${a2}::DOUBLE * (${sqlApply(value)} - ${lo}::DOUBLE))::INTEGER`;
13670
- }
13671
- }
13672
- var NO_INDEX = { from: NaN };
13673
- function getIndexColumns(client) {
13674
- if (!client.filterIndexable) return NO_INDEX;
13602
+ // ../core/src/util/index-columns.js
13603
+ function indexColumns(client) {
13604
+ if (!client.filterIndexable) return null;
13675
13605
  const q = client.query();
13676
13606
  const from = getBaseTable(q);
13677
- if (!from || !q.groupby) return NO_INDEX;
13678
- const g = new Set(q.groupby().map((c4) => c4.column));
13607
+ if (typeof from !== "string" || !q.select) return null;
13679
13608
  const aggr = [];
13680
13609
  const dims = [];
13681
13610
  const aux = {};
13682
- let auxAs;
13683
13611
  for (const entry of q.select()) {
13684
13612
  const { as, expr: { aggregate, args } } = entry;
13685
13613
  const op = aggregate?.toUpperCase?.();
13686
13614
  switch (op) {
13687
13615
  case "COUNT":
13688
13616
  case "SUM":
13689
- aggr.push({ [as]: sql`SUM("${as}")::DOUBLE` });
13617
+ aggr.push({ [as]: agg`SUM("${as}")::DOUBLE` });
13690
13618
  break;
13691
13619
  case "AVG":
13692
- aux[auxAs = "__count__"] = sql`COUNT(*)`;
13693
- aggr.push({ [as]: sql`(SUM("${as}" * ${auxAs}) / SUM(${auxAs}))::DOUBLE` });
13620
+ aggr.push({ [as]: avgExpr(aux, as, args[0]) });
13694
13621
  break;
13695
13622
  case "ARG_MAX":
13696
- aux[auxAs = `__max_${as}__`] = sql`MAX(${args[1]})`;
13697
- aggr.push({ [as]: sql`ARG_MAX("${as}", ${auxAs})` });
13623
+ aggr.push({ [as]: argmaxExpr(aux, as, args) });
13698
13624
  break;
13699
13625
  case "ARG_MIN":
13700
- aux[auxAs = `__min_${as}__`] = sql`MIN(${args[1]})`;
13701
- aggr.push({ [as]: sql`ARG_MIN("${as}", ${auxAs})` });
13626
+ aggr.push({ [as]: argminExpr(aux, as, args) });
13627
+ break;
13628
+ case "VARIANCE":
13629
+ case "VAR_SAMP":
13630
+ aux[as] = null;
13631
+ aggr.push({ [as]: varianceExpr(aux, args[0], from) });
13632
+ break;
13633
+ case "VAR_POP":
13634
+ aux[as] = null;
13635
+ aggr.push({ [as]: varianceExpr(aux, args[0], from, false) });
13636
+ break;
13637
+ case "STDDEV":
13638
+ case "STDDEV_SAMP":
13639
+ aux[as] = null;
13640
+ aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from)})` });
13641
+ break;
13642
+ case "STDDEV_POP":
13643
+ aux[as] = null;
13644
+ aggr.push({ [as]: agg`SQRT(${varianceExpr(aux, args[0], from, false)})` });
13645
+ break;
13646
+ case "COVAR_SAMP":
13647
+ aux[as] = null;
13648
+ aggr.push({ [as]: covarianceExpr(aux, args, from) });
13649
+ break;
13650
+ case "COVAR_POP":
13651
+ aux[as] = null;
13652
+ aggr.push({ [as]: covarianceExpr(aux, args, from, false) });
13653
+ break;
13654
+ case "CORR":
13655
+ aux[as] = null;
13656
+ aggr.push({ [as]: corrExpr(aux, args, from) });
13657
+ break;
13658
+ case "REGR_COUNT":
13659
+ aux[as] = null;
13660
+ aggr.push({ [as]: agg`${regrCountExpr(aux, args)}::DOUBLE` });
13661
+ break;
13662
+ case "REGR_AVGX":
13663
+ aux[as] = null;
13664
+ aggr.push({ [as]: regrAvgXExpr(aux, args) });
13665
+ break;
13666
+ case "REGR_AVGY":
13667
+ aux[as] = null;
13668
+ aggr.push({ [as]: regrAvgYExpr(aux, args) });
13669
+ break;
13670
+ case "REGR_SYY":
13671
+ aux[as] = null;
13672
+ aggr.push({ [as]: regrVarExpr(aux, 0, args, from) });
13673
+ break;
13674
+ case "REGR_SXX":
13675
+ aux[as] = null;
13676
+ aggr.push({ [as]: regrVarExpr(aux, 1, args, from) });
13677
+ break;
13678
+ case "REGR_SXY":
13679
+ aux[as] = null;
13680
+ aggr.push({ [as]: covarianceExpr(aux, args, from, null) });
13681
+ break;
13682
+ case "REGR_SLOPE":
13683
+ aux[as] = null;
13684
+ aggr.push({ [as]: regrSlopeExpr(aux, args, from) });
13685
+ break;
13686
+ case "REGR_INTERCEPT":
13687
+ aux[as] = null;
13688
+ aggr.push({ [as]: regrInterceptExpr(aux, args, from) });
13689
+ break;
13690
+ case "REGR_R2":
13691
+ aux[as] = null;
13692
+ aggr.push({ [as]: agg`(${corrExpr(aux, args, from)}) ** 2` });
13702
13693
  break;
13703
13694
  case "MAX":
13704
13695
  case "MIN":
@@ -13708,14 +13699,22 @@ function getIndexColumns(client) {
13708
13699
  case "BOOL_AND":
13709
13700
  case "BOOL_OR":
13710
13701
  case "PRODUCT":
13711
- aggr.push({ [as]: sql`${op}("${as}")` });
13702
+ aggr.push({ [as]: agg`${op}("${as}")` });
13712
13703
  break;
13713
13704
  default:
13714
- if (g.has(as)) dims.push(as);
13705
+ if (!aggregate) dims.push(as);
13715
13706
  else return null;
13716
13707
  }
13717
13708
  }
13718
- return { aggr, dims, aux, from };
13709
+ if (!aggr.length) return null;
13710
+ return { from, dims, aggr, aux };
13711
+ }
13712
+ function auxName(type2, ...args) {
13713
+ const cols = args.length ? "_" + args.map(sanitize).join("_") : "";
13714
+ return `__${type2}${cols}__`;
13715
+ }
13716
+ function sanitize(col) {
13717
+ return `${col}`.replaceAll('"', "").replaceAll(" ", "_");
13719
13718
  }
13720
13719
  function getBaseTable(query) {
13721
13720
  const subq = query.subqueries;
@@ -13732,6 +13731,291 @@ function getBaseTable(query) {
13732
13731
  }
13733
13732
  return base;
13734
13733
  }
13734
+ function countExpr(aux, arg) {
13735
+ const n = auxName("count", arg);
13736
+ aux[n] = agg`COUNT(${arg})`;
13737
+ return agg`SUM(${n})`.annotate({ name: n });
13738
+ }
13739
+ function avgExpr(aux, as, arg) {
13740
+ const n = countExpr(aux, arg);
13741
+ return agg`(SUM("${as}" * ${n.name}) / ${n})`;
13742
+ }
13743
+ function avg2(x3, from) {
13744
+ return sql`(SELECT AVG(${x3}) FROM "${from}")`;
13745
+ }
13746
+ function argmaxExpr(aux, as, [, y3]) {
13747
+ const max4 = auxName("max", y3);
13748
+ aux[max4] = agg`MAX(${y3})`;
13749
+ return agg`ARG_MAX("${as}", ${max4})`;
13750
+ }
13751
+ function argminExpr(aux, as, [, y3]) {
13752
+ const min5 = auxName("min", y3);
13753
+ aux[min5] = agg`MIN(${y3})`;
13754
+ return agg`ARG_MIN("${as}", ${min5})`;
13755
+ }
13756
+ function varianceExpr(aux, x3, from, correction = true) {
13757
+ const n = countExpr(aux, x3);
13758
+ const ssq = auxName("rssq", x3);
13759
+ const sum4 = auxName("rsum", x3);
13760
+ const delta = sql`${x3} - ${avg2(x3, from)}`;
13761
+ aux[ssq] = agg`SUM((${delta}) ** 2)`;
13762
+ aux[sum4] = agg`SUM(${delta})`;
13763
+ const adj = correction ? ` - 1` : "";
13764
+ return agg`(SUM(${ssq}) - (SUM(${sum4}) ** 2 / ${n})) / (${n}${adj})`;
13765
+ }
13766
+ function covarianceExpr(aux, args, from, correction = true) {
13767
+ const n = regrCountExpr(aux, args);
13768
+ const sxy = regrSumXYExpr(aux, args, from);
13769
+ const sx = regrSumExpr(aux, 1, args, from);
13770
+ const sy = regrSumExpr(aux, 0, args, from);
13771
+ const adj = correction === null ? "" : correction ? ` / (${n} - 1)` : ` / ${n}`;
13772
+ return agg`(${sxy} - ${sx} * ${sy} / ${n})${adj}`;
13773
+ }
13774
+ function corrExpr(aux, args, from) {
13775
+ const n = regrCountExpr(aux, args);
13776
+ const sxy = regrSumXYExpr(aux, args, from);
13777
+ const sxx = regrSumSqExpr(aux, 1, args, from);
13778
+ const syy = regrSumSqExpr(aux, 0, args, from);
13779
+ const sx = regrSumExpr(aux, 1, args, from);
13780
+ const sy = regrSumExpr(aux, 0, args, from);
13781
+ const vx = agg`(${sxx} - (${sx} ** 2) / ${n})`;
13782
+ const vy = agg`(${syy} - (${sy} ** 2) / ${n})`;
13783
+ return agg`(${sxy} - ${sx} * ${sy} / ${n}) / SQRT(${vx} * ${vy})`;
13784
+ }
13785
+ function regrCountExpr(aux, [y3, x3]) {
13786
+ const n = auxName("count", y3, x3);
13787
+ aux[n] = agg`REGR_COUNT(${y3}, ${x3})`;
13788
+ return agg`SUM(${n})`.annotate({ name: n });
13789
+ }
13790
+ function regrSumExpr(aux, i, args, from) {
13791
+ const v2 = args[i];
13792
+ const o = args[1 - i];
13793
+ const sum4 = auxName("rs", v2);
13794
+ aux[sum4] = agg`SUM(${v2} - ${avg2(v2, from)}) FILTER (${o} IS NOT NULL)`;
13795
+ return agg`SUM(${sum4})`;
13796
+ }
13797
+ function regrSumSqExpr(aux, i, args, from) {
13798
+ const v2 = args[i];
13799
+ const u4 = args[1 - i];
13800
+ const ssq = auxName("rss", v2);
13801
+ aux[ssq] = agg`SUM((${v2} - ${avg2(v2, from)}) ** 2) FILTER (${u4} IS NOT NULL)`;
13802
+ return agg`SUM(${ssq})`;
13803
+ }
13804
+ function regrSumXYExpr(aux, args, from) {
13805
+ const [y3, x3] = args;
13806
+ const sxy = auxName("sxy", y3, x3);
13807
+ aux[sxy] = agg`SUM((${x3} - ${avg2(x3, from)}) * (${y3} - ${avg2(y3, from)}))`;
13808
+ return agg`SUM(${sxy})`;
13809
+ }
13810
+ function regrAvgXExpr(aux, args) {
13811
+ const [y3, x3] = args;
13812
+ const n = regrCountExpr(aux, args);
13813
+ const a2 = auxName("avg", x3, y3);
13814
+ aux[a2] = agg`REGR_AVGX(${y3}, ${x3})`;
13815
+ return agg`(SUM(${a2} * ${n.name}) / ${n})`;
13816
+ }
13817
+ function regrAvgYExpr(aux, args) {
13818
+ const [y3, x3] = args;
13819
+ const n = regrCountExpr(aux, args);
13820
+ const a2 = auxName("avg", y3, x3);
13821
+ aux[a2] = agg`REGR_AVGY(${y3}, ${x3})`;
13822
+ return agg`(SUM(${a2} * ${n.name}) / ${n})`;
13823
+ }
13824
+ function regrVarExpr(aux, i, args, from) {
13825
+ const n = regrCountExpr(aux, args);
13826
+ const sum4 = regrSumExpr(aux, i, args, from);
13827
+ const ssq = regrSumSqExpr(aux, i, args, from);
13828
+ return agg`(${ssq} - (${sum4} ** 2 / ${n}))`;
13829
+ }
13830
+ function regrSlopeExpr(aux, args, from) {
13831
+ const cov = covarianceExpr(aux, args, from, null);
13832
+ const varx = regrVarExpr(aux, 1, args, from);
13833
+ return agg`(${cov}) / ${varx}`;
13834
+ }
13835
+ function regrInterceptExpr(aux, args, from) {
13836
+ const ax = regrAvgXExpr(aux, args);
13837
+ const ay = regrAvgYExpr(aux, args);
13838
+ const m = regrSlopeExpr(aux, args, from);
13839
+ return agg`${ay} - (${m}) * ${ax}`;
13840
+ }
13841
+
13842
+ // ../core/src/util/hash.js
13843
+ function fnv_hash(v2) {
13844
+ let a2 = 2166136261;
13845
+ for (let i = 0, n = v2.length; i < n; ++i) {
13846
+ const c4 = v2.charCodeAt(i);
13847
+ const d = c4 & 65280;
13848
+ if (d) a2 = fnv_multiply(a2 ^ d >> 8);
13849
+ a2 = fnv_multiply(a2 ^ c4 & 255);
13850
+ }
13851
+ return fnv_mix(a2);
13852
+ }
13853
+ function fnv_multiply(a2) {
13854
+ return a2 + (a2 << 1) + (a2 << 4) + (a2 << 7) + (a2 << 8) + (a2 << 24);
13855
+ }
13856
+ function fnv_mix(a2) {
13857
+ a2 += a2 << 13;
13858
+ a2 ^= a2 >>> 7;
13859
+ a2 += a2 << 3;
13860
+ a2 ^= a2 >>> 17;
13861
+ a2 += a2 << 5;
13862
+ return a2 & 4294967295;
13863
+ }
13864
+
13865
+ // ../core/src/DataCubeIndexer.js
13866
+ var Skip = { skip: true, result: null };
13867
+ var DataCubeIndexer = class {
13868
+ /**
13869
+ * Create a new data cube index table manager.
13870
+ * @param {import('./Coordinator.js').Coordinator} coordinator A Mosaic coordinator.
13871
+ * @param {object} [options] Indexer options.
13872
+ * @param {boolean} [options.enabled=true] Flag to enable/disable indexer.
13873
+ * @param {boolean} [options.temp=true] Flag to indicate if generated data
13874
+ * cube index tables should be temporary tables.
13875
+ */
13876
+ constructor(coordinator2, {
13877
+ enabled = true,
13878
+ temp = true
13879
+ } = {}) {
13880
+ this.indexes = /* @__PURE__ */ new Map();
13881
+ this.active = null;
13882
+ this.temp = temp;
13883
+ this.mc = coordinator2;
13884
+ this._enabled = enabled;
13885
+ }
13886
+ /**
13887
+ * Set the enabled state of this indexer. If false, any cached state is
13888
+ * cleared and subsequent index calls will return null until re-enabled.
13889
+ * @param {boolean} state The enabled state.
13890
+ */
13891
+ enabled(state) {
13892
+ if (state === void 0) {
13893
+ return this._enabled;
13894
+ } else if (this._enabled !== state) {
13895
+ if (!state) this.clear();
13896
+ this._enabled = state;
13897
+ }
13898
+ }
13899
+ /**
13900
+ * Clear the cache of data cube index table entries for the current active
13901
+ * selection clause. This method will also cancel any queued data cube table
13902
+ * creation queries that have not yet been submitted to the database. This
13903
+ * method does _not_ drop any existing data cube tables.
13904
+ */
13905
+ clear() {
13906
+ this.mc.cancel(Array.from(this.indexes.values(), (info) => info?.result));
13907
+ this.indexes.clear();
13908
+ this.active = null;
13909
+ }
13910
+ /**
13911
+ * Return data cube index table information for the active state of a
13912
+ * client-selection pair, or null if the client is not indexable. This
13913
+ * method has multiple possible side effects, including data cube table
13914
+ * generation and updating internal caches.
13915
+ * @param {import('./MosaicClient.js').MosaicClient} client A Mosaic client.
13916
+ * @param {import('./Selection.js').Selection} selection A Mosaic selection
13917
+ * to filter the client by.
13918
+ * @param {import('./util/selection-types.js').SelectionClause} activeClause
13919
+ * A representative active selection clause for which to (possibly) generate
13920
+ * data cube index tables.
13921
+ * @returns {DataCubeInfo | Skip | null} Data cube index table
13922
+ * information and query generator, or null if the client is not indexable.
13923
+ */
13924
+ index(client, selection2, activeClause) {
13925
+ if (!this._enabled) return null;
13926
+ const { indexes: indexes2, mc, temp } = this;
13927
+ const { source } = activeClause;
13928
+ if (!source) return null;
13929
+ if (this.active) {
13930
+ if (this.active.source !== source) this.clear();
13931
+ if (this.active?.source === null) return null;
13932
+ }
13933
+ let { active } = this;
13934
+ if (!active) {
13935
+ this.active = active = activeColumns(activeClause);
13936
+ if (active.source === null) return null;
13937
+ }
13938
+ if (indexes2.has(client)) {
13939
+ return indexes2.get(client);
13940
+ }
13941
+ const indexCols = indexColumns(client);
13942
+ let info;
13943
+ if (!indexCols) {
13944
+ info = null;
13945
+ } else if (selection2.skip(client, activeClause)) {
13946
+ info = Skip;
13947
+ } else {
13948
+ const filter3 = selection2.remove(source).predicate(client);
13949
+ info = dataCubeInfo(client.query(filter3), active, indexCols);
13950
+ info.result = mc.exec(create(info.table, info.create, { temp }));
13951
+ info.result.catch((e) => mc.logger().error(e));
13952
+ }
13953
+ indexes2.set(client, info);
13954
+ return info;
13955
+ }
13956
+ };
13957
+ function activeColumns(clause) {
13958
+ const { source, meta } = clause;
13959
+ const clausePred = clause.predicate;
13960
+ const clauseCols = clausePred?.columns;
13961
+ let predicate;
13962
+ let columns;
13963
+ if (!meta || !clauseCols) {
13964
+ return { source: null, columns, predicate };
13965
+ }
13966
+ const { type: type2, scales: scales2, bin: bin3, pixelSize = 1 } = meta;
13967
+ if (type2 === "point") {
13968
+ predicate = (x3) => x3;
13969
+ columns = Object.fromEntries(
13970
+ clauseCols.map((col) => [`${col}`, asColumn(col)])
13971
+ );
13972
+ } else if (type2 === "interval" && scales2) {
13973
+ const bins2 = scales2.map((s2) => binInterval(s2, pixelSize, bin3));
13974
+ if (bins2.some((b) => !b)) {
13975
+ } else if (bins2.length === 1) {
13976
+ predicate = (p) => p ? isBetween("active0", p.range.map(bins2[0])) : [];
13977
+ columns = { active0: bins2[0](clausePred.field) };
13978
+ } else {
13979
+ predicate = (p) => p ? and(p.children.map(
13980
+ ({ range: range3 }, i) => isBetween(`active${i}`, range3.map(bins2[i]))
13981
+ )) : [];
13982
+ columns = Object.fromEntries(
13983
+ // @ts-ignore
13984
+ clausePred.children.map((p, i) => [`active${i}`, bins2[i](p.field)])
13985
+ );
13986
+ }
13987
+ }
13988
+ return { source: columns ? source : null, columns, predicate };
13989
+ }
13990
+ var BIN = { ceil: "CEIL", round: "ROUND" };
13991
+ function binInterval(scale3, pixelSize, bin3) {
13992
+ const { type: type2, domain, range: range3, apply: apply2, sqlApply } = scaleTransform(scale3);
13993
+ if (!apply2) return;
13994
+ const fn = BIN[`${bin3}`.toLowerCase()] || "FLOOR";
13995
+ const lo = apply2(Math.min(...domain));
13996
+ const hi = apply2(Math.max(...domain));
13997
+ const a2 = type2 === "identity" ? 1 : Math.abs(range3[1] - range3[0]) / (hi - lo);
13998
+ const s2 = a2 / pixelSize === 1 ? "" : `${a2 / pixelSize}::DOUBLE * `;
13999
+ const d = lo === 0 ? "" : ` - ${lo}::DOUBLE`;
14000
+ return (value) => sql`${fn}(${s2}(${sqlApply(value)}${d}))::INTEGER`;
14001
+ }
14002
+ function dataCubeInfo(clientQuery, active, indexCols) {
14003
+ const { dims, aggr, aux } = indexCols;
14004
+ const { columns } = active;
14005
+ const query = clientQuery.select({ ...columns, ...aux }).groupby(Object.keys(columns));
14006
+ const [subq] = query.subqueries;
14007
+ if (subq) {
14008
+ const cols = Object.values(columns).flatMap((c4) => c4.columns);
14009
+ subqueryPushdown(subq, cols);
14010
+ }
14011
+ const order = query.orderby();
14012
+ query.query.orderby = [];
14013
+ const create4 = query.toString();
14014
+ const id2 = (fnv_hash(create4) >>> 0).toString(16);
14015
+ const table = `cube_index_${id2}`;
14016
+ const select2 = Query.select(dims, aggr).from(table).groupby(dims).orderby(order);
14017
+ return new DataCubeInfo({ table, create: create4, active, select: select2 });
14018
+ }
13735
14019
  function subqueryPushdown(query, cols) {
13736
14020
  const memo2 = /* @__PURE__ */ new Set();
13737
14021
  const pushdown = (q) => {
@@ -13744,78 +14028,65 @@ function subqueryPushdown(query, cols) {
13744
14028
  };
13745
14029
  pushdown(query);
13746
14030
  }
13747
-
13748
- // ../core/src/FilterGroup.js
13749
- var FilterGroup = class {
14031
+ var DataCubeInfo = class {
13750
14032
  /**
13751
- * @param {import('./Coordinator.js').Coordinator} coordinator The Mosaic coordinator.
13752
- * @param {*} selection The shared filter selection.
13753
- * @param {*} index Boolean flag or options hash for data cube indexer.
13754
- * Falsy values disable indexing.
14033
+ * Create a new DataCubeInfo instance.
14034
+ * @param {object} options
13755
14035
  */
13756
- constructor(coordinator2, selection2, index2 = true) {
13757
- this.mc = coordinator2;
13758
- this.selection = selection2;
13759
- this.clients = /* @__PURE__ */ new Set();
13760
- this.indexer = index2 ? new DataCubeIndexer(this.mc, { ...index2, selection: selection2 }) : null;
13761
- const { value, activate } = this.handlers = {
13762
- value: () => this.update(),
13763
- activate: (clause) => this.indexer?.index(this.clients, clause)
13764
- };
13765
- selection2.addEventListener("value", value);
13766
- selection2.addEventListener("activate", activate);
13767
- }
13768
- finalize() {
13769
- const { value, activate } = this.handlers;
13770
- this.selection.removeEventListener("value", value);
13771
- this.selection.removeEventListener("activate", activate);
13772
- }
13773
- reset() {
13774
- this.indexer?.reset();
14036
+ constructor({ table, create: create4, active, select: select2 } = {}) {
14037
+ this.table = table;
14038
+ this.create = create4;
14039
+ this.result = null;
14040
+ this.active = active;
14041
+ this.select = select2;
14042
+ this.skip = false;
14043
+ }
14044
+ /**
14045
+ * Generate a data cube index table query for the given predicate.
14046
+ * @param {import('@uwdata/mosaic-sql').SQLExpression} predicate The current
14047
+ * active clause predicate.
14048
+ * @returns {Query} A data cube index table query.
14049
+ */
14050
+ query(predicate) {
14051
+ return this.select.clone().where(this.active.predicate(predicate));
13775
14052
  }
13776
- add(client) {
13777
- (this.clients = new Set(this.clients)).add(client);
13778
- return this;
14053
+ };
14054
+
14055
+ // ../core/src/util/query-result.js
14056
+ var QueryResult = class extends Promise {
14057
+ /**
14058
+ * Create a new query result Promise.
14059
+ */
14060
+ constructor() {
14061
+ let resolve;
14062
+ let reject;
14063
+ super((r, e) => {
14064
+ resolve = r;
14065
+ reject = e;
14066
+ });
14067
+ this._resolve = resolve;
14068
+ this._reject = reject;
13779
14069
  }
13780
- remove(client) {
13781
- if (this.clients.has(client)) {
13782
- (this.clients = new Set(this.clients)).delete(client);
13783
- }
14070
+ /**
14071
+ * Resolve the result Promise with the provided value.
14072
+ * @param {*} value The result value.
14073
+ * @returns {this}
14074
+ */
14075
+ fulfill(value) {
14076
+ this._resolve(value);
13784
14077
  return this;
13785
14078
  }
13786
14079
  /**
13787
- * Internal method to process a selection update.
13788
- * The return value is passed as a selection callback value.
13789
- * @returns {Promise} A Promise that resolves when the update completes.
14080
+ * Rejects the result Promise with the provided error.
14081
+ * @param {*} error The error value.
14082
+ * @returns {this}
13790
14083
  */
13791
- update() {
13792
- const { mc, indexer, clients, selection: selection2 } = this;
13793
- const hasIndex = indexer?.index(clients);
13794
- return hasIndex ? indexer.update() : defaultUpdate(mc, clients, selection2);
14084
+ reject(error) {
14085
+ this._reject(error);
14086
+ return this;
13795
14087
  }
13796
14088
  };
13797
- function defaultUpdate(mc, clients, selection2) {
13798
- return Promise.all(Array.from(clients).map((client) => {
13799
- const filter3 = selection2.predicate(client);
13800
- if (filter3 != null) {
13801
- return mc.updateClient(client, client.query(filter3));
13802
- }
13803
- }));
13804
- }
13805
-
13806
- // ../core/src/util/query-result.js
13807
- function queryResult() {
13808
- let resolve;
13809
- let reject;
13810
- const p = new Promise((r, e) => {
13811
- resolve = r;
13812
- reject = e;
13813
- });
13814
- return Object.assign(p, {
13815
- fulfill: (value) => (resolve(value), p),
13816
- reject: (err) => (reject(err), p)
13817
- });
13818
- }
14089
+ QueryResult.prototype.constructor = Promise;
13819
14090
 
13820
14091
  // ../core/src/QueryConsolidator.js
13821
14092
  function wait(callback) {
@@ -13891,7 +14162,7 @@ function consolidate(group3, enqueue, record) {
13891
14162
  record: false,
13892
14163
  query: group3.query = consolidatedQuery(group3, record)
13893
14164
  },
13894
- result: group3.result = queryResult()
14165
+ result: group3.result = new QueryResult()
13895
14166
  });
13896
14167
  } else {
13897
14168
  for (const { entry, priority } of group3) {
@@ -14107,115 +14378,124 @@ function priorityQueue(ranks) {
14107
14378
 
14108
14379
  // ../core/src/QueryManager.js
14109
14380
  var Priority = { High: 0, Normal: 1, Low: 2 };
14110
- function QueryManager() {
14111
- const queue = priorityQueue(3);
14112
- let db;
14113
- let clientCache;
14114
- let logger;
14115
- let recorders = [];
14116
- let pending = null;
14117
- let consolidate2;
14118
- function next() {
14119
- if (pending || queue.isEmpty()) return;
14120
- const { request, result } = queue.next();
14121
- pending = submit(request, result);
14122
- pending.finally(() => {
14123
- pending = null;
14124
- next();
14381
+ var QueryManager = class {
14382
+ constructor() {
14383
+ this.queue = priorityQueue(3);
14384
+ this.db = null;
14385
+ this.clientCache = null;
14386
+ this._logger = null;
14387
+ this._logQueries = false;
14388
+ this.recorders = [];
14389
+ this.pending = null;
14390
+ this._consolidate = null;
14391
+ }
14392
+ next() {
14393
+ if (this.pending || this.queue.isEmpty()) return;
14394
+ const { request, result } = this.queue.next();
14395
+ this.pending = this.submit(request, result);
14396
+ this.pending.finally(() => {
14397
+ this.pending = null;
14398
+ this.next();
14125
14399
  });
14126
14400
  }
14127
- function enqueue(entry, priority = Priority.Normal) {
14128
- queue.insert(entry, priority);
14129
- next();
14401
+ enqueue(entry, priority = Priority.Normal) {
14402
+ this.queue.insert(entry, priority);
14403
+ this.next();
14130
14404
  }
14131
- function recordQuery(sql2) {
14132
- if (recorders.length && sql2) {
14133
- recorders.forEach((rec) => rec.add(sql2));
14405
+ recordQuery(sql2) {
14406
+ if (this.recorders.length && sql2) {
14407
+ this.recorders.forEach((rec) => rec.add(sql2));
14134
14408
  }
14135
14409
  }
14136
- async function submit(request, result) {
14410
+ async submit(request, result) {
14137
14411
  try {
14138
14412
  const { query, type: type2, cache = false, record = true, options } = request;
14139
14413
  const sql2 = query ? `${query}` : null;
14140
14414
  if (record) {
14141
- recordQuery(sql2);
14415
+ this.recordQuery(sql2);
14142
14416
  }
14143
14417
  if (cache) {
14144
- const cached = clientCache.get(sql2);
14418
+ const cached = this.clientCache.get(sql2);
14145
14419
  if (cached) {
14146
- logger.debug("Cache");
14420
+ this._logger.debug("Cache");
14147
14421
  result.fulfill(cached);
14148
14422
  return;
14149
14423
  }
14150
14424
  }
14151
14425
  const t03 = performance.now();
14152
- const data = await db.query({ type: type2, sql: sql2, ...options });
14153
- if (cache) clientCache.set(sql2, data);
14154
- logger.debug(`Request: ${(performance.now() - t03).toFixed(1)}`);
14426
+ if (this._logQueries) {
14427
+ this._logger.debug("Query", { type: type2, sql: sql2, ...options });
14428
+ }
14429
+ const data = await this.db.query({ type: type2, sql: sql2, ...options });
14430
+ if (cache) this.clientCache.set(sql2, data);
14431
+ this._logger.debug(`Request: ${(performance.now() - t03).toFixed(1)}`);
14155
14432
  result.fulfill(data);
14156
14433
  } catch (err) {
14157
14434
  result.reject(err);
14158
14435
  }
14159
14436
  }
14160
- return {
14161
- cache(value) {
14162
- return value !== void 0 ? clientCache = value === true ? lruCache() : value || voidCache() : clientCache;
14163
- },
14164
- logger(value) {
14165
- return value ? logger = value : logger;
14166
- },
14167
- connector(connector) {
14168
- return connector ? db = connector : db;
14169
- },
14170
- consolidate(flag) {
14171
- if (flag && !consolidate2) {
14172
- consolidate2 = consolidator(enqueue, clientCache, recordQuery);
14173
- } else if (!flag && consolidate2) {
14174
- consolidate2 = null;
14175
- }
14176
- },
14177
- request(request, priority = Priority.Normal) {
14178
- const result = queryResult();
14179
- const entry = { request, result };
14180
- if (consolidate2) {
14181
- consolidate2.add(entry, priority);
14182
- } else {
14183
- enqueue(entry, priority);
14184
- }
14185
- return result;
14186
- },
14187
- cancel(requests) {
14188
- const set3 = new Set(requests);
14189
- queue.remove(({ result }) => set3.has(result));
14190
- },
14191
- clear() {
14192
- queue.remove(({ result }) => {
14193
- result.reject("Cleared");
14194
- return true;
14195
- });
14196
- },
14197
- record() {
14198
- let state = [];
14199
- const recorder = {
14200
- add(query) {
14201
- state.push(query);
14202
- },
14203
- reset() {
14204
- state = [];
14205
- },
14206
- snapshot() {
14207
- return state.slice();
14208
- },
14209
- stop() {
14210
- recorders = recorders.filter((x3) => x3 !== recorder);
14211
- return state;
14212
- }
14213
- };
14214
- recorders.push(recorder);
14215
- return recorder;
14437
+ cache(value) {
14438
+ return value !== void 0 ? this.clientCache = value === true ? lruCache() : value || voidCache() : this.clientCache;
14439
+ }
14440
+ logger(value) {
14441
+ return value ? this._logger = value : this._logger;
14442
+ }
14443
+ logQueries(value) {
14444
+ return value !== void 0 ? this._logQueries = !!value : this._logQueries;
14445
+ }
14446
+ connector(connector) {
14447
+ return connector ? this.db = connector : this.db;
14448
+ }
14449
+ consolidate(flag) {
14450
+ if (flag && !this._consolidate) {
14451
+ this._consolidate = consolidator(this.enqueue.bind(this), this.clientCache, this.recordQuery.bind(this));
14452
+ } else if (!flag && this._consolidate) {
14453
+ this._consolidate = null;
14216
14454
  }
14217
- };
14218
- }
14455
+ }
14456
+ request(request, priority = Priority.Normal) {
14457
+ const result = new QueryResult();
14458
+ const entry = { request, result };
14459
+ if (this._consolidate) {
14460
+ this._consolidate.add(entry, priority);
14461
+ } else {
14462
+ this.enqueue(entry, priority);
14463
+ }
14464
+ return result;
14465
+ }
14466
+ cancel(requests) {
14467
+ const set3 = new Set(requests);
14468
+ if (set3.size) {
14469
+ this.queue.remove(({ result }) => set3.has(result));
14470
+ }
14471
+ }
14472
+ clear() {
14473
+ this.queue.remove(({ result }) => {
14474
+ result.reject("Cleared");
14475
+ return true;
14476
+ });
14477
+ }
14478
+ record() {
14479
+ let state = [];
14480
+ const recorder = {
14481
+ add(query) {
14482
+ state.push(query);
14483
+ },
14484
+ reset() {
14485
+ state = [];
14486
+ },
14487
+ snapshot() {
14488
+ return state.slice();
14489
+ },
14490
+ stop() {
14491
+ this.recorders = this.recorders.filter((x3) => x3 !== recorder);
14492
+ return state;
14493
+ }
14494
+ };
14495
+ this.recorders.push(recorder);
14496
+ return recorder;
14497
+ }
14498
+ };
14219
14499
 
14220
14500
  // ../core/src/util/js-type.js
14221
14501
  function jsType(type2) {
@@ -14296,23 +14576,26 @@ function convertArrowColumn(column3) {
14296
14576
  }
14297
14577
  if (DataType.isInt(type2) && type2.bitWidth >= 64) {
14298
14578
  const size = column3.length;
14299
- const array4 = new Float64Array(size);
14579
+ const array4 = column3.nullCount ? new Array(size) : new Float64Array(size);
14300
14580
  for (let row = 0; row < size; ++row) {
14301
14581
  const v2 = column3.get(row);
14302
- array4[row] = v2 == null ? NaN : Number(v2);
14582
+ array4[row] = v2 == null ? null : Number(v2);
14303
14583
  }
14304
14584
  return array4;
14305
14585
  }
14306
14586
  if (DataType.isDecimal(type2)) {
14307
14587
  const scale3 = 1 / Math.pow(10, type2.scale);
14308
14588
  const size = column3.length;
14309
- const array4 = new Float64Array(size);
14589
+ const array4 = column3.nullCount ? new Array(size) : new Float64Array(size);
14310
14590
  for (let row = 0; row < size; ++row) {
14311
14591
  const v2 = column3.get(row);
14312
- array4[row] = v2 == null ? NaN : decimalToNumber(v2, scale3);
14592
+ array4[row] = v2 == null ? null : decimalToNumber(v2, scale3);
14313
14593
  }
14314
14594
  return array4;
14315
14595
  }
14596
+ if (column3.nullCount) {
14597
+ return Array.from(column3);
14598
+ }
14316
14599
  return column3.toArray();
14317
14600
  }
14318
14601
  var BASE32 = Array.from(
@@ -14419,58 +14702,92 @@ function coordinator(instance8) {
14419
14702
  return _instance;
14420
14703
  }
14421
14704
  var Coordinator = class {
14422
- constructor(db = socketConnector(), options = {}) {
14423
- const {
14424
- logger = console,
14425
- manager = QueryManager()
14426
- } = options;
14705
+ constructor(db = socketConnector(), {
14706
+ logger = console,
14707
+ manager = new QueryManager(),
14708
+ cache = true,
14709
+ consolidate: consolidate2 = true,
14710
+ indexes: indexes2 = {}
14711
+ } = {}) {
14427
14712
  this.manager = manager;
14713
+ this.manager.cache(cache);
14714
+ this.manager.consolidate(consolidate2);
14715
+ this.dataCubeIndexer = new DataCubeIndexer(this, indexes2);
14428
14716
  this.logger(logger);
14429
- this.configure(options);
14430
14717
  this.databaseConnector(db);
14431
14718
  this.clear();
14432
14719
  }
14433
- logger(logger) {
14434
- if (arguments.length) {
14435
- this._logger = logger || voidLogger();
14436
- this.manager.logger(this._logger);
14437
- }
14438
- return this._logger;
14439
- }
14440
14720
  /**
14441
- * Set configuration options for this coordinator.
14442
- * @param {object} [options] Configration options.
14443
- * @param {boolean} [options.cache=true] Boolean flag to enable/disable query caching.
14444
- * @param {boolean} [options.consolidate=true] Boolean flag to enable/disable query consolidation.
14445
- * @param {boolean|object} [options.indexes=true] Boolean flag to enable/disable
14446
- * automatic data cube indexes or an index options object.
14721
+ * Clear the coordinator state.
14722
+ * @param {object} [options] Options object.
14723
+ * @param {boolean} [options.clients=true] If true, disconnect all clients.
14724
+ * @param {boolean} [options.cache=true] If true, clear the query cache.
14447
14725
  */
14448
- configure({ cache = true, consolidate: consolidate2 = true, indexes: indexes2 = true } = {}) {
14449
- this.manager.cache(cache);
14450
- this.manager.consolidate(consolidate2);
14451
- this.indexes = indexes2;
14452
- }
14453
14726
  clear({ clients = true, cache = true } = {}) {
14454
14727
  this.manager.clear();
14455
14728
  if (clients) {
14729
+ this.filterGroups?.forEach((group3) => group3.disconnect());
14730
+ this.filterGroups = /* @__PURE__ */ new Map();
14456
14731
  this.clients?.forEach((client) => this.disconnect(client));
14457
- this.filterGroups?.forEach((group3) => group3.finalize());
14458
14732
  this.clients = /* @__PURE__ */ new Set();
14459
- this.filterGroups = /* @__PURE__ */ new Map();
14460
14733
  }
14461
14734
  if (cache) this.manager.cache().clear();
14462
14735
  }
14736
+ /**
14737
+ * Get or set the database connector.
14738
+ * @param {*} [db] The database connector to use.
14739
+ * @returns The current database connector.
14740
+ */
14463
14741
  databaseConnector(db) {
14464
14742
  return this.manager.connector(db);
14465
14743
  }
14744
+ /**
14745
+ * Get or set the logger.
14746
+ * @param {*} logger The logger to use.
14747
+ * @returns The current logger
14748
+ */
14749
+ logger(logger) {
14750
+ if (arguments.length) {
14751
+ this._logger = logger || voidLogger();
14752
+ this.manager.logger(this._logger);
14753
+ }
14754
+ return this._logger;
14755
+ }
14466
14756
  // -- Query Management ----
14757
+ /**
14758
+ * Cancel previosuly submitted query requests. These queries will be
14759
+ * canceled if they are queued but have not yet been submitted.
14760
+ * @param {import('./util/query-result.js').QueryResult[]} requests An array
14761
+ * of query result objects, such as those returned by the `query` method.
14762
+ */
14467
14763
  cancel(requests) {
14468
14764
  this.manager.cancel(requests);
14469
14765
  }
14766
+ /**
14767
+ * Issue a query for which no result (return value) is needed.
14768
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14769
+ * @param {object} [options] An options object.
14770
+ * @param {number} [options.priority] The query priority, defaults to
14771
+ * `Priority.Normal`.
14772
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14773
+ * promise.
14774
+ */
14470
14775
  exec(query, { priority = Priority.Normal } = {}) {
14471
14776
  query = Array.isArray(query) ? query.join(";\n") : query;
14472
14777
  return this.manager.request({ type: "exec", query }, priority);
14473
14778
  }
14779
+ /**
14780
+ * Issue a query to the backing database. The submitted query may be
14781
+ * consolidate with other queries and its results may be cached.
14782
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14783
+ * @param {object} [options] An options object.
14784
+ * @param {'arrow' | 'json'} [options.type] The query result format type.
14785
+ * @param {boolean} [options.cache=true] If true, cache the query result.
14786
+ * @param {number} [options.priority] The query priority, defaults to
14787
+ * `Priority.Normal`.
14788
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14789
+ * promise.
14790
+ */
14474
14791
  query(query, {
14475
14792
  type: type2 = "arrow",
14476
14793
  cache = true,
@@ -14479,6 +14796,15 @@ var Coordinator = class {
14479
14796
  } = {}) {
14480
14797
  return this.manager.request({ type: type2, query, cache, options }, priority);
14481
14798
  }
14799
+ /**
14800
+ * Issue a query to prefetch data for later use. The query result is cached
14801
+ * for efficient future access.
14802
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The query.
14803
+ * @param {object} [options] An options object.
14804
+ * @param {'arrow' | 'json'} [options.type] The query result format type.
14805
+ * @returns {import('./util/query-result.js').QueryResult} A query result
14806
+ * promise.
14807
+ */
14482
14808
  prefetch(query, options = {}) {
14483
14809
  return this.query(query, { ...options, cache: true, priority: Priority.Low });
14484
14810
  }
@@ -14491,26 +14817,44 @@ var Coordinator = class {
14491
14817
  return this.manager.request({ type: "load-bundle", options }, priority);
14492
14818
  }
14493
14819
  // -- Client Management ----
14820
+ /**
14821
+ * Update client data by submitting the given query and returning the
14822
+ * data (or error) to the client.
14823
+ * @param {import('./MosaicClient.js').MosaicClient} client A Mosaic client.
14824
+ * @param {import('@uwdata/mosaic-sql').Query | string} query The data query.
14825
+ * @param {number} [priority] The query priority.
14826
+ * @returns {Promise} A Promise that resolves upon completion of the update.
14827
+ */
14494
14828
  updateClient(client, query, priority = Priority.Normal) {
14495
14829
  client.queryPending();
14496
14830
  return this.query(query, { priority }).then(
14497
14831
  (data) => client.queryResult(data).update(),
14498
14832
  (err) => {
14499
- client.queryError(err);
14500
14833
  this._logger.error(err);
14834
+ client.queryError(err);
14501
14835
  }
14502
- );
14836
+ ).catch((err) => this._logger.error(err));
14503
14837
  }
14838
+ /**
14839
+ * Issue a query request for a client. If the query is null or undefined,
14840
+ * the client is simply updated. Otherwise `updateClient` is called. As a
14841
+ * side effect, this method clears the current data cube indexer state.
14842
+ * @param {import('./MosaicClient.js').MosaicClient} client The client
14843
+ * to update.
14844
+ * @param {import('@uwdata/mosaic-sql').Query | string | null} [query]
14845
+ * The query to issue.
14846
+ */
14504
14847
  requestQuery(client, query) {
14505
- this.filterGroups.get(client.filterBy)?.reset();
14848
+ this.dataCubeIndexer.clear();
14506
14849
  return query ? this.updateClient(client, query) : client.update();
14507
14850
  }
14508
14851
  /**
14509
14852
  * Connect a client to the coordinator.
14510
- * @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
14853
+ * @param {import('./MosaicClient.js').MosaicClient} client The Mosaic
14854
+ * client to connect.
14511
14855
  */
14512
14856
  async connect(client) {
14513
- const { clients, filterGroups, indexes: indexes2 } = this;
14857
+ const { clients } = this;
14514
14858
  if (clients.has(client)) {
14515
14859
  throw new Error("Client already connected.");
14516
14860
  }
@@ -14520,30 +14864,64 @@ var Coordinator = class {
14520
14864
  if (fields?.length) {
14521
14865
  client.fieldInfo(await queryFieldInfo(this, fields));
14522
14866
  }
14523
- const filter3 = client.filterBy;
14524
- if (filter3) {
14525
- if (filterGroups.has(filter3)) {
14526
- filterGroups.get(filter3).add(client);
14527
- } else {
14528
- const group3 = new FilterGroup(this, filter3, indexes2);
14529
- filterGroups.set(filter3, group3.add(client));
14530
- }
14531
- }
14867
+ connectSelection(this, client.filterBy, client);
14532
14868
  client.requestQuery();
14533
14869
  }
14534
14870
  /**
14535
14871
  * Disconnect a client from the coordinator.
14536
- *
14537
- * @param {import('./MosaicClient.js').MosaicClient} client the client to disconnect
14872
+ * @param {import('./MosaicClient.js').MosaicClient} client The Mosaic
14873
+ * client to disconnect.
14538
14874
  */
14539
14875
  disconnect(client) {
14540
14876
  const { clients, filterGroups } = this;
14541
14877
  if (!clients.has(client)) return;
14542
14878
  clients.delete(client);
14543
- filterGroups.get(client.filterBy)?.remove(client);
14544
14879
  client.coordinator = null;
14880
+ const group3 = filterGroups.get(client.filterBy);
14881
+ if (group3) {
14882
+ group3.clients.delete(client);
14883
+ }
14545
14884
  }
14546
14885
  };
14886
+ function connectSelection(mc, selection2, client) {
14887
+ if (!selection2) return;
14888
+ let entry = mc.filterGroups.get(selection2);
14889
+ if (!entry) {
14890
+ const activate = (clause) => activateSelection(mc, selection2, clause);
14891
+ const value = () => updateSelection(mc, selection2);
14892
+ selection2.addEventListener("activate", activate);
14893
+ selection2.addEventListener("value", value);
14894
+ entry = {
14895
+ selection: selection2,
14896
+ clients: /* @__PURE__ */ new Set(),
14897
+ disconnect() {
14898
+ selection2.removeEventListener("activate", activate);
14899
+ selection2.removeEventListener("value", value);
14900
+ }
14901
+ };
14902
+ mc.filterGroups.set(selection2, entry);
14903
+ }
14904
+ entry.clients.add(client);
14905
+ }
14906
+ function activateSelection(mc, selection2, clause) {
14907
+ const { dataCubeIndexer, filterGroups } = mc;
14908
+ const { clients } = filterGroups.get(selection2);
14909
+ for (const client of clients) {
14910
+ dataCubeIndexer.index(client, selection2, clause);
14911
+ }
14912
+ }
14913
+ function updateSelection(mc, selection2) {
14914
+ const { dataCubeIndexer, filterGroups } = mc;
14915
+ const { clients } = filterGroups.get(selection2);
14916
+ const { active } = selection2;
14917
+ return Promise.allSettled(Array.from(clients, (client) => {
14918
+ const info = dataCubeIndexer.index(client, selection2, active);
14919
+ const filter3 = info ? null : selection2.predicate(client);
14920
+ if (info?.skip || !info && !filter3) return;
14921
+ const query = info?.query(active.predicate) ?? client.query(filter3);
14922
+ return mc.updateClient(client, query);
14923
+ }));
14924
+ }
14547
14925
 
14548
14926
  // ../core/src/util/AsyncDispatch.js
14549
14927
  var AsyncDispatch = class {
@@ -14600,7 +14978,7 @@ var AsyncDispatch = class {
14600
14978
  * queue of unemitted event values prior to enqueueing a new value.
14601
14979
  * This default implementation simply returns null, indicating that
14602
14980
  * any other unemitted event values should be dropped (that is, all
14603
- * queued events are filtered)
14981
+ * queued events are filtered).
14604
14982
  * @param {string} type The event type.
14605
14983
  * @param {*} value The new event value that will be enqueued.
14606
14984
  * @returns {(value: *) => boolean|null} A dispatch queue filter
@@ -14617,6 +14995,16 @@ var AsyncDispatch = class {
14617
14995
  const entry = this._callbacks.get(type2);
14618
14996
  entry?.queue.clear();
14619
14997
  }
14998
+ /**
14999
+ * Returns a promise that resolves when any pending updates complete for
15000
+ * the event of the given type currently being processed. The Promise will
15001
+ * resolve immediately if the queue for the given event type is empty.
15002
+ * @param {string} type The event type to wait for.
15003
+ * @returns {Promise} A pending event promise.
15004
+ */
15005
+ async pending(type2) {
15006
+ await this._callbacks.get(type2)?.pending;
15007
+ }
14620
15008
  /**
14621
15009
  * Emit an event value to listeners for the given event type.
14622
15010
  * If a previous emit has not yet resolved, the event value
@@ -14804,10 +15192,13 @@ var Selection = class _Selection extends Param {
14804
15192
  * @param {boolean} [options.cross=false] Boolean flag indicating
14805
15193
  * cross-filtered resolution. If true, selection clauses will not
14806
15194
  * be applied to the clients they are associated with.
15195
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
15196
+ * of clauses should correspond to an empty selection with no records. This
15197
+ * setting determines the default selection state.
14807
15198
  * @returns {Selection} The new Selection instance.
14808
15199
  */
14809
- static intersect({ cross: cross3 = false } = {}) {
14810
- return new _Selection(new SelectionResolver({ cross: cross3 }));
15200
+ static intersect({ cross: cross3 = false, empty: empty4 = false } = {}) {
15201
+ return new _Selection(new SelectionResolver({ cross: cross3, empty: empty4 }));
14811
15202
  }
14812
15203
  /**
14813
15204
  * Create a new Selection instance with a
@@ -14816,10 +15207,13 @@ var Selection = class _Selection extends Param {
14816
15207
  * @param {boolean} [options.cross=false] Boolean flag indicating
14817
15208
  * cross-filtered resolution. If true, selection clauses will not
14818
15209
  * be applied to the clients they are associated with.
15210
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
15211
+ * of clauses should correspond to an empty selection with no records. This
15212
+ * setting determines the default selection state.
14819
15213
  * @returns {Selection} The new Selection instance.
14820
15214
  */
14821
- static union({ cross: cross3 = false } = {}) {
14822
- return new _Selection(new SelectionResolver({ cross: cross3, union: true }));
15215
+ static union({ cross: cross3 = false, empty: empty4 = false } = {}) {
15216
+ return new _Selection(new SelectionResolver({ cross: cross3, empty: empty4, union: true }));
14823
15217
  }
14824
15218
  /**
14825
15219
  * Create a new Selection instance with a singular resolution strategy
@@ -14828,18 +15222,25 @@ var Selection = class _Selection extends Param {
14828
15222
  * @param {boolean} [options.cross=false] Boolean flag indicating
14829
15223
  * cross-filtered resolution. If true, selection clauses will not
14830
15224
  * be applied to the clients they are associated with.
15225
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
15226
+ * of clauses should correspond to an empty selection with no records. This
15227
+ * setting determines the default selection state.
14831
15228
  * @returns {Selection} The new Selection instance.
14832
15229
  */
14833
- static single({ cross: cross3 = false } = {}) {
14834
- return new _Selection(new SelectionResolver({ cross: cross3, single: true }));
15230
+ static single({ cross: cross3 = false, empty: empty4 = false } = {}) {
15231
+ return new _Selection(new SelectionResolver({ cross: cross3, empty: empty4, single: true }));
14835
15232
  }
14836
15233
  /**
14837
15234
  * Create a new Selection instance with a
14838
15235
  * cross-filtered intersect resolution strategy.
15236
+ * @param {object} [options] The selection options.
15237
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
15238
+ * of clauses should correspond to an empty selection with no records. This
15239
+ * setting determines the default selection state.
14839
15240
  * @returns {Selection} The new Selection instance.
14840
15241
  */
14841
- static crossfilter() {
14842
- return new _Selection(new SelectionResolver({ cross: true }));
15242
+ static crossfilter({ empty: empty4 = false } = {}) {
15243
+ return new _Selection(new SelectionResolver({ cross: true, empty: empty4 }));
14843
15244
  }
14844
15245
  /**
14845
15246
  * Create a new Selection instance.
@@ -14872,6 +15273,24 @@ var Selection = class _Selection extends Param {
14872
15273
  s2._value.active = { source };
14873
15274
  return s2;
14874
15275
  }
15276
+ /**
15277
+ * The selection clause resolver.
15278
+ */
15279
+ get resolver() {
15280
+ return this._resolver;
15281
+ }
15282
+ /**
15283
+ * Indicate if this selection has a single resolution strategy.
15284
+ */
15285
+ get single() {
15286
+ return this._resolver.single;
15287
+ }
15288
+ /**
15289
+ * The current array of selection clauses.
15290
+ */
15291
+ get clauses() {
15292
+ return super.value;
15293
+ }
14875
15294
  /**
14876
15295
  * The current active (most recently updated) selection clause.
14877
15296
  */
@@ -14886,16 +15305,12 @@ var Selection = class _Selection extends Param {
14886
15305
  return this.active?.value;
14887
15306
  }
14888
15307
  /**
14889
- * The current array of selection clauses.
15308
+ * The value corresponding to a given source. Returns undefined if
15309
+ * this selection does not include a clause from this source.
15310
+ * @param {*} source The clause source to look up the value for.
14890
15311
  */
14891
- get clauses() {
14892
- return super.value;
14893
- }
14894
- /**
14895
- * Indicate if this selection has a single resolution strategy.
14896
- */
14897
- get single() {
14898
- return this._resolver.single;
15312
+ valueFor(source) {
15313
+ return this.clauses.find((c4) => c4.source === source)?.value;
14899
15314
  }
14900
15315
  /**
14901
15316
  * Emit an activate event with the given selection clause.
@@ -14973,11 +15388,15 @@ var SelectionResolver = class {
14973
15388
  * If false, an intersection strategy is used.
14974
15389
  * @param {boolean} [options.cross=false] Boolean flag to indicate cross-filtering.
14975
15390
  * @param {boolean} [options.single=false] Boolean flag to indicate single clauses only.
15391
+ * @param {boolean} [options.empty=false] Boolean flag indicating if a lack
15392
+ * of clauses should correspond to an empty selection with no records. This
15393
+ * setting determines the default selection state.
14976
15394
  */
14977
- constructor({ union, cross: cross3, single } = {}) {
15395
+ constructor({ union, cross: cross3, single, empty: empty4 } = {}) {
14978
15396
  this.union = !!union;
14979
15397
  this.cross = !!cross3;
14980
15398
  this.single = !!single;
15399
+ this.empty = !!empty4;
14981
15400
  }
14982
15401
  /**
14983
15402
  * Resolve a list of selection clauses according to the resolution strategy.
@@ -15012,7 +15431,10 @@ var SelectionResolver = class {
15012
15431
  * based on the current state of this selection.
15013
15432
  */
15014
15433
  predicate(clauseList, active, client) {
15015
- const { union } = this;
15434
+ const { empty: empty4, union } = this;
15435
+ if (empty4 && !clauseList.length) {
15436
+ return ["FALSE"];
15437
+ }
15016
15438
  if (this.skip(client, active)) return void 0;
15017
15439
  const predicates = clauseList.filter((clause) => !this.skip(client, clause)).map((clause) => clause.predicate);
15018
15440
  return union && predicates.length > 1 ? or(predicates) : predicates;
@@ -15032,6 +15454,50 @@ var SelectionResolver = class {
15032
15454
  }
15033
15455
  };
15034
15456
 
15457
+ // ../core/src/SelectionClause.js
15458
+ function clausePoints(fields, value, {
15459
+ source,
15460
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0
15461
+ }) {
15462
+ let predicate = null;
15463
+ if (value) {
15464
+ const clauses = value.map((vals) => {
15465
+ const list = vals.map((v2, i) => isNotDistinct(fields[i], literal(v2)));
15466
+ return list.length > 1 ? and(list) : list[0];
15467
+ });
15468
+ predicate = clauses.length > 1 ? or(clauses) : clauses[0];
15469
+ }
15470
+ return {
15471
+ meta: { type: "point" },
15472
+ source,
15473
+ clients,
15474
+ value,
15475
+ predicate
15476
+ };
15477
+ }
15478
+ function clauseInterval(field2, value, {
15479
+ source,
15480
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0,
15481
+ bin: bin3,
15482
+ scale: scale3,
15483
+ pixelSize = 1
15484
+ }) {
15485
+ const predicate = value != null ? isBetween(field2, value) : null;
15486
+ const meta = { type: "interval", scales: scale3 && [scale3], bin: bin3, pixelSize };
15487
+ return { meta, source, clients, value, predicate };
15488
+ }
15489
+ function clauseIntervals(fields, value, {
15490
+ source,
15491
+ clients = source ? /* @__PURE__ */ new Set([source]) : void 0,
15492
+ bin: bin3,
15493
+ scales: scales2 = [],
15494
+ pixelSize = 1
15495
+ }) {
15496
+ const predicate = value != null ? and(fields.map((f, i) => isBetween(f, value[i]))) : null;
15497
+ const meta = { type: "interval", scales: scales2, bin: bin3, pixelSize };
15498
+ return { meta, source, clients, value, predicate };
15499
+ }
15500
+
15035
15501
  // ../core/src/util/synchronizer.js
15036
15502
  function synchronizer() {
15037
15503
  const set3 = /* @__PURE__ */ new Set();
@@ -15076,6 +15542,39 @@ function synchronizer() {
15076
15542
  };
15077
15543
  }
15078
15544
 
15545
+ // ../core/src/util/to-data-columns.js
15546
+ function toDataColumns(data) {
15547
+ return isArrowTable(data) ? arrowToColumns(data) : arrayToColumns(data);
15548
+ }
15549
+ function arrowToColumns(data) {
15550
+ const { numRows, numCols, schema: { fields } } = data;
15551
+ const columns = {};
15552
+ for (let col = 0; col < numCols; ++col) {
15553
+ const name = fields[col].name;
15554
+ if (columns[name]) {
15555
+ console.warn(`Redundant column name "${name}". Skipping...`);
15556
+ } else {
15557
+ columns[name] = convertArrowColumn(data.getChildAt(col));
15558
+ }
15559
+ }
15560
+ return { numRows, columns };
15561
+ }
15562
+ function arrayToColumns(data) {
15563
+ const numRows = data.length;
15564
+ if (typeof data[0] === "object") {
15565
+ const names = numRows ? Object.keys(data[0]) : [];
15566
+ const columns = {};
15567
+ if (names.length > 0) {
15568
+ names.forEach((name) => {
15569
+ columns[name] = data.map((d) => d[name]);
15570
+ });
15571
+ }
15572
+ return { numRows, columns };
15573
+ } else {
15574
+ return { numRows, values: data };
15575
+ }
15576
+ }
15577
+
15079
15578
  // ../../node_modules/@observablehq/plot/src/index.js
15080
15579
  var src_exports = {};
15081
15580
  __export(src_exports, {
@@ -15147,6 +15646,7 @@ __export(src_exports, {
15147
15646
  find: () => find2,
15148
15647
  formatIsoDate: () => formatIsoDate,
15149
15648
  formatMonth: () => formatMonth,
15649
+ formatNumber: () => formatNumber,
15150
15650
  formatWeekday: () => formatWeekday,
15151
15651
  frame: () => frame2,
15152
15652
  geo: () => geo,
@@ -15186,6 +15686,7 @@ __export(src_exports, {
15186
15686
  normalize: () => normalize3,
15187
15687
  normalizeX: () => normalizeX,
15188
15688
  normalizeY: () => normalizeY,
15689
+ numberInterval: () => numberInterval,
15189
15690
  plot: () => plot,
15190
15691
  pointer: () => pointer,
15191
15692
  pointerX: () => pointerX,
@@ -15221,11 +15722,13 @@ __export(src_exports, {
15221
15722
  textY: () => textY,
15222
15723
  tickX: () => tickX,
15223
15724
  tickY: () => tickY,
15725
+ timeInterval: () => timeInterval2,
15224
15726
  tip: () => tip,
15225
15727
  transform: () => basic,
15226
15728
  tree: () => tree,
15227
15729
  treeLink: () => treeLink,
15228
15730
  treeNode: () => treeNode,
15731
+ utcInterval: () => utcInterval,
15229
15732
  valueof: () => valueof,
15230
15733
  vector: () => vector,
15231
15734
  vectorX: () => vectorX,
@@ -27791,10 +28294,10 @@ function parseTimeInterval(input) {
27791
28294
  if (period > 1 && !interval2.every) throw new Error(`non-periodic interval: ${name}`);
27792
28295
  return [name, period];
27793
28296
  }
27794
- function maybeTimeInterval(input) {
28297
+ function timeInterval2(input) {
27795
28298
  return asInterval(parseTimeInterval(input), "time");
27796
28299
  }
27797
- function maybeUtcInterval(input) {
28300
+ function utcInterval(input) {
27798
28301
  return asInterval(parseTimeInterval(input), "utc");
27799
28302
  }
27800
28303
  function asInterval([name, period], type2) {
@@ -27812,7 +28315,7 @@ function generalizeTimeInterval(interval2, n) {
27812
28315
  if (!tickIntervals.some(([, d]) => d === duration)) return;
27813
28316
  if (duration % durationDay2 === 0 && durationDay2 < duration && duration < durationMonth2) return;
27814
28317
  const [i] = tickIntervals[bisector(([, step]) => Math.log(step)).center(tickIntervals, Math.log(duration * n))];
27815
- return (interval2[intervalType] === "time" ? maybeTimeInterval : maybeUtcInterval)(i);
28318
+ return (interval2[intervalType] === "time" ? timeInterval2 : utcInterval)(i);
27816
28319
  }
27817
28320
  function formatTimeInterval(name, type2, anchor) {
27818
28321
  const format3 = type2 === "time" ? timeFormat : utcFormat;
@@ -27877,7 +28380,7 @@ function valueof(data, value, type2) {
27877
28380
  return valueType === "string" ? maybeTypedMap(data, field(value), type2) : valueType === "function" ? maybeTypedMap(data, value, type2) : valueType === "number" || value instanceof Date || valueType === "boolean" ? map2(data, constant(value), type2) : typeof value?.transform === "function" ? maybeTypedArrayify(value.transform(data), type2) : maybeTake(maybeTypedArrayify(value, type2), data?.[reindex]);
27878
28381
  }
27879
28382
  function maybeTake(values2, index2) {
27880
- return index2 ? take(values2, index2) : values2;
28383
+ return values2 != null && index2 ? take(values2, index2) : values2;
27881
28384
  }
27882
28385
  function maybeTypedMap(data, f, type2) {
27883
28386
  return map2(data, type2?.prototype instanceof TypedArray ? floater(f) : f, type2);
@@ -28048,26 +28551,26 @@ function maybeIntervalTransform(interval2, type2) {
28048
28551
  }
28049
28552
  function maybeInterval(interval2, type2) {
28050
28553
  if (interval2 == null) return;
28051
- if (typeof interval2 === "number") {
28052
- if (0 < interval2 && interval2 < 1 && Number.isInteger(1 / interval2)) interval2 = -1 / interval2;
28053
- const n = Math.abs(interval2);
28054
- return interval2 < 0 ? {
28055
- floor: (d) => Math.floor(d * n) / n,
28056
- offset: (d) => (d * n + 1) / n,
28057
- // note: no optional step for simplicity
28058
- range: (lo, hi) => range(Math.ceil(lo * n), hi * n).map((x3) => x3 / n)
28059
- } : {
28060
- floor: (d) => Math.floor(d / n) * n,
28061
- offset: (d) => d + n,
28062
- // note: no optional step for simplicity
28063
- range: (lo, hi) => range(Math.ceil(lo / n), hi / n).map((x3) => x3 * n)
28064
- };
28065
- }
28066
- if (typeof interval2 === "string") return (type2 === "time" ? maybeTimeInterval : maybeUtcInterval)(interval2);
28554
+ if (typeof interval2 === "number") return numberInterval(interval2);
28555
+ if (typeof interval2 === "string") return (type2 === "time" ? timeInterval2 : utcInterval)(interval2);
28067
28556
  if (typeof interval2.floor !== "function") throw new Error("invalid interval; missing floor method");
28068
28557
  if (typeof interval2.offset !== "function") throw new Error("invalid interval; missing offset method");
28069
28558
  return interval2;
28070
28559
  }
28560
+ function numberInterval(interval2) {
28561
+ interval2 = +interval2;
28562
+ if (0 < interval2 && interval2 < 1 && Number.isInteger(1 / interval2)) interval2 = -1 / interval2;
28563
+ const n = Math.abs(interval2);
28564
+ return interval2 < 0 ? {
28565
+ floor: (d) => Math.floor(d * n) / n,
28566
+ offset: (d, s2 = 1) => (d * n + Math.floor(s2)) / n,
28567
+ range: (lo, hi) => range(Math.ceil(lo * n), hi * n).map((x3) => x3 / n)
28568
+ } : {
28569
+ floor: (d) => Math.floor(d / n) * n,
28570
+ offset: (d, s2 = 1) => d + n * Math.floor(s2),
28571
+ range: (lo, hi) => range(Math.ceil(lo / n), hi / n).map((x3) => x3 * n)
28572
+ };
28573
+ }
28071
28574
  function maybeRangeInterval(interval2, type2) {
28072
28575
  interval2 = maybeInterval(interval2, type2);
28073
28576
  if (interval2 && typeof interval2.range !== "function") throw new Error("invalid interval: missing range method");
@@ -28938,251 +29441,6 @@ function getSource(channels, key) {
28938
29441
  return channel.source === null ? null : channel;
28939
29442
  }
28940
29443
 
28941
- // ../../node_modules/@observablehq/plot/src/context.js
28942
- function createContext(options = {}) {
28943
- const { document: document2 = typeof window !== "undefined" ? window.document : void 0, clip } = options;
28944
- return { document: document2, clip: maybeClip(clip) };
28945
- }
28946
- function create3(name, { document: document2 }) {
28947
- return select_default2(creator_default(name).call(document2.documentElement));
28948
- }
28949
-
28950
- // ../../node_modules/@observablehq/plot/src/warnings.js
28951
- var warnings = 0;
28952
- var lastMessage;
28953
- function consumeWarnings() {
28954
- const w = warnings;
28955
- warnings = 0;
28956
- lastMessage = void 0;
28957
- return w;
28958
- }
28959
- function warn(message) {
28960
- if (message === lastMessage) return;
28961
- lastMessage = message;
28962
- console.warn(message);
28963
- ++warnings;
28964
- }
28965
-
28966
- // ../../node_modules/@observablehq/plot/src/projection.js
28967
- var pi4 = Math.PI;
28968
- var tau5 = 2 * pi4;
28969
- var defaultAspectRatio = 0.618;
28970
- function createProjection({
28971
- projection: projection3,
28972
- inset: globalInset = 0,
28973
- insetTop = globalInset,
28974
- insetRight = globalInset,
28975
- insetBottom = globalInset,
28976
- insetLeft = globalInset
28977
- } = {}, dimensions) {
28978
- if (projection3 == null) return;
28979
- if (typeof projection3.stream === "function") return projection3;
28980
- let options;
28981
- let domain;
28982
- let clip = "frame";
28983
- if (isObject2(projection3)) {
28984
- let inset;
28985
- ({
28986
- type: projection3,
28987
- domain,
28988
- inset,
28989
- insetTop = inset !== void 0 ? inset : insetTop,
28990
- insetRight = inset !== void 0 ? inset : insetRight,
28991
- insetBottom = inset !== void 0 ? inset : insetBottom,
28992
- insetLeft = inset !== void 0 ? inset : insetLeft,
28993
- clip = clip,
28994
- ...options
28995
- } = projection3);
28996
- if (projection3 == null) return;
28997
- }
28998
- if (typeof projection3 !== "function") ({ type: projection3 } = namedProjection(projection3));
28999
- const { width, height, marginLeft, marginRight, marginTop, marginBottom } = dimensions;
29000
- const dx = width - marginLeft - marginRight - insetLeft - insetRight;
29001
- const dy = height - marginTop - marginBottom - insetTop - insetBottom;
29002
- projection3 = projection3?.({ width: dx, height: dy, clip, ...options });
29003
- if (projection3 == null) return;
29004
- clip = maybePostClip(clip, marginLeft, marginTop, width - marginRight, height - marginBottom);
29005
- let tx = marginLeft + insetLeft;
29006
- let ty = marginTop + insetTop;
29007
- let transform3;
29008
- if (domain != null) {
29009
- const [[x06, y06], [x12, y12]] = path_default(projection3).bounds(domain);
29010
- const k2 = Math.min(dx / (x12 - x06), dy / (y12 - y06));
29011
- if (k2 > 0) {
29012
- tx -= (k2 * (x06 + x12) - dx) / 2;
29013
- ty -= (k2 * (y06 + y12) - dy) / 2;
29014
- transform3 = transform_default({
29015
- point(x3, y3) {
29016
- this.stream.point(x3 * k2 + tx, y3 * k2 + ty);
29017
- }
29018
- });
29019
- } else {
29020
- warn(`Warning: the projection could not be fit to the specified domain; using the default scale.`);
29021
- }
29022
- }
29023
- transform3 ??= tx === 0 && ty === 0 ? identity8() : transform_default({
29024
- point(x3, y3) {
29025
- this.stream.point(x3 + tx, y3 + ty);
29026
- }
29027
- });
29028
- return { stream: (s2) => projection3.stream(transform3.stream(clip(s2))) };
29029
- }
29030
- function namedProjection(projection3) {
29031
- switch (`${projection3}`.toLowerCase()) {
29032
- case "albers-usa":
29033
- return scaleProjection(albersUsa_default, 0.7463, 0.4673);
29034
- case "albers":
29035
- return conicProjection2(albers_default, 0.7463, 0.4673);
29036
- case "azimuthal-equal-area":
29037
- return scaleProjection(azimuthalEqualArea_default, 4, 4);
29038
- case "azimuthal-equidistant":
29039
- return scaleProjection(azimuthalEquidistant_default, tau5, tau5);
29040
- case "conic-conformal":
29041
- return conicProjection2(conicConformal_default, tau5, tau5);
29042
- case "conic-equal-area":
29043
- return conicProjection2(conicEqualArea_default, 6.1702, 2.9781);
29044
- case "conic-equidistant":
29045
- return conicProjection2(conicEquidistant_default, 7.312, 3.6282);
29046
- case "equal-earth":
29047
- return scaleProjection(equalEarth_default, 5.4133, 2.6347);
29048
- case "equirectangular":
29049
- return scaleProjection(equirectangular_default, tau5, pi4);
29050
- case "gnomonic":
29051
- return scaleProjection(gnomonic_default, 3.4641, 3.4641);
29052
- case "identity":
29053
- return { type: identity8 };
29054
- case "reflect-y":
29055
- return { type: reflectY };
29056
- case "mercator":
29057
- return scaleProjection(mercator_default, tau5, tau5);
29058
- case "orthographic":
29059
- return scaleProjection(orthographic_default, 2, 2);
29060
- case "stereographic":
29061
- return scaleProjection(stereographic_default, 2, 2);
29062
- case "transverse-mercator":
29063
- return scaleProjection(transverseMercator_default, tau5, tau5);
29064
- default:
29065
- throw new Error(`unknown projection type: ${projection3}`);
29066
- }
29067
- }
29068
- function maybePostClip(clip, x12, y12, x22, y22) {
29069
- if (clip === false || clip == null || typeof clip === "number") return (s2) => s2;
29070
- if (clip === true) clip = "frame";
29071
- switch (`${clip}`.toLowerCase()) {
29072
- case "frame":
29073
- return clipRectangle(x12, y12, x22, y22);
29074
- default:
29075
- throw new Error(`unknown projection clip type: ${clip}`);
29076
- }
29077
- }
29078
- function scaleProjection(createProjection2, kx2, ky2) {
29079
- return {
29080
- type: ({ width, height, rotate, precision = 0.15, clip }) => {
29081
- const projection3 = createProjection2();
29082
- if (precision != null) projection3.precision?.(precision);
29083
- if (rotate != null) projection3.rotate?.(rotate);
29084
- if (typeof clip === "number") projection3.clipAngle?.(clip);
29085
- projection3.scale(Math.min(width / kx2, height / ky2));
29086
- projection3.translate([width / 2, height / 2]);
29087
- return projection3;
29088
- },
29089
- aspectRatio: ky2 / kx2
29090
- };
29091
- }
29092
- function conicProjection2(createProjection2, kx2, ky2) {
29093
- const { type: type2, aspectRatio } = scaleProjection(createProjection2, kx2, ky2);
29094
- return {
29095
- type: (options) => {
29096
- const { parallels, domain, width, height } = options;
29097
- const projection3 = type2(options);
29098
- if (parallels != null) {
29099
- projection3.parallels(parallels);
29100
- if (domain === void 0) {
29101
- projection3.fitSize([width, height], { type: "Sphere" });
29102
- }
29103
- }
29104
- return projection3;
29105
- },
29106
- aspectRatio
29107
- };
29108
- }
29109
- var identity8 = constant({ stream: (stream) => stream });
29110
- var reflectY = constant(
29111
- transform_default({
29112
- point(x3, y3) {
29113
- this.stream.point(x3, -y3);
29114
- }
29115
- })
29116
- );
29117
- function project(cx, cy, values2, projection3) {
29118
- const x3 = values2[cx];
29119
- const y3 = values2[cy];
29120
- const n = x3.length;
29121
- const X3 = values2[cx] = new Float64Array(n).fill(NaN);
29122
- const Y3 = values2[cy] = new Float64Array(n).fill(NaN);
29123
- let i;
29124
- const stream = projection3.stream({
29125
- point(x4, y4) {
29126
- X3[i] = x4;
29127
- Y3[i] = y4;
29128
- }
29129
- });
29130
- for (i = 0; i < n; ++i) {
29131
- stream.point(x3[i], y3[i]);
29132
- }
29133
- }
29134
- function hasProjection({ projection: projection3 } = {}) {
29135
- if (projection3 == null) return false;
29136
- if (typeof projection3.stream === "function") return true;
29137
- if (isObject2(projection3)) projection3 = projection3.type;
29138
- return projection3 != null;
29139
- }
29140
- function projectionAspectRatio(projection3) {
29141
- if (typeof projection3?.stream === "function") return defaultAspectRatio;
29142
- if (isObject2(projection3)) projection3 = projection3.type;
29143
- if (projection3 == null) return;
29144
- if (typeof projection3 !== "function") {
29145
- const { aspectRatio } = namedProjection(projection3);
29146
- if (aspectRatio) return aspectRatio;
29147
- }
29148
- return defaultAspectRatio;
29149
- }
29150
- function applyPosition(channels, scales2, { projection: projection3 }) {
29151
- const { x: x3, y: y3 } = channels;
29152
- let position3 = {};
29153
- if (x3) position3.x = x3;
29154
- if (y3) position3.y = y3;
29155
- position3 = valueObject(position3, scales2);
29156
- if (projection3 && x3?.scale === "x" && y3?.scale === "y") project("x", "y", position3, projection3);
29157
- if (x3) position3.x = coerceNumbers(position3.x);
29158
- if (y3) position3.y = coerceNumbers(position3.y);
29159
- return position3;
29160
- }
29161
- function getGeometryChannels(channel) {
29162
- const X3 = [];
29163
- const Y3 = [];
29164
- const x3 = { scale: "x", value: X3 };
29165
- const y3 = { scale: "y", value: Y3 };
29166
- const sink = {
29167
- point(x4, y4) {
29168
- X3.push(x4);
29169
- Y3.push(y4);
29170
- },
29171
- lineStart() {
29172
- },
29173
- lineEnd() {
29174
- },
29175
- polygonStart() {
29176
- },
29177
- polygonEnd() {
29178
- },
29179
- sphere() {
29180
- }
29181
- };
29182
- for (const object of channel.value) stream_default(object, sink);
29183
- return [x3, y3];
29184
- }
29185
-
29186
29444
  // ../../node_modules/@observablehq/plot/src/scales/schemes.js
29187
29445
  var categoricalSchemes = /* @__PURE__ */ new Map([
29188
29446
  ["accent", Accent_default],
@@ -29427,8 +29685,9 @@ function createScaleQ(key, scale3, channels, {
29427
29685
  const [min5, max4] = extent(domain);
29428
29686
  if (min5 > 0 || max4 < 0) {
29429
29687
  domain = slice3(domain);
29430
- if (orderof(domain) !== Math.sign(min5)) domain[domain.length - 1] = 0;
29431
- else domain[0] = 0;
29688
+ const o = orderof(domain) || 1;
29689
+ if (o === Math.sign(min5)) domain[0] = 0;
29690
+ else domain[domain.length - 1] = 0;
29432
29691
  }
29433
29692
  }
29434
29693
  if (reverse3) domain = reverse(domain);
@@ -29579,6 +29838,22 @@ function interpolatePiecewise(interpolate) {
29579
29838
  return (i, j) => (t) => interpolate(i + t * (j - i));
29580
29839
  }
29581
29840
 
29841
+ // ../../node_modules/@observablehq/plot/src/warnings.js
29842
+ var warnings = 0;
29843
+ var lastMessage;
29844
+ function consumeWarnings() {
29845
+ const w = warnings;
29846
+ warnings = 0;
29847
+ lastMessage = void 0;
29848
+ return w;
29849
+ }
29850
+ function warn(message) {
29851
+ if (message === lastMessage) return;
29852
+ lastMessage = message;
29853
+ console.warn(message);
29854
+ ++warnings;
29855
+ }
29856
+
29582
29857
  // ../../node_modules/@observablehq/plot/src/scales/diverging.js
29583
29858
  function createScaleD(key, scale3, transform3, channels, {
29584
29859
  type: type2,
@@ -30234,6 +30509,373 @@ function exposeScale({ scale: scale3, type: type2, domain, range: range3, interp
30234
30509
  };
30235
30510
  }
30236
30511
 
30512
+ // ../../node_modules/@observablehq/plot/src/facet.js
30513
+ function createFacets(channelsByScale, options) {
30514
+ const { fx, fy } = createScales(channelsByScale, options);
30515
+ const fxDomain = fx?.scale.domain();
30516
+ const fyDomain = fy?.scale.domain();
30517
+ return fxDomain && fyDomain ? cross(fxDomain, fyDomain).map(([x3, y3], i) => ({ x: x3, y: y3, i })) : fxDomain ? fxDomain.map((x3, i) => ({ x: x3, i })) : fyDomain ? fyDomain.map((y3, i) => ({ y: y3, i })) : void 0;
30518
+ }
30519
+ function recreateFacets(facets, { x: X3, y: Y3 }) {
30520
+ X3 &&= facetIndex(X3);
30521
+ Y3 &&= facetIndex(Y3);
30522
+ return facets.filter(
30523
+ X3 && Y3 ? (f) => X3.has(f.x) && Y3.has(f.y) : X3 ? (f) => X3.has(f.x) : (f) => Y3.has(f.y)
30524
+ ).sort(
30525
+ X3 && Y3 ? (a2, b) => X3.get(a2.x) - X3.get(b.x) || Y3.get(a2.y) - Y3.get(b.y) : X3 ? (a2, b) => X3.get(a2.x) - X3.get(b.x) : (a2, b) => Y3.get(a2.y) - Y3.get(b.y)
30526
+ );
30527
+ }
30528
+ function facetGroups(data, { fx, fy }) {
30529
+ const I = range2(data);
30530
+ const FX = fx?.value;
30531
+ const FY = fy?.value;
30532
+ return fx && fy ? rollup(
30533
+ I,
30534
+ (G) => (G.fx = FX[G[0]], G.fy = FY[G[0]], G),
30535
+ (i) => FX[i],
30536
+ (i) => FY[i]
30537
+ ) : fx ? rollup(
30538
+ I,
30539
+ (G) => (G.fx = FX[G[0]], G),
30540
+ (i) => FX[i]
30541
+ ) : rollup(
30542
+ I,
30543
+ (G) => (G.fy = FY[G[0]], G),
30544
+ (i) => FY[i]
30545
+ );
30546
+ }
30547
+ function facetTranslator(fx, fy, { marginTop, marginLeft }) {
30548
+ return fx && fy ? ({ x: x3, y: y3 }) => `translate(${fx(x3) - marginLeft},${fy(y3) - marginTop})` : fx ? ({ x: x3 }) => `translate(${fx(x3) - marginLeft},0)` : ({ y: y3 }) => `translate(0,${fy(y3) - marginTop})`;
30549
+ }
30550
+ function facetExclude(index2) {
30551
+ const ex = [];
30552
+ const e = new Uint32Array(sum2(index2, (d) => d.length));
30553
+ for (const i of index2) {
30554
+ let n = 0;
30555
+ for (const j of index2) {
30556
+ if (i === j) continue;
30557
+ e.set(j, n);
30558
+ n += j.length;
30559
+ }
30560
+ ex.push(e.slice(0, n));
30561
+ }
30562
+ return ex;
30563
+ }
30564
+ var facetAnchors = /* @__PURE__ */ new Map([
30565
+ ["top", facetAnchorTop],
30566
+ ["right", facetAnchorRight],
30567
+ ["bottom", facetAnchorBottom],
30568
+ ["left", facetAnchorLeft],
30569
+ ["top-left", and2(facetAnchorTop, facetAnchorLeft)],
30570
+ ["top-right", and2(facetAnchorTop, facetAnchorRight)],
30571
+ ["bottom-left", and2(facetAnchorBottom, facetAnchorLeft)],
30572
+ ["bottom-right", and2(facetAnchorBottom, facetAnchorRight)],
30573
+ ["top-empty", facetAnchorTopEmpty],
30574
+ ["right-empty", facetAnchorRightEmpty],
30575
+ ["bottom-empty", facetAnchorBottomEmpty],
30576
+ ["left-empty", facetAnchorLeftEmpty],
30577
+ ["empty", facetAnchorEmpty]
30578
+ ]);
30579
+ function maybeFacetAnchor(facetAnchor) {
30580
+ if (facetAnchor == null) return null;
30581
+ const anchor = facetAnchors.get(`${facetAnchor}`.toLowerCase());
30582
+ if (anchor) return anchor;
30583
+ throw new Error(`invalid facet anchor: ${facetAnchor}`);
30584
+ }
30585
+ var indexCache = /* @__PURE__ */ new WeakMap();
30586
+ function facetIndex(V) {
30587
+ let I = indexCache.get(V);
30588
+ if (!I) indexCache.set(V, I = new InternMap(map2(V, (v2, i) => [v2, i])));
30589
+ return I;
30590
+ }
30591
+ function facetIndexOf(V, v2) {
30592
+ return facetIndex(V).get(v2);
30593
+ }
30594
+ function facetFind(facets, x3, y3) {
30595
+ x3 = keyof2(x3);
30596
+ y3 = keyof2(y3);
30597
+ return facets.find((f) => Object.is(keyof2(f.x), x3) && Object.is(keyof2(f.y), y3));
30598
+ }
30599
+ function facetEmpty(facets, x3, y3) {
30600
+ return facetFind(facets, x3, y3)?.empty;
30601
+ }
30602
+ function facetAnchorTop(facets, { y: Y3 }, { y: y3 }) {
30603
+ return Y3 ? facetIndexOf(Y3, y3) === 0 : true;
30604
+ }
30605
+ function facetAnchorBottom(facets, { y: Y3 }, { y: y3 }) {
30606
+ return Y3 ? facetIndexOf(Y3, y3) === Y3.length - 1 : true;
30607
+ }
30608
+ function facetAnchorLeft(facets, { x: X3 }, { x: x3 }) {
30609
+ return X3 ? facetIndexOf(X3, x3) === 0 : true;
30610
+ }
30611
+ function facetAnchorRight(facets, { x: X3 }, { x: x3 }) {
30612
+ return X3 ? facetIndexOf(X3, x3) === X3.length - 1 : true;
30613
+ }
30614
+ function facetAnchorTopEmpty(facets, { y: Y3 }, { x: x3, y: y3, empty: empty4 }) {
30615
+ if (empty4) return false;
30616
+ if (!Y3) return;
30617
+ const i = facetIndexOf(Y3, y3);
30618
+ if (i > 0) return facetEmpty(facets, x3, Y3[i - 1]);
30619
+ }
30620
+ function facetAnchorBottomEmpty(facets, { y: Y3 }, { x: x3, y: y3, empty: empty4 }) {
30621
+ if (empty4) return false;
30622
+ if (!Y3) return;
30623
+ const i = facetIndexOf(Y3, y3);
30624
+ if (i < Y3.length - 1) return facetEmpty(facets, x3, Y3[i + 1]);
30625
+ }
30626
+ function facetAnchorLeftEmpty(facets, { x: X3 }, { x: x3, y: y3, empty: empty4 }) {
30627
+ if (empty4) return false;
30628
+ if (!X3) return;
30629
+ const i = facetIndexOf(X3, x3);
30630
+ if (i > 0) return facetEmpty(facets, X3[i - 1], y3);
30631
+ }
30632
+ function facetAnchorRightEmpty(facets, { x: X3 }, { x: x3, y: y3, empty: empty4 }) {
30633
+ if (empty4) return false;
30634
+ if (!X3) return;
30635
+ const i = facetIndexOf(X3, x3);
30636
+ if (i < X3.length - 1) return facetEmpty(facets, X3[i + 1], y3);
30637
+ }
30638
+ function facetAnchorEmpty(facets, channels, { empty: empty4 }) {
30639
+ return empty4;
30640
+ }
30641
+ function and2(a2, b) {
30642
+ return function() {
30643
+ return a2.apply(null, arguments) && b.apply(null, arguments);
30644
+ };
30645
+ }
30646
+ function facetFilter(facets, { channels: { fx, fy }, groups: groups2 }) {
30647
+ return fx && fy ? facets.map(({ x: x3, y: y3 }) => groups2.get(x3)?.get(y3) ?? []) : fx ? facets.map(({ x: x3 }) => groups2.get(x3) ?? []) : facets.map(({ y: y3 }) => groups2.get(y3) ?? []);
30648
+ }
30649
+
30650
+ // ../../node_modules/@observablehq/plot/src/projection.js
30651
+ var pi4 = Math.PI;
30652
+ var tau5 = 2 * pi4;
30653
+ var defaultAspectRatio = 0.618;
30654
+ function createProjection({
30655
+ projection: projection3,
30656
+ inset: globalInset = 0,
30657
+ insetTop = globalInset,
30658
+ insetRight = globalInset,
30659
+ insetBottom = globalInset,
30660
+ insetLeft = globalInset
30661
+ } = {}, dimensions) {
30662
+ if (projection3 == null) return;
30663
+ if (typeof projection3.stream === "function") return projection3;
30664
+ let options;
30665
+ let domain;
30666
+ let clip = "frame";
30667
+ if (isObject2(projection3)) {
30668
+ let inset;
30669
+ ({
30670
+ type: projection3,
30671
+ domain,
30672
+ inset,
30673
+ insetTop = inset !== void 0 ? inset : insetTop,
30674
+ insetRight = inset !== void 0 ? inset : insetRight,
30675
+ insetBottom = inset !== void 0 ? inset : insetBottom,
30676
+ insetLeft = inset !== void 0 ? inset : insetLeft,
30677
+ clip = clip,
30678
+ ...options
30679
+ } = projection3);
30680
+ if (projection3 == null) return;
30681
+ }
30682
+ if (typeof projection3 !== "function") ({ type: projection3 } = namedProjection(projection3));
30683
+ const { width, height, marginLeft, marginRight, marginTop, marginBottom } = dimensions;
30684
+ const dx = width - marginLeft - marginRight - insetLeft - insetRight;
30685
+ const dy = height - marginTop - marginBottom - insetTop - insetBottom;
30686
+ projection3 = projection3?.({ width: dx, height: dy, clip, ...options });
30687
+ if (projection3 == null) return;
30688
+ clip = maybePostClip(clip, marginLeft, marginTop, width - marginRight, height - marginBottom);
30689
+ let tx = marginLeft + insetLeft;
30690
+ let ty = marginTop + insetTop;
30691
+ let transform3;
30692
+ if (domain != null) {
30693
+ const [[x06, y06], [x12, y12]] = path_default(projection3).bounds(domain);
30694
+ const k2 = Math.min(dx / (x12 - x06), dy / (y12 - y06));
30695
+ if (k2 > 0) {
30696
+ tx -= (k2 * (x06 + x12) - dx) / 2;
30697
+ ty -= (k2 * (y06 + y12) - dy) / 2;
30698
+ transform3 = transform_default({
30699
+ point(x3, y3) {
30700
+ this.stream.point(x3 * k2 + tx, y3 * k2 + ty);
30701
+ }
30702
+ });
30703
+ } else {
30704
+ warn(`Warning: the projection could not be fit to the specified domain; using the default scale.`);
30705
+ }
30706
+ }
30707
+ transform3 ??= tx === 0 && ty === 0 ? identity8() : transform_default({
30708
+ point(x3, y3) {
30709
+ this.stream.point(x3 + tx, y3 + ty);
30710
+ }
30711
+ });
30712
+ return { stream: (s2) => projection3.stream(transform3.stream(clip(s2))) };
30713
+ }
30714
+ function namedProjection(projection3) {
30715
+ switch (`${projection3}`.toLowerCase()) {
30716
+ case "albers-usa":
30717
+ return scaleProjection(albersUsa_default, 0.7463, 0.4673);
30718
+ case "albers":
30719
+ return conicProjection2(albers_default, 0.7463, 0.4673);
30720
+ case "azimuthal-equal-area":
30721
+ return scaleProjection(azimuthalEqualArea_default, 4, 4);
30722
+ case "azimuthal-equidistant":
30723
+ return scaleProjection(azimuthalEquidistant_default, tau5, tau5);
30724
+ case "conic-conformal":
30725
+ return conicProjection2(conicConformal_default, tau5, tau5);
30726
+ case "conic-equal-area":
30727
+ return conicProjection2(conicEqualArea_default, 6.1702, 2.9781);
30728
+ case "conic-equidistant":
30729
+ return conicProjection2(conicEquidistant_default, 7.312, 3.6282);
30730
+ case "equal-earth":
30731
+ return scaleProjection(equalEarth_default, 5.4133, 2.6347);
30732
+ case "equirectangular":
30733
+ return scaleProjection(equirectangular_default, tau5, pi4);
30734
+ case "gnomonic":
30735
+ return scaleProjection(gnomonic_default, 3.4641, 3.4641);
30736
+ case "identity":
30737
+ return { type: identity8 };
30738
+ case "reflect-y":
30739
+ return { type: reflectY };
30740
+ case "mercator":
30741
+ return scaleProjection(mercator_default, tau5, tau5);
30742
+ case "orthographic":
30743
+ return scaleProjection(orthographic_default, 2, 2);
30744
+ case "stereographic":
30745
+ return scaleProjection(stereographic_default, 2, 2);
30746
+ case "transverse-mercator":
30747
+ return scaleProjection(transverseMercator_default, tau5, tau5);
30748
+ default:
30749
+ throw new Error(`unknown projection type: ${projection3}`);
30750
+ }
30751
+ }
30752
+ function maybePostClip(clip, x12, y12, x22, y22) {
30753
+ if (clip === false || clip == null || typeof clip === "number") return (s2) => s2;
30754
+ if (clip === true) clip = "frame";
30755
+ switch (`${clip}`.toLowerCase()) {
30756
+ case "frame":
30757
+ return clipRectangle(x12, y12, x22, y22);
30758
+ default:
30759
+ throw new Error(`unknown projection clip type: ${clip}`);
30760
+ }
30761
+ }
30762
+ function scaleProjection(createProjection2, kx2, ky2) {
30763
+ return {
30764
+ type: ({ width, height, rotate, precision = 0.15, clip }) => {
30765
+ const projection3 = createProjection2();
30766
+ if (precision != null) projection3.precision?.(precision);
30767
+ if (rotate != null) projection3.rotate?.(rotate);
30768
+ if (typeof clip === "number") projection3.clipAngle?.(clip);
30769
+ projection3.scale(Math.min(width / kx2, height / ky2));
30770
+ projection3.translate([width / 2, height / 2]);
30771
+ return projection3;
30772
+ },
30773
+ aspectRatio: ky2 / kx2
30774
+ };
30775
+ }
30776
+ function conicProjection2(createProjection2, kx2, ky2) {
30777
+ const { type: type2, aspectRatio } = scaleProjection(createProjection2, kx2, ky2);
30778
+ return {
30779
+ type: (options) => {
30780
+ const { parallels, domain, width, height } = options;
30781
+ const projection3 = type2(options);
30782
+ if (parallels != null) {
30783
+ projection3.parallels(parallels);
30784
+ if (domain === void 0) {
30785
+ projection3.fitSize([width, height], { type: "Sphere" });
30786
+ }
30787
+ }
30788
+ return projection3;
30789
+ },
30790
+ aspectRatio
30791
+ };
30792
+ }
30793
+ var identity8 = constant({ stream: (stream) => stream });
30794
+ var reflectY = constant(
30795
+ transform_default({
30796
+ point(x3, y3) {
30797
+ this.stream.point(x3, -y3);
30798
+ }
30799
+ })
30800
+ );
30801
+ function project(cx, cy, values2, projection3) {
30802
+ const x3 = values2[cx];
30803
+ const y3 = values2[cy];
30804
+ const n = x3.length;
30805
+ const X3 = values2[cx] = new Float64Array(n).fill(NaN);
30806
+ const Y3 = values2[cy] = new Float64Array(n).fill(NaN);
30807
+ let i;
30808
+ const stream = projection3.stream({
30809
+ point(x4, y4) {
30810
+ X3[i] = x4;
30811
+ Y3[i] = y4;
30812
+ }
30813
+ });
30814
+ for (i = 0; i < n; ++i) {
30815
+ stream.point(x3[i], y3[i]);
30816
+ }
30817
+ }
30818
+ function hasProjection({ projection: projection3 } = {}) {
30819
+ if (projection3 == null) return false;
30820
+ if (typeof projection3.stream === "function") return true;
30821
+ if (isObject2(projection3)) projection3 = projection3.type;
30822
+ return projection3 != null;
30823
+ }
30824
+ function projectionAspectRatio(projection3) {
30825
+ if (typeof projection3?.stream === "function") return defaultAspectRatio;
30826
+ if (isObject2(projection3)) projection3 = projection3.type;
30827
+ if (projection3 == null) return;
30828
+ if (typeof projection3 !== "function") {
30829
+ const { aspectRatio } = namedProjection(projection3);
30830
+ if (aspectRatio) return aspectRatio;
30831
+ }
30832
+ return defaultAspectRatio;
30833
+ }
30834
+ function applyPosition(channels, scales2, { projection: projection3 }) {
30835
+ const { x: x3, y: y3 } = channels;
30836
+ let position3 = {};
30837
+ if (x3) position3.x = x3;
30838
+ if (y3) position3.y = y3;
30839
+ position3 = valueObject(position3, scales2);
30840
+ if (projection3 && x3?.scale === "x" && y3?.scale === "y") project("x", "y", position3, projection3);
30841
+ if (x3) position3.x = coerceNumbers(position3.x);
30842
+ if (y3) position3.y = coerceNumbers(position3.y);
30843
+ return position3;
30844
+ }
30845
+ function getGeometryChannels(channel) {
30846
+ const X3 = [];
30847
+ const Y3 = [];
30848
+ const x3 = { scale: "x", value: X3 };
30849
+ const y3 = { scale: "y", value: Y3 };
30850
+ const sink = {
30851
+ point(x4, y4) {
30852
+ X3.push(x4);
30853
+ Y3.push(y4);
30854
+ },
30855
+ lineStart() {
30856
+ },
30857
+ lineEnd() {
30858
+ },
30859
+ polygonStart() {
30860
+ },
30861
+ polygonEnd() {
30862
+ },
30863
+ sphere() {
30864
+ }
30865
+ };
30866
+ for (const object of channel.value) stream_default(object, sink);
30867
+ return [x3, y3];
30868
+ }
30869
+
30870
+ // ../../node_modules/@observablehq/plot/src/context.js
30871
+ function createContext(options = {}) {
30872
+ const { document: document2 = typeof window !== "undefined" ? window.document : void 0, clip } = options;
30873
+ return { document: document2, clip: maybeClip(clip) };
30874
+ }
30875
+ function create3(name, { document: document2 }) {
30876
+ return select_default2(creator_default(name).call(document2.documentElement));
30877
+ }
30878
+
30237
30879
  // ../../node_modules/@observablehq/plot/src/memoize.js
30238
30880
  function memoize1(compute) {
30239
30881
  let cacheValue, cacheKeys;
@@ -30598,6 +31240,153 @@ function applyFrameAnchor({ frameAnchor }, { width, height, marginTop, marginRig
30598
31240
  ];
30599
31241
  }
30600
31242
 
31243
+ // ../../node_modules/@observablehq/plot/src/mark.js
31244
+ var Mark = class {
31245
+ constructor(data, channels = {}, options = {}, defaults23) {
31246
+ const {
31247
+ facet = "auto",
31248
+ facetAnchor,
31249
+ fx,
31250
+ fy,
31251
+ sort: sort3,
31252
+ dx = 0,
31253
+ dy = 0,
31254
+ margin = 0,
31255
+ marginTop = margin,
31256
+ marginRight = margin,
31257
+ marginBottom = margin,
31258
+ marginLeft = margin,
31259
+ clip = defaults23?.clip,
31260
+ channels: extraChannels,
31261
+ tip: tip2,
31262
+ render
31263
+ } = options;
31264
+ this.data = data;
31265
+ this.sort = isDomainSort(sort3) ? sort3 : null;
31266
+ this.initializer = initializer(options).initializer;
31267
+ this.transform = this.initializer ? options.transform : basic(options).transform;
31268
+ if (facet === null || facet === false) {
31269
+ this.facet = null;
31270
+ } else {
31271
+ this.facet = keyword(facet === true ? "include" : facet, "facet", ["auto", "include", "exclude", "super"]);
31272
+ this.fx = data === singleton && typeof fx === "string" ? [fx] : fx;
31273
+ this.fy = data === singleton && typeof fy === "string" ? [fy] : fy;
31274
+ }
31275
+ this.facetAnchor = maybeFacetAnchor(facetAnchor);
31276
+ channels = maybeNamed(channels);
31277
+ if (extraChannels !== void 0) channels = { ...maybeChannels(extraChannels), ...channels };
31278
+ if (defaults23 !== void 0) channels = { ...styles(this, options, defaults23), ...channels };
31279
+ this.channels = Object.fromEntries(
31280
+ Object.entries(channels).map(([name, channel]) => {
31281
+ if (isOptions(channel.value)) {
31282
+ const { value, label = channel.label, scale: scale3 = channel.scale } = channel.value;
31283
+ channel = { ...channel, label, scale: scale3, value };
31284
+ }
31285
+ if (data === singleton && typeof channel.value === "string") {
31286
+ const { value } = channel;
31287
+ channel = { ...channel, value: [value] };
31288
+ }
31289
+ return [name, channel];
31290
+ }).filter(([name, { value, optional: optional2 }]) => {
31291
+ if (value != null) return true;
31292
+ if (optional2) return false;
31293
+ throw new Error(`missing channel value: ${name}`);
31294
+ })
31295
+ );
31296
+ this.dx = +dx;
31297
+ this.dy = +dy;
31298
+ this.marginTop = +marginTop;
31299
+ this.marginRight = +marginRight;
31300
+ this.marginBottom = +marginBottom;
31301
+ this.marginLeft = +marginLeft;
31302
+ this.clip = maybeClip(clip);
31303
+ this.tip = maybeTip(tip2);
31304
+ if (this.facet === "super") {
31305
+ if (fx || fy) throw new Error(`super-faceting cannot use fx or fy`);
31306
+ for (const name in this.channels) {
31307
+ const { scale: scale3 } = channels[name];
31308
+ if (scale3 !== "x" && scale3 !== "y") continue;
31309
+ throw new Error(`super-faceting cannot use x or y`);
31310
+ }
31311
+ }
31312
+ if (render != null) {
31313
+ this.render = composeRender(render, this.render);
31314
+ }
31315
+ }
31316
+ initialize(facets, facetChannels, plotOptions) {
31317
+ let data = arrayify2(this.data);
31318
+ if (facets === void 0 && data != null) facets = [range2(data)];
31319
+ const originalFacets = facets;
31320
+ if (this.transform != null) ({ facets, data } = this.transform(data, facets, plotOptions)), data = arrayify2(data);
31321
+ if (facets !== void 0) facets.original = originalFacets;
31322
+ const channels = createChannels(this.channels, data);
31323
+ if (this.sort != null) channelDomain(data, facets, channels, facetChannels, this.sort);
31324
+ return { data, facets, channels };
31325
+ }
31326
+ filter(index2, channels, values2) {
31327
+ for (const name in channels) {
31328
+ const { filter: filter3 = defined } = channels[name];
31329
+ if (filter3 !== null) {
31330
+ const value = values2[name];
31331
+ index2 = index2.filter((i) => filter3(value[i]));
31332
+ }
31333
+ }
31334
+ return index2;
31335
+ }
31336
+ // If there is a projection, and there are paired x and y channels associated
31337
+ // with the x and y scale respectively (and not already in screen coordinates
31338
+ // as with an initializer), then apply the projection, replacing the x and y
31339
+ // values. Note that the x and y scales themselves don’t exist if there is a
31340
+ // projection, but whether the channels are associated with scales still
31341
+ // determines whether the projection should apply; think of the projection as
31342
+ // a combination xy-scale.
31343
+ project(channels, values2, context) {
31344
+ for (const cx in channels) {
31345
+ if (channels[cx].scale === "x" && /^x|x$/.test(cx)) {
31346
+ const cy = cx.replace(/^x|x$/, "y");
31347
+ if (cy in channels && channels[cy].scale === "y") {
31348
+ project(cx, cy, values2, context.projection);
31349
+ }
31350
+ }
31351
+ }
31352
+ }
31353
+ scale(channels, scales2, context) {
31354
+ const values2 = valueObject(channels, scales2);
31355
+ if (context.projection) this.project(channels, values2, context);
31356
+ return values2;
31357
+ }
31358
+ };
31359
+ function marks(...marks2) {
31360
+ marks2.plot = Mark.prototype.plot;
31361
+ return marks2;
31362
+ }
31363
+ function composeRender(r1, r2) {
31364
+ if (r1 == null) return r2 === null ? void 0 : r2;
31365
+ if (r2 == null) return r1 === null ? void 0 : r1;
31366
+ if (typeof r1 !== "function") throw new TypeError(`invalid render transform: ${r1}`);
31367
+ if (typeof r2 !== "function") throw new TypeError(`invalid render transform: ${r2}`);
31368
+ return function(i, s2, v2, d, c4, next) {
31369
+ return r1.call(this, i, s2, v2, d, c4, (i2, s3, v3, d2, c5) => {
31370
+ return r2.call(this, i2, s3, v3, d2, c5, next);
31371
+ });
31372
+ };
31373
+ }
31374
+ function maybeChannels(channels) {
31375
+ return Object.fromEntries(
31376
+ Object.entries(maybeNamed(channels)).map(([name, channel]) => {
31377
+ channel = typeof channel === "string" ? { value: channel, label: name } : maybeValue(channel);
31378
+ if (channel.filter === void 0 && channel.scale == null) channel = { ...channel, filter: null };
31379
+ return [name, channel];
31380
+ })
31381
+ );
31382
+ }
31383
+ function maybeTip(tip2) {
31384
+ return tip2 === true ? "xy" : tip2 === false || tip2 == null ? null : typeof tip2 === "string" ? keyword(tip2, "tip", ["x", "y", "xy"]) : tip2;
31385
+ }
31386
+ function withTip(options, pointer2) {
31387
+ return options?.tip === true ? { ...options, tip: pointer2 } : isObject2(options?.tip) && options.tip.pointer === void 0 ? { ...options, tip: { ...options.tip, pointer: pointer2 } } : options;
31388
+ }
31389
+
30601
31390
  // ../../node_modules/@observablehq/plot/src/dimensions.js
30602
31391
  function createDimensions(scales2, marks2, options = {}) {
30603
31392
  let marginTopDefault = 0.5 - offset, marginRightDefault = 0.5 + offset, marginBottomDefault = 0.5 + offset, marginLeftDefault = 0.5 - offset;
@@ -30708,291 +31497,6 @@ function aspectRatioLength(k2, scale3) {
30708
31497
  return Math.abs(transform3(max4) - transform3(min5));
30709
31498
  }
30710
31499
 
30711
- // ../../node_modules/@observablehq/plot/src/facet.js
30712
- function createFacets(channelsByScale, options) {
30713
- const { fx, fy } = createScales(channelsByScale, options);
30714
- const fxDomain = fx?.scale.domain();
30715
- const fyDomain = fy?.scale.domain();
30716
- return fxDomain && fyDomain ? cross(fxDomain, fyDomain).map(([x3, y3], i) => ({ x: x3, y: y3, i })) : fxDomain ? fxDomain.map((x3, i) => ({ x: x3, i })) : fyDomain ? fyDomain.map((y3, i) => ({ y: y3, i })) : void 0;
30717
- }
30718
- function recreateFacets(facets, { x: X3, y: Y3 }) {
30719
- X3 &&= facetIndex(X3);
30720
- Y3 &&= facetIndex(Y3);
30721
- return facets.filter(
30722
- X3 && Y3 ? (f) => X3.has(f.x) && Y3.has(f.y) : X3 ? (f) => X3.has(f.x) : (f) => Y3.has(f.y)
30723
- ).sort(
30724
- X3 && Y3 ? (a2, b) => X3.get(a2.x) - X3.get(b.x) || Y3.get(a2.y) - Y3.get(b.y) : X3 ? (a2, b) => X3.get(a2.x) - X3.get(b.x) : (a2, b) => Y3.get(a2.y) - Y3.get(b.y)
30725
- );
30726
- }
30727
- function facetGroups(data, { fx, fy }) {
30728
- const I = range2(data);
30729
- const FX = fx?.value;
30730
- const FY = fy?.value;
30731
- return fx && fy ? rollup(
30732
- I,
30733
- (G) => (G.fx = FX[G[0]], G.fy = FY[G[0]], G),
30734
- (i) => FX[i],
30735
- (i) => FY[i]
30736
- ) : fx ? rollup(
30737
- I,
30738
- (G) => (G.fx = FX[G[0]], G),
30739
- (i) => FX[i]
30740
- ) : rollup(
30741
- I,
30742
- (G) => (G.fy = FY[G[0]], G),
30743
- (i) => FY[i]
30744
- );
30745
- }
30746
- function facetTranslator(fx, fy, { marginTop, marginLeft }) {
30747
- return fx && fy ? ({ x: x3, y: y3 }) => `translate(${fx(x3) - marginLeft},${fy(y3) - marginTop})` : fx ? ({ x: x3 }) => `translate(${fx(x3) - marginLeft},0)` : ({ y: y3 }) => `translate(0,${fy(y3) - marginTop})`;
30748
- }
30749
- function facetExclude(index2) {
30750
- const ex = [];
30751
- const e = new Uint32Array(sum2(index2, (d) => d.length));
30752
- for (const i of index2) {
30753
- let n = 0;
30754
- for (const j of index2) {
30755
- if (i === j) continue;
30756
- e.set(j, n);
30757
- n += j.length;
30758
- }
30759
- ex.push(e.slice(0, n));
30760
- }
30761
- return ex;
30762
- }
30763
- var facetAnchors = /* @__PURE__ */ new Map([
30764
- ["top", facetAnchorTop],
30765
- ["right", facetAnchorRight],
30766
- ["bottom", facetAnchorBottom],
30767
- ["left", facetAnchorLeft],
30768
- ["top-left", and2(facetAnchorTop, facetAnchorLeft)],
30769
- ["top-right", and2(facetAnchorTop, facetAnchorRight)],
30770
- ["bottom-left", and2(facetAnchorBottom, facetAnchorLeft)],
30771
- ["bottom-right", and2(facetAnchorBottom, facetAnchorRight)],
30772
- ["top-empty", facetAnchorTopEmpty],
30773
- ["right-empty", facetAnchorRightEmpty],
30774
- ["bottom-empty", facetAnchorBottomEmpty],
30775
- ["left-empty", facetAnchorLeftEmpty],
30776
- ["empty", facetAnchorEmpty]
30777
- ]);
30778
- function maybeFacetAnchor(facetAnchor) {
30779
- if (facetAnchor == null) return null;
30780
- const anchor = facetAnchors.get(`${facetAnchor}`.toLowerCase());
30781
- if (anchor) return anchor;
30782
- throw new Error(`invalid facet anchor: ${facetAnchor}`);
30783
- }
30784
- var indexCache = /* @__PURE__ */ new WeakMap();
30785
- function facetIndex(V) {
30786
- let I = indexCache.get(V);
30787
- if (!I) indexCache.set(V, I = new InternMap(map2(V, (v2, i) => [v2, i])));
30788
- return I;
30789
- }
30790
- function facetIndexOf(V, v2) {
30791
- return facetIndex(V).get(v2);
30792
- }
30793
- function facetFind(facets, x3, y3) {
30794
- x3 = keyof2(x3);
30795
- y3 = keyof2(y3);
30796
- return facets.find((f) => Object.is(keyof2(f.x), x3) && Object.is(keyof2(f.y), y3));
30797
- }
30798
- function facetEmpty(facets, x3, y3) {
30799
- return facetFind(facets, x3, y3)?.empty;
30800
- }
30801
- function facetAnchorTop(facets, { y: Y3 }, { y: y3 }) {
30802
- return Y3 ? facetIndexOf(Y3, y3) === 0 : true;
30803
- }
30804
- function facetAnchorBottom(facets, { y: Y3 }, { y: y3 }) {
30805
- return Y3 ? facetIndexOf(Y3, y3) === Y3.length - 1 : true;
30806
- }
30807
- function facetAnchorLeft(facets, { x: X3 }, { x: x3 }) {
30808
- return X3 ? facetIndexOf(X3, x3) === 0 : true;
30809
- }
30810
- function facetAnchorRight(facets, { x: X3 }, { x: x3 }) {
30811
- return X3 ? facetIndexOf(X3, x3) === X3.length - 1 : true;
30812
- }
30813
- function facetAnchorTopEmpty(facets, { y: Y3 }, { x: x3, y: y3, empty: empty4 }) {
30814
- if (empty4) return false;
30815
- if (!Y3) return;
30816
- const i = facetIndexOf(Y3, y3);
30817
- if (i > 0) return facetEmpty(facets, x3, Y3[i - 1]);
30818
- }
30819
- function facetAnchorBottomEmpty(facets, { y: Y3 }, { x: x3, y: y3, empty: empty4 }) {
30820
- if (empty4) return false;
30821
- if (!Y3) return;
30822
- const i = facetIndexOf(Y3, y3);
30823
- if (i < Y3.length - 1) return facetEmpty(facets, x3, Y3[i + 1]);
30824
- }
30825
- function facetAnchorLeftEmpty(facets, { x: X3 }, { x: x3, y: y3, empty: empty4 }) {
30826
- if (empty4) return false;
30827
- if (!X3) return;
30828
- const i = facetIndexOf(X3, x3);
30829
- if (i > 0) return facetEmpty(facets, X3[i - 1], y3);
30830
- }
30831
- function facetAnchorRightEmpty(facets, { x: X3 }, { x: x3, y: y3, empty: empty4 }) {
30832
- if (empty4) return false;
30833
- if (!X3) return;
30834
- const i = facetIndexOf(X3, x3);
30835
- if (i < X3.length - 1) return facetEmpty(facets, X3[i + 1], y3);
30836
- }
30837
- function facetAnchorEmpty(facets, channels, { empty: empty4 }) {
30838
- return empty4;
30839
- }
30840
- function and2(a2, b) {
30841
- return function() {
30842
- return a2.apply(null, arguments) && b.apply(null, arguments);
30843
- };
30844
- }
30845
- function facetFilter(facets, { channels: { fx, fy }, groups: groups2 }) {
30846
- return fx && fy ? facets.map(({ x: x3, y: y3 }) => groups2.get(x3)?.get(y3) ?? []) : fx ? facets.map(({ x: x3 }) => groups2.get(x3) ?? []) : facets.map(({ y: y3 }) => groups2.get(y3) ?? []);
30847
- }
30848
-
30849
- // ../../node_modules/@observablehq/plot/src/mark.js
30850
- var Mark = class {
30851
- constructor(data, channels = {}, options = {}, defaults23) {
30852
- const {
30853
- facet = "auto",
30854
- facetAnchor,
30855
- fx,
30856
- fy,
30857
- sort: sort3,
30858
- dx = 0,
30859
- dy = 0,
30860
- margin = 0,
30861
- marginTop = margin,
30862
- marginRight = margin,
30863
- marginBottom = margin,
30864
- marginLeft = margin,
30865
- clip = defaults23?.clip,
30866
- channels: extraChannels,
30867
- tip: tip2,
30868
- render
30869
- } = options;
30870
- this.data = data;
30871
- this.sort = isDomainSort(sort3) ? sort3 : null;
30872
- this.initializer = initializer(options).initializer;
30873
- this.transform = this.initializer ? options.transform : basic(options).transform;
30874
- if (facet === null || facet === false) {
30875
- this.facet = null;
30876
- } else {
30877
- this.facet = keyword(facet === true ? "include" : facet, "facet", ["auto", "include", "exclude", "super"]);
30878
- this.fx = data === singleton && typeof fx === "string" ? [fx] : fx;
30879
- this.fy = data === singleton && typeof fy === "string" ? [fy] : fy;
30880
- }
30881
- this.facetAnchor = maybeFacetAnchor(facetAnchor);
30882
- channels = maybeNamed(channels);
30883
- if (extraChannels !== void 0) channels = { ...maybeChannels(extraChannels), ...channels };
30884
- if (defaults23 !== void 0) channels = { ...styles(this, options, defaults23), ...channels };
30885
- this.channels = Object.fromEntries(
30886
- Object.entries(channels).map(([name, channel]) => {
30887
- if (isOptions(channel.value)) {
30888
- const { value, label = channel.label, scale: scale3 = channel.scale } = channel.value;
30889
- channel = { ...channel, label, scale: scale3, value };
30890
- }
30891
- if (data === singleton && typeof channel.value === "string") {
30892
- const { value } = channel;
30893
- channel = { ...channel, value: [value] };
30894
- }
30895
- return [name, channel];
30896
- }).filter(([name, { value, optional: optional2 }]) => {
30897
- if (value != null) return true;
30898
- if (optional2) return false;
30899
- throw new Error(`missing channel value: ${name}`);
30900
- })
30901
- );
30902
- this.dx = +dx;
30903
- this.dy = +dy;
30904
- this.marginTop = +marginTop;
30905
- this.marginRight = +marginRight;
30906
- this.marginBottom = +marginBottom;
30907
- this.marginLeft = +marginLeft;
30908
- this.clip = maybeClip(clip);
30909
- this.tip = maybeTip(tip2);
30910
- if (this.facet === "super") {
30911
- if (fx || fy) throw new Error(`super-faceting cannot use fx or fy`);
30912
- for (const name in this.channels) {
30913
- const { scale: scale3 } = channels[name];
30914
- if (scale3 !== "x" && scale3 !== "y") continue;
30915
- throw new Error(`super-faceting cannot use x or y`);
30916
- }
30917
- }
30918
- if (render != null) {
30919
- this.render = composeRender(render, this.render);
30920
- }
30921
- }
30922
- initialize(facets, facetChannels, plotOptions) {
30923
- let data = arrayify2(this.data);
30924
- if (facets === void 0 && data != null) facets = [range2(data)];
30925
- const originalFacets = facets;
30926
- if (this.transform != null) ({ facets, data } = this.transform(data, facets, plotOptions)), data = arrayify2(data);
30927
- if (facets !== void 0) facets.original = originalFacets;
30928
- const channels = createChannels(this.channels, data);
30929
- if (this.sort != null) channelDomain(data, facets, channels, facetChannels, this.sort);
30930
- return { data, facets, channels };
30931
- }
30932
- filter(index2, channels, values2) {
30933
- for (const name in channels) {
30934
- const { filter: filter3 = defined } = channels[name];
30935
- if (filter3 !== null) {
30936
- const value = values2[name];
30937
- index2 = index2.filter((i) => filter3(value[i]));
30938
- }
30939
- }
30940
- return index2;
30941
- }
30942
- // If there is a projection, and there are paired x and y channels associated
30943
- // with the x and y scale respectively (and not already in screen coordinates
30944
- // as with an initializer), then apply the projection, replacing the x and y
30945
- // values. Note that the x and y scales themselves don’t exist if there is a
30946
- // projection, but whether the channels are associated with scales still
30947
- // determines whether the projection should apply; think of the projection as
30948
- // a combination xy-scale.
30949
- project(channels, values2, context) {
30950
- for (const cx in channels) {
30951
- if (channels[cx].scale === "x" && /^x|x$/.test(cx)) {
30952
- const cy = cx.replace(/^x|x$/, "y");
30953
- if (cy in channels && channels[cy].scale === "y") {
30954
- project(cx, cy, values2, context.projection);
30955
- }
30956
- }
30957
- }
30958
- }
30959
- scale(channels, scales2, context) {
30960
- const values2 = valueObject(channels, scales2);
30961
- if (context.projection) this.project(channels, values2, context);
30962
- return values2;
30963
- }
30964
- };
30965
- function marks(...marks2) {
30966
- marks2.plot = Mark.prototype.plot;
30967
- return marks2;
30968
- }
30969
- function composeRender(r1, r2) {
30970
- if (r1 == null) return r2 === null ? void 0 : r2;
30971
- if (r2 == null) return r1 === null ? void 0 : r1;
30972
- if (typeof r1 !== "function") throw new TypeError(`invalid render transform: ${r1}`);
30973
- if (typeof r2 !== "function") throw new TypeError(`invalid render transform: ${r2}`);
30974
- return function(i, s2, v2, d, c4, next) {
30975
- return r1.call(this, i, s2, v2, d, c4, (i2, s3, v3, d2, c5) => {
30976
- return r2.call(this, i2, s3, v3, d2, c5, next);
30977
- });
30978
- };
30979
- }
30980
- function maybeChannels(channels) {
30981
- return Object.fromEntries(
30982
- Object.entries(maybeNamed(channels)).map(([name, channel]) => {
30983
- channel = typeof channel === "string" ? { value: channel, label: name } : maybeValue(channel);
30984
- if (channel.filter === void 0 && channel.scale == null) channel = { ...channel, filter: null };
30985
- return [name, channel];
30986
- })
30987
- );
30988
- }
30989
- function maybeTip(tip2) {
30990
- return tip2 === true ? "xy" : tip2 === false || tip2 == null ? null : typeof tip2 === "string" ? keyword(tip2, "tip", ["x", "y", "xy"]) : tip2;
30991
- }
30992
- function withTip(options, pointer2) {
30993
- return options?.tip === true ? { ...options, tip: pointer2 } : isObject2(options?.tip) && options.tip.pointer === void 0 ? { ...options, tip: { ...options.tip, pointer: pointer2 } } : options;
30994
- }
30995
-
30996
31500
  // ../../node_modules/@observablehq/plot/src/interactions/pointer.js
30997
31501
  var states = /* @__PURE__ */ new WeakMap();
30998
31502
  function pointerK(kx2, ky2, { x: x3, y: y3, px, py, maxRadius = 40, channels, render, ...options } = {}) {
@@ -32537,7 +33041,7 @@ function inferTextChannel(scale3, data, ticks2, tickFormat2, anchor) {
32537
33041
  return { value: inferTickFormat(scale3, data, ticks2, tickFormat2, anchor) };
32538
33042
  }
32539
33043
  function inferTickFormat(scale3, data, ticks2, tickFormat2, anchor) {
32540
- return typeof tickFormat2 === "function" ? tickFormat2 : tickFormat2 === void 0 && data && isTemporal(data) ? inferTimeFormat(scale3.type, data, anchor) ?? formatDefault : scale3.tickFormat ? scale3.tickFormat(typeof ticks2 === "number" ? ticks2 : null, tickFormat2) : tickFormat2 === void 0 ? formatDefault : typeof tickFormat2 === "string" ? (isTemporal(scale3.domain()) ? utcFormat : format)(tickFormat2) : constant(tickFormat2);
33044
+ return typeof tickFormat2 === "function" && !(scale3.type === "log" && scale3.tickFormat) ? tickFormat2 : tickFormat2 === void 0 && data && isTemporal(data) ? inferTimeFormat(scale3.type, data, anchor) ?? formatDefault : scale3.tickFormat ? scale3.tickFormat(typeof ticks2 === "number" ? ticks2 : null, tickFormat2) : tickFormat2 === void 0 ? formatDefault : typeof tickFormat2 === "string" ? (isTemporal(scale3.domain()) ? utcFormat : format)(tickFormat2) : constant(tickFormat2);
32541
33045
  }
32542
33046
  function inclusiveRange(interval2, min5, max4) {
32543
33047
  return interval2.range(min5, interval2.offset(interval2.floor(max4)));
@@ -32906,7 +33410,7 @@ var Tip = class extends Mark {
32906
33410
  for (const key in defaults5) if (key in this.channels) this[key] = defaults5[key];
32907
33411
  this.splitLines = splitter2(this);
32908
33412
  this.clipLine = clipper(this);
32909
- this.format = { ...format3 };
33413
+ this.format = typeof format3 === "string" || typeof format3 === "function" ? { title: format3 } : { ...format3 };
32910
33414
  }
32911
33415
  render(index2, scales2, values2, dimensions, context) {
32912
33416
  const mark = this;
@@ -32925,10 +33429,10 @@ var Tip = class extends Mark {
32925
33429
  const ee = widthof(ellipsis);
32926
33430
  let sources, format3;
32927
33431
  if ("title" in values2) {
32928
- sources = values2.channels;
33432
+ sources = getSourceChannels.call(this, { title: values2.channels.title }, scales2);
32929
33433
  format3 = formatTitle;
32930
33434
  } else {
32931
- sources = getSourceChannels.call(this, values2, scales2);
33435
+ sources = getSourceChannels.call(this, values2.channels, scales2);
32932
33436
  format3 = formatChannels;
32933
33437
  }
32934
33438
  const g = create3("svg:g", context).call(applyIndirectStyles, this, dimensions, context).call(applyIndirectTextStyles, this).call(applyTransform, this, { x: X3 && x3, y: Y3 && y3 }).call(
@@ -33064,7 +33568,7 @@ function getPath(anchor, m, r, width, height) {
33064
33568
  return `M0,0l${m / 2},${-m / 2}v${m / 2 - h / 2}h${w}v${h}h${-w}v${m / 2 - h / 2}z`;
33065
33569
  }
33066
33570
  }
33067
- function getSourceChannels({ channels }, scales2) {
33571
+ function getSourceChannels(channels, scales2) {
33068
33572
  const sources = {};
33069
33573
  let format3 = this.format;
33070
33574
  format3 = maybeExpandPairedFormat(format3, channels, "x");
@@ -33113,7 +33617,7 @@ function maybeExpandPairedFormat(format3, channels, key) {
33113
33617
  return Object.fromEntries(entries);
33114
33618
  }
33115
33619
  function formatTitle(i, index2, { title }) {
33116
- return formatDefault(title.value[i], i);
33620
+ return this.format.title(title.value[i], i);
33117
33621
  }
33118
33622
  function* formatChannels(i, index2, channels, scales2, values2) {
33119
33623
  for (const key in channels) {
@@ -33364,6 +33868,7 @@ function plot(options = {}) {
33364
33868
  if (subtitle != null) figure.append(createTitleElement(document2, subtitle, "h3"));
33365
33869
  figure.append(...legends, svg);
33366
33870
  if (caption != null) figure.append(createFigcaption(document2, caption));
33871
+ if ("value" in svg) figure.value = svg.value, delete svg.value;
33367
33872
  }
33368
33873
  figure.scale = exposeScales(scales2.scales);
33369
33874
  figure.legend = exposeLegends(scaleDescriptors, context, options);
@@ -33384,10 +33889,6 @@ function createFigcaption(document2, caption) {
33384
33889
  e.append(caption);
33385
33890
  return e;
33386
33891
  }
33387
- function plotThis({ marks: marks2 = [], ...options } = {}) {
33388
- return plot({ ...options, marks: [...marks2, this] });
33389
- }
33390
- Mark.prototype.plot = plotThis;
33391
33892
  function flatMarks(marks2) {
33392
33893
  return marks2.flat(Infinity).filter((mark) => mark != null).map(markify);
33393
33894
  }
@@ -33414,7 +33915,7 @@ function applyScaleTransform(channel, options) {
33414
33915
  type: type2,
33415
33916
  percent,
33416
33917
  interval: interval2,
33417
- transform: transform3 = percent ? (x3) => x3 * 100 : maybeIntervalTransform(interval2, type2)
33918
+ transform: transform3 = percent ? (x3) => x3 == null ? NaN : x3 * 100 : maybeIntervalTransform(interval2, type2)
33418
33919
  } = options[scale3] ?? {};
33419
33920
  if (transform3 == null) return;
33420
33921
  channel.value = map2(channel.value, transform3);
@@ -33973,7 +34474,7 @@ function maybeThresholds(thresholds, interval2, defaultThresholds = thresholdAut
33973
34474
  case "auto":
33974
34475
  return thresholdAuto;
33975
34476
  }
33976
- return maybeUtcInterval(thresholds);
34477
+ return utcInterval(thresholds);
33977
34478
  }
33978
34479
  return thresholds;
33979
34480
  }
@@ -36128,14 +36629,15 @@ function interpolatorBarycentric({ random = lcg(42) } = {}) {
36128
36629
  if (x3 < 0 || x3 >= width || y3 < 0 || y3 >= height) continue;
36129
36630
  const xp = x3 + 0.5;
36130
36631
  const yp = y3 + 0.5;
36131
- const ga = ((By - Cy) * (xp - Cx) + (yp - Cy) * (Cx - Bx)) / z;
36132
- if (ga < 0) continue;
36133
- const gb = ((Cy - Ay) * (xp - Cx) + (yp - Cy) * (Ax - Cx)) / z;
36134
- if (gb < 0) continue;
36135
- const gc = 1 - ga - gb;
36136
- if (gc < 0) continue;
36632
+ const s2 = Math.sign(z);
36633
+ const ga = (By - Cy) * (xp - Cx) + (yp - Cy) * (Cx - Bx);
36634
+ if (ga * s2 < 0) continue;
36635
+ const gb = (Cy - Ay) * (xp - Cx) + (yp - Cy) * (Ax - Cx);
36636
+ if (gb * s2 < 0) continue;
36637
+ const gc = z - (ga + gb);
36638
+ if (gc * s2 < 0) continue;
36137
36639
  const i2 = x3 + width * y3;
36138
- W[i2] = mix(va, ga, vb, gb, vc, gc, x3, y3);
36640
+ W[i2] = mix(va, ga / z, vb, gb / z, vc, gc / z, x3, y3);
36139
36641
  S[i2] = 1;
36140
36642
  }
36141
36643
  }
@@ -37934,7 +38436,7 @@ function dodge(y3, x3, anchor, padding, r, options) {
37934
38436
  for (let I of facets) {
37935
38437
  const tree2 = (0, import_interval_tree_1d.default)();
37936
38438
  I = I.filter(R ? (i) => finite2(X3[i]) && positive(R[i]) : (i) => finite2(X3[i]));
37937
- const intervals = new Float64Array(2 * I.length + 2);
38439
+ const intervals2 = new Float64Array(2 * I.length + 2);
37938
38440
  for (const i of I) {
37939
38441
  const ri = radius2(i);
37940
38442
  const y06 = ky2 ? ri + padding : 0;
@@ -37946,14 +38448,14 @@ function dodge(y3, x3, anchor, padding, r, options) {
37946
38448
  const dx = X3[i] - X3[j];
37947
38449
  const dr = padding + (R ? R[i] + R[j] : 2 * cr);
37948
38450
  const dy = Math.sqrt(dr * dr - dx * dx);
37949
- intervals[k2++] = yj - dy;
37950
- intervals[k2++] = yj + dy;
38451
+ intervals2[k2++] = yj - dy;
38452
+ intervals2[k2++] = yj + dy;
37951
38453
  });
37952
- let candidates = intervals.slice(0, k2);
38454
+ let candidates = intervals2.slice(0, k2);
37953
38455
  if (ky2) candidates = candidates.filter((y4) => y4 >= 0);
37954
38456
  out: for (const y4 of candidates.sort(compare)) {
37955
38457
  for (let j = 0; j < k2; j += 2) {
37956
- if (intervals[j] + 1e-6 < y4 && y4 < intervals[j + 1] - 1e-6) {
38458
+ if (intervals2[j] + 1e-6 < y4 && y4 < intervals2[j + 1] - 1e-6) {
37957
38459
  continue out;
37958
38460
  }
37959
38461
  }
@@ -38194,6 +38696,11 @@ function selectChannel(v2, selector, options) {
38194
38696
  });
38195
38697
  }
38196
38698
 
38699
+ // ../../node_modules/@observablehq/plot/src/index.js
38700
+ Mark.prototype.plot = function({ marks: marks2 = [], ...options } = {}) {
38701
+ return plot({ ...options, marks: [...marks2, this] });
38702
+ };
38703
+
38197
38704
  // src/plot-attributes.js
38198
38705
  var attributeMap = /* @__PURE__ */ new Map([
38199
38706
  ["style", "style"],
@@ -38379,6 +38886,7 @@ var attributeMap = /* @__PURE__ */ new Map([
38379
38886
  ["rRange", "r.range"],
38380
38887
  ["rClamp", "r.clamp"],
38381
38888
  ["rNice", "r.nice"],
38889
+ ["rLabel", "r.label"],
38382
38890
  ["rPercent", "r.percent"],
38383
38891
  ["rZero", "r.zero"],
38384
38892
  ["rBase", "r.base"],
@@ -38438,39 +38946,35 @@ var OPTIONS_ONLY_MARKS = /* @__PURE__ */ new Set([
38438
38946
  "sphere",
38439
38947
  "graticule"
38440
38948
  ]);
38949
+ var SELECT_TRANSFORMS = /* @__PURE__ */ new Map([
38950
+ ["first", selectFirst],
38951
+ ["last", selectLast],
38952
+ ["maxX", selectMaxX],
38953
+ ["maxY", selectMaxY],
38954
+ ["minX", selectMinX],
38955
+ ["minY", selectMinY],
38956
+ ["nearest", pointer],
38957
+ ["nearestX", pointerX],
38958
+ ["nearestXY", pointerY]
38959
+ ]);
38441
38960
  async function plotRenderer(plot2) {
38442
38961
  const spec = { marks: [] };
38443
38962
  const symbols3 = [];
38444
38963
  const { attributes, marks: marks2 } = plot2;
38445
38964
  setAttributes(attributes, spec, symbols3);
38446
- const indices = [];
38965
+ const indices2 = [];
38447
38966
  for (const mark of marks2) {
38448
38967
  for (const { type: type2, data, options } of mark.plotSpecs()) {
38449
- if (OPTIONS_ONLY_MARKS.has(type2)) {
38450
- spec.marks.push(src_exports[type2](options));
38451
- } else if (isArrowTable(data)) {
38452
- const opts = Object.fromEntries(
38453
- Object.entries(options).map(([k2, v2]) => {
38454
- let val = v2;
38455
- if (typeof v2 === "string") {
38456
- val = data.getChild(v2) ?? v2;
38457
- } else if (typeof v2 === "object") {
38458
- const value = data.getChild(v2.value);
38459
- val = value ? { value } : v2;
38460
- }
38461
- return [k2, val];
38462
- })
38463
- );
38464
- spec.marks.push(src_exports[type2]({ length: data.numRows }, opts));
38465
- } else {
38466
- spec.marks.push(src_exports[type2](data, options));
38467
- }
38468
- indices.push(mark.index);
38968
+ const { select: select2, ...rest } = options;
38969
+ const opt = SELECT_TRANSFORMS.get(select2)?.(rest) ?? rest;
38970
+ const arg = OPTIONS_ONLY_MARKS.has(type2) ? [opt] : [data, opt];
38971
+ spec.marks.push(src_exports[type2](...arg));
38972
+ indices2.push(mark.index);
38469
38973
  }
38470
38974
  }
38471
38975
  inferLabels(spec, plot2);
38472
38976
  const svg = plot(spec);
38473
- annotatePlot(svg, indices);
38977
+ annotatePlot(svg, indices2);
38474
38978
  setSymbolAttributes(plot2, svg, attributes, symbols3);
38475
38979
  for (const interactor of plot2.interactors) {
38476
38980
  await interactor.init(svg);
@@ -38536,27 +39040,28 @@ function inferLabel(key, spec, marks2) {
38536
39040
  }
38537
39041
  spec[key] = { ...scale3, label: candidate };
38538
39042
  }
38539
- function annotatePlot(svg, indices) {
39043
+ function annotatePlot(svg, indices2) {
38540
39044
  const facets = svg.querySelectorAll('g[aria-label="facet"]');
38541
39045
  if (facets.length) {
38542
39046
  for (const facet of facets) {
38543
- annotateMarks(facet, indices);
39047
+ annotateMarks(facet, indices2);
38544
39048
  }
38545
39049
  } else {
38546
- annotateMarks(svg, indices);
39050
+ annotateMarks(svg, indices2);
38547
39051
  }
38548
39052
  }
38549
- function annotateMarks(svg, indices) {
39053
+ function annotateMarks(svg, indices2) {
38550
39054
  let index2 = -1;
38551
39055
  for (const child of svg.children) {
38552
39056
  const aria = child.getAttribute("aria-label") || "";
38553
39057
  const skip = child.nodeName === "style" || aria.includes("-axis") || aria.includes("-grid");
38554
39058
  if (!skip) {
38555
- child.setAttribute("data-index", indices[++index2]);
39059
+ child.setAttribute("data-index", indices2[++index2]);
38556
39060
  }
38557
39061
  }
38558
39062
  }
38559
39063
  function getType(data, channel) {
39064
+ if (!data) return;
38560
39065
  const { columns } = data;
38561
39066
  const col = columns[channel] ?? columns[channel + "1"] ?? columns[channel + "2"];
38562
39067
  if (col) {
@@ -38606,8 +39111,8 @@ var Plot = class {
38606
39111
  innerHeight(defaultValue = 400) {
38607
39112
  const { top: top2, bottom: bottom2 } = this.margins();
38608
39113
  let h = this.getAttribute("height");
38609
- if (h == null && defaultValue != null) {
38610
- h = defaultValue;
39114
+ if (h == null) {
39115
+ h = maybeAspectRatio(this, top2, bottom2) || defaultValue;
38611
39116
  this.setAttribute("height", h, { silent: true });
38612
39117
  }
38613
39118
  return h - top2 - bottom2;
@@ -38711,6 +39216,16 @@ var Plot = class {
38711
39216
  this.legends.push({ legend: legend2, include });
38712
39217
  }
38713
39218
  };
39219
+ function maybeAspectRatio(plot2, top2, bottom2) {
39220
+ const ar = plot2.getAttribute("aspectRatio");
39221
+ if (ar == null) return;
39222
+ const x3 = plot2.getAttribute("xDomain");
39223
+ const y3 = plot2.getAttribute("yDomain");
39224
+ if (!x3 || !y3) return;
39225
+ const dx = Math.abs(x3[1] - x3[0]);
39226
+ const dy = Math.abs(y3[1] - y3[0]);
39227
+ return dy * plot2.innerWidth() / (ar * dx) + top2 + bottom2;
39228
+ }
38714
39229
 
38715
39230
  // src/marks/util/is-color.js
38716
39231
  function isColor2(value) {
@@ -38757,7 +39272,8 @@ var constantOptions = /* @__PURE__ */ new Set([
38757
39272
  "crossOrigin",
38758
39273
  "paintOrder",
38759
39274
  "pointerEvents",
38760
- "target"
39275
+ "target",
39276
+ "select"
38761
39277
  ]);
38762
39278
  function isConstantOption(value) {
38763
39279
  return constantOptions.has(value);
@@ -38784,39 +39300,6 @@ function isSymbol2(value) {
38784
39300
  return symbols2.has(`${value}`.toLowerCase());
38785
39301
  }
38786
39302
 
38787
- // src/marks/util/to-data-columns.js
38788
- function toDataColumns(data) {
38789
- return isArrowTable(data) ? arrowToColumns(data) : arrayToColumns(data);
38790
- }
38791
- function arrowToColumns(data) {
38792
- const { numRows, numCols, schema: { fields } } = data;
38793
- const columns = {};
38794
- for (let col = 0; col < numCols; ++col) {
38795
- const name = fields[col].name;
38796
- if (columns[name]) {
38797
- console.warn(`Redundant column name "${name}". Skipping...`);
38798
- } else {
38799
- columns[name] = convertArrowColumn(data.getChildAt(col));
38800
- }
38801
- }
38802
- return { numRows, columns };
38803
- }
38804
- function arrayToColumns(data) {
38805
- const numRows = data.length;
38806
- if (typeof data[0] === "object") {
38807
- const names = numRows ? Object.keys(data[0]) : [];
38808
- const columns = {};
38809
- if (names.length > 0) {
38810
- names.forEach((name) => {
38811
- columns[name] = data.map((d) => d[name]);
38812
- });
38813
- }
38814
- return { numRows, columns };
38815
- } else {
38816
- return { numRows, values: data };
38817
- }
38818
- }
38819
-
38820
39303
  // src/marks/Mark.js
38821
39304
  var isColorChannel = (channel) => channel === "stroke" || channel === "fill";
38822
39305
  var isOpacityChannel = (channel) => /opacity$/i.test(channel);
@@ -38885,7 +39368,7 @@ var Mark2 = class extends MosaicClient {
38885
39368
  }
38886
39369
  /**
38887
39370
  * @param {import('../plot.js').Plot} plot The plot.
38888
- * @param {number} index
39371
+ * @param {number} index
38889
39372
  */
38890
39373
  setPlot(plot2, index2) {
38891
39374
  this.plot = plot2;
@@ -38960,18 +39443,8 @@ var Mark2 = class extends MosaicClient {
38960
39443
  * @returns {object[]}
38961
39444
  */
38962
39445
  plotSpecs() {
38963
- const { type: type2, detail, channels } = this;
38964
- const { numRows: length4, values: values2, columns } = this.data || {};
38965
- const options = {};
38966
- const side = {};
38967
- for (const c4 of channels) {
38968
- const obj = detail.has(c4.channel) ? side : options;
38969
- obj[c4.channel] = channelOption(c4, columns);
38970
- }
38971
- if (detail.size) options.channels = side;
38972
- const data = values2 ?? (this.data ? { length: length4 } : null);
38973
- const spec = [{ type: type2, data, options }];
38974
- return spec;
39446
+ const { type: type2, data, detail, channels } = this;
39447
+ return markPlotSpec(type2, detail, channels, data);
38975
39448
  }
38976
39449
  };
38977
39450
  function channelOption(c4, columns) {
@@ -39002,6 +39475,18 @@ function markQuery(channels, table, skip = []) {
39002
39475
  }
39003
39476
  return q;
39004
39477
  }
39478
+ function markPlotSpec(type2, detail, channels, data, options = {}) {
39479
+ const { numRows: length4, values: values2, columns } = data ?? {};
39480
+ const side = {};
39481
+ for (const c4 of channels) {
39482
+ const obj = detail.has(c4.channel) ? side : options;
39483
+ obj[c4.channel] = channelOption(c4, columns);
39484
+ }
39485
+ if (detail.size) options.channels = side;
39486
+ const specData = values2 ?? (data ? { length: length4 } : null);
39487
+ const spec = [{ type: type2, data: specData, options }];
39488
+ return spec;
39489
+ }
39005
39490
 
39006
39491
  // src/marks/util/channel-scale.js
39007
39492
  function channelScale(mark, channel) {
@@ -39428,7 +39913,7 @@ var Grid2DMark = class extends Mark2 {
39428
39913
  }
39429
39914
  /**
39430
39915
  * @param {import('../plot.js').Plot} plot The plot.
39431
- * @param {number} index
39916
+ * @param {number} index
39432
39917
  */
39433
39918
  setPlot(plot2, index2) {
39434
39919
  const update2 = () => {
@@ -39676,6 +40161,17 @@ function transform2(geometry, x3, y3) {
39676
40161
  return geometry;
39677
40162
  }
39678
40163
 
40164
+ // src/marks/util/permute.js
40165
+ function indices(length4) {
40166
+ return Array.from({ length: length4 }, (_, i) => i);
40167
+ }
40168
+ function permute2(data, order) {
40169
+ const ord = order.reduce((acc, val, i) => (acc[val] = i, acc), {});
40170
+ const idx = indices(data.length);
40171
+ idx.sort((a2, b) => ord[data[a2]] - ord[data[b]]);
40172
+ return idx;
40173
+ }
40174
+
39679
40175
  // src/marks/util/raster.js
39680
40176
  function createCanvas(w, h) {
39681
40177
  if (typeof document !== "undefined") {
@@ -39810,12 +40306,13 @@ var RasterMark = class extends Grid2DMark {
39810
40306
  const { alpha, alphaProp, color: color3, colorProp } = rasterEncoding(this);
39811
40307
  const alphaData = columns[alphaProp] ?? [];
39812
40308
  const colorData = columns[colorProp] ?? [];
40309
+ const idx = numRows > 1 && colorProp && this.groupby?.includes(colorProp) ? permute2(colorData, this.plot.getAttribute("colorDomain")) : indices(numRows);
39813
40310
  this.data = {
39814
40311
  numRows,
39815
40312
  columns: {
39816
40313
  src: Array.from({ length: numRows }, (_, i) => {
39817
- color3?.(img.data, w, h, colorData[i]);
39818
- alpha?.(img.data, w, h, alphaData[i]);
40314
+ color3?.(img.data, w, h, colorData[idx[i]]);
40315
+ alpha?.(img.data, w, h, alphaData[idx[i]]);
39819
40316
  ctx.putImageData(img, 0, 0);
39820
40317
  return canvas.toDataURL();
39821
40318
  })
@@ -39902,7 +40399,7 @@ function colorScale(mark, prop) {
39902
40399
  const domainAttr = plot2.getAttribute("colorDomain");
39903
40400
  const domainFixed = domainAttr === Fixed;
39904
40401
  const domainTransient = domainAttr?.[Transient];
39905
- const domain = !domainFixed && !domainTransient && domainAttr || (flat ? data.sort(ascending) : discrete ? gridDomainDiscrete(data) : gridDomainContinuous(data));
40402
+ const domain = !domainFixed && !domainTransient && domainAttr || (flat ? data.slice().sort(ascending) : discrete ? gridDomainDiscrete(data) : gridDomainContinuous(data));
39906
40403
  if (domainFixed || domainTransient || !domainAttr) {
39907
40404
  if (!domainFixed) domain[Transient] = true;
39908
40405
  plot2.setAttribute("colorDomain", domain);
@@ -40025,7 +40522,7 @@ function lineDensity(q, x3, y3, z, xn, yn, groupby = [], normalize4 = true) {
40025
40522
  sql`(y0 > 0 OR y0 + dy > 0)`
40026
40523
  ));
40027
40524
  const num = Query.select({ x: sql`GREATEST(MAX(ABS(dx)), MAX(ABS(dy)))` }).from("pairs");
40028
- const indices = Query.select({ i: sql`UNNEST(range((${num})))::INTEGER` });
40525
+ const indices2 = Query.select({ i: sql`UNNEST(range((${num})))::INTEGER` });
40029
40526
  const raster2 = Query.unionAll(
40030
40527
  Query.select(groups2, {
40031
40528
  x: sql`x0 + i`,
@@ -40044,7 +40541,7 @@ function lineDensity(q, x3, y3, z, xn, yn, groupby = [], normalize4 = true) {
40044
40541
  "y",
40045
40542
  normalize4 ? { w: sql`1.0 / COUNT(*) OVER (PARTITION BY ${pointPart})` } : null
40046
40543
  ).where(and(isBetween("x", [0, xn], true), isBetween("y", [0, yn], true)));
40047
- return Query.with({ pairs: pairs2, indices, raster: raster2, points: points2 }).from("points").select(groupby, {
40544
+ return Query.with({ pairs: pairs2, indices: indices2, raster: raster2, points: points2 }).from("points").select(groupby, {
40048
40545
  index: sql`x + y * ${xn}::INTEGER`,
40049
40546
  density: normalize4 ? sum("w") : count()
40050
40547
  }).groupby("index", groupby);
@@ -40209,6 +40706,220 @@ function points(data, bins2, x06, y06, deltaX, deltaY, invertX, invertY, offset2
40209
40706
  return { numRows, columns };
40210
40707
  }
40211
40708
 
40709
+ // src/marks/util/stats.js
40710
+ function ibetainv2(p, a2, b) {
40711
+ var EPS2 = 1e-8;
40712
+ var a1 = a2 - 1;
40713
+ var b1 = b - 1;
40714
+ var j = 0;
40715
+ var lna, lnb, pp, t, u4, err, x3, al, h, w, afac;
40716
+ if (p <= 0) return 0;
40717
+ if (p >= 1) return 1;
40718
+ if (a2 >= 1 && b >= 1) {
40719
+ pp = p < 0.5 ? p : 1 - p;
40720
+ t = Math.sqrt(-2 * Math.log(pp));
40721
+ x3 = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
40722
+ if (p < 0.5) x3 = -x3;
40723
+ al = (x3 * x3 - 3) / 6;
40724
+ h = 2 / (1 / (2 * a2 - 1) + 1 / (2 * b - 1));
40725
+ w = x3 * Math.sqrt(al + h) / h - (1 / (2 * b - 1) - 1 / (2 * a2 - 1)) * (al + 5 / 6 - 2 / (3 * h));
40726
+ x3 = a2 / (a2 + b * Math.exp(2 * w));
40727
+ } else {
40728
+ lna = Math.log(a2 / (a2 + b));
40729
+ lnb = Math.log(b / (a2 + b));
40730
+ t = Math.exp(a2 * lna) / a2;
40731
+ u4 = Math.exp(b * lnb) / b;
40732
+ w = t + u4;
40733
+ if (p < t / w) x3 = Math.pow(a2 * w * p, 1 / a2);
40734
+ else x3 = 1 - Math.pow(b * w * (1 - p), 1 / b);
40735
+ }
40736
+ afac = -gammaln2(a2) - gammaln2(b) + gammaln2(a2 + b);
40737
+ for (; j < 10; j++) {
40738
+ if (x3 === 0 || x3 === 1) return x3;
40739
+ err = ibeta2(x3, a2, b) - p;
40740
+ t = Math.exp(a1 * Math.log(x3) + b1 * Math.log(1 - x3) + afac);
40741
+ u4 = err / t;
40742
+ x3 -= t = u4 / (1 - 0.5 * Math.min(1, u4 * (a1 / x3 - b1 / (1 - x3))));
40743
+ if (x3 <= 0) x3 = 0.5 * (x3 + t);
40744
+ if (x3 >= 1) x3 = 0.5 * (x3 + t + 1);
40745
+ if (Math.abs(t) < EPS2 * x3 && j > 0) break;
40746
+ }
40747
+ return x3;
40748
+ }
40749
+ function ibeta2(x3, a2, b) {
40750
+ var bt = x3 === 0 || x3 === 1 ? 0 : Math.exp(gammaln2(a2 + b) - gammaln2(a2) - gammaln2(b) + a2 * Math.log(x3) + b * Math.log(1 - x3));
40751
+ if (x3 < 0 || x3 > 1) return 0;
40752
+ if (x3 < (a2 + 1) / (a2 + b + 2))
40753
+ return bt * betacf2(x3, a2, b) / a2;
40754
+ return 1 - bt * betacf2(1 - x3, b, a2) / b;
40755
+ }
40756
+ function betacf2(x3, a2, b) {
40757
+ var fpmin = 1e-30;
40758
+ var m = 1;
40759
+ var qab = a2 + b;
40760
+ var qap = a2 + 1;
40761
+ var qam = a2 - 1;
40762
+ var c4 = 1;
40763
+ var d = 1 - qab * x3 / qap;
40764
+ var m2, aa2, del, h;
40765
+ if (Math.abs(d) < fpmin) d = fpmin;
40766
+ d = 1 / d;
40767
+ h = d;
40768
+ for (; m <= 100; m++) {
40769
+ m2 = 2 * m;
40770
+ aa2 = m * (b - m) * x3 / ((qam + m2) * (a2 + m2));
40771
+ d = 1 + aa2 * d;
40772
+ if (Math.abs(d) < fpmin) d = fpmin;
40773
+ c4 = 1 + aa2 / c4;
40774
+ if (Math.abs(c4) < fpmin) c4 = fpmin;
40775
+ d = 1 / d;
40776
+ h *= d * c4;
40777
+ aa2 = -(a2 + m) * (qab + m) * x3 / ((a2 + m2) * (qap + m2));
40778
+ d = 1 + aa2 * d;
40779
+ if (Math.abs(d) < fpmin) d = fpmin;
40780
+ c4 = 1 + aa2 / c4;
40781
+ if (Math.abs(c4) < fpmin) c4 = fpmin;
40782
+ d = 1 / d;
40783
+ del = d * c4;
40784
+ h *= del;
40785
+ if (Math.abs(del - 1) < 3e-7) break;
40786
+ }
40787
+ return h;
40788
+ }
40789
+ function gammaln2(x3) {
40790
+ var j = 0;
40791
+ var cof = [
40792
+ 76.18009172947146,
40793
+ -86.5053203294167,
40794
+ 24.01409824083091,
40795
+ -1.231739572450155,
40796
+ 0.001208650973866179,
40797
+ -5395239384953e-18
40798
+ ];
40799
+ var ser = 1.000000000190015;
40800
+ var xx, y3, tmp2;
40801
+ tmp2 = (y3 = xx = x3) + 5.5;
40802
+ tmp2 -= (xx + 0.5) * Math.log(tmp2);
40803
+ for (; j < 6; j++) ser += cof[j] / ++y3;
40804
+ return Math.log(2.506628274631 * ser / xx) - tmp2;
40805
+ }
40806
+ function qt2(p, dof) {
40807
+ var x3 = ibetainv2(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5);
40808
+ x3 = Math.sqrt(dof * (1 - x3) / x3);
40809
+ return p > 0.5 ? x3 : -x3;
40810
+ }
40811
+ function erfinv(x3) {
40812
+ let w = -Math.log((1 - x3) * (1 + x3));
40813
+ let p;
40814
+ if (w < 6.25) {
40815
+ w -= 3.125;
40816
+ p = -364441206401782e-35;
40817
+ p = -16850591381820166e-35 + p * w;
40818
+ p = 128584807152564e-32 + p * w;
40819
+ p = 11157877678025181e-33 + p * w;
40820
+ p = -1333171662854621e-31 + p * w;
40821
+ p = 20972767875968562e-33 + p * w;
40822
+ p = 6637638134358324e-30 + p * w;
40823
+ p = -4054566272975207e-29 + p * w;
40824
+ p = -8151934197605472e-29 + p * w;
40825
+ p = 26335093153082323e-28 + p * w;
40826
+ p = -12975133253453532e-27 + p * w;
40827
+ p = -5415412054294628e-26 + p * w;
40828
+ p = 10512122733215323e-25 + p * w;
40829
+ p = -4112633980346984e-24 + p * w;
40830
+ p = -29070369957882005e-24 + p * w;
40831
+ p = 42347877827932404e-23 + p * w;
40832
+ p = -13654692000834679e-22 + p * w;
40833
+ p = -13882523362786469e-21 + p * w;
40834
+ p = 18673420803405714e-20 + p * w;
40835
+ p = -740702534166267e-18 + p * w;
40836
+ p = -0.006033670871430149 + p * w;
40837
+ p = 0.24015818242558962 + p * w;
40838
+ p = 1.6536545626831027 + p * w;
40839
+ } else if (w < 16) {
40840
+ w = Math.sqrt(w) - 3.25;
40841
+ p = 22137376921775787e-25;
40842
+ p = 9075656193888539e-23 + p * w;
40843
+ p = -27517406297064545e-23 + p * w;
40844
+ p = 18239629214389228e-24 + p * w;
40845
+ p = 15027403968909828e-22 + p * w;
40846
+ p = -4013867526981546e-21 + p * w;
40847
+ p = 29234449089955446e-22 + p * w;
40848
+ p = 12475304481671779e-21 + p * w;
40849
+ p = -47318229009055734e-21 + p * w;
40850
+ p = 6828485145957318e-20 + p * w;
40851
+ p = 24031110387097894e-21 + p * w;
40852
+ p = -3550375203628475e-19 + p * w;
40853
+ p = 9532893797373805e-19 + p * w;
40854
+ p = -0.0016882755560235047 + p * w;
40855
+ p = 0.002491442096107851 + p * w;
40856
+ p = -0.003751208507569241 + p * w;
40857
+ p = 0.005370914553590064 + p * w;
40858
+ p = 1.0052589676941592 + p * w;
40859
+ p = 3.0838856104922208 + p * w;
40860
+ } else if (Number.isFinite(w)) {
40861
+ w = Math.sqrt(w) - 5;
40862
+ p = -27109920616438573e-27;
40863
+ p = -2555641816996525e-25 + p * w;
40864
+ p = 15076572693500548e-25 + p * w;
40865
+ p = -3789465440126737e-24 + p * w;
40866
+ p = 761570120807834e-23 + p * w;
40867
+ p = -1496002662714924e-23 + p * w;
40868
+ p = 2914795345090108e-23 + p * w;
40869
+ p = -6771199775845234e-23 + p * w;
40870
+ p = 22900482228026655e-23 + p * w;
40871
+ p = -99298272942317e-20 + p * w;
40872
+ p = 4526062597223154e-21 + p * w;
40873
+ p = -1968177810553167e-20 + p * w;
40874
+ p = 7599527703001776e-20 + p * w;
40875
+ p = -21503011930044477e-20 + p * w;
40876
+ p = -13871931833623122e-20 + p * w;
40877
+ p = 1.0103004648645344 + p * w;
40878
+ p = 4.849906401408584 + p * w;
40879
+ } else {
40880
+ p = Infinity;
40881
+ }
40882
+ return p * x3;
40883
+ }
40884
+
40885
+ // src/marks/ErrorBarMark.js
40886
+ var ErrorBarMark = class extends Mark2 {
40887
+ constructor(type2, source, options) {
40888
+ const dim = type2.endsWith("X") ? "y" : "x";
40889
+ const { ci = 0.95, ...channels } = options;
40890
+ super(type2, source, channels);
40891
+ this.dim = dim;
40892
+ this.field = this.channelField(dim).field;
40893
+ this.channels = this.channels.filter((c4) => c4.channel !== dim);
40894
+ this.ci = handleParam(ci, (value) => {
40895
+ return this.ci = value, this.update();
40896
+ });
40897
+ }
40898
+ query(filter3 = []) {
40899
+ const { channels, field: field2, source: { table } } = this;
40900
+ const fields = channels.concat([
40901
+ { field: avg(field2), as: "__avg__" },
40902
+ { field: count(field2), as: "__n__" },
40903
+ { field: stddev(field2), as: "__sd__" }
40904
+ ]);
40905
+ return markQuery(fields, table).where(filter3);
40906
+ }
40907
+ queryResult(data) {
40908
+ this.data = toDataColumns(data);
40909
+ return this;
40910
+ }
40911
+ plotSpecs() {
40912
+ const { type: type2, dim, detail, data, ci, channels } = this;
40913
+ const p = Math.SQRT2 * erfinv(ci);
40914
+ const { columns: { __avg__: u4, __sd__: s2, __n__: n } } = data;
40915
+ const options = {
40916
+ [`${dim}1`]: u4.map((u5, i) => u5 - p * s2[i] / Math.sqrt(n[i])),
40917
+ [`${dim}2`]: u4.map((u5, i) => u5 + p * s2[i] / Math.sqrt(n[i]))
40918
+ };
40919
+ return markPlotSpec(type2, detail, channels, data, options);
40920
+ }
40921
+ };
40922
+
40212
40923
  // src/marks/GeoMark.js
40213
40924
  var DEFAULT_GEOMETRY_COLUMN = "geom";
40214
40925
  var GeoMark = class extends Mark2 {
@@ -40248,50 +40959,48 @@ var HexbinMark = class extends Mark2 {
40248
40959
  query(filter3 = []) {
40249
40960
  if (this.hasOwnData()) return null;
40250
40961
  const { plot: plot2, binWidth, channels, source } = this;
40251
- const [x12, x22] = extentX(this, filter3);
40252
- const [y12, y22] = extentY(this, filter3);
40253
- const ox2 = 0.5 - plot2.getAttribute("marginLeft");
40254
- const oy2 = 0 - plot2.getAttribute("marginTop");
40255
- const dx = `${binWidth}::DOUBLE`;
40256
- const dy = `${binWidth * (1.5 / Math.sqrt(3))}::DOUBLE`;
40257
- const xr = `${plot2.innerWidth() / (x22 - x12)}::DOUBLE`;
40258
- const yr = `${plot2.innerHeight() / (y22 - y12)}::DOUBLE`;
40259
40962
  let x3, y3;
40260
- const aggr = /* @__PURE__ */ new Set();
40963
+ const dims = /* @__PURE__ */ new Set();
40261
40964
  const cols = {};
40262
- let orderby;
40263
40965
  for (const c4 of channels) {
40264
40966
  if (c4.channel === "orderby") {
40265
- orderby = c4.value;
40266
40967
  } else if (c4.channel === "x") {
40267
40968
  x3 = c4;
40268
40969
  } else if (c4.channel === "y") {
40269
40970
  y3 = c4;
40270
40971
  } else if (Object.hasOwn(c4, "field")) {
40271
- cols[c4.as] = c4.field;
40272
- if (c4.field.aggregate) {
40273
- c4.field.columns.forEach((col) => aggr.add(col));
40972
+ const { as, field: field2 } = c4;
40973
+ cols[as] = field2;
40974
+ if (!field2.aggregate) {
40975
+ dims.add(as);
40274
40976
  }
40275
40977
  }
40276
40978
  }
40277
- const q = Query.select({
40278
- [x3.as]: sql`${x12}::DOUBLE + ((x + 0.5 * (y & 1)) * ${dx} + ${ox2})::DOUBLE / ${xr}`,
40279
- [y3.as]: sql`${y22}::DOUBLE - (y * ${dy} + ${oy2})::DOUBLE / ${yr}`,
40979
+ const [x12, x22] = extentX(this, filter3);
40980
+ const [y12, y22] = extentY(this, filter3);
40981
+ const ox2 = 0.5 - plot2.getAttribute("marginLeft");
40982
+ const oy2 = 0 - plot2.getAttribute("marginTop");
40983
+ const dx = `${binWidth}::DOUBLE`;
40984
+ const dy = `${binWidth * (1.5 / Math.sqrt(3))}::DOUBLE`;
40985
+ const xr = `${plot2.innerWidth() / (x22 - x12)}::DOUBLE`;
40986
+ const yr = `${plot2.innerHeight() / (y22 - y12)}::DOUBLE`;
40987
+ return Query.select({
40988
+ [x3.as]: sql`${x12}::DOUBLE + ((_x + 0.5 * (_y & 1)) * ${dx} + ${ox2})::DOUBLE / ${xr}`,
40989
+ [y3.as]: sql`${y22}::DOUBLE - (_y * ${dy} + ${oy2})::DOUBLE / ${yr}`,
40280
40990
  ...cols
40281
- }).groupby("x", "y");
40282
- if (orderby) q.orderby(orderby);
40283
- const xx = `${xr} * (${x3.field} - ${x12}::DOUBLE)`;
40284
- const yy = `${yr} * (${y22}::DOUBLE - ${y3.field})`;
40285
- const hex2 = Query.select({
40286
- py: sql`(${yy} - ${oy2}) / ${dy}`,
40287
- pj: sql`ROUND(py)::INTEGER`,
40288
- px: sql`(${xx} - ${ox2}) / ${dx} - 0.5 * (pj & 1)`,
40289
- pi: sql`ROUND(px)::INTEGER`,
40290
- tt: sql`ABS(py-pj) * 3 > 1 AND (px-pi)**2 + (py-pj)**2 > (px - pi - 0.5 * CASE WHEN px < pi THEN -1 ELSE 1 END)**2 + (py - pj - CASE WHEN py < pj THEN -1 ELSE 1 END)**2`,
40291
- x: sql`CASE WHEN tt THEN (pi + (CASE WHEN px < pi THEN -0.5 ELSE 0.5 END) + (CASE WHEN pj & 1 <> 0 THEN 0.5 ELSE -0.5 END))::INTEGER ELSE pi END`,
40292
- y: sql`CASE WHEN tt THEN (pj + CASE WHEN py < pj THEN -1 ELSE 1 END)::INTEGER ELSE pj END`
40293
- }).select(Array.from(aggr)).from(source.table).where(isNotNull(x3.field), isNotNull(y3.field), filter3);
40294
- return q.from(hex2);
40991
+ }).groupby("_x", "_y", ...dims).from(
40992
+ // Subquery performs hex binning in screen space and also passes
40993
+ // original columns through (the DB should optimize this).
40994
+ Query.select({
40995
+ _py: sql`(${yr} * (${y22}::DOUBLE - ${y3.field}) - ${oy2}) / ${dy}`,
40996
+ _pj: sql`ROUND(_py)::INTEGER`,
40997
+ _px: sql`(${xr} * (${x3.field} - ${x12}::DOUBLE) - ${ox2}) / ${dx} - 0.5 * (_pj & 1)`,
40998
+ _pi: sql`ROUND(_px)::INTEGER`,
40999
+ _tt: sql`ABS(_py-_pj) * 3 > 1 AND (_px-_pi)**2 + (_py-_pj)**2 > (_px - _pi - 0.5 * CASE WHEN _px < _pi THEN -1 ELSE 1 END)**2 + (_py - _pj - CASE WHEN _py < _pj THEN -1 ELSE 1 END)**2`,
41000
+ _x: sql`CASE WHEN _tt THEN (_pi + (CASE WHEN _px < _pi THEN -0.5 ELSE 0.5 END) + (CASE WHEN _pj & 1 <> 0 THEN 0.5 ELSE -0.5 END))::INTEGER ELSE _pi END`,
41001
+ _y: sql`CASE WHEN _tt THEN (_pj + CASE WHEN _py < _pj THEN -1 ELSE 1 END)::INTEGER ELSE _pj END`
41002
+ }, "*").from(source.table).where(isNotNull(x3.field), isNotNull(y3.field), filter3)
41003
+ );
40295
41004
  }
40296
41005
  };
40297
41006
 
@@ -40428,12 +41137,13 @@ var RasterTileMark = class extends Grid2DMark {
40428
41137
  const { alpha, alphaProp, color: color3, colorProp } = rasterEncoding(this);
40429
41138
  const alphaData = columns[alphaProp] ?? [];
40430
41139
  const colorData = columns[colorProp] ?? [];
41140
+ const idx = numRows > 1 && colorProp && this.groupby?.includes(colorProp) ? permute2(colorData, this.plot.getAttribute("colorDomain")) : indices(numRows);
40431
41141
  this.data = {
40432
41142
  numRows,
40433
41143
  columns: {
40434
41144
  src: Array.from({ length: numRows }, (_, i) => {
40435
- color3?.(img.data, w, h, colorData[i]);
40436
- alpha?.(img.data, w, h, alphaData[i]);
41145
+ color3?.(img.data, w, h, colorData[idx[i]]);
41146
+ alpha?.(img.data, w, h, alphaData[idx[i]]);
40437
41147
  ctx.putImageData(img, 0, 0);
40438
41148
  return canvas.toDataURL();
40439
41149
  })
@@ -40519,109 +41229,6 @@ function tileFloor(value) {
40519
41229
  return floored === value ? floored - 1 : floored;
40520
41230
  }
40521
41231
 
40522
- // src/marks/util/stats.js
40523
- function ibetainv2(p, a2, b) {
40524
- var EPS2 = 1e-8;
40525
- var a1 = a2 - 1;
40526
- var b1 = b - 1;
40527
- var j = 0;
40528
- var lna, lnb, pp, t, u4, err, x3, al, h, w, afac;
40529
- if (p <= 0) return 0;
40530
- if (p >= 1) return 1;
40531
- if (a2 >= 1 && b >= 1) {
40532
- pp = p < 0.5 ? p : 1 - p;
40533
- t = Math.sqrt(-2 * Math.log(pp));
40534
- x3 = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t;
40535
- if (p < 0.5) x3 = -x3;
40536
- al = (x3 * x3 - 3) / 6;
40537
- h = 2 / (1 / (2 * a2 - 1) + 1 / (2 * b - 1));
40538
- w = x3 * Math.sqrt(al + h) / h - (1 / (2 * b - 1) - 1 / (2 * a2 - 1)) * (al + 5 / 6 - 2 / (3 * h));
40539
- x3 = a2 / (a2 + b * Math.exp(2 * w));
40540
- } else {
40541
- lna = Math.log(a2 / (a2 + b));
40542
- lnb = Math.log(b / (a2 + b));
40543
- t = Math.exp(a2 * lna) / a2;
40544
- u4 = Math.exp(b * lnb) / b;
40545
- w = t + u4;
40546
- if (p < t / w) x3 = Math.pow(a2 * w * p, 1 / a2);
40547
- else x3 = 1 - Math.pow(b * w * (1 - p), 1 / b);
40548
- }
40549
- afac = -gammaln2(a2) - gammaln2(b) + gammaln2(a2 + b);
40550
- for (; j < 10; j++) {
40551
- if (x3 === 0 || x3 === 1) return x3;
40552
- err = ibeta2(x3, a2, b) - p;
40553
- t = Math.exp(a1 * Math.log(x3) + b1 * Math.log(1 - x3) + afac);
40554
- u4 = err / t;
40555
- x3 -= t = u4 / (1 - 0.5 * Math.min(1, u4 * (a1 / x3 - b1 / (1 - x3))));
40556
- if (x3 <= 0) x3 = 0.5 * (x3 + t);
40557
- if (x3 >= 1) x3 = 0.5 * (x3 + t + 1);
40558
- if (Math.abs(t) < EPS2 * x3 && j > 0) break;
40559
- }
40560
- return x3;
40561
- }
40562
- function ibeta2(x3, a2, b) {
40563
- var bt = x3 === 0 || x3 === 1 ? 0 : Math.exp(gammaln2(a2 + b) - gammaln2(a2) - gammaln2(b) + a2 * Math.log(x3) + b * Math.log(1 - x3));
40564
- if (x3 < 0 || x3 > 1) return 0;
40565
- if (x3 < (a2 + 1) / (a2 + b + 2))
40566
- return bt * betacf2(x3, a2, b) / a2;
40567
- return 1 - bt * betacf2(1 - x3, b, a2) / b;
40568
- }
40569
- function betacf2(x3, a2, b) {
40570
- var fpmin = 1e-30;
40571
- var m = 1;
40572
- var qab = a2 + b;
40573
- var qap = a2 + 1;
40574
- var qam = a2 - 1;
40575
- var c4 = 1;
40576
- var d = 1 - qab * x3 / qap;
40577
- var m2, aa2, del, h;
40578
- if (Math.abs(d) < fpmin) d = fpmin;
40579
- d = 1 / d;
40580
- h = d;
40581
- for (; m <= 100; m++) {
40582
- m2 = 2 * m;
40583
- aa2 = m * (b - m) * x3 / ((qam + m2) * (a2 + m2));
40584
- d = 1 + aa2 * d;
40585
- if (Math.abs(d) < fpmin) d = fpmin;
40586
- c4 = 1 + aa2 / c4;
40587
- if (Math.abs(c4) < fpmin) c4 = fpmin;
40588
- d = 1 / d;
40589
- h *= d * c4;
40590
- aa2 = -(a2 + m) * (qab + m) * x3 / ((a2 + m2) * (qap + m2));
40591
- d = 1 + aa2 * d;
40592
- if (Math.abs(d) < fpmin) d = fpmin;
40593
- c4 = 1 + aa2 / c4;
40594
- if (Math.abs(c4) < fpmin) c4 = fpmin;
40595
- d = 1 / d;
40596
- del = d * c4;
40597
- h *= del;
40598
- if (Math.abs(del - 1) < 3e-7) break;
40599
- }
40600
- return h;
40601
- }
40602
- function gammaln2(x3) {
40603
- var j = 0;
40604
- var cof = [
40605
- 76.18009172947146,
40606
- -86.5053203294167,
40607
- 24.01409824083091,
40608
- -1.231739572450155,
40609
- 0.001208650973866179,
40610
- -5395239384953e-18
40611
- ];
40612
- var ser = 1.000000000190015;
40613
- var xx, y3, tmp2;
40614
- tmp2 = (y3 = xx = x3) + 5.5;
40615
- tmp2 -= (xx + 0.5) * Math.log(tmp2);
40616
- for (; j < 6; j++) ser += cof[j] / ++y3;
40617
- return Math.log(2.506628274631 * ser / xx) - tmp2;
40618
- }
40619
- function qt2(p, dof) {
40620
- var x3 = ibetainv2(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5);
40621
- x3 = Math.sqrt(dof * (1 - x3) / x3);
40622
- return p > 0.5 ? x3 : -x3;
40623
- }
40624
-
40625
41232
  // src/marks/RegressionMark.js
40626
41233
  var RegressionMark = class extends Mark2 {
40627
41234
  constructor(source, options) {
@@ -40708,7 +41315,7 @@ function concat(a2, b) {
40708
41315
  return array4;
40709
41316
  }
40710
41317
  function linePoints(fit2) {
40711
- const { x0: x06, x1: x12, xm, intercept, slope, n, ssx, ssy, ...rest } = fit2.columns;
41318
+ const { x0: x06 = [], x1: x12 = [], xm, intercept, slope, n, ssx, ssy, ...rest } = fit2.columns;
40712
41319
  const predict = (x4, i) => intercept[i] + x4 * slope[i];
40713
41320
  const x3 = concat(x06, x12);
40714
41321
  const y3 = concat(x06.map(predict), x12.map(predict));
@@ -40812,7 +41419,8 @@ var Highlight = class {
40812
41419
  for (let i = 0; i < nodes.length; ++i) {
40813
41420
  const node = nodes[i];
40814
41421
  const base = values2[i];
40815
- const t = test(node.__data__);
41422
+ const data = node.__data__;
41423
+ const t = test(Array.isArray(data) ? data[0] : data);
40816
41424
  for (let j = 0; j < channels.length; ++j) {
40817
41425
  const [attr, value] = channels[j];
40818
41426
  node.setAttribute(attr, t ? base[j] : value);
@@ -40828,8 +41436,10 @@ async function predicateFunction(mark, selection2) {
40828
41436
  const filter3 = mark.filterBy?.predicate(mark, true);
40829
41437
  const s2 = { __: and(pred) };
40830
41438
  const q = mark.query(filter3);
40831
- const p = q.groupby().length ? q.select(s2) : q.$select(s2);
40832
- const data = await mark.coordinator.query(p);
41439
+ (q.queries || [q]).forEach((q2) => {
41440
+ q2.groupby().length ? q2.select(s2) : q2.$select(s2);
41441
+ });
41442
+ const data = await mark.coordinator.query(q);
40833
41443
  const v2 = data.getChild?.("__");
40834
41444
  return !(data.numRows || data.length) ? () => false : v2 ? (i) => v2.get(i) : (i) => data[i].__;
40835
41445
  }
@@ -40935,13 +41545,12 @@ var Interval1D = class {
40935
41545
  }
40936
41546
  clause(value) {
40937
41547
  const { mark, pixelSize, field: field2, scale: scale3 } = this;
40938
- return {
41548
+ return clauseInterval(field2, value, {
40939
41549
  source: this,
40940
- schema: { type: "interval", pixelSize, scales: [scale3] },
40941
41550
  clients: this.peers ? mark.plot.markSet : (/* @__PURE__ */ new Set()).add(mark),
40942
- value,
40943
- predicate: value ? isBetween(field2, value) : null
40944
- };
41551
+ scale: scale3,
41552
+ pixelSize
41553
+ });
40945
41554
  }
40946
41555
  init(svg, root2) {
40947
41556
  const { brush: brush3, channel, style } = this;
@@ -40949,9 +41558,10 @@ var Interval1D = class {
40949
41558
  const rx = svg.scale("x").range;
40950
41559
  const ry = svg.scale("y").range;
40951
41560
  brush3.extent([[min2(rx), min2(ry)], [max2(rx), max2(ry)]]);
41561
+ const range3 = this.value?.map(this.scale.apply).sort(ascending);
40952
41562
  const facets = select_default2(svg).selectAll('g[aria-label="facet"]');
40953
41563
  root2 = facets.size() ? facets : select_default2(root2 ?? svg);
40954
- this.g = root2.append("g").attr("class", `interval-${channel}`).each(patchScreenCTM).call(brush3).call(brush3.moveSilent, this.value?.map(this.scale.apply));
41564
+ this.g = root2.append("g").attr("class", `interval-${channel}`).each(patchScreenCTM).call(brush3).call(brush3.moveSilent, range3);
40955
41565
  if (style) {
40956
41566
  const brushes = this.g.selectAll("rect.selection");
40957
41567
  for (const name in style) {
@@ -40965,7 +41575,6 @@ var Interval1D = class {
40965
41575
  };
40966
41576
 
40967
41577
  // src/interactors/Interval2D.js
40968
- var asc = (a2, b) => a2 - b;
40969
41578
  var Interval2D = class {
40970
41579
  constructor(mark, {
40971
41580
  selection: selection2,
@@ -40998,8 +41607,8 @@ var Interval2D = class {
40998
41607
  let yr = void 0;
40999
41608
  if (extent4) {
41000
41609
  const [a2, b] = extent4;
41001
- xr = [a2[0], b[0]].map((v2) => invert(v2, xscale, pixelSize)).sort(asc);
41002
- yr = [a2[1], b[1]].map((v2) => invert(v2, yscale, pixelSize)).sort(asc);
41610
+ xr = [a2[0], b[0]].map((v2) => invert(v2, xscale, pixelSize)).sort(ascending);
41611
+ yr = [a2[1], b[1]].map((v2) => invert(v2, yscale, pixelSize)).sort(ascending);
41003
41612
  }
41004
41613
  if (!closeTo(xr, value?.[0]) || !closeTo(yr, value?.[1])) {
41005
41614
  this.value = extent4 ? [xr, yr] : void 0;
@@ -41009,13 +41618,12 @@ var Interval2D = class {
41009
41618
  }
41010
41619
  clause(value) {
41011
41620
  const { mark, pixelSize, xfield, yfield, xscale, yscale } = this;
41012
- return {
41621
+ return clauseIntervals([xfield, yfield], value, {
41013
41622
  source: this,
41014
- schema: { type: "interval", pixelSize, scales: [xscale, yscale] },
41015
41623
  clients: this.peers ? mark.plot.markSet : (/* @__PURE__ */ new Set()).add(mark),
41016
- value,
41017
- predicate: value ? and(isBetween(xfield, value[0]), isBetween(yfield, value[1])) : null
41018
- };
41624
+ scales: [xscale, yscale],
41625
+ pixelSize
41626
+ });
41019
41627
  }
41020
41628
  init(svg) {
41021
41629
  const { brush: brush3, style } = this;
@@ -41034,8 +41642,8 @@ var Interval2D = class {
41034
41642
  }
41035
41643
  }
41036
41644
  if (this.value) {
41037
- const [x12, x22] = this.value[0].map(xscale.apply).sort(asc);
41038
- const [y12, y22] = this.value[1].map(yscale.apply).sort(asc);
41645
+ const [x12, x22] = this.value[0].map(xscale.apply).sort(ascending);
41646
+ const [y12, y22] = this.value[1].map(yscale.apply).sort(ascending);
41039
41647
  this.g.call(brush3.moveSilent, [[x12, y12], [x22, y22]]);
41040
41648
  }
41041
41649
  svg.addEventListener("pointerenter", (evt) => {
@@ -41048,61 +41656,83 @@ var Interval2D = class {
41048
41656
  var Nearest = class {
41049
41657
  constructor(mark, {
41050
41658
  selection: selection2,
41051
- channel,
41052
- field: field2
41659
+ pointer: pointer2,
41660
+ channels,
41661
+ fields,
41662
+ maxRadius = 40
41053
41663
  }) {
41054
41664
  this.mark = mark;
41055
41665
  this.selection = selection2;
41056
41666
  this.clients = (/* @__PURE__ */ new Set()).add(mark);
41057
- this.channel = channel;
41058
- this.field = field2 || getField(mark, [channel]);
41667
+ this.pointer = pointer2;
41668
+ this.channels = channels || (pointer2 === "x" ? ["x"] : pointer2 === "y" ? ["y"] : ["x", "y"]);
41669
+ this.fields = fields || this.channels.map((c4) => getField(mark, [c4]));
41670
+ this.maxRadius = maxRadius;
41671
+ this.valueIndex = -1;
41059
41672
  }
41060
41673
  clause(value) {
41061
- const { clients, field: field2 } = this;
41062
- const predicate = value ? eq(field2, literal(value)) : null;
41063
- return {
41674
+ const { clients, fields } = this;
41675
+ return clausePoints(fields, value ? [value] : value, {
41064
41676
  source: this,
41065
- schema: { type: "point" },
41066
- clients,
41067
- value,
41068
- predicate
41069
- };
41677
+ clients
41678
+ });
41070
41679
  }
41071
41680
  init(svg) {
41072
41681
  const that = this;
41073
- const { mark, channel, selection: selection2 } = this;
41074
- const { data } = mark;
41075
- const key = mark.channelField(channel).as;
41682
+ const { mark, channels, selection: selection2, maxRadius } = this;
41683
+ const { data: { columns } } = mark;
41684
+ const keys = channels.map((c4) => mark.channelField(c4).as);
41685
+ const param = !isSelection(selection2);
41076
41686
  const facets = select_default2(svg).selectAll('g[aria-label="facet"]');
41077
41687
  const root2 = facets.size() ? facets : select_default2(svg);
41078
- const scale3 = svg.scale(channel);
41079
- const param = !isSelection(selection2);
41080
- root2.on("pointerdown pointermove", function(evt) {
41081
- const [x3, y3] = pointer_default(evt, this);
41082
- const z = findNearest(data.columns[key], scale3.invert(channel === "x" ? x3 : y3));
41083
- selection2.update(param ? z : that.clause(z));
41688
+ const xscale = svg.scale("x").apply;
41689
+ const yscale = svg.scale("y").apply;
41690
+ const X3 = Array.from(columns[mark.channelField("x").as], xscale);
41691
+ const Y3 = Array.from(columns[mark.channelField("y").as], yscale);
41692
+ const sx = this.pointer === "y" ? 0.01 : 1;
41693
+ const sy = this.pointer === "x" ? 0.01 : 1;
41694
+ root2.on("pointerenter pointerdown pointermove", function(evt) {
41695
+ const [px, py] = pointer_default(evt, this);
41696
+ const i = findNearest(X3, Y3, px, py, sx, sy, maxRadius);
41697
+ if (i !== this.valueIndex) {
41698
+ this.valueIndex = i;
41699
+ const v2 = i < 0 ? void 0 : keys.map((k2) => columns[k2][i]);
41700
+ if (param) {
41701
+ if (i > -1) selection2.update(v2.length > 1 ? v2 : v2[0]);
41702
+ } else {
41703
+ selection2.update(that.clause(v2));
41704
+ }
41705
+ }
41084
41706
  });
41085
41707
  if (param) return;
41708
+ root2.on("pointerleave", () => {
41709
+ selection2.update(that.clause(void 0));
41710
+ });
41086
41711
  svg.addEventListener("pointerenter", (evt) => {
41087
- if (!evt.buttons) this.selection.activate(this.clause(0));
41712
+ if (!evt.buttons) {
41713
+ const v2 = this.channels.map(() => 0);
41714
+ selection2.activate(this.clause(v2));
41715
+ }
41088
41716
  });
41089
41717
  }
41090
41718
  };
41091
- function findNearest(values2, value) {
41092
- let dist2 = Infinity;
41093
- let nearest;
41094
- for (let i = 0; i < values2.length; ++i) {
41095
- const delta = Math.abs(values2[i] - value);
41096
- if (delta < dist2) {
41097
- dist2 = delta;
41098
- nearest = values2[i];
41719
+ function findNearest(x3, y3, px, py, sx, sy, maxRadius) {
41720
+ let dist2 = maxRadius * maxRadius;
41721
+ let nearest = -1;
41722
+ for (let i = 0; i < x3.length; ++i) {
41723
+ const dx = sx * (x3[i] - px);
41724
+ const dy = sy * (y3[i] - py);
41725
+ const dd = dx * dx + dy * dy;
41726
+ if (dd <= dist2) {
41727
+ dist2 = dd;
41728
+ nearest = i;
41099
41729
  }
41100
41730
  }
41101
41731
  return nearest;
41102
41732
  }
41103
41733
 
41104
41734
  // src/interactors/PanZoom.js
41105
- var asc2 = (a2, b) => a2 - b;
41735
+ var asc = (a2, b) => a2 - b;
41106
41736
  var PanZoom = class {
41107
41737
  constructor(mark, {
41108
41738
  x: x3 = new Selection(),
@@ -41144,13 +41774,11 @@ var PanZoom = class {
41144
41774
  }
41145
41775
  }
41146
41776
  clause(value, field2, scale3) {
41147
- return {
41777
+ return clauseInterval(field2, value, {
41148
41778
  source: this,
41149
- schema: { type: "interval", scales: [scale3] },
41150
41779
  clients: this.mark.plot.markSet,
41151
- value,
41152
- predicate: value ? isBetween(field2, value) : null
41153
- };
41780
+ scale: scale3
41781
+ });
41154
41782
  }
41155
41783
  init(svg) {
41156
41784
  this.svg = svg;
@@ -41159,8 +41787,8 @@ var PanZoom = class {
41159
41787
  const { panx, pany, mark: { plot: { element } }, xsel, ysel } = this;
41160
41788
  this.xscale = svg.scale("x");
41161
41789
  this.yscale = svg.scale("y");
41162
- const rx = this.xscale.range.slice().sort(asc2);
41163
- const ry = this.yscale.range.slice().sort(asc2);
41790
+ const rx = this.xscale.range.slice().sort(asc);
41791
+ const ry = this.yscale.range.slice().sort(asc);
41164
41792
  const tx = extent3(panx, [-Infinity, Infinity], rx);
41165
41793
  const ty = extent3(pany, [-Infinity, Infinity], ry);
41166
41794
  const z = zoom_default2().extent([[rx[0], ry[0]], [rx[1], ry[1]]]).scaleExtent(this.zoom).translateExtent([[tx[0], ty[0]], [tx[1], ty[1]]]).on("start", () => {
@@ -41212,42 +41840,35 @@ var Toggle = class {
41212
41840
  this.mark = mark;
41213
41841
  this.selection = selection2;
41214
41842
  this.peers = peers;
41215
- this.channels = channels.map((c4) => {
41843
+ const fields = this.fields = [];
41844
+ const as = this.as = [];
41845
+ channels.forEach((c4) => {
41216
41846
  const q = c4 === "color" ? ["color", "fill", "stroke"] : c4 === "x" ? ["x", "x1", "x2"] : c4 === "y" ? ["y", "y1", "y2"] : [c4];
41217
41847
  for (let i = 0; i < q.length; ++i) {
41218
41848
  const f = mark.channelField(q[i], { exact: true });
41219
- if (f) return {
41220
- field: f.field?.basis || f.field,
41221
- as: f.as
41222
- };
41849
+ if (f) {
41850
+ fields.push(f.field?.basis || f.field);
41851
+ as.push(f.as);
41852
+ return;
41853
+ }
41223
41854
  }
41224
41855
  throw new Error(`Missing channel: ${c4}`);
41225
41856
  });
41226
41857
  }
41227
41858
  clause(value) {
41228
- const { channels, mark } = this;
41229
- let predicate = null;
41230
- if (value) {
41231
- const clauses = value.map((vals) => {
41232
- const list = vals.map((v2, i) => {
41233
- return isNotDistinct(channels[i].field, literal(v2));
41234
- });
41235
- return list.length > 1 ? and(list) : list[0];
41236
- });
41237
- predicate = clauses.length > 1 ? or(clauses) : clauses[0];
41238
- }
41239
- return {
41859
+ const { fields, mark } = this;
41860
+ return clausePoints(fields, value, {
41240
41861
  source: this,
41241
- schema: { type: "point" },
41242
- clients: this.peers ? mark.plot.markSet : (/* @__PURE__ */ new Set()).add(mark),
41243
- value,
41244
- predicate
41245
- };
41862
+ clients: this.peers ? mark.plot.markSet : (/* @__PURE__ */ new Set()).add(mark)
41863
+ });
41246
41864
  }
41247
41865
  init(svg, selector, accessor) {
41248
- const { mark, channels, selection: selection2 } = this;
41866
+ const { mark, as, selection: selection2 } = this;
41249
41867
  const { data: { columns = {} } = {} } = mark;
41250
- accessor ??= (target) => channels.map((c4) => columns[c4.as][target.__data__]);
41868
+ accessor ??= (target) => as.map((name) => {
41869
+ const data = target.__data__;
41870
+ return columns[name][Array.isArray(data) ? data[0] : data];
41871
+ });
41251
41872
  selector ??= `[data-index="${mark.index}"]`;
41252
41873
  const groups2 = new Set(svg.querySelectorAll(selector));
41253
41874
  svg.addEventListener("pointerdown", (evt) => {
@@ -41272,7 +41893,7 @@ var Toggle = class {
41272
41893
  });
41273
41894
  svg.addEventListener("pointerenter", (evt) => {
41274
41895
  if (evt.buttons) return;
41275
- this.selection.activate(this.clause([this.channels.map(() => 0)]));
41896
+ this.selection.activate(this.clause([this.fields.map(() => 0)]));
41276
41897
  });
41277
41898
  }
41278
41899
  };
@@ -41299,7 +41920,7 @@ var Legend = class {
41299
41920
  constructor(channel, options) {
41300
41921
  const { as, field: field2, ...rest } = options;
41301
41922
  this.channel = channel;
41302
- this.options = { label: null, ...rest };
41923
+ this.options = rest;
41303
41924
  this.type = null;
41304
41925
  this.handler = null;
41305
41926
  this.selection = as;
@@ -41307,7 +41928,7 @@ var Legend = class {
41307
41928
  this.legend = null;
41308
41929
  this.element = document.createElement("div");
41309
41930
  this.element.setAttribute("class", "legend");
41310
- Object.assign(this.element, { value: this });
41931
+ Object.defineProperty(this.element, "value", { value: this });
41311
41932
  }
41312
41933
  setPlot(plot2) {
41313
41934
  this.plot = plot2;
@@ -41319,8 +41940,10 @@ var Legend = class {
41319
41940
  }
41320
41941
  update() {
41321
41942
  if (!this.legend) return;
41322
- const { value } = this.selection;
41323
- const curr = value && value.length ? new Set(value.map((v2) => v2[0])) : null;
41943
+ const { selection: selection2, handler } = this;
41944
+ const { single, value } = selection2;
41945
+ const vals = single ? value : selection2.valueFor(handler);
41946
+ const curr = vals && vals.length ? new Set(vals.map((v2) => v2[0])) : null;
41324
41947
  const nodes = this.legend.querySelectorAll(TOGGLE_SELECTOR);
41325
41948
  for (const node of nodes) {
41326
41949
  const selected = curr ? curr.has(node.__data__) : true;
@@ -41329,9 +41952,13 @@ var Legend = class {
41329
41952
  }
41330
41953
  };
41331
41954
  function createLegend(legend2, svg) {
41332
- const { channel, options, selection: selection2 } = legend2;
41955
+ const { channel, plot: plot2, selection: selection2 } = legend2;
41333
41956
  const scale3 = svg.scale(channel);
41334
41957
  const type2 = scale3.type === "ordinal" ? SWATCH : RAMP;
41958
+ const options = {
41959
+ label: plot2.getAttribute(`${channel}Label`) ?? null,
41960
+ ...legend2.options
41961
+ };
41335
41962
  const opt = type2 === SWATCH ? options : options.label ? { tickSize: 2, ...options } : { tickSize: 2, marginTop: 1, height: 29, ...options };
41336
41963
  const el = svg.legend(channel, opt);
41337
41964
  legend2.legend = el;
@@ -41363,11 +41990,19 @@ function getInteractor(legend2, type2) {
41363
41990
  if (handler) return handler;
41364
41991
  const mark = interactorMark(legend2);
41365
41992
  if (type2 === SWATCH) {
41366
- legend2.handler = new Toggle(mark, { selection: selection2, channels: [channel] });
41993
+ legend2.handler = new Toggle(mark, {
41994
+ selection: selection2,
41995
+ channels: [channel],
41996
+ peers: false
41997
+ });
41367
41998
  selection2.addEventListener("value", () => legend2.update());
41368
41999
  } else {
41369
- const brush3 = { fill: "none", stroke: "currentColor" };
41370
- legend2.handler = new Interval1D(mark, { selection: selection2, channel, brush: brush3 });
42000
+ legend2.handler = new Interval1D(mark, {
42001
+ selection: selection2,
42002
+ channel,
42003
+ brush: { fill: "none", stroke: "currentColor" },
42004
+ peers: false
42005
+ });
41371
42006
  }
41372
42007
  return legend2.handler;
41373
42008
  }
@@ -41413,11 +42048,104 @@ function spatialScale(sourceScale, width) {
41413
42048
  return scale2({ x: { ...rest, type: type2, range: [0, width] } });
41414
42049
  }
41415
42050
 
42051
+ // src/transforms/bin-step.js
42052
+ function binStep(span, steps, minstep = 0, logb = Math.LN10) {
42053
+ let v2;
42054
+ const level = Math.ceil(Math.log(steps) / logb);
42055
+ let step = Math.max(
42056
+ minstep,
42057
+ Math.pow(10, Math.round(Math.log(span) / logb) - level)
42058
+ );
42059
+ while (Math.ceil(span / step) > steps) {
42060
+ step *= 10;
42061
+ }
42062
+ const div = [5, 2];
42063
+ for (let i = 0, n = div.length; i < n; ++i) {
42064
+ v2 = step / div[i];
42065
+ if (v2 >= minstep && span / v2 <= steps) step = v2;
42066
+ }
42067
+ return step;
42068
+ }
42069
+ function bins(min5, max4, options) {
42070
+ let { step, steps, minstep = 0, nice: nice3 = true } = options;
42071
+ if (nice3 !== false) {
42072
+ const span = max4 - min5;
42073
+ const logb = Math.LN10;
42074
+ step = step || binStep(span, steps || 25, minstep, logb);
42075
+ let v2 = Math.log(step);
42076
+ const precision = v2 >= 0 ? 0 : ~~(-v2 / logb) + 1;
42077
+ const eps2 = Math.pow(10, -precision - 1);
42078
+ v2 = Math.floor(min5 / step + eps2) * step;
42079
+ min5 = min5 < v2 ? v2 - step : v2;
42080
+ max4 = Math.ceil(max4 / step) * step;
42081
+ steps = Math.round((max4 - min5) / step);
42082
+ }
42083
+ return { min: min5, max: max4, steps };
42084
+ }
42085
+
42086
+ // src/transforms/time-interval.js
42087
+ var YEAR = "year";
42088
+ var MONTH = "month";
42089
+ var DAY = "day";
42090
+ var HOUR = "hour";
42091
+ var MINUTE = "minute";
42092
+ var SECOND = "second";
42093
+ var MILLISECOND = "millisecond";
42094
+ var durationSecond3 = 1e3;
42095
+ var durationMinute3 = durationSecond3 * 60;
42096
+ var durationHour3 = durationMinute3 * 60;
42097
+ var durationDay3 = durationHour3 * 24;
42098
+ var durationWeek3 = durationDay3 * 7;
42099
+ var durationMonth3 = durationDay3 * 30;
42100
+ var durationYear3 = durationDay3 * 365;
42101
+ var intervals = [
42102
+ [SECOND, 1, durationSecond3],
42103
+ [SECOND, 5, 5 * durationSecond3],
42104
+ [SECOND, 15, 15 * durationSecond3],
42105
+ [SECOND, 30, 30 * durationSecond3],
42106
+ [MINUTE, 1, durationMinute3],
42107
+ [MINUTE, 5, 5 * durationMinute3],
42108
+ [MINUTE, 15, 15 * durationMinute3],
42109
+ [MINUTE, 30, 30 * durationMinute3],
42110
+ [HOUR, 1, durationHour3],
42111
+ [HOUR, 3, 3 * durationHour3],
42112
+ [HOUR, 6, 6 * durationHour3],
42113
+ [HOUR, 12, 12 * durationHour3],
42114
+ [DAY, 1, durationDay3],
42115
+ [DAY, 7, durationWeek3],
42116
+ [MONTH, 1, durationMonth3],
42117
+ [MONTH, 3, 3 * durationMonth3],
42118
+ [YEAR, 1, durationYear3]
42119
+ ];
42120
+ function timeInterval3(min5, max4, steps) {
42121
+ const span = max4 - min5;
42122
+ const target = span / steps;
42123
+ let i = bisector((i2) => i2[2]).right(intervals, target);
42124
+ if (i === intervals.length) {
42125
+ return { interval: YEAR, step: binStep(span, steps) };
42126
+ } else if (i) {
42127
+ i = intervals[target / intervals[i - 1][2] < intervals[i][2] / target ? i - 1 : i];
42128
+ return { interval: i[0], step: i[1] };
42129
+ } else {
42130
+ return { interval: MILLISECOND, step: binStep(span, steps, 1) };
42131
+ }
42132
+ }
42133
+
41416
42134
  // src/transforms/bin.js
41417
- var EXTENT = /* @__PURE__ */ new Set(["rectY-x", "rectX-y", "rect-x", "rect-y"]);
41418
- function bin2(field2, options = { steps: 25 }) {
42135
+ var EXTENT = /* @__PURE__ */ new Set([
42136
+ "rectY-x",
42137
+ "rectX-y",
42138
+ "rect-x",
42139
+ "rect-y",
42140
+ "ruleY-x",
42141
+ "ruleX-y"
42142
+ ]);
42143
+ function hasExtent(mark, channel) {
42144
+ return EXTENT.has(`${mark.type}-${channel}`);
42145
+ }
42146
+ function bin2(field2, options = {}) {
41419
42147
  const fn = (mark, channel) => {
41420
- if (EXTENT.has(`${mark.type}-${channel}`)) {
42148
+ if (hasExtent(mark, channel)) {
41421
42149
  return {
41422
42150
  [`${channel}1`]: binField(mark, channel, field2, options),
41423
42151
  [`${channel}2`]: binField(mark, channel, field2, { ...options, offset: 1 })
@@ -41435,57 +42163,39 @@ function binField(mark, channel, column3, options) {
41435
42163
  return {
41436
42164
  column: column3,
41437
42165
  label: column3,
41438
- get stats() {
41439
- return { column: column3, stats: ["min", "max"] };
41440
- },
41441
42166
  get columns() {
41442
42167
  return [column3];
41443
42168
  },
41444
42169
  get basis() {
41445
42170
  return column3;
41446
42171
  },
42172
+ get stats() {
42173
+ return { column: column3, stats: ["min", "max"] };
42174
+ },
41447
42175
  toString() {
41448
- const { apply: apply2, sqlApply, sqlInvert } = channelScale(mark, channel);
41449
- const { min: min5, max: max4 } = mark.channelField(channel);
41450
- const b = bins(apply2(min5), apply2(max4), options);
41451
- const col = sqlApply(column3);
41452
- const base = b.min === 0 ? col : `(${col} - ${b.min})`;
41453
- const alpha = `${(b.max - b.min) / b.steps}::DOUBLE`;
41454
- const off = options.offset ? `${options.offset} + ` : "";
41455
- const expr = `${b.min} + ${alpha} * (${off}FLOOR(${base} / ${alpha}))`;
41456
- return `${sqlInvert(expr)}`;
42176
+ const { type: type2, min: min5, max: max4 } = mark.channelField(channel);
42177
+ const { interval: i, steps, offset: offset2 = 0 } = options;
42178
+ const interval2 = i ?? (type2 === "date" || hasTimeScale(mark, channel) ? "date" : "number");
42179
+ if (interval2 === "number") {
42180
+ const { apply: apply2, sqlApply, sqlInvert } = channelScale(mark, channel);
42181
+ const b = bins(apply2(min5), apply2(max4), options);
42182
+ const col = sqlApply(column3);
42183
+ const base = b.min === 0 ? col : `(${col} - ${b.min})`;
42184
+ const alpha = `${(b.max - b.min) / b.steps}::DOUBLE`;
42185
+ const off = offset2 ? `${offset2} + ` : "";
42186
+ const expr = `${b.min} + ${alpha} * (${off}FLOOR(${base} / ${alpha}))`;
42187
+ return `${sqlInvert(expr)}`;
42188
+ } else {
42189
+ const { interval: unit3, step = 1 } = interval2 === "date" ? timeInterval3(min5, max4, steps || 40) : options;
42190
+ const off = offset2 ? ` + INTERVAL ${offset2 * step} ${unit3}` : "";
42191
+ return `(${dateBin(column3, unit3, step)}${off})`;
42192
+ }
41457
42193
  }
41458
42194
  };
41459
42195
  }
41460
- function bins(min5, max4, options) {
41461
- let { steps = 25, minstep = 0, nice: nice3 = true } = options;
41462
- if (nice3 !== false) {
41463
- const span = max4 - min5;
41464
- const maxb = steps;
41465
- const logb = Math.LN10;
41466
- const level = Math.ceil(Math.log(maxb) / logb);
41467
- let step = Math.max(
41468
- minstep,
41469
- Math.pow(10, Math.round(Math.log(span) / logb) - level)
41470
- );
41471
- while (Math.ceil(span / step) > maxb) {
41472
- step *= 10;
41473
- }
41474
- const div = [5, 2];
41475
- let v2;
41476
- for (let i = 0, n = div.length; i < n; ++i) {
41477
- v2 = step / div[i];
41478
- if (v2 >= minstep && span / v2 <= maxb) step = v2;
41479
- }
41480
- v2 = Math.log(step);
41481
- const precision = v2 >= 0 ? 0 : ~~(-v2 / logb) + 1;
41482
- const eps2 = Math.pow(10, -precision - 1);
41483
- v2 = Math.floor(min5 / step + eps2) * step;
41484
- min5 = min5 < v2 ? v2 - step : v2;
41485
- max4 = Math.ceil(max4 / step) * step;
41486
- steps = Math.round((max4 - min5) / step);
41487
- }
41488
- return { min: min5, max: max4, steps };
42196
+ function hasTimeScale(mark, channel) {
42197
+ const scale3 = mark.plot.getAttribute(`${channel}Scale`);
42198
+ return scale3 === "utc" || scale3 === "time";
41489
42199
  }
41490
42200
  export {
41491
42201
  ConnectedMark,
@@ -41493,6 +42203,7 @@ export {
41493
42203
  DenseLineMark,
41494
42204
  Density1DMark,
41495
42205
  Density2DMark,
42206
+ ErrorBarMark,
41496
42207
  Fixed,
41497
42208
  GeoMark,
41498
42209
  Grid2DMark,