Подтвердить что ты не робот

Может ли d3.js нарисовать два диаграммы рассеяния на одном графике, используя данные из того же источника?

Все обучающие материалы d3, которые я нашел, используют данные, расположенные в массивах объектов, из которых они набирают одну точку для каждого объекта в массиве. Данные приведены в следующей структуре:

data = [
     {id: 1, x: 4, y: 10, type: 1},
     {id: 2, x: 5, y: 20, type: 2}
     ...
]

Значения x и y используются для создания диаграммы рассеяния. Параметр type используется для изменения цвета каждой точки. См. Этот пример jsfiddle для примера: http://jsfiddle.net/uxbHv/

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

dataSet = [
     {xVar: 5, yVar1: 90, yVar2: 22},
     {xVar: 25, yVar1: 30, yVar2: 25},
     {xVar: 45, yVar1: 50, yVar2: 80},
     {xVar: 65, yVar1: 55, yVar2: 9},
     {xVar: 85, yVar1: 25, yVar2: 95}
]

Я могу нарисовать xVar отдельно против yVar1 или yVar2, но я не могу понять, как получить оба на одном графике: http://jsfiddle.net/634QG/

4b9b3361

Ответ 1

Общее правило при использовании data-join заключается в том, что вы хотите, чтобы сопоставление "один-к-одному" от данных к элементам. Итак, если у вас есть две серии в вашей диаграмме рассеяния, вам понадобятся два элемента контейнера (например, G elements) для представления серии. Поскольку в настоящее время у вас есть только один массив data, вы также захотите использовать array.map для преобразования представления данных в два параллельных массива с тем же представление. Таким образом, вам не нужно дублировать код для каждой серии.

Скажите, что ваши данные были представлены в CSV файле с одним столбцом для значений x и несколькими другими столбцами для y-значений для каждой серии:

x,y1,y2
5,90,22
25,30,25
45,50,80
65,55,9
85,25,95

Если вы хотите, чтобы код был полностью общим, вам сначала нужно вычислить имена серий, например ["y1", "y2"]. (Если вы добавили третий столбец в файл CSV, это может быть ["y1", "y2", "y3"].) Вы можете вычислить имена, используя d3.keys, которые извлекает именованные свойства из объекта. Например, d3.keys({foo: 1, bar: 2}) возвращает ["foo", "bar"].

// Compute the series names ("y1", "y2", etc.) from the loaded CSV.
var seriesNames = d3.keys(data[0])
    .filter(function(d) { return d !== "x"; })
    .sort();

Теперь, когда у вас есть имена серий, вы можете создать массив массивов точек. Внешний массив представляет собой серию (из которых две), а внутренние массивы хранят точки данных. Вы можете одновременно преобразовать точки в согласованное представление (объекты с параметрами x и y), что позволяет повторно использовать код по серии.

// Map the data to an array of arrays of {x, y} tuples.
var series = seriesNames.map(function(series) {
  return data.map(function(d) {
    return {x: +d.x, y: +d[series]};
  });
});

Обратите внимание, что в этом коде используется оператор + для принуждения значений CSV к номерам. (CSV файлы являются нетипизированными, поэтому они изначально являются строками.)

Теперь, когда вы перенесли данные в обычный формат, вы можете создавать элементы G для каждой серии, а затем крутить элементы внутри каждой точки. Полученная структура SVG будет выглядеть так:

<g class="series">
  <circle class="point" r="4.5" cx="1" cy="2"/>
  <circle class="point" r="4.5" cx="3" cy="2"/>
  …
</g>
<g class="series">
  <circle class="point" r="4.5" cx="5" cy="4"/>
  <circle class="point" r="4.5" cx="7" cy="6"/>
  …
</g>

И соответствующий код D3:

// Add the points!
svg.selectAll(".series")
    .data(series)
  .enter().append("g")
    .attr("class", "series")
    .style("fill", function(d, i) { return z(i); })
  .selectAll(".point")
    .data(function(d) { return d; })
  .enter().append("circle")
    .attr("class", "point")
    .attr("r", 4.5)
    .attr("cx", function(d) { return x(d.x); })
    .attr("cy", function(d) { return y(d.y); });

Ive также добавил немного кода, чтобы присвоить каждой серии уникальный цвет, добавив стиль заливки в содержащий G элемент. Конечно, есть много разных способов сделать это. (Например, вы можете быть более конкретными относительно цвета для каждой серии.) Ive также не учитывал код, который вычисляет домены ваших x и y масштабов (а также рендеринг осей), но если вы хотите увидеть весь рабочий пример:

Ответ 2

Поместите два круга для каждой точки данных в один элемент svg:g. Это создает взаимно однозначное сопоставление данных для элементов, но все же позволяет показывать две разные точки.

var nodeEnter = vis1.selectAll("circle")
      .data(dataSet)
      .enter()
      .insert("svg:g");

nodeEnter.insert("svg:circle")
           .attr("cx", function (d) { return 100 - d.xVar})
           .attr("cy", function (d) { return 100 - d.yVar1})
           .attr("r", 2)
           .style("fill", "green");

nodeEnter.insert("svg:circle")
           .attr("cx", function (d) { return 100 - d.xVar})
           .attr("cy", function (d) { return 100 - d.yVar2})
           .attr("r", 2)
           .style("fill", "blue");

Работа JSFiddle.