@uwdata/mosaic-plot 0.12.1 → 0.13.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.
@@ -103,7 +103,7 @@ var require_search_bounds = __commonJS({
103
103
  }
104
104
  return -1;
105
105
  }
106
- function norm(a2, y3, c4, l, h, f) {
106
+ function norm2(a2, y3, c4, l, h, f) {
107
107
  if (typeof c4 === "function") {
108
108
  return f(a2, y3, c4, l === void 0 ? 0 : l | 0, h === void 0 ? a2.length - 1 : h | 0);
109
109
  }
@@ -111,19 +111,19 @@ var require_search_bounds = __commonJS({
111
111
  }
112
112
  module.exports = {
113
113
  ge: function(a2, y3, c4, l, h) {
114
- return norm(a2, y3, c4, l, h, ge);
114
+ return norm2(a2, y3, c4, l, h, ge);
115
115
  },
116
116
  gt: function(a2, y3, c4, l, h) {
117
- return norm(a2, y3, c4, l, h, gt2);
117
+ return norm2(a2, y3, c4, l, h, gt2);
118
118
  },
119
119
  lt: function(a2, y3, c4, l, h) {
120
- return norm(a2, y3, c4, l, h, lt2);
120
+ return norm2(a2, y3, c4, l, h, lt2);
121
121
  },
122
122
  le: function(a2, y3, c4, l, h) {
123
- return norm(a2, y3, c4, l, h, le);
123
+ return norm2(a2, y3, c4, l, h, le);
124
124
  },
125
125
  eq: function(a2, y3, c4, l, h) {
126
- return norm(a2, y3, c4, l, h, eq2);
126
+ return norm2(a2, y3, c4, l, h, eq2);
127
127
  }
128
128
  };
129
129
  }
@@ -489,168 +489,9 @@ var Fixed = Symbol("Fixed");
489
489
  var Transient = Symbol("Transient");
490
490
  var Transform = Symbol("Transform");
491
491
 
492
- // ../core/src/util/throttle.js
493
- var NIL = {};
494
- function throttle(callback, debounce = false) {
495
- let curr;
496
- let next;
497
- let pending = NIL;
498
- function invoke(event) {
499
- curr = callback(event).catch(() => {
500
- }).finally(() => {
501
- if (next) {
502
- const { value } = next;
503
- next = null;
504
- invoke(value);
505
- } else {
506
- curr = null;
507
- }
508
- });
509
- }
510
- function enqueue(event) {
511
- next = { event };
512
- }
513
- function process(event) {
514
- curr ? enqueue(event) : invoke(event);
515
- }
516
- function delay(event) {
517
- if (pending !== event) {
518
- requestAnimationFrame(() => {
519
- const e = pending;
520
- pending = NIL;
521
- process(e);
522
- });
523
- }
524
- pending = event;
525
- }
526
- return debounce ? delay : process;
527
- }
528
-
529
- // ../core/src/MosaicClient.js
530
- var MosaicClient = class {
531
- /**
532
- * Constructor.
533
- * @param {*} filterSelection An optional selection to interactively filter
534
- * this client's data. If provided, a coordinator will re-query and update
535
- * the client when the selection updates.
536
- */
537
- constructor(filterSelection) {
538
- this._filterBy = filterSelection;
539
- this._requestUpdate = throttle(() => this.requestQuery(), true);
540
- this._coordinator = null;
541
- }
542
- /**
543
- * Return this client's connected coordinator.
544
- */
545
- get coordinator() {
546
- return this._coordinator;
547
- }
548
- /**
549
- * Set this client's connected coordinator.
550
- */
551
- set coordinator(coordinator2) {
552
- this._coordinator = coordinator2;
553
- }
554
- /**
555
- * Return this client's filter selection.
556
- */
557
- get filterBy() {
558
- return this._filterBy;
559
- }
560
- /**
561
- * Return a boolean indicating if the client query can be sped up with
562
- * materialized views of pre-aggregated data. Should return true if changes to
563
- * the filterBy selection does not change the groupby domain of the client
564
- * query.
565
- */
566
- get filterStable() {
567
- return true;
568
- }
569
- /**
570
- * Return an array of fields queried by this client.
571
- * @returns {object[]|null} The fields to retrieve info for.
572
- */
573
- fields() {
574
- return null;
575
- }
576
- /**
577
- * Called by the coordinator to set the field info for this client.
578
- * @param {*} info The field info result.
579
- * @returns {this}
580
- */
581
- fieldInfo(info) {
582
- return this;
583
- }
584
- /**
585
- * Return a query specifying the data needed by this client.
586
- * @param {*} [filter] The filtering criteria to apply in the query.
587
- * @returns {*} The client query
588
- */
589
- query(filter3) {
590
- return null;
591
- }
592
- /**
593
- * Called by the coordinator to inform the client that a query is pending.
594
- * @returns {this}
595
- */
596
- queryPending() {
597
- return this;
598
- }
599
- /**
600
- * Called by the coordinator to return a query result.
601
- * @param {*} data The query result.
602
- * @returns {this}
603
- */
604
- queryResult(data) {
605
- return this;
606
- }
607
- /**
608
- * Called by the coordinator to report a query execution error.
609
- * @param {*} error
610
- * @returns {this}
611
- */
612
- queryError(error) {
613
- return this;
614
- }
615
- /**
616
- * Request the coordinator to execute a query for this client.
617
- * If an explicit query is not provided, the client query method will
618
- * be called, filtered by the current filterBy selection.
619
- * @returns {Promise}
620
- */
621
- requestQuery(query) {
622
- const q = query || this.query(this.filterBy?.predicate(this));
623
- return this._coordinator.requestQuery(this, q);
624
- }
625
- /**
626
- * Request that the coordinator perform a throttled update of this client
627
- * using the default query. Unlike requestQuery, for which every call will
628
- * result in an executed query, multiple calls to requestUpdate may be
629
- * consolidated into a single update.
630
- */
631
- requestUpdate() {
632
- this._requestUpdate();
633
- }
634
- /**
635
- * Reset this client, initiating new field info and query requests.
636
- * @returns {Promise}
637
- */
638
- initialize() {
639
- return this._coordinator.initializeClient(this);
640
- }
641
- /**
642
- * Requests a client update.
643
- * For example to (re-)render an interface component.
644
- *
645
- * @returns {this | Promise<any>}
646
- */
647
- update() {
648
- return this;
649
- }
650
- };
651
-
652
492
  // ../../node_modules/@uwdata/flechette/src/constants.js
653
493
  var MAGIC = Uint8Array.of(65, 82, 82, 79, 87, 49);
494
+ var EOS = Uint8Array.of(255, 255, 255, 255, 0, 0, 0, 0);
654
495
  var Version = (
655
496
  /** @type {const} */
656
497
  {
@@ -3065,7 +2906,7 @@ function literalToSQL(value) {
3065
2906
  case "number":
3066
2907
  return Number.isFinite(value) ? `${value}` : "NULL";
3067
2908
  case "string":
3068
- return `'${value.replace(`'`, `''`)}'`;
2909
+ return `'${value.replaceAll(`'`, `''`)}'`;
3069
2910
  case "boolean":
3070
2911
  return value ? "TRUE" : "FALSE";
3071
2912
  default:
@@ -3456,6 +3297,9 @@ var ColumnNameRefNode = class extends ColumnRefNode {
3456
3297
  };
3457
3298
 
3458
3299
  // ../sql/src/ast/column-param.js
3300
+ function isColumnParam(value) {
3301
+ return value instanceof ColumnParamNode;
3302
+ }
3459
3303
  var ColumnParamNode = class extends ColumnRefNode {
3460
3304
  /**
3461
3305
  * Instantiate a column param node.
@@ -4877,7 +4721,7 @@ function collectAggregates(root2) {
4877
4721
  function collectColumns(root2) {
4878
4722
  const cols = {};
4879
4723
  walk(root2, (node) => {
4880
- if (node.type === COLUMN_REF) {
4724
+ if (node.type === COLUMN_REF || node.type === COLUMN_PARAM) {
4881
4725
  cols[node] = node;
4882
4726
  }
4883
4727
  });
@@ -4921,21 +4765,21 @@ function bin2d(q, xp, yp, aggs, xn, groupby) {
4921
4765
  }
4922
4766
 
4923
4767
  // ../sql/src/transforms/bin-linear-1d.js
4924
- function binLinear1d(query, x3, weight) {
4768
+ function binLinear1d(query, x3, weight = void 0, groupby = []) {
4925
4769
  const w = weight ? (x4) => mul(x4, weight) : (x4) => x4;
4926
4770
  const p0 = floor(x3);
4927
4771
  const p1 = add(p0, 1);
4928
4772
  return Query.from(Query.unionAll(
4929
4773
  query.clone().select({ i: int322(p0), w: w(sub(p1, x3)) }),
4930
4774
  query.clone().select({ i: int322(p1), w: w(sub(x3, p0)) })
4931
- )).select({ index: "i", density: sum("w") }).groupby("index").having(neq("density", 0));
4775
+ )).select({ index: "i", density: sum("w") }, groupby).groupby("index", groupby).having(neq("density", 0));
4932
4776
  }
4933
4777
 
4934
4778
  // ../sql/src/transforms/bin-linear-2d.js
4935
4779
  function identity(x3) {
4936
4780
  return x3;
4937
4781
  }
4938
- function binLinear2d(q, xp, yp, weight, xn, groupby) {
4782
+ function binLinear2d(q, xp, yp, weight, xn, groupby = []) {
4939
4783
  const w = weight ? (x3) => mul(x3, weight) : identity;
4940
4784
  const subq = (i, w2) => q.clone().select({ xp, yp, i, w: w2 });
4941
4785
  const index2 = (x3, y3) => add(x3, mul(y3, xn));
@@ -5136,6 +4980,8 @@ function sufficientStatistics(node, preagg, avg2) {
5136
4980
  return sumExpr(preagg, node);
5137
4981
  case "avg":
5138
4982
  return avgExpr(preagg, node);
4983
+ case "geomean":
4984
+ return geomeanExpr(preagg, node);
5139
4985
  case "arg_max":
5140
4986
  return argmaxExpr(preagg, node);
5141
4987
  case "arg_min":
@@ -5219,6 +5065,12 @@ function avgExpr(preagg, node) {
5219
5065
  const { expr, name } = countExpr(preagg, node);
5220
5066
  return div(sum(mul(as, name)), expr);
5221
5067
  }
5068
+ function geomeanExpr(preagg, node) {
5069
+ const x3 = node.args[0];
5070
+ const expr = addStat(preagg, sum(ln(x3)), node);
5071
+ const { expr: n } = countExpr(preagg, node);
5072
+ return exp(div(sum(expr), n));
5073
+ }
5222
5074
  function argmaxExpr(preagg, node) {
5223
5075
  const expr = addStat(preagg, node);
5224
5076
  const maxy = addStat(preagg, max(node.args[1]), node);
@@ -5665,7 +5517,7 @@ var statMap = {
5665
5517
  [Min]: min,
5666
5518
  [Nulls]: (column3) => count().where(isNull(column3))
5667
5519
  };
5668
- function summarize(table, column3, stats) {
5520
+ function summarize({ table, column: column3, stats }) {
5669
5521
  return Query.from(table).select(Array.from(stats, (s2) => ({ [s2]: statMap[s2](column3) })));
5670
5522
  }
5671
5523
  async function queryFieldInfo(mc, fields) {
@@ -5676,7 +5528,7 @@ async function queryFieldInfo(mc, fields) {
5676
5528
  }
5677
5529
  }
5678
5530
  async function getFieldInfo(mc, { table, column: column3, stats }) {
5679
- const q = Query.from({ source: table }).select({ column: column3 }).groupby(column3.aggregate ? sql`ALL` : []);
5531
+ const q = Query.from({ source: table }).select({ column: column3 }).groupby(isNode(column3) && isAggregateExpression(column3) ? sql`ALL` : []);
5680
5532
  const [desc2] = Array.from(await mc.query(Query.describe(q)));
5681
5533
  const info = {
5682
5534
  table,
@@ -5685,16 +5537,16 @@ async function getFieldInfo(mc, { table, column: column3, stats }) {
5685
5537
  type: jsType(desc2.column_type),
5686
5538
  nullable: desc2.null === "YES"
5687
5539
  };
5688
- if (!(stats?.length || stats?.size)) return info;
5540
+ if (!stats?.length) return info;
5689
5541
  const [result] = await mc.query(
5690
- summarize(table, column3, stats),
5542
+ summarize({ table, column: column3, stats }),
5691
5543
  { persist: true }
5692
5544
  );
5693
5545
  return Object.assign(info, result);
5694
5546
  }
5695
5547
  async function getTableInfo(mc, table) {
5696
- const result = await mc.query(`DESCRIBE ${asTableRef(table)}`);
5697
- return Array.from(result).map((desc2) => ({
5548
+ const result = Array.from(await mc.query(`DESCRIBE ${asTableRef(table)}`));
5549
+ return result.map((desc2) => ({
5698
5550
  table,
5699
5551
  column: desc2.column_name,
5700
5552
  sqlType: desc2.column_type,
@@ -6291,13 +6143,13 @@ var Coordinator = class {
6291
6143
  }
6292
6144
  /**
6293
6145
  * Issue a query for which no result (return value) is needed.
6294
- * @param {QueryType | QueryType[]} query The query or an array of queries.
6146
+ * @param { import('./types.js').QueryType[] |
6147
+ * import('./types.js').QueryType} query The query or an array of queries.
6295
6148
  * Each query should be either a Query builder object or a SQL string.
6296
6149
  * @param {object} [options] An options object.
6297
6150
  * @param {number} [options.priority] The query priority, defaults to
6298
6151
  * `Priority.Normal`.
6299
- * @returns {QueryResult} A query result
6300
- * promise.
6152
+ * @returns {QueryResult} A query result promise.
6301
6153
  */
6302
6154
  exec(query, { priority = Priority.Normal } = {}) {
6303
6155
  query = Array.isArray(query) ? query.filter((x3) => x3).join(";\n") : query;
@@ -6306,11 +6158,14 @@ var Coordinator = class {
6306
6158
  /**
6307
6159
  * Issue a query to the backing database. The submitted query may be
6308
6160
  * consolidate with other queries and its results may be cached.
6309
- * @param {QueryType} query The query as either a Query builder object
6310
- * or a SQL string.
6161
+ * @param {import('./types.js').QueryType} query The query as either a Query
6162
+ * builder object or a SQL string.
6311
6163
  * @param {object} [options] An options object.
6312
6164
  * @param {'arrow' | 'json'} [options.type] The query result format type.
6313
- * @param {boolean} [options.cache=true] If true, cache the query result.
6165
+ * @param {boolean} [options.cache=true] If true, cache the query result
6166
+ * client-side within the QueryManager.
6167
+ * @param {boolean} [options.persist] If true, request the database
6168
+ * server to persist a cached query server-side.
6314
6169
  * @param {number} [options.priority] The query priority, defaults to
6315
6170
  * `Priority.Normal`.
6316
6171
  * @returns {QueryResult} A query result promise.
@@ -6326,8 +6181,8 @@ var Coordinator = class {
6326
6181
  /**
6327
6182
  * Issue a query to prefetch data for later use. The query result is cached
6328
6183
  * for efficient future access.
6329
- * @param {QueryType} query The query as either a Query builder object
6330
- * or a SQL string.
6184
+ * @param {import('./types.js').QueryType} query The query as either a Query
6185
+ * builder object or a SQL string.
6331
6186
  * @param {object} [options] An options object.
6332
6187
  * @param {'arrow' | 'json'} [options.type] The query result format type.
6333
6188
  * @returns {QueryResult} A query result promise.
@@ -6362,13 +6217,13 @@ var Coordinator = class {
6362
6217
  * Update client data by submitting the given query and returning the
6363
6218
  * data (or error) to the client.
6364
6219
  * @param {MosaicClient} client A Mosaic client.
6365
- * @param {QueryType} query The data query.
6220
+ * @param {import('./types.js').QueryType} query The data query.
6366
6221
  * @param {number} [priority] The query priority.
6367
6222
  * @returns {Promise} A Promise that resolves upon completion of the update.
6368
6223
  */
6369
6224
  updateClient(client, query, priority = Priority.Normal) {
6370
6225
  client.queryPending();
6371
- return this.query(query, { priority }).then(
6226
+ return client._pending = this.query(query, { priority }).then(
6372
6227
  (data) => client.queryResult(data).update(),
6373
6228
  (err) => {
6374
6229
  this._logger.error(err);
@@ -6381,7 +6236,7 @@ var Coordinator = class {
6381
6236
  * the client is simply updated. Otherwise `updateClient` is called. As a
6382
6237
  * side effect, this method clears the current preaggregator state.
6383
6238
  * @param {MosaicClient} client The client to update.
6384
- * @param {QueryType | null} [query] The query to issue.
6239
+ * @param {import('./types.js').QueryType | null} [query] The query to issue.
6385
6240
  */
6386
6241
  requestQuery(client, query) {
6387
6242
  this.preaggregator.clear();
@@ -6398,7 +6253,7 @@ var Coordinator = class {
6398
6253
  }
6399
6254
  clients.add(client);
6400
6255
  client.coordinator = this;
6401
- this.initializeClient(client);
6256
+ client._pending = this.initializeClient(client);
6402
6257
  connectSelection(this, client.filterBy, client);
6403
6258
  }
6404
6259
  async initializeClient(client) {
@@ -6406,6 +6261,7 @@ var Coordinator = class {
6406
6261
  if (fields?.length) {
6407
6262
  client.fieldInfo(await queryFieldInfo(this, fields));
6408
6263
  }
6264
+ await client.prepare();
6409
6265
  return client.requestQuery();
6410
6266
  }
6411
6267
  /**
@@ -7025,6 +6881,179 @@ var SelectionResolver = class {
7025
6881
  }
7026
6882
  };
7027
6883
 
6884
+ // ../core/src/util/throttle.js
6885
+ var NIL = {};
6886
+ function throttle(callback, debounce = false) {
6887
+ let curr;
6888
+ let next;
6889
+ let pending = NIL;
6890
+ function invoke(event) {
6891
+ curr = callback(event).catch(() => {
6892
+ }).finally(() => {
6893
+ if (next) {
6894
+ const { value } = next;
6895
+ next = null;
6896
+ invoke(value);
6897
+ } else {
6898
+ curr = null;
6899
+ }
6900
+ });
6901
+ }
6902
+ function enqueue(event) {
6903
+ next = { event };
6904
+ }
6905
+ function process(event) {
6906
+ curr ? enqueue(event) : invoke(event);
6907
+ }
6908
+ function delay(event) {
6909
+ if (pending !== event) {
6910
+ requestAnimationFrame(() => {
6911
+ const e = pending;
6912
+ pending = NIL;
6913
+ process(e);
6914
+ });
6915
+ }
6916
+ pending = event;
6917
+ }
6918
+ return debounce ? delay : process;
6919
+ }
6920
+
6921
+ // ../core/src/MosaicClient.js
6922
+ var MosaicClient = class {
6923
+ /**
6924
+ * Constructor.
6925
+ * @param {*} filterSelection An optional selection to interactively filter
6926
+ * this client's data. If provided, a coordinator will re-query and update
6927
+ * the client when the selection updates.
6928
+ */
6929
+ constructor(filterSelection) {
6930
+ this._filterBy = filterSelection;
6931
+ this._requestUpdate = throttle(() => this.requestQuery(), true);
6932
+ this._coordinator = null;
6933
+ this._pending = Promise.resolve();
6934
+ }
6935
+ /**
6936
+ * Return this client's connected coordinator.
6937
+ */
6938
+ get coordinator() {
6939
+ return this._coordinator;
6940
+ }
6941
+ /**
6942
+ * Set this client's connected coordinator.
6943
+ */
6944
+ set coordinator(coordinator2) {
6945
+ this._coordinator = coordinator2;
6946
+ }
6947
+ /**
6948
+ * Return a Promise that resolves once the client has updated.
6949
+ */
6950
+ get pending() {
6951
+ return this._pending;
6952
+ }
6953
+ /**
6954
+ * Return this client's filter selection.
6955
+ */
6956
+ get filterBy() {
6957
+ return this._filterBy;
6958
+ }
6959
+ /**
6960
+ * Return a boolean indicating if the client query can be sped up with
6961
+ * materialized views of pre-aggregated data. Should return true if changes to
6962
+ * the filterBy selection does not change the groupby domain of the client
6963
+ * query.
6964
+ */
6965
+ get filterStable() {
6966
+ return true;
6967
+ }
6968
+ /**
6969
+ * Return an array of fields queried by this client.
6970
+ * @returns {import('./types.js').FieldInfoRequest[] | null}
6971
+ * The fields to retrieve info for.
6972
+ */
6973
+ fields() {
6974
+ return null;
6975
+ }
6976
+ /**
6977
+ * Called by the coordinator to set the field info for this client.
6978
+ * @param {import('./types.js').FieldInfo[]} info The field info result.
6979
+ * @returns {this}
6980
+ */
6981
+ fieldInfo(info) {
6982
+ return this;
6983
+ }
6984
+ /**
6985
+ * Prepare the client before the query() method is called.
6986
+ */
6987
+ async prepare() {
6988
+ }
6989
+ /**
6990
+ * Return a query specifying the data needed by this client.
6991
+ * @param {*} [filter] The filtering criteria to apply in the query.
6992
+ * @returns {*} The client query
6993
+ */
6994
+ query(filter3) {
6995
+ return null;
6996
+ }
6997
+ /**
6998
+ * Called by the coordinator to inform the client that a query is pending.
6999
+ * @returns {this}
7000
+ */
7001
+ queryPending() {
7002
+ return this;
7003
+ }
7004
+ /**
7005
+ * Called by the coordinator to return a query result.
7006
+ * @param {*} data The query result.
7007
+ * @returns {this}
7008
+ */
7009
+ queryResult(data) {
7010
+ return this;
7011
+ }
7012
+ /**
7013
+ * Called by the coordinator to report a query execution error.
7014
+ * @param {*} error
7015
+ * @returns {this}
7016
+ */
7017
+ queryError(error) {
7018
+ return this;
7019
+ }
7020
+ /**
7021
+ * Request the coordinator to execute a query for this client.
7022
+ * If an explicit query is not provided, the client query method will
7023
+ * be called, filtered by the current filterBy selection.
7024
+ * @returns {Promise}
7025
+ */
7026
+ requestQuery(query) {
7027
+ const q = query || this.query(this.filterBy?.predicate(this));
7028
+ return this._coordinator.requestQuery(this, q);
7029
+ }
7030
+ /**
7031
+ * Request that the coordinator perform a throttled update of this client
7032
+ * using the default query. Unlike requestQuery, for which every call will
7033
+ * result in an executed query, multiple calls to requestUpdate may be
7034
+ * consolidated into a single update.
7035
+ */
7036
+ requestUpdate() {
7037
+ this._requestUpdate();
7038
+ }
7039
+ /**
7040
+ * Reset this client, initiating new field info, call the prepare method, and query requests.
7041
+ * @returns {Promise}
7042
+ */
7043
+ initialize() {
7044
+ return this._coordinator.initializeClient(this);
7045
+ }
7046
+ /**
7047
+ * Requests a client update.
7048
+ * For example to (re-)render an interface component.
7049
+ *
7050
+ * @returns {this | Promise<any>}
7051
+ */
7052
+ update() {
7053
+ return this;
7054
+ }
7055
+ };
7056
+
7028
7057
  // ../core/src/SelectionClause.js
7029
7058
  function clausePoint(field3, value, {
7030
7059
  source,
@@ -30992,6 +31021,9 @@ var DEFAULT_ATTRIBUTES = {
30992
31021
  marginBottom: 30
30993
31022
  };
30994
31023
  var Plot = class {
31024
+ /**
31025
+ * @param {HTMLElement} [element]
31026
+ */
30995
31027
  constructor(element) {
30996
31028
  this.attributes = { ...DEFAULT_ATTRIBUTES };
30997
31029
  this.listeners = null;
@@ -30999,12 +31031,12 @@ var Plot = class {
30999
31031
  this.legends = [];
31000
31032
  this.marks = [];
31001
31033
  this.markset = null;
31034
+ this.params = /* @__PURE__ */ new Map();
31035
+ this.synch = synchronizer();
31002
31036
  this.element = element || document.createElement("div");
31003
31037
  this.element.setAttribute("class", "plot");
31004
31038
  this.element.style.display = "flex";
31005
- this.element.value = this;
31006
- this.params = /* @__PURE__ */ new Map();
31007
- this.synch = synchronizer();
31039
+ Object.assign(this.element, { value: this });
31008
31040
  }
31009
31041
  margins() {
31010
31042
  return {
@@ -31148,7 +31180,9 @@ function isColor2(value) {
31148
31180
 
31149
31181
  // src/marks/util/is-constant-option.js
31150
31182
  var constantOptions = /* @__PURE__ */ new Set([
31183
+ "offset",
31151
31184
  "order",
31185
+ "reverse",
31152
31186
  "sort",
31153
31187
  "label",
31154
31188
  "anchor",
@@ -31220,7 +31254,7 @@ var isFieldObject = (channel, field3) => {
31220
31254
  var fieldEntry = (channel, field3) => ({
31221
31255
  channel,
31222
31256
  field: field3,
31223
- as: isColumnRef(field3) ? field3.column : channel
31257
+ as: isColumnRef(field3) && !isColumnParam(field3) ? field3.column : channel
31224
31258
  });
31225
31259
  var valueEntry = (channel, value) => ({ channel, value });
31226
31260
  var isDataArray = (source) => Array.isArray(source);
@@ -31316,7 +31350,11 @@ var Mark2 = class extends MosaicClient {
31316
31350
  reqs[channel]?.forEach((s2) => entry.add(s2));
31317
31351
  }
31318
31352
  const table = this.sourceTable();
31319
- return Array.from(fields, ([c4, s2]) => ({ table, column: c4, stats: s2 }));
31353
+ return Array.from(fields, ([c4, s2]) => ({
31354
+ table,
31355
+ column: c4,
31356
+ stats: Array.from(s2)
31357
+ }));
31320
31358
  }
31321
31359
  fieldInfo(info) {
31322
31360
  const lookup = Object.fromEntries(info.map((x3) => [x3.column, x3]));
@@ -31373,7 +31411,7 @@ function markQuery(channels, table, skip = []) {
31373
31411
  const { channel, field: field3, as } = c4;
31374
31412
  if (skip.includes(channel)) continue;
31375
31413
  if (channel === "orderby") {
31376
- q.orderby(c4.value);
31414
+ q.orderby(c4.value ?? field3);
31377
31415
  } else if (field3) {
31378
31416
  if (isAggregateExpression(field3)) {
31379
31417
  aggr = true;
@@ -31505,7 +31543,7 @@ var ConnectedMark = class extends Mark2 {
31505
31543
  const cols = q._select.map((c4) => c4.alias).filter((c4) => c4 !== as && c4 !== value);
31506
31544
  return m4(q, expr, as, value, cols);
31507
31545
  } else {
31508
- return q.orderby(field3);
31546
+ return q.orderby(as);
31509
31547
  }
31510
31548
  }
31511
31549
  };
@@ -31514,13 +31552,33 @@ var ConnectedMark = class extends Mark2 {
31514
31552
  function array3(size, proto = []) {
31515
31553
  return new proto.constructor(size);
31516
31554
  }
31517
- function grid1d(size, index2, value) {
31518
- const G = array3(size, value);
31519
- const n = value.length;
31520
- for (let i = 0; i < n; ++i) {
31521
- G[index2[i]] = value[i];
31555
+ function grid1d(size, index2, value, columns, groupby) {
31556
+ const numRows = index2.length;
31557
+ const result = {};
31558
+ const cells = [];
31559
+ if (groupby?.length) {
31560
+ const group3 = new Int32Array(numRows);
31561
+ const gvalues = groupby.map((name) => columns[name]);
31562
+ const cellMap = {};
31563
+ for (let row = 0; row < numRows; ++row) {
31564
+ const key = gvalues.map((group4) => group4[row]);
31565
+ group3[row] = cellMap[key] ??= cells.push(key) - 1;
31566
+ }
31567
+ for (let i = 0; i < groupby.length; ++i) {
31568
+ result[groupby[i]] = cells.map((cell2) => cell2[i]);
31569
+ }
31570
+ const G = result._grid = cells.map(() => array3(size, value));
31571
+ for (let row = 0; row < numRows; ++row) {
31572
+ G[group3[row]][index2[row]] = value[row];
31573
+ }
31574
+ } else {
31575
+ cells.push([]);
31576
+ const [G] = result._grid = [array3(size, value)];
31577
+ for (let row = 0; row < numRows; ++row) {
31578
+ G[index2[row]] = value[row];
31579
+ }
31522
31580
  }
31523
- return G;
31581
+ return { numRows: cells.length, columns: result };
31524
31582
  }
31525
31583
  function grid2d(w, h, index2, columns, aggregates, groupby, interpolate) {
31526
31584
  const numRows = index2.length;
@@ -32378,9 +32436,16 @@ function stripXY(mark, filter3) {
32378
32436
  }
32379
32437
 
32380
32438
  // src/marks/Density1DMark.js
32439
+ var GROUPBY = { fill: 1, stroke: 1, z: 1 };
32381
32440
  var Density1DMark = class extends Mark2 {
32382
32441
  constructor(type2, source, options) {
32383
- const { bins: bins2 = 1024, bandwidth = 20, ...channels } = options;
32442
+ const {
32443
+ bins: bins2 = 1024,
32444
+ bandwidth = 20,
32445
+ normalize: normalize4 = false,
32446
+ stack: stack2 = false,
32447
+ ...channels
32448
+ } = options;
32384
32449
  const dim = type2.endsWith("X") ? "y" : "x";
32385
32450
  super(type2, source, channels, dim === "x" ? xext : yext);
32386
32451
  this.dim = dim;
@@ -32389,7 +32454,13 @@ var Density1DMark = class extends Mark2 {
32389
32454
  });
32390
32455
  this.bandwidth = handleParam(bandwidth, (value) => {
32391
32456
  this.bandwidth = value;
32392
- return this.grid ? this.convolve().update() : null;
32457
+ return this.grids ? this.convolve().update() : null;
32458
+ });
32459
+ this.normalize = handleParam(normalize4, (value) => {
32460
+ return this.normalize = value, this.convolve().update();
32461
+ });
32462
+ this.stack = handleParam(stack2, (value) => {
32463
+ return this.stack = value, this.update();
32393
32464
  });
32394
32465
  }
32395
32466
  get filterStable() {
@@ -32404,42 +32475,67 @@ var Density1DMark = class extends Mark2 {
32404
32475
  const [x3, bx] = binExpr(this, dim, bins2, extent4);
32405
32476
  const q = markQuery(channels, this.sourceTable(), [dim]).where(filter3.concat(isBetween(bx, extent4)));
32406
32477
  const v2 = this.channelField("weight") ? "weight" : null;
32407
- return binLinear1d(q, x3, v2);
32478
+ const g = this.groupby = channels.flatMap((c4) => {
32479
+ return GROUPBY[c4.channel] && c4.field ? c4.as : [];
32480
+ });
32481
+ return binLinear1d(q, x3, v2, g);
32408
32482
  }
32409
32483
  queryResult(data) {
32410
- const { columns: { index: index2, density: density2 } } = toDataColumns(data);
32411
- this.grid = grid1d(this.bins, index2, density2);
32484
+ const c4 = toDataColumns(data).columns;
32485
+ this.grids = grid1d(this.bins, c4.index, c4.density, c4, this.groupby);
32412
32486
  return this.convolve();
32413
32487
  }
32414
32488
  convolve() {
32415
- const { bins: bins2, bandwidth, dim, grid, plot: plot2, extent: [lo, hi] } = this;
32416
- const neg = grid.some((v3) => v3 < 0);
32489
+ const {
32490
+ bins: bins2,
32491
+ bandwidth,
32492
+ normalize: normalize4,
32493
+ dim,
32494
+ grids,
32495
+ groupby,
32496
+ plot: plot2,
32497
+ extent: [lo, hi]
32498
+ } = this;
32499
+ const cols = grids.columns;
32500
+ const numGrids = grids.numRows;
32501
+ const b = this.channelField(dim).as;
32502
+ const v2 = dim === "x" ? "y" : "x";
32417
32503
  const size = dim === "x" ? plot2.innerWidth() : plot2.innerHeight();
32504
+ const neg = cols._grid.some((grid) => grid.some((v3) => v3 < 0));
32418
32505
  const config = dericheConfig(bandwidth * (bins2 - 1) / size, neg);
32419
- const result = dericheConv1d(config, grid, bins2);
32420
- const v2 = dim === "x" ? "y" : "x";
32421
- const b = this.channelField(dim).as;
32422
32506
  const b0 = +lo;
32423
32507
  const delta = (hi - b0) / (bins2 - 1);
32424
- const scale3 = 1 / delta;
32425
- const _b = new Float64Array(bins2);
32426
- const _v = new Float64Array(bins2);
32427
- for (let i = 0; i < bins2; ++i) {
32428
- _b[i] = b0 + i * delta;
32429
- _v[i] = result[i] * scale3;
32430
- }
32431
- this.data = { numRows: bins2, columns: { [b]: _b, [v2]: _v } };
32508
+ const numRows = bins2 * numGrids;
32509
+ const _b = new Float64Array(numRows);
32510
+ const _v = new Float64Array(numRows);
32511
+ const _g = groupby.reduce((m, name) => (m[name] = Array(numRows), m), {});
32512
+ for (let k2 = 0, g = 0; g < numGrids; ++g) {
32513
+ groupby.forEach((name) => _g[name].fill(cols[name][g], k2, k2 + bins2));
32514
+ const grid = cols._grid[g];
32515
+ const result = dericheConv1d(config, grid, bins2);
32516
+ const scale3 = 1 / norm(grid, result, delta, normalize4);
32517
+ for (let i = 0; i < bins2; ++i, ++k2) {
32518
+ _b[k2] = b0 + i * delta;
32519
+ _v[k2] = result[i] * scale3;
32520
+ }
32521
+ }
32522
+ this.data = { numRows, columns: { [b]: _b, [v2]: _v, ..._g } };
32432
32523
  return this;
32433
32524
  }
32434
32525
  plotSpecs() {
32435
- const { type: type2, data: { numRows: length4, columns }, channels, dim } = this;
32436
- const options = dim === "x" ? { y: columns.y } : { x: columns.x };
32526
+ const { type: type2, data: { numRows: length4, columns }, channels, dim, stack: stack2 } = this;
32527
+ const _ = type2.startsWith("area") && !stack2 ? "2" : "";
32528
+ const options = dim === "x" ? { [`y${_}`]: columns.y } : { [`x${_}`]: columns.x };
32437
32529
  for (const c4 of channels) {
32438
32530
  options[c4.channel] = channelOption(c4, columns);
32439
32531
  }
32440
32532
  return [{ type: type2, data: { length: length4 }, options }];
32441
32533
  }
32442
32534
  };
32535
+ function norm(grid, smoothed, delta, type2) {
32536
+ const value = type2 === true || type2 === "sum" ? sum2(grid) : type2 === "max" ? max2(smoothed) : delta;
32537
+ return value || 1;
32538
+ }
32443
32539
 
32444
32540
  // src/marks/Density2DMark.js
32445
32541
  var Density2DMark = class extends Grid2DMark {
@@ -33607,12 +33703,13 @@ var Nearest = class {
33607
33703
  selection2.update(that.clause(void 0));
33608
33704
  });
33609
33705
  svg.addEventListener("pointerenter", (evt) => {
33610
- if (!evt.buttons) {
33611
- const v2 = this.channels.map(() => 0);
33612
- selection2.activate(this.clause(v2));
33613
- }
33706
+ if (!evt.buttons) this.activate();
33614
33707
  });
33615
33708
  }
33709
+ activate() {
33710
+ const v2 = this.channels.map(() => 0);
33711
+ this.selection.activate(this.clause(v2));
33712
+ }
33616
33713
  };
33617
33714
  function calculateXY(svg, mark) {
33618
33715
  const { data: { columns } } = mark;
@@ -33708,7 +33805,7 @@ var PanZoom = class {
33708
33805
  this.svg = svg;
33709
33806
  if (this.initialized) return;
33710
33807
  else this.initialized = true;
33711
- const { panx, pany, mark: { plot: { element } }, xsel, ysel } = this;
33808
+ const { panx, pany, mark: { plot: { element } } } = this;
33712
33809
  this.xscale = svg.scale("x");
33713
33810
  this.yscale = svg.scale("y");
33714
33811
  const rx = this.xscale.range.slice().sort(asc2);
@@ -33725,19 +33822,21 @@ var PanZoom = class {
33725
33822
  element.addEventListener("pointerenter", (evt) => {
33726
33823
  if (enter) return;
33727
33824
  else enter = true;
33728
- if (evt.buttons) return;
33729
- if (panx) {
33730
- const { xscale, xfield } = this;
33731
- xsel.activate(this.clause(xscale.domain, xfield, xscale));
33732
- }
33733
- if (pany) {
33734
- const { yscale, yfield } = this;
33735
- ysel.activate(this.clause(yscale.domain, yfield, yscale));
33736
- }
33825
+ if (!evt.buttons) this.activate();
33737
33826
  });
33738
33827
  element.addEventListener("pointerleave", () => enter = false);
33739
33828
  }
33740
33829
  }
33830
+ activate() {
33831
+ if (this.panx) {
33832
+ const { xscale, xfield } = this;
33833
+ this.xsel.activate(this.clause(xscale.domain, xfield, xscale));
33834
+ }
33835
+ if (this.pany) {
33836
+ const { yscale, yfield } = this;
33837
+ this.ysel.activate(this.clause(yscale.domain, yfield, yscale));
33838
+ }
33839
+ }
33741
33840
  };
33742
33841
  function extent3(ext, defaultTrue, defaultFalse) {
33743
33842
  return ext ? Array.isArray(ext) ? ext : defaultTrue : defaultFalse;
@@ -34122,8 +34221,8 @@ var Toggle = class {
34122
34221
  channels,
34123
34222
  peers = true
34124
34223
  }) {
34125
- this.value = null;
34126
34224
  this.mark = mark;
34225
+ this.value = null;
34127
34226
  this.selection = selection2;
34128
34227
  this.peers = peers;
34129
34228
  const fields = this.fields = [];
@@ -34175,10 +34274,12 @@ var Toggle = class {
34175
34274
  }
34176
34275
  });
34177
34276
  svg.addEventListener("pointerenter", (evt) => {
34178
- if (evt.buttons) return;
34179
- this.selection.activate(this.clause([this.fields.map(() => 0)]));
34277
+ if (!evt.buttons) this.activate();
34180
34278
  });
34181
34279
  }
34280
+ activate() {
34281
+ this.selection.activate(this.clause([this.fields.map(() => 0)]));
34282
+ }
34182
34283
  };
34183
34284
  function isTargetElement(groups2, node) {
34184
34285
  return groups2.some((g) => g.contains(node));