Skip to content

Instantly share code, notes, and snippets.

@donghaoren
Last active February 19, 2023 07:30
Show Gist options
  • Save donghaoren/023b2246569e8f0615017507b473e55e to your computer and use it in GitHub Desktop.
Save donghaoren/023b2246569e8f0615017507b473e55e to your computer and use it in GitHub Desktop.
Responsive Vega Chart Demo

A responsive chart demo in Vega. The spec is a modification of a Vega-Lite output:

  • Set width and height to be signals. The signals gets their initial values from containerSize(), and listens to subsequent resize events on window:resize.
  • Use autosize: { type: "fit", contains: "padding" }. This ensures that the width / height correspond to the entire chart, not the plotting area.

Click Open and resize the window to see this example in action.

<!DOCTYPE html>
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@3"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@5"></script>
<div
id="view"
style="position: fixed; left: 0; right: 0; top: 0; bottom: 0"
></div>
<script>
const spec = {
$schema: "https://vega.github.io/schema/vega/v5.json",
description: "Stock prices of 5 Tech Companies over Time.",
autosize: { type: "fit", contains: "padding" },
padding: 5,
style: "cell",
signals: [
{
name: "width",
init: "containerSize()[0]",
on: [{ events: "window:resize", update: "containerSize()[0]" }]
},
{
name: "height",
init: "containerSize()[1]",
on: [{ events: "window:resize", update: "containerSize()[1]" }]
}
],
data: [
{
name: "source_0",
url: "https://vega.github.io/editor/data/stocks.csv",
format: { type: "csv", parse: { date: "date" } },
transform: [
{
type: "formula",
as: "year_date",
expr: 'datetime(year(datum["date"]), 0, 1, 0, 0, 0, 0)'
},
{
type: "aggregate",
groupby: ["year_date", "symbol"],
ops: ["mean"],
fields: ["price"],
as: ["mean_price"]
}
]
},
{
name: "data_0",
source: "source_0",
transform: [
{
type: "filter",
expr: 'datum["year_date"] !== null && !isNaN(datum["year_date"])'
}
]
}
],
marks: [
{
name: "layer_0_pathgroup",
type: "group",
from: {
facet: {
name: "faceted_path_layer_0_main",
data: "source_0",
groupby: ["symbol"]
}
},
encode: {
update: {
width: { field: { group: "width" } },
height: { field: { group: "height" } }
}
},
marks: [
{
name: "layer_0_marks",
type: "line",
style: ["line"],
sort: { field: 'datum["year_date"]' },
from: { data: "faceted_path_layer_0_main" },
encode: {
update: {
stroke: { scale: "color", field: "symbol" },
x: { scale: "x", field: "year_date" },
y: { scale: "y", field: "mean_price" },
defined: {
signal:
'datum["year_date"] !== null && !isNaN(datum["year_date"]) && datum["mean_price"] !== null && !isNaN(datum["mean_price"])'
}
}
}
}
]
},
{
name: "layer_1_marks",
type: "symbol",
style: ["point"],
from: { data: "data_0" },
encode: {
update: {
opacity: { value: 1 },
fill: { scale: "color", field: "symbol" },
x: { scale: "x", field: "year_date" },
y: { scale: "y", field: "mean_price" }
}
}
}
],
scales: [
{
name: "x",
type: "time",
domain: {
fields: [
{ data: "source_0", field: "year_date" },
{ data: "data_0", field: "year_date" }
]
},
range: [0, { signal: "width" }]
},
{
name: "y",
type: "linear",
domain: {
fields: [
{ data: "source_0", field: "mean_price" },
{ data: "data_0", field: "mean_price" }
]
},
range: [{ signal: "height" }, 0],
nice: true,
zero: true
},
{
name: "color",
type: "ordinal",
domain: {
fields: [
{ data: "source_0", field: "symbol" },
{ data: "data_0", field: "symbol" }
],
sort: true
},
range: "category"
}
],
axes: [
{
scale: "x",
orient: "bottom",
gridScale: "y",
grid: true,
tickCount: { signal: "ceil(width/40)" },
domain: false,
labels: false,
maxExtent: 0,
minExtent: 0,
ticks: false,
zindex: 0
},
{
scale: "y",
orient: "left",
gridScale: "x",
grid: true,
tickCount: { signal: "ceil(height/40)" },
domain: false,
labels: false,
maxExtent: 0,
minExtent: 0,
ticks: false,
zindex: 0
},
{
scale: "x",
orient: "bottom",
grid: false,
title: "date (year)",
labelFlush: true,
labelOverlap: true,
tickCount: { signal: "ceil(width/40)" },
encode: {
labels: {
update: { text: { signal: "timeFormat(datum.value, '%Y')" } }
}
},
zindex: 0
},
{
scale: "y",
orient: "left",
grid: false,
title: "Mean of price",
labelOverlap: true,
tickCount: { signal: "ceil(height/40)" },
zindex: 0
}
],
legends: [
{
stroke: "color",
gradientLength: { signal: "clamp(height, 64, 200)" },
symbolType: "circle",
title: "symbol",
fill: "color",
encode: { symbols: { update: { opacity: { value: 1 } } } }
}
]
};
const view = new vega.View(vega.parse(spec), {
renderer: "canvas", // renderer (canvas or svg)
container: "#view", // parent DOM container
hover: true // enable hover processing
});
view.runAsync();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment