Потоковые данные
В этом уроке вы научитесь передавать новые данные в визуализацию Vega-Lite в потоковом режиме. Если вы пока не знакомы с Vega-Lite, сначала прочитайте вводный урок.
Мы будем использовать API View из Vega и обновлять данные методом change. Данные в Vega и Vega-Lite обновляются либо через взаимодействие с визуализацией, либо через явно заданные изменения. В обоих случаях данные проходят через среду выполнения Vega, которая оптимизирует обработку. Этот урок посвящён второму варианту: потоковой передаче данных без действий пользователя.
Чтобы использовать view.change, сначала укажите имя обновляемого источника данных: view.change('data', ... ). Это имя нужно задать в исходной спецификации, как описано в разделе именованных источников. Второй аргумент view.change определяет, какие данные добавить и какие удалить. Для добавления передайте массив записей с той же структурой, что у существующих данных. В нашем примере она выглядит так:
{
"x": number,
"y": number,
"category": number
}
Для удаления точек можно передать сами записи, аналогично добавлению выше (для этого вам нужно хранить эти записи), либо отобрать существующие данные по значениям полей и передать предикат в remove(). Здесь используется function (t) { return t.x < minimumX; }. Если вы знакомы с D3, эта схема insert и remove напоминает подход enter/exit.
Объединим эти операции:
var changeSet = vega
.changeset()
.insert(valueGenerator())
.remove(function (t) {
return t.x < minimumX;
});
view.change('table', changeSet).run();
Объект представления предоставляет метод встраивания, который помогает загружать спецификации Vega/Vega-Lite на веб-страницы. При успешном завершении он возвращает выполненный Promise с объектом, содержащим view и spec. Через view можно обратиться к описанному выше view.change, а spec содержит спецификацию Vega, скомпилированную из исходной спецификации Vega-Lite. При ошибке встраивания возвращается отклонённый Promise с объектом ошибки.
Для простоты мы генерируем данные, имитируя обновления в реальном времени. Этот код можно легко заменить запросом данных с сервера. В примере «реальное время» имитирует window.setInterval, периодически вызывающий view.change.
Ниже приведён JavaScript-код примера. Убедитесь, что ваша HTML-страница содержит элемент div с идентификатором 'chart'.
var vlSpec = {
$schema: 'https://vega.github.io/schema/vega-lite/v6.json',
data: {name: 'table'},
width: 400,
mark: 'line',
encoding: {
x: {field: 'x', type: 'quantitative', scale: {zero: false}},
y: {field: 'y', type: 'quantitative'},
color: {field: 'category', type: 'nominal'},
},
};
vegaEmbed('#chart', vlSpec).then(function (res) {
/**
* Создаёт новые записи с помощью случайного блуждания.
*/
function newGenerator() {
var counter = -1;
var previousY = [5, 5, 5, 5];
return function () {
counter++;
var newVals = previousY.map(function (v, c) {
return {
x: counter,
y: v + Math.round(Math.random() * 10 - c * 3),
category: c,
};
});
previousY = newVals.map(function (v) {
return v.y;
});
return newVals;
};
}
var valueGenerator = newGenerator();
var minimumX = -100;
window.setInterval(function () {
minimumX++;
var changeSet = vega
.changeset()
.insert(valueGenerator())
.remove(function (t) {
return t.x < minimumX;
});
res.view.change('table', changeSet).run();
}, 1000);
});
Новые данные могут менять компоновку, но Vega не всегда пересчитывает размеры диаграммы. Из-за этой оптимизации, например, оси могут оказаться обрезанными. Чтобы решить проблему, настройте autosize или явно вызывайте view.resize при обновлении данных.
На этом урок заканчивается: вы научились передавать новые данные в диаграмму в потоковом режиме. Для использования Vega-Lite с WebSocket в оригинале приведён демонстрационный проект «Vega-Lite with websockets». Другие визуализации можно найти в галерее, а дополнительные настройки — в документации.