Линейная диаграмма NVD3 с данными в реальном времени
У меня действительно простая линейная диаграмма, написанная с использованием NVD3.js. Я написал простую перерисовку по таймеру, извлеченную из примеров, которые я видел, но получаю ошибку
Uncaught TypeError: Не удается прочитать свойство 'y' из undefined
JS
var data = [{
"key": "Long",
"values": getData()
}];
var chart;
nv.addGraph(function () {
chart = nv.models.cumulativeLineChart()
.x(function (d) { return d[0] })
.y(function (d) { return d[1] / 100 })
.color(d3.scale.category10().range());
chart.xAxis
.tickFormat(function (d) {
return d3.time.format('%x')(new Date(d))
});
chart.yAxis
.tickFormat(d3.format(',.1%'));
d3.select('#chart svg')
.datum(data)
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function redraw() {
d3.select('#chart svg')
.datum(data)
.transition().duration(500)
.call(chart);
}
function getData() {
var arr = [];
var theDate = new Date(2012, 01, 01, 0, 0, 0, 0);
for (var x = 0; x < 30; x++) {
arr.push([theDate.getTime(), Math.random() * 10]);
theDate.setDate(theDate.getDate() + 1);
}
return arr;
}
setInterval(function () {
var long = data[0].values;
var next = new Date(long[long.length - 1][0]);
next.setMonth(next.getMonth() + 1)
long.shift();
long.push([next.getTime(), Math.random() * 100]);
redraw();
}, 1500);
Ответы
Ответ 1
Второй ответ (после комментария)
Я посмотрел на источник для cumulativeLineChart. Вы можете увидеть, что свойство display.y создается во время создания диаграммы. Он опирается на частный метод: "индексировать". Если какая-либо производная этого метода была обнародована, возможно, вы могли бы сделать что-то вроде chart.reindexify()
перед перерисованием.
Как временное обходное решение, вы можете воссоздать диаграмму с нуля при каждом обновлении. Если вы удалите переход, это, похоже, работает нормально. Пример jsfiddle: http://jsfiddle.net/kaliatech/PGyKF/.
Первый ответ
Я считаю, что есть ошибка в cumulativeLineChart. Похоже, что cumulativeLineChart динамически добавляет свойство display.y к значениям данных в серии. Однако он не восстанавливает это свойство, когда новые значения добавляются в серию для перерисовки. Я даже не знаю, как это сделать, хотя я новичок в NVD3.
Вам действительно нужен CumulativeLineChart или нормальная линейная диаграмма? Если это так, мне пришлось внести следующие изменения в ваш код:
- Изменить cumulativeLineChart на lineChart
- Измените использование 2-мерных массивов данных, используя объекты данных (с x, y свойствами)
- (Я не достаточно знаком с NVD3, чтобы сказать, какие форматы данных ожидаются. 2D-массив, очевидно, работает для начальных нагрузок, но я думаю, что он не работает для последующих перерисовок. Вероятно, это связано с той же проблемой, что и вы имея с cumulativeLineChart. Я думал, что изменение объектов будет также фиксировать cumulativeLineChart, но это не похоже.)
Я также изменил следующее, хотя и не так важно:
-
Изменена функция getData до создать новый экземпляр Date, чтобы избежать неожиданных последствий обмена ссылкой, поскольку дата увеличивается.
-
Изменена функция интервала обновления для генерации новых данных с шагом в несколько дней (а не месяцев) с значениями y в том же диапазоне, что и функция getData.
Здесь работает jsfiddle с этими изменениями:
Ответ 2
Я нашел то, что считаю лучшим решением. Проблема возникает из-за того, что совокупная диаграмма устанавливает функцию y во время обработки. Всякий раз, когда вы хотите обновить график, сначала установите его на значение по умолчанию, которое возвращает правильный исходный y. В своей функции перерисовки сделайте это до обновления:
chart.y(function (d) { return d.y; });
Еще лучше было бы, если бы кумулятивная диаграмма могла сделать это сама для себя (сохранить исходную функцию доступа перед настройкой новой и вернуть ее перед повторной индексацией). Если у меня появится шанс, я попытаюсь исправить ошибку.
Ответ 3
Я столкнулся с той же проблемой. Я изменил функцию y() на строки из
.y(function(d) { return d.display.y })
к
.y(function(d) { return d.display ? d.display.y : d.y })
Это избавляет от ошибки. Очевидно, что он не будет отображать (несуществующее) индексированное значение в случае ошибки, но, по моему опыту, диаграмма снова обновляется с отображаемым дисплеем и выглядит корректно.