Published
Edited
Aug 2, 2020
3 stars
Insert cell
Insert cell
Insert cell
// https://observablehq.com/@uwdata/multi-view-composition?collection=@uwdata/visualization-curriculum
// https://vega.github.io/vega-lite-api/
answer = {
const hover =
vl.selectSingle("hover").fields(["date"]).nearest(true).on("mouseover").empty("none").clear("mouseout");
const dateField = vl.x().fieldT("date");
const priceSymbolFields = [ vl.y().fieldQ("price"), vl.color().fieldN("symbol") ];
// Select and transform 'points' are 'rule' dependent in the layering
const pointsSelect = marks.includes("rule") ? null : hover;
const pointsTransform = marks.includes("rule") ? vl.filter(hover) : vl.filter("true");
const lines = vl.markLine()
.encode([dateField].concat(priceSymbolFields));
const points = vl.markPoint()
.encode([dateField].concat(priceSymbolFields))
.select(pointsSelect)
.transform(pointsTransform);
const rule = vl.markRule()
.encode(
dateField,
vl.opacity().if(hover, vl.value(0.3)).value(0),
vl.tooltip([...new Set(stocks.map(s => s.symbol))].sort())
)
.select(hover)
.transform(vl.pivot("symbol").value("price").groupby("date"));
const linesPointsLayers = marks.filter(m => ["lines","points"].includes(m)).map(m => eval(m));
const ruleLayer = marks.filter(m => ["rule"].includes(m)).map(m => eval(m));
//return vl.layer([vl.layer([lines, points]), rule])
return vl.layer([vl.layer(linesPointsLayers)].concat(ruleLayer))
.data(stocks)
.render();
} // answer
Insert cell
Insert cell
originalSpec = {
const spec =
{ "$schema": "https://vega.github.io/schema/vega-lite/v4.json",
"data": {values: stocks},
"width": 400,
"height": 300,
"encoding": {"x": {"field": "date", "type": "temporal"}},
"layer": [
{
"encoding": {
"color": {"field": "symbol", "type": "nominal"},
"y": {"field": "price", "type": "quantitative"}
},
"layer": [
{"mark": "line"},
{"transform": [{"filter": {"selection": "hover"}}], "mark": "point"}
]
},
{
"transform": [{"pivot": "symbol", "value": "price", "groupby": ["date"]}],
"mark": "rule",
"encoding": {
"opacity": {
"condition": {"value": 0.3, "selection": "hover"},
"value": 0
},
"tooltip": [
{"field": "AAPL", "type": "quantitative"},
{"field": "AMZN", "type": "quantitative"},
{"field": "GOOG", "type": "quantitative"},
{"field": "IBM", "type": "quantitative"},
{"field": "MSFT", "type": "quantitative"}
]
},
"selection": {
"hover": {
"type": "single",
"fields": ["date"],
"nearest": true,
"on": "mouseover",
"empty": "none",
"clear": "mouseout"
}
}
}
]
};
// https://github.com/observablehq/vega/blob/master/vega-lite/index.js
// https://vega.github.io/vega-lite-api/api/#utilities
const div = document.createElement("div");
const view = div.value = new vl.vega.View(vl.vega.parse(vl.vegalite.compile(spec).spec));
return view.initialize(div).runAsync().then(function() { return div; });
} // originalSpec
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more