@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.
- package/dist/mosaic-schema.json +416 -0
- package/dist/mosaic-spec.js +125 -54
- package/dist/mosaic-spec.min.js +20 -20
- package/dist/types/spec/Param.d.ts +1 -1
- package/dist/types/spec/marks/Density.d.ts +22 -7
- package/package.json +5 -5
- package/src/spec/Param.ts +1 -0
- package/src/spec/marks/Density.ts +25 -7
package/dist/mosaic-spec.js
CHANGED
|
@@ -103,7 +103,7 @@ var require_search_bounds = __commonJS({
|
|
|
103
103
|
}
|
|
104
104
|
return -1;
|
|
105
105
|
}
|
|
106
|
-
function
|
|
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
|
|
114
|
+
return norm2(a2, y3, c4, l, h, ge);
|
|
115
115
|
},
|
|
116
116
|
gt: function(a2, y3, c4, l, h) {
|
|
117
|
-
return
|
|
117
|
+
return norm2(a2, y3, c4, l, h, gt2);
|
|
118
118
|
},
|
|
119
119
|
lt: function(a2, y3, c4, l, h) {
|
|
120
|
-
return
|
|
120
|
+
return norm2(a2, y3, c4, l, h, lt2);
|
|
121
121
|
},
|
|
122
122
|
le: function(a2, y3, c4, l, h) {
|
|
123
|
-
return
|
|
123
|
+
return norm2(a2, y3, c4, l, h, le);
|
|
124
124
|
},
|
|
125
125
|
eq: function(a2, y3, c4, l, h) {
|
|
126
|
-
return
|
|
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 {
|
|
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 {
|
|
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
|
|
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 (!
|
|
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
|
|
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]) => ({
|
|
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
|
|
32181
|
-
const
|
|
32182
|
-
|
|
32183
|
-
|
|
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
|
|
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 {
|
|
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.
|
|
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
|
-
|
|
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
|
|
33073
|
-
this.
|
|
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 {
|
|
33078
|
-
|
|
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
|
|
33087
|
-
const _b = new Float64Array(
|
|
33088
|
-
const _v = new Float64Array(
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33092
|
-
|
|
33093
|
-
|
|
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
|
|
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((
|
|
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
|
|
35669
|
-
return this.columns.map((
|
|
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;
|