{
const domain = ["Cylinders", "Horsepower", "Weight_in_lbs","Acceleration", "Displacement"];
const textStyle = {
dx: -2,
align: 'right',
baseline: 'bottom'
};
const scale = {
type: 'point',
padding: 0
};
const axis = {
domain: false,
ticks: false,
title: false,
grid: true,
gridColor: '#888',
labelAngle: 0,
labelPadding: 8,
labelFontWeight: 'bold'
};
const lines = vl.markLine({
strokeWidth: 0.5,
opacity: 0.5
})
.encode(
vl.color().fieldN('Origin').sort('ascending'),
vl.detail().fieldN('index'),
vl.x().fieldO('key').scale(scale).axis(axis),
vl.y().fieldQ('norm_val').axis(null)
);
const topTick = vl.layer([
vl.markText(textStyle)
.encode(vl.text().max("max")),
vl.markTick({style:"tick", size: 8, color:"#ccc"})
])
.encode(
vl.x().fieldN("key"),
vl.y().value(0)
);
const midTick = vl.layer([
vl.markText(textStyle)
.encode(vl.text().max("mid")),
vl.markTick({style:"tick", size: 8, color:"#ccc"})
])
.encode(
vl.x().fieldN("key"),
vl.y().value(150)
);
const bottomTick = vl.layer([
vl.markText(textStyle)
.encode(vl.text().max("min")),
vl.markTick({style:"tick", size: 8, color:"#ccc"})
])
.encode(
vl.x().fieldN("key"),
vl.y().value(300)
);
return vl.layer([lines, topTick, midTick, bottomTick])
.data(carData)
.transform([
vl.window({"op": "count", "as": "index"}),
vl.fold(domain),
vl.joinaggregate([
{"op": "min", "field": "value", "as": "min"},
{"op": "max", "field": "value", "as": "max"}
]).groupby("key"),
vl.calculate("(datum.value - datum.min) / (datum.max-datum.min)").as("norm_val"),
vl.calculate("(datum.min + datum.max) / 2").as("mid")
])
.width(700)
.height(300)
.render()
}