Я пытаюсь реализовать диаграмму потоковых данных в реальном времени, которая считывает страницу, которая выводит последние несколько точек данных каждую секунду, используя плагин chart.js-плагин-потоковая передача от nagix.
Я читаю массив в URL-адресе, потому что «разрешение» диаграммы меняется в зависимости от того, какой датчик подключен к серверной части. Некоторые из них выдают 1 раз в секунду, а некоторые — 10 раз в секунду, а во втором случае обновление графика 10 раз в секунду не кажется хорошей идеей, как из-за вычислительной мощности (старые компьютеры), так и из-за количества запросов, отправленных на датчики.
Таким образом, мой URL-адрес выводит массив объектов для последних 20 точек данных (примерно от 2 до 20 секунд данных), и я обновляю диаграмму 1 раз в секунду.
Я надеялся, что диаграмма просто добавит только новые точки, но у меня странное поведение. Я проверил временные метки, и они верны.
Массив данных извлекается с помощью простого вызова jQuery $.get()
к URL-адресу представления Django, который генерирует массив при каждом вызове.
Это пример вывода URL-адреса за вызов для датчика 1/секунда:
[
{y: 0.74, x: 1558531380957},
{y: 0.96, x: 1558531379950},
{y: 1.08, x: 1558531378942},
{y: 1.11, x: 1558531377939},
{y: 1.13, x: 1558531376932},
{y: 1.1, x: 1558531375930},
{y: 0.59, x: 1558531374914},
{y: 0.75, x: 1558531373911},
{y: 1.25, x: 1558531372902},
{y: 0.75, x: 1558531371898},
{y: 0.85, x: 1558531370893},
{y: 0.59, x: 1558531369889},
{y: 0.4, x: 1558531368887},
{y: 1.08, x: 1558531367879},
{y: 1.31, x: 1558531366871},
{y: 0.63, x: 1558531365866},
{y: 1.19, x: 1558531364859},
{y: 1.26, x: 1558531363854},
{y: 0.92, x: 1558531362848},
{y: 1.31, x: 1558531361837},
]
В следующий раз, когда он будет вызван, вывод удалит первую точку, массив будет «прокручиваться», и в конце появится 1 новая точка.
Объекты внутри массива имеют формат: {"y": <float>, "x": <timestamp-in-ms>}
Моя конфигурация диаграммы:
$(document).ready(function() {
var chartColors = {
red: 'rgb(255, 99, 132)',
blue: 'rgb(54, 162, 235)'
};
var color = Chart.helpers.color;
var config = {
type: 'line',
data: {
datasets: [{
label: 'Z-Score',
backgroundColor: color(chartColors.blue).alpha(0.75).rgbString(),
borderColor: chartColors.red,
fill: false,
lineTension: 0,
data: []
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
title: {
display: false,
},
scales: {
xAxes: [{
type: 'realtime',
realtime: {
duration: 60000,
refresh: 1000,
delay: 2000,
pause: false,
ttl: undefined,
frameRate: 48,
onRefresh: function(chart) {
var data = []
$.get( "{% url 'live_z_score' %}", function(zScoreJSON) {
data = zScoreJSON
Array.prototype.push.apply(
chart.data.datasets[0].data, data
);
});
}
}
}],
yAxes: [{
scaleLabel: {
display: true,
labelString: 'value'
}
}]
},
tooltips: {
mode: 'nearest',
intersect: false
},
hover: {
mode: 'nearest',
intersect: false
}
}
};
var ctx = document.getElementById('myChart').getContext('2d');
window.myChart = new Chart(ctx, config);
});
На данный момент это работает, за исключением того, что у меня странное поведение, когда линия соединяет первую точку со всеми последующими точками:
Пример GIF (размер GIF слишком велик, он длится около 40 секунд)
Кажется, что график создает новую строку каждый раз, когда он извлекает новые данные, вместо того, чтобы сбрасывать предыдущую строку? Я не уверен, как он обрабатывает данные внутри.
На данный момент я точно не знаю, в чем может быть проблема. Диаграмма как бы работает, так как она создает линию, которая точно соответствует графику, но тогда кажется, что она соединяет первую точку в массиве вместе с последней точкой в массиве. Вы можете увидеть это поведение в GIF.
Это потому, что вы добавляете 20 точек данных onRefresh()
каждую секунду, но только одна точка данных из 20 точек является новой, а остальные уже вставлены. Этот плагин не выполняет дедупликацию данных, даже если существуют одни и те же данные с одной и той же отметкой времени, поэтому вы видите, как линия повторяет одни и те же точки снова и снова.
Обходным путем может быть сохранение последней временной метки в вашем массиве при ее вставке и отфильтровывание более старых данных при следующем вызове onRefresh
, чтобы в chart.data.datasets[0].data
передавались только новые данные.