Использование вложенных данных с D3.js - PullRequest
3 голосов
/ 18 августа 2011

Я пытаюсь отобразить красивый линейный график, используя D3.У меня проблема с форматом данных.

У меня есть следующие данные (в качестве примера):

var data = [
    {
      label: "name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    },{
      label: "another name",
      data: [[14444123, 0.012321312],
             [14444123, 0.012321312],
             [14444123, 0.012321312], ...]
    }
];

Каждая запись содержит как ее название, так и данныеатрибут с массивом точек (каждая точка представлена ​​в виде массива, где item [0] - это x отметка времени, а item [1] - значение).

Моя проблема в том, что она работает неправильно.

Это код D3, который у меня есть на данный момент:

var w = options.width,
    h = options.height,
    p = options.padding,
    x = d3.scale.linear()
        .domain([0, 1])
        .range([0, w]),
    y = d3.scale.linear()
        .domain([options.ydomainstart, options.ydomainend])
        .range([h, 0]);

var vis = d3.select(options.element)
    .data(data)
   .append("svg:svg")
    .attr("width", w + p * 2)
    .attr("height", h + p * 2)
   .append("svg:g");

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", p)
    .attr("y1", 0)
    .attr("y2", h - p);

vis.append("svg:line")
    .attr("stroke", '#808080')
    .attr("x1", p)
    .attr("x2", w)
    .attr("y1", h - p)
    .attr("y2", h - p);

var rules = vis.selectAll("g.rule")
    .data(data)
   .enter()
   .append("svg:text")
    .attr("x", w - p)
    .attr("y", function(d, i) { return 15 + i*12; })
    .attr("text-anchor", "end")
    .attr("font-size", 12)
    .attr("fill", function(d, i) { return defaultColors[i % 5]; })
    .text(function(d) { return d.label;});

var lines = rules.data(function(d, i) {
        return d.data;
    })
   .append("svg:path")
    .attr("stroke", function(d, i) { return defaultColors[i % 5]; })
    .attr("d", d3.svg.line()
    .x(function(d) {
        return x(d[0]);
    })
    .y(function(d) {
        return y(d[1]);
    }));

Проблема, с которой я столкнулся в этой части кода:

.x(function(d) {
    return x(d[0]);
})
.y(function(d) {
    return y(d[1]);
}));

Данные внутри 'd'НЕ является массивом точек [x, y], но вместо этого каждое значение внутри каждого массива.

То есть, в первом элементе d содержит координату x, во втором - координату y, в третьем элементе, он содержит координату x в следующей точке и т. д.

Это похоже на то, что он рекурсивно входит в массив, а затем снова для каждого значения внутри.

Я понятия не имею, как это исправить.

1 Ответ

10 голосов
/ 15 сентября 2011

Здесь есть несколько проблем.

Сначала вы добавляете элемент svg: path к элементу svg: text.Мне кажется, что вы пытаетесь создать элемент svg: g с классом "rule", но ваш код определяет выделение rules как набор элементов svg: text.Сначала создайте элементы svg: g, а затем добавьте элементы svg: text:

var rules = vis.selectAll("g.rule")
    .data(data)
  .enter().append("svg:g")
    .attr("class", "rule");

rules.append("svg:text")
    …

Вторая проблема заключается в том, что оператор данных вычисляется один раз для каждой группы, а не один раз для каждого элемента.Подробнее см. Раздел «Работа с выборками» в справочнике по API.У вас есть один элемент svg: svg в vis, поэтому у вас есть одна группа в rules, и поэтому ваша функция данных вызывается только один раз:

function(d, i) {
  return d.data;
}

Затем полученные элементы данных отображаются навыбор rules, который уже определил данные из предыдущего selectAll и добавляет его при создании.

Простое исправление заключается в использовании оператора map вместо оператора данных, которыйоценивается один раз для элемента, а не один раз для группы.

rules.append("svg:path")
    .map(function(d) { return d.data; })
    .attr("d", d3.svg.line()
    …

В качестве альтернативы, вы можете передать данные непосредственно в генератор строк, но для этого необходимо заранее объявить генератор строк, а не вставлять их в строку:

var line = d3.svg.line()
    .x(function(d) { return x(d[0]); })
    .y(function(d) { return y(d[1]); });

rules.append("svg:path")
    .attr("d", function(d) { return line(d.data); })
    …

Надеюсь, это помогло!

...