Published
Edited
Sep 28, 2020
1 fork
24 stars
Insert cell
Insert cell
chart = {
const mouseover = vl
.selectSingle("index")
.on("mouseover")
.encodings("x")
.nearest(true)
.init({ x: { year: 2005, month: 1, date: 1 } });

const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);

const hiddenPoints = base.markPoint({ opacity: 0 }).select(mouseover);
const line = base
.markLine()
.transform(
vl.lookup("symbol").from(mouseover.key("symbol")),
vl.calculate(
"datum.index && datum.index.price > 0 ? (datum.price - datum.index.price)/datum.index.price : 0"
).as("indexed_price")
)
.encode(
vl.y().fieldQ("indexed_price").axis({ format: "%" }),
vl.color().fieldN("symbol")
);

const tooltipBase = base
.transform(vl.filter(mouseover))
.encode(vl.color().value("firebrick"));

const tooltip = vl.layer(
tooltipBase.markRule({ strokeWidth: 0.5 }),
tooltipBase.markText({ align: "center", fontWeight: 100 }).encode(
vl.y().value(310),
vl.text().fieldT("date").timeUnit("yearmonth")
)
);

return vl
.layer(hiddenPoints, line, tooltip)
.data("data/stocks.csv")
.width(width - 150)
.height(300)
.render();
}
Insert cell
Insert cell
{
const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);

const line = base
.markLine()
.encode(vl.y().fieldQ("price"), vl.color().fieldN("symbol"));

return vl
.layer(line)
.data("data/stocks.csv")
.width(650)
.height(300)
.render();
}
Insert cell
Insert cell
{
const mouseover = vl
.selectSingle("index")
.on("mouseover")
.encodings("x")
.nearest(true)
.init({ x: { year: 2005, month: 1, date: 1 } });

const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);

const hiddenPoints = base
.markPoint({ opacity: 0.1 })
.select(mouseover)
.encode(
// Let's color code it interactively to demonstrate it is working, but we will remove it later
vl.color().if(mouseover, vl.value("firebrick")).value("steelblue")
);

return vl
.layer(hiddenPoints)
.data("data/stocks.csv")
.width(650)
.height(300)
.render();
}
Insert cell
Insert cell
{
const mouseover = vl
.selectSingle("index")
.on("mouseover")
.encodings("x")
.nearest(true)
.init({ x: { year: 2005, month: 1, date: 1 } });

const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);

const hiddenPoints = base
.markPoint({ opacity: 0.1 })
.select(mouseover)
.encode(
// Let's color code it interactively to demonstrate it is working, but we will remove it later
vl.color().if(mouseover, vl.value("firebrick")).value("steelblue")
);

const line = base
.markLine()
.transform(
vl.lookup("symbol").from(mouseover.key("symbol")),
vl.calculate(
"datum.index && datum.index.price > 0 ? (datum.price - datum.index.price)/datum.index.price : 0"
).as("indexed_price")
)
.encode(
vl.y().fieldQ("indexed_price").axis({ format: "%" }),
vl.color().fieldN("symbol")
);

return vl
.layer(hiddenPoints, line)
.data("data/stocks.csv")
.width(650)
.height(300)
.render();
}
Insert cell
Insert cell
{
const mouseover = vl
.selectSingle("index")
.on("mouseover")
.encodings("x")
.nearest(true)
.init({ x: { year: 2005, month: 1, date: 1 } });

const base = vl.mark().encode(
vl.x().fieldT("date").axis(null)
);

const hiddenPoints = base.markPoint({ opacity: 0 }).select(mouseover);

const tooltipBase = base
.transform(vl.filter(mouseover))
.encode(vl.color().value("firebrick"));

const tooltip = vl.layer(
tooltipBase.markRule({ strokeWidth: 0.5 }),
tooltipBase.markText({ align: "center", fontWeight: 100 }).encode(
vl.y().value(310),
vl.text().fieldT("date").timeUnit("yearmonth")
)
);

return vl
.layer(hiddenPoints, tooltip)
.data("data/stocks.csv")
.width(650)
.height(300)
.render();
}
Insert cell
Insert cell
Insert cell
vegaEmbed({
$schema: "https://vega.github.io/schema/vega-lite/v4.json",
data: {
values: data,
format: { parse: { date: "date" } }
},
width: 650,
height: 300,
layer: [
{
selection: {
index: {
type: "single",
on: "mouseover",
encodings: ["x"],
nearest: true,
init: { x: { year: 2005, month: 1, date: 1 } }
}
},
mark: "point",
encoding: {
x: { field: "date", type: "temporal", axis: null },
opacity: { value: 0 }
}
},
{
transform: [
{
lookup: "symbol",
from: { selection: "index", key: "symbol" }
},
{
calculate:
"datum.index && datum.index.price > 0 ? (datum.price - datum.index.price)/datum.index.price : 0",
as: "indexed_price"
}
],
mark: "line",
encoding: {
x: { field: "date", type: "temporal", axis: null },
y: {
field: "indexed_price",
type: "quantitative",
axis: { format: "%" }
},
color: { field: "symbol", type: "nominal" }
}
},
{
transform: [{ filter: { selection: "index" } }],
encoding: {
x: { field: "date", type: "temporal", axis: null },
color: { value: "firebrick" }
},
layer: [
{ mark: { type: "rule", strokeWidth: 0.5 } },
{
mark: { type: "text", align: "center", fontWeight: 100 },
encoding: {
text: { field: "date", timeUnit: "yearmonth" },
y: { value: 310 }
}
}
]
}
]
})
Insert cell
Insert cell
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