I’d like to extend Vega’s transform map with a new transform class, but I’m running into some difficulties. Here is what I have so far. I’ve sketched out my intended roadmap in the comments, but I’m having some difficulty even loading the Vega transform into Vega-lite. I’ve found Vega-lite’s typescript interface, but I’m not sure how to register my transform.
<!doctype html>
<html>
<head>
<title>Too Much Data</title>
<meta charset="utf-8" />
<!--
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
-->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega-lite.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/vega-embed.js"></script>
<style media="screen">
h1 {
text-align: center;
font-family: Georgia, serif
}
#vis {
width: 100%;
}
</style>
</head>
<body>
<h1>Too Much Data</h1>
<!-- Container for the visualization -->
<div id="vis"></div>
<script>
// Assign the specification to a local variable vlSpec.
var vlSpec =
{ $schema: "https://vega.github.io/schema/vega-lite/v5.json"
, data:
{"values":
[{"time": "2023-08-31 15:12:40", "data": 265.1037232391961, "category": 1}, {"time": "2023-08-31 15:15:26", "data": 989.2391954577464, "category": 1}, {"time": "2023-08-31 15:15:29", "data": 426.3748533977788, "category": 0}, {"time": "2023-08-31 15:18:11", "data": 563.7725296786067, "category": 1}, {"time": "2023-08-31 15:21:25", "data": 322.4493083566362, "category": 0}, {"time": "2023-08-31 15:24:54", "data": 822.6771646740021, "category": 1}, {"time": "2023-08-31 15:28:10", "data": 294.37404484299054, "category": 1}, {"time": "2023-08-31 15:28:22", "data": 838.7462086185608, "category": 0}, {"time": "2023-08-31 15:35:58", "data": 961.3893188770259, "category": 0}, {"time": "2023-08-31 15:36:07", "data": 241.45631836625802, "category": 0}, {"time": "2023-08-31 15:49:33", "data": 191.96326506124362, "category": 0}, {"time": "2023-08-31 15:51:15", "data": 450.50733664623965, "category": 1}, {"time": "2023-08-31 15:56:35", "data": 390.5921971631632, "category": 1}, {"time": "2023-08-31 15:57:52", "data": 829.8364876130439, "category": 1}, {"time": "2023-08-31 16:01:06", "data": 996.0349700996576, "category": 0}, {"time": "2023-08-31 16:02:36", "data": 78.24722444300802, "category": 0}, {"time": "2023-08-31 16:14:05", "data": 942.3350040849994, "category": 0}, {"time": "2023-08-31 16:14:56", "data": 860.58714895142, "category": 1}, {"time": "2023-08-31 16:15:08", "data": 515.199102407516, "category": 1}, {"time": "2023-08-31 16:23:20", "data": 166.05721829849873, "category": 1}, {"time": "2023-08-31 16:30:05", "data": 439.73137493646266, "category": 0}, {"time": "2023-08-31 16:32:31", "data": 869.245076742056, "category": 0}, {"time": "2023-08-31 16:35:48", "data": 480.50968063008304, "category": 1}, {"time": "2023-08-31 16:37:50", "data": 476.877035209344, "category": 1}, {"time": "2023-08-31 16:39:36", "data": 733.3017448826324, "category": 0}, {"time": "2023-08-31 16:44:17", "data": 636.686519092496, "category": 1}, {"time": "2023-08-31 16:45:08", "data": 694.5261775005811, "category": 0}, {"time": "2023-08-31 16:51:36", "data": 695.7401884245502, "category": 0}, {"time": "2023-08-31 16:55:29", "data": 570.0935946720598, "category": 1}, {"time": "2023-08-31 16:57:05", "data": 277.22052647262717, "category": 0}, {"time": "2023-08-31 16:58:27", "data": 480.36926264607274, "category": 1}, {"time": "2023-08-31 17:02:34", "data": 893.3698570026319, "category": 1}, {"time": "2023-08-31 17:05:32", "data": 236.71895124154685, "category": 1}, {"time": "2023-08-31 17:08:46", "data": 573.0841835923452, "category": 0}, {"time": "2023-08-31 17:14:37", "data": 191.7254918774728, "category": 0}, {"time": "2023-08-31 17:16:43", "data": 94.93763899240804, "category": 1}, {"time": "2023-08-31 17:24:40", "data": 936.4038465823089, "category": 0}, {"time": "2023-08-31 17:31:09", "data": 390.84825100994567, "category": 1}, {"time": "2023-08-31 17:35:35", "data": 14.48187309843274, "category": 0}, {"time": "2023-08-31 17:35:47", "data": 443.05398617944593, "category": 1}, {"time": "2023-08-31 17:40:44", "data": 30.0828399028229, "category": 0}, {"time": "2023-08-31 17:48:33", "data": 768.0549896500464, "category": 1}, {"time": "2023-08-31 17:53:29", "data": 71.57068127924227, "category": 0}, {"time": "2023-08-31 18:04:56", "data": 594.7138236213322, "category": 0}, {"time": "2023-08-31 18:06:44", "data": 29.21370270526036, "category": 0}, {"time": "2023-08-31 18:28:22", "data": 852.7093808483378, "category": 1}, {"time": "2023-08-31 18:30:01", "data": 576.9728506525139, "category": 1}, {"time": "2023-08-31 18:31:41", "data": 968.1882202042807, "category": 1}, {"time": "2023-08-31 18:31:51", "data": 185.6873327854428, "category": 1}, {"time": "2023-08-31 18:33:31", "data": 258.211113709635, "category": 0}, {"time": "2023-08-31 18:36:36", "data": 641.264570256715, "category": 1}, {"time": "2023-08-31 18:39:52", "data": 717.6143367808544, "category": 1}, {"time": "2023-08-31 18:39:52", "data": 191.4611806426172, "category": 1}, {"time": "2023-08-31 18:41:38", "data": 136.9116350629923, "category": 0}, {"time": "2023-08-31 18:57:48", "data": 62.11343548023751, "category": 1}, {"time": "2023-08-31 18:58:26", "data": 529.5089127094398, "category": 0}, {"time": "2023-08-31 19:07:54", "data": 153.13269404700824, "category": 1}, {"time": "2023-08-31 19:09:17", "data": 705.4049459845114, "category": 0}, {"time": "2023-08-31 19:11:07", "data": 300.90132125121005, "category": 1}, {"time": "2023-08-31 19:20:25", "data": 946.4725291504993, "category": 1}, {"time": "2023-08-31 19:23:48", "data": 319.04133613813724, "category": 1}, {"time": "2023-08-31 19:24:25", "data": 464.2923297748929, "category": 1}, {"time": "2023-08-31 19:28:02", "data": 836.436678063193, "category": 1}, {"time": "2023-08-31 19:28:08", "data": 5.992853044164859, "category": 1}, {"time": "2023-08-31 19:40:01", "data": 873.6847072580948, "category": 1}, {"time": "2023-08-31 19:43:41", "data": 431.0286183407737, "category": 1}, {"time": "2023-08-31 19:51:22", "data": 396.43260404732825, "category": 0}, {"time": "2023-08-31 19:54:08", "data": 575.9715221353141, "category": 0}, {"time": "2023-08-31 19:55:53", "data": 44.016217670442614, "category": 0}, {"time": "2023-08-31 19:58:14", "data": 988.9639046666363, "category": 1}, {"time": "2023-08-31 20:05:53", "data": 742.2798696276691, "category": 0}, {"time": "2023-08-31 20:07:13", "data": 982.7119961613008, "category": 0}, {"time": "2023-08-31 20:15:20", "data": 976.3381077100345, "category": 1}, {"time": "2023-08-31 20:20:15", "data": 498.5276910780252, "category": 0}, {"time": "2023-08-31 20:22:29", "data": 301.4863894174468, "category": 1}, {"time": "2023-08-31 20:31:03", "data": 232.56452406666895, "category": 1}, {"time": "2023-08-31 20:33:52", "data": 694.171014904713, "category": 1}, {"time": "2023-08-31 20:35:45", "data": 102.79567934930212, "category": 1}, {"time": "2023-08-31 20:47:32", "data": 431.64822699883376, "category": 1}, {"time": "2023-08-31 20:55:19", "data": 683.217576875891, "category": 0}, {"time": "2023-08-31 20:55:36", "data": 879.5945045918183, "category": 1}, {"time": "2023-08-31 21:04:28", "data": 164.6834561802648, "category": 1}, {"time": "2023-08-31 21:06:04", "data": 22.588620229922583, "category": 1}, {"time": "2023-08-31 21:07:10", "data": 757.0796861192514, "category": 1}, {"time": "2023-08-31 21:23:43", "data": 848.456892794343, "category": 1}, {"time": "2023-08-31 21:34:38", "data": 447.89147371830785, "category": 1}, {"time": "2023-08-31 21:45:30", "data": 862.3116375036777, "category": 1}, {"time": "2023-08-31 21:47:00", "data": 967.0312319533795, "category": 0}, {"time": "2023-08-31 21:47:56", "data": 966.4938018703745, "category": 1}, {"time": "2023-08-31 21:49:45", "data": 890.2567189914545, "category": 0}, {"time": "2023-08-31 21:55:40", "data": 362.80312104639677, "category": 1}, {"time": "2023-08-31 21:58:55", "data": 834.7469369912607, "category": 1}, {"time": "2023-08-31 22:01:02", "data": 584.1447613550432, "category": 1}, {"time": "2023-08-31 22:01:06", "data": 82.66592460479994, "category": 1}, {"time": "2023-08-31 22:02:00", "data": 332.67959271479384, "category": 0}, {"time": "2023-08-31 22:02:32", "data": 316.51081491367347, "category": 0}, {"time": "2023-08-31 22:08:31", "data": 336.10098602094985, "category": 1}, {"time": "2023-08-31 22:18:52", "data": 873.7313013506864, "category": 0}, {"time": "2023-08-31 22:19:24", "data": 312.42947148514776, "category": 1}, {"time": "2023-08-31 22:28:48", "data": 582.8096654568776, "category": 1}]
}
, params:
[ {name: "test", expr: "span(grid_time)/1000"}
]
, transform:
[ {filter: "datum.data > 0"}
]
, title: "Too Much Data"
, config: { font: "monospace" }
, width: "container"
, layer:
[ { params:
[ { name: "grid"
, bind: "scales"
, select:
{ type: "interval"
, encodings: ["x"]
, on: "[mousedown[!event.shiftKey], mouseup] > mousemove"
, translate: "[mousedown[!event.shiftKey], mouseup] > mousemove!"
}
}
, { name: "brush"
, select:
{ type: "interval"
, encodings: ["x"]
, on: "[mousedown[event.shiftKey], mouseup] > mousemove"
, translate: "[mousedown[event.shiftKey], mouseup] > mousemove!"
}
}
]
, mark: "point"
, encoding:
{ x: {field: "time", type: "temporal"}
, y: {field: "data", type: "quantitative"}
, color: {field: "category", type: "nominal"}
}
}
, { data: {values: [{}]}
, mark:
{ type: "rect"
, x: 10
, y: 10
, x2: 182
, y2: 100
, fillOpacity: 0.05
, stroke: "darkgrey"
, strokeWidth: 2
, fill: "azure"
}
}
, { data: {values: [{}]}
, mark:
{ type: "rect"
, fillOpacity: 0.05
, stroke: "darkgrey"
, strokeWidth: 2
, fill: "azure"
}
, encoding:
{ "x": {"value": 200}
, "y": {"value": 120}
, "x2": {"value": 240}
, "y2": {"value": 160}
}
}
, { //data: {values: [{time: 1693521211000}]}
transform:
[ { filter: {param: "brush", empty: true}}
, { window: [{op: "row_number", as: "row_number"}]}
, { extent: "time", param: "time_extent"}
, { aggregate:
[ {op: "count", as: "count"}
//, {op: "values", field: "time", as: "values"}
//, {op: "argmax", field: "time", as: "argmax"}
//, {op: "argmin", field: "time", as: "argmin"}
]
}
//, { type: "default", values: []}
, { default: []}
]
, mark:
{ type: "text"
, x: 15
, y: 15
, align: "left"
, baseline: "top"
, text: {expr: "warn(true ? 'foo' : 'bar')"}
}
//, encoding:
// { text: {field: "data", type: "nominal"}
// , y: {field: "row_number", type: "ordinal", axis: null}
// }
}
]
}
// Insert a predetermined row only when the dataset is empty.
// This can happen because aggregate does not understand empty sets,
// i.e. "count" goes from 3,2,1,<empty dataset> rather than 3,2,1,0.
class Default extends vega.Transform {
Definition =
{ type: "Filter"
, metadata: {changes: true}
, params:
[ { name: "values", type: "any", array: true }
]
}
constructor(params) {
// todo: provide initial value
// { count: 0, cache: null } ??
super(null, params)
}
transform(params, pulse) {
// rough draft (probably wrong):
// 1. For each add, increment this.value.count
// 2. For each rem, decrement this.value.count
// 3. if this.value.count == 0 {
// if this.value.cache == null {
// // need to lookup null/undefined/==/===
// // need to console.log some tuples to learn the
// // expected ingest format
// this.value.cache = ingest(params.values)
// }
// pulse.add.push(this.value.cache)
// } else {
// // pretty sure I have to remove the default, i.e. will
// // persist during subsequent pulses
// pulse.rem.push(this.value.cache)
// }
// 4. Handle params.modified() ...
// reset count to 0 (??) - before step 3, then after step 3:
// pulse.visit(pulse.REFLOW, ...) // anything except ADD/REM/MOD
// For each, increment this.value.count
// Will these count strategies actually work? No idea. Need to
// console.log all changes to count.
// ???
const out = pulse.fork(pulse.ALL)
pulse.visit(pulse.ADD, t => {
console.log(t)
})
return out
}
}
// problem: need to convert the vega interface to the vega-lite interface.
vega.transforms["default"] = Default
// Embed the visualization in the container with id `vis`
vegaEmbed('#vis', vlSpec).then(function(result) {
// Access the Vega view instance as result.view
// (https://vega.github.io/vega/docs/api/view/)
}).catch(console.error);
</script>
</body>
</html>