Add Vega graphic as an example

Vega is a data format, though one could say configuration format, for
declaratively defining data visualizations. It can be generated from
Python using Altair, but how about generating it with RCL?

I don't know if this is a good idea, but it is at least possible.
And it's already way more convenient to write than writing json in
the online editor, because in RCL you don't have to quote the keys.
This commit is contained in:
Ruud van Asseldonk 2024-07-22 21:02:17 +02:00
parent 5f3b4efb2f
commit 972fa2fe4e

122
examples/vega.rcl Normal file
View file

@ -0,0 +1,122 @@
// This example contains a Vega data visualization, see also [1]. You can
// evaluate this example to json using `rcl je examples/vega.rcl`, and then
// paste it into [2] to see the chart. The example is based on the default
// bar chart example at [3].
// [1]: https://vega.github.io/vega/
// [2]: https://vega.github.io/editor/#/edited
// [3]: https://vega.github.io/editor/#/examples/vega/bar-chart
// There is no simple way to change the font in one place in Vega, we have to
// set all these properties. So write a function, so we can write it once and
// import it into all our graphics. For the purpose of the example, it is
// inlined here though.
let config_font = font => {
title = { font = font },
axis = { labelFont = font, titleFont = font },
legend = { labelFont = font, titleFont = font },
header = { labelFont = font, titleFont = font },
mark = { font = font },
title = { font = font, subtitleFont = font },
};
let head = {
"$schema": "https://vega.github.io/schema/vega/v5.json",
description = "A basic bar chart example.",
width = 400,
height = 200,
padding = 5,
config = config_font("Cantarell"),
};
let data_table = {
name = "table",
// Note, we inline the data here, but if you have a different json data set,
// we could just write `values = import "data.json"` here to include it.
values = [
{ "category": "A", "amount": 28 },
{ "category": "B", "amount": 55 },
{ "category": "C", "amount": 43 },
{ "category": "D", "amount": 91 },
{ "category": "E", "amount": 81 },
{ "category": "F", "amount": 53 },
{ "category": "G", "amount": 19 },
{ "category": "H", "amount": 87 },
],
};
let signal_tooltip = {
name = "tooltip",
value = {},
// In the original example, this is a bit verbose. We can distill the data
// into its essence here, and generate the expanded form with repeating field
// names using a list comperhension below.
let on_events = { "rect:pointerover": "datum", "rect:pointerout": "{}" };
on = [for event, update in on_events: { events = event, update = update }],
};
let scales = [
{
name = "xscale",
type = "band",
domain = { data = "table", field = "category" },
range = "width",
// TODO: This should be a float, but RCL does not support those yet.
padding = "0.05",
round = true,
},
{
name = "yscale",
domain = { data = "table", field = "amount" },
nice = true,
range = "height",
},
];
{
for k, v in head: k: v,
data = [data_table],
signals = [signal_tooltip],
scales = scales,
axes = [
{ orient = "bottom", scale = "xscale" },
{ orient = "left", scale = "yscale" },
],
marks = [
{
type = "rect",
from = { data = "table" },
encode = {
enter = {
width = { band = 1, scale = "xscale" },
x = { field = "category", scale = "xscale" },
y = { field = "amount", scale = "yscale" },
y2 = { scale = "yscale", value = 0 },
},
hover = { fill = { value = "red" } },
update = { fill = { value = "steelblue" } },
},
},
{
type = "text",
encode = {
enter = {
align = { value = "center" },
baseline = { value = "bottom" },
fill = { value = "#333" },
},
update = {
fillOpacity = [
{ test = "datum === tooltip", value = 0 },
{ value = 1 },
],
text = { signal = "tooltip.amount" },
// TODO: Band should be a float here as well.
x = { band = "0.5", scale = "xscale", signal = "tooltip.category" },
y = { offset = -2, scale = "yscale", signal = "tooltip.amount" },
},
},
},
],
}