Линейная диаграмма 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 })

Это избавляет от ошибки. Очевидно, что он не будет отображать (несуществующее) индексированное значение в случае ошибки, но, по моему опыту, диаграмма снова обновляется с отображаемым дисплеем и выглядит корректно.