@uwdata/mosaic-spec 0.12.1 → 0.12.2

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
  }
@@ -563,14 +563,15 @@ var MosaicClient = class {
563
563
  }
564
564
  /**
565
565
  * Return an array of fields queried by this client.
566
- * @returns {object[]|null} The fields to retrieve info for.
566
+ * @returns {import('./types.js').FieldInfoRequest[] | null}
567
+ * The fields to retrieve info for.
567
568
  */
568
569
  fields() {
569
570
  return null;
570
571
  }
571
572
  /**
572
573
  * Called by the coordinator to set the field info for this client.
573
- * @param {*} info The field info result.
574
+ * @param {import('./types.js').FieldInfo[]} info The field info result.
574
575
  * @returns {this}
575
576
  */
576
577
  fieldInfo(info) {
@@ -3451,6 +3452,9 @@ var ColumnNameRefNode = class extends ColumnRefNode {
3451
3452
  };
3452
3453
 
3453
3454
  // ../sql/src/ast/column-param.js
3455
+ function isColumnParam(value) {
3456
+ return value instanceof ColumnParamNode;
3457
+ }
3454
3458
  var ColumnParamNode = class extends ColumnRefNode {
3455
3459
  /**
3456
3460
  * Instantiate a column param node.
@@ -5039,7 +5043,7 @@ function collectAggregates(root2) {
5039
5043
  function collectColumns(root2) {
5040
5044
  const cols = {};
5041
5045
  walk(root2, (node) => {
5042
- if (node.type === COLUMN_REF) {
5046
+ if (node.type === COLUMN_REF || node.type === COLUMN_PARAM) {
5043
5047
  cols[node] = node;
5044
5048
  }
5045
5049
  });
@@ -5170,21 +5174,21 @@ function bin2d(q, xp, yp, aggs, xn, groupby) {
5170
5174
  }
5171
5175
 
5172
5176
  // ../sql/src/transforms/bin-linear-1d.js
5173
- function binLinear1d(query, x3, weight) {
5177
+ function binLinear1d(query, x3, weight = void 0, groupby = []) {
5174
5178
  const w = weight ? (x4) => mul(x4, weight) : (x4) => x4;
5175
5179
  const p0 = floor(x3);
5176
5180
  const p1 = add(p0, 1);
5177
5181
  return Query.from(Query.unionAll(
5178
5182
  query.clone().select({ i: int322(p0), w: w(sub(p1, x3)) }),
5179
5183
  query.clone().select({ i: int322(p1), w: w(sub(x3, p0)) })
5180
- )).select({ index: "i", density: sum("w") }).groupby("index").having(neq("density", 0));
5184
+ )).select({ index: "i", density: sum("w") }, groupby).groupby("index", groupby).having(neq("density", 0));
5181
5185
  }
5182
5186
 
5183
5187
  // ../sql/src/transforms/bin-linear-2d.js
5184
5188
  function identity(x3) {
5185
5189
  return x3;
5186
5190
  }
5187
- function binLinear2d(q, xp, yp, weight, xn, groupby) {
5191
+ function binLinear2d(q, xp, yp, weight, xn, groupby = []) {
5188
5192
  const w = weight ? (x3) => mul(x3, weight) : identity;
5189
5193
  const subq = (i, w2) => q.clone().select({ xp, yp, i, w: w2 });
5190
5194
  const index2 = (x3, y3) => add(x3, mul(y3, xn));
@@ -5914,7 +5918,7 @@ var statMap = {
5914
5918
  [Min]: min,
5915
5919
  [Nulls]: (column3) => count().where(isNull(column3))
5916
5920
  };
5917
- function summarize(table3, column3, stats) {
5921
+ function summarize({ table: table3, column: column3, stats }) {
5918
5922
  return Query.from(table3).select(Array.from(stats, (s2) => ({ [s2]: statMap[s2](column3) })));
5919
5923
  }
5920
5924
  async function queryFieldInfo(mc, fields) {
@@ -5925,7 +5929,7 @@ async function queryFieldInfo(mc, fields) {
5925
5929
  }
5926
5930
  }
5927
5931
  async function getFieldInfo(mc, { table: table3, column: column3, stats }) {
5928
- const q = Query.from({ source: table3 }).select({ column: column3 }).groupby(column3.aggregate ? sql`ALL` : []);
5932
+ const q = Query.from({ source: table3 }).select({ column: column3 }).groupby(isNode(column3) && isAggregateExpression(column3) ? sql`ALL` : []);
5929
5933
  const [desc2] = Array.from(await mc.query(Query.describe(q)));
5930
5934
  const info = {
5931
5935
  table: table3,
@@ -5934,16 +5938,16 @@ async function getFieldInfo(mc, { table: table3, column: column3, stats }) {
5934
5938
  type: jsType(desc2.column_type),
5935
5939
  nullable: desc2.null === "YES"
5936
5940
  };
5937
- if (!(stats?.length || stats?.size)) return info;
5941
+ if (!stats?.length) return info;
5938
5942
  const [result] = await mc.query(
5939
- summarize(table3, column3, stats),
5943
+ summarize({ table: table3, column: column3, stats }),
5940
5944
  { persist: true }
5941
5945
  );
5942
5946
  return Object.assign(info, result);
5943
5947
  }
5944
5948
  async function getTableInfo(mc, table3) {
5945
- const result = await mc.query(`DESCRIBE ${asTableRef(table3)}`);
5946
- return Array.from(result).map((desc2) => ({
5949
+ const result = Array.from(await mc.query(`DESCRIBE ${asTableRef(table3)}`));
5950
+ return result.map((desc2) => ({
5947
5951
  table: table3,
5948
5952
  column: desc2.column_name,
5949
5953
  sqlType: desc2.column_type,
@@ -6559,7 +6563,10 @@ var Coordinator = class {
6559
6563
  * or a SQL string.
6560
6564
  * @param {object} [options] An options object.
6561
6565
  * @param {'arrow' | 'json'} [options.type] The query result format type.
6562
- * @param {boolean} [options.cache=true] If true, cache the query result.
6566
+ * @param {boolean} [options.cache=true] If true, cache the query result
6567
+ * client-side within the QueryManager.
6568
+ * @param {boolean} [options.persist] If true, request the database
6569
+ * server to persist a cached query server-side.
6563
6570
  * @param {number} [options.priority] The query priority, defaults to
6564
6571
  * `Priority.Normal`.
6565
6572
  * @returns {QueryResult} A query result promise.
@@ -31810,7 +31817,9 @@ function isColor2(value) {
31810
31817
 
31811
31818
  // ../plot/src/marks/util/is-constant-option.js
31812
31819
  var constantOptions = /* @__PURE__ */ new Set([
31820
+ "offset",
31813
31821
  "order",
31822
+ "reverse",
31814
31823
  "sort",
31815
31824
  "label",
31816
31825
  "anchor",
@@ -31882,7 +31891,7 @@ var isFieldObject = (channel, field3) => {
31882
31891
  var fieldEntry = (channel, field3) => ({
31883
31892
  channel,
31884
31893
  field: field3,
31885
- as: isColumnRef(field3) ? field3.column : channel
31894
+ as: isColumnRef(field3) && !isColumnParam(field3) ? field3.column : channel
31886
31895
  });
31887
31896
  var valueEntry = (channel, value) => ({ channel, value });
31888
31897
  var isDataArray = (source) => Array.isArray(source);
@@ -31978,7 +31987,11 @@ var Mark2 = class extends MosaicClient {
31978
31987
  reqs[channel]?.forEach((s2) => entry.add(s2));
31979
31988
  }
31980
31989
  const table3 = this.sourceTable();
31981
- return Array.from(fields, ([c4, s2]) => ({ table: table3, column: c4, stats: s2 }));
31990
+ return Array.from(fields, ([c4, s2]) => ({
31991
+ table: table3,
31992
+ column: c4,
31993
+ stats: Array.from(s2)
31994
+ }));
31982
31995
  }
31983
31996
  fieldInfo(info) {
31984
31997
  const lookup = Object.fromEntries(info.map((x3) => [x3.column, x3]));
@@ -32176,13 +32189,33 @@ var ConnectedMark = class extends Mark2 {
32176
32189
  function array3(size, proto = []) {
32177
32190
  return new proto.constructor(size);
32178
32191
  }
32179
- function grid1d(size, index2, value) {
32180
- const G = array3(size, value);
32181
- const n = value.length;
32182
- for (let i = 0; i < n; ++i) {
32183
- G[index2[i]] = value[i];
32192
+ function grid1d(size, index2, value, columns, groupby) {
32193
+ const numRows = index2.length;
32194
+ const result = {};
32195
+ const cells = [];
32196
+ if (groupby?.length) {
32197
+ const group3 = new Int32Array(numRows);
32198
+ const gvalues = groupby.map((name2) => columns[name2]);
32199
+ const cellMap = {};
32200
+ for (let row = 0; row < numRows; ++row) {
32201
+ const key = gvalues.map((group4) => group4[row]);
32202
+ group3[row] = cellMap[key] ??= cells.push(key) - 1;
32203
+ }
32204
+ for (let i = 0; i < groupby.length; ++i) {
32205
+ result[groupby[i]] = cells.map((cell3) => cell3[i]);
32206
+ }
32207
+ const G = result._grid = cells.map(() => array3(size, value));
32208
+ for (let row = 0; row < numRows; ++row) {
32209
+ G[group3[row]][index2[row]] = value[row];
32210
+ }
32211
+ } else {
32212
+ cells.push([]);
32213
+ const [G] = result._grid = [array3(size, value)];
32214
+ for (let row = 0; row < numRows; ++row) {
32215
+ G[index2[row]] = value[row];
32216
+ }
32184
32217
  }
32185
- return G;
32218
+ return { numRows: cells.length, columns: result };
32186
32219
  }
32187
32220
  function grid2d(w, h, index2, columns, aggregates, groupby, interpolate) {
32188
32221
  const numRows = index2.length;
@@ -33040,9 +33073,16 @@ function stripXY(mark2, filter3) {
33040
33073
  }
33041
33074
 
33042
33075
  // ../plot/src/marks/Density1DMark.js
33076
+ var GROUPBY = { fill: 1, stroke: 1, z: 1 };
33043
33077
  var Density1DMark = class extends Mark2 {
33044
33078
  constructor(type2, source, options) {
33045
- const { bins: bins2 = 1024, bandwidth = 20, ...channels } = options;
33079
+ const {
33080
+ bins: bins2 = 1024,
33081
+ bandwidth = 20,
33082
+ normalize: normalize4 = false,
33083
+ stack: stack2 = false,
33084
+ ...channels
33085
+ } = options;
33046
33086
  const dim = type2.endsWith("X") ? "y" : "x";
33047
33087
  super(type2, source, channels, dim === "x" ? xext : yext);
33048
33088
  this.dim = dim;
@@ -33051,7 +33091,13 @@ var Density1DMark = class extends Mark2 {
33051
33091
  });
33052
33092
  this.bandwidth = handleParam(bandwidth, (value) => {
33053
33093
  this.bandwidth = value;
33054
- return this.grid ? this.convolve().update() : null;
33094
+ return this.grids ? this.convolve().update() : null;
33095
+ });
33096
+ this.normalize = handleParam(normalize4, (value) => {
33097
+ return this.normalize = value, this.convolve().update();
33098
+ });
33099
+ this.stack = handleParam(stack2, (value) => {
33100
+ return this.stack = value, this.update();
33055
33101
  });
33056
33102
  }
33057
33103
  get filterStable() {
@@ -33066,42 +33112,67 @@ var Density1DMark = class extends Mark2 {
33066
33112
  const [x3, bx] = binExpr(this, dim, bins2, extent4);
33067
33113
  const q = markQuery(channels, this.sourceTable(), [dim]).where(filter3.concat(isBetween(bx, extent4)));
33068
33114
  const v2 = this.channelField("weight") ? "weight" : null;
33069
- return binLinear1d(q, x3, v2);
33115
+ const g = this.groupby = channels.flatMap((c4) => {
33116
+ return GROUPBY[c4.channel] && c4.field ? c4.as : [];
33117
+ });
33118
+ return binLinear1d(q, x3, v2, g);
33070
33119
  }
33071
33120
  queryResult(data) {
33072
- const { columns: { index: index2, density: density3 } } = toDataColumns(data);
33073
- this.grid = grid1d(this.bins, index2, density3);
33121
+ const c4 = toDataColumns(data).columns;
33122
+ this.grids = grid1d(this.bins, c4.index, c4.density, c4, this.groupby);
33074
33123
  return this.convolve();
33075
33124
  }
33076
33125
  convolve() {
33077
- const { bins: bins2, bandwidth, dim, grid: grid2, plot: plot3, extent: [lo, hi] } = this;
33078
- const neg = grid2.some((v3) => v3 < 0);
33126
+ const {
33127
+ bins: bins2,
33128
+ bandwidth,
33129
+ normalize: normalize4,
33130
+ dim,
33131
+ grids,
33132
+ groupby,
33133
+ plot: plot3,
33134
+ extent: [lo, hi]
33135
+ } = this;
33136
+ const cols = grids.columns;
33137
+ const numGrids = grids.numRows;
33138
+ const b = this.channelField(dim).as;
33139
+ const v2 = dim === "x" ? "y" : "x";
33079
33140
  const size = dim === "x" ? plot3.innerWidth() : plot3.innerHeight();
33141
+ const neg = cols._grid.some((grid2) => grid2.some((v3) => v3 < 0));
33080
33142
  const config = dericheConfig(bandwidth * (bins2 - 1) / size, neg);
33081
- const result = dericheConv1d(config, grid2, bins2);
33082
- const v2 = dim === "x" ? "y" : "x";
33083
- const b = this.channelField(dim).as;
33084
33143
  const b0 = +lo;
33085
33144
  const delta = (hi - b0) / (bins2 - 1);
33086
- const scale3 = 1 / delta;
33087
- const _b = new Float64Array(bins2);
33088
- const _v = new Float64Array(bins2);
33089
- for (let i = 0; i < bins2; ++i) {
33090
- _b[i] = b0 + i * delta;
33091
- _v[i] = result[i] * scale3;
33092
- }
33093
- this.data = { numRows: bins2, columns: { [b]: _b, [v2]: _v } };
33145
+ const numRows = bins2 * numGrids;
33146
+ const _b = new Float64Array(numRows);
33147
+ const _v = new Float64Array(numRows);
33148
+ const _g = groupby.reduce((m, name2) => (m[name2] = Array(numRows), m), {});
33149
+ for (let k2 = 0, g = 0; g < numGrids; ++g) {
33150
+ groupby.forEach((name2) => _g[name2].fill(cols[name2][g], k2, k2 + bins2));
33151
+ const grid2 = cols._grid[g];
33152
+ const result = dericheConv1d(config, grid2, bins2);
33153
+ const scale3 = 1 / norm(grid2, result, delta, normalize4);
33154
+ for (let i = 0; i < bins2; ++i, ++k2) {
33155
+ _b[k2] = b0 + i * delta;
33156
+ _v[k2] = result[i] * scale3;
33157
+ }
33158
+ }
33159
+ this.data = { numRows, columns: { [b]: _b, [v2]: _v, ..._g } };
33094
33160
  return this;
33095
33161
  }
33096
33162
  plotSpecs() {
33097
- const { type: type2, data: { numRows: length4, columns }, channels, dim } = this;
33098
- const options = dim === "x" ? { y: columns.y } : { x: columns.x };
33163
+ const { type: type2, data: { numRows: length4, columns }, channels, dim, stack: stack2 } = this;
33164
+ const _ = type2.startsWith("area") && !stack2 ? "2" : "";
33165
+ const options = dim === "x" ? { [`y${_}`]: columns.y } : { [`x${_}`]: columns.x };
33099
33166
  for (const c4 of channels) {
33100
33167
  options[c4.channel] = channelOption(c4, columns);
33101
33168
  }
33102
33169
  return [{ type: type2, data: { length: length4 }, options }];
33103
33170
  }
33104
33171
  };
33172
+ function norm(grid2, smoothed, delta, type2) {
33173
+ const value = type2 === true || type2 === "sum" ? sum2(grid2) : type2 === "max" ? max2(smoothed) : delta;
33174
+ return value || 1;
33175
+ }
33105
33176
 
33106
33177
  // ../plot/src/marks/Density2DMark.js
33107
33178
  var Density2DMark = class extends Grid2DMark {
@@ -35169,6 +35240,7 @@ var Menu = class extends MosaicClient {
35169
35240
  constructor({
35170
35241
  element,
35171
35242
  filterBy,
35243
+ as,
35172
35244
  from: from2,
35173
35245
  column: column3,
35174
35246
  label = column3,
@@ -35176,8 +35248,7 @@ var Menu = class extends MosaicClient {
35176
35248
  // TODO
35177
35249
  options,
35178
35250
  value,
35179
- field: field3 = column3,
35180
- as
35251
+ field: field3 = column3
35181
35252
  } = {}) {
35182
35253
  super(filterBy);
35183
35254
  this.from = from2;
@@ -35194,8 +35265,8 @@ var Menu = class extends MosaicClient {
35194
35265
  this.select = document.createElement("select");
35195
35266
  this.element.appendChild(this.select);
35196
35267
  if (options) {
35197
- this.data = options.map((value2) => isObject2(value2) ? value2 : { value: value2 });
35198
- this.selectedValue(value ?? "");
35268
+ this.data = options.map((opt) => isObject2(opt) ? opt : { value: opt });
35269
+ this.selectedValue(value === void 0 ? "" : value);
35199
35270
  this.update();
35200
35271
  }
35201
35272
  if (selection2) {
@@ -35269,7 +35340,7 @@ var Menu = class extends MosaicClient {
35269
35340
  }
35270
35341
  if (selection2) {
35271
35342
  const value = isSelection(selection2) ? selection2.valueFor(this) : selection2.value;
35272
- this.selectedValue(value ?? "");
35343
+ this.selectedValue(value === void 0 ? "" : value);
35273
35344
  }
35274
35345
  return this;
35275
35346
  }
@@ -35665,8 +35736,8 @@ var Table2 = class extends MosaicClient {
35665
35736
  coordinator().prefetch(query.clone().offset(offset2 + this.limit));
35666
35737
  }
35667
35738
  fields() {
35668
- const from2 = this.sourceTable();
35669
- return this.columns.map((name2) => column(name2, from2));
35739
+ const table3 = this.sourceTable();
35740
+ return this.columns.map((column3) => ({ column: column3, table: table3 }));
35670
35741
  }
35671
35742
  fieldInfo(info) {
35672
35743
  this.schema = info;