Как нарисовать точечный график с несколькими значениями y для каждого значения x? - PullRequest
1 голос
/ 15 апреля 2019

У меня есть данные в следующем формате, который я хотел бы построить с использованием d3:

data = [
        { x: 0.2, y: [ 1, 2, 4 ] },
        { x: 0.3, y: [ 2 ] },
        { x: 0.5, y: [ 4, 7, 8, 12, 19 ] }
        { x: 1.4, y: [ 1, 3 ] }
       ]

Обычно значения по оси Y являются целыми числами, но здесь они являются массивами, поэтому следующий код неработать по назначению:

svg.selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
        .attr("cx", function(d){ return x(d.x) })
        .attr("cy", function(d){ return y(d.y) })
        .attr("r", 2)

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

Другие подобные вопросы на этом сайте касаются только данных, которыеимеет фиксированное количество значений по оси Y, поэтому я не нашел способа изменить эти решения для этой проблемы.

Ответы [ 2 ]

1 голос
/ 15 апреля 2019

Традиционным ответом D3 здесь будет добавление группы для каждого объекта, а затем добавление круга для каждого значения y для каждой группы.

Однако, поскольку вы, похоже, начинающий D3 (поправьте меняесли я не прав), я бы предложил создать только один массив объектов, который вы можете передать data.

. Есть несколько способов сделать это, например:

const newData = data.reduce(function(a, c) {
  return a.concat(c.y.map(function(d) {
    return {
      x: c.x,
      y: d
    }
  }));
}, []);

Вот ваш код с этим изменением:

const data = [{
    x: 0.2,
    y: [1, 2, 4]
  },
  {
    x: 0.3,
    y: [2]
  },
  {
    x: 0.5,
    y: [4, 7, 8, 12, 19]
  }, {
    x: 1.4,
    y: [1, 3]
  }
];

const newData = data.reduce(function(a, c) {
  return a.concat(c.y.map(function(d) {
    return {
      x: c.x,
      y: d
    }
  }));
}, []);

const x = d3.scaleLinear()
  .domain([0, 2])
  .range([0, 300]);

const y = d3.scaleLinear()
  .domain([0, 20])
  .range([0, 150]);

const svg = d3.select("svg");
svg.selectAll("circle")
  .data(newData)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return x(d.x)
  })
  .attr("cy", function(d) {
    return y(d.y)
  })
  .attr("r", 4)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
0 голосов
/ 15 апреля 2019

Почему бы не попробовать развернуть массив данных раньше?Это должно быть легко обрабатывать.

data = [{
    x: 0.2,
    y: [1, 2, 4]
  },
  {
    x: 0.3,
    y: [2]
  },
  {
    x: 0.5,
    y: [4, 7, 8, 12, 19],
  },
  {
    x: 1.4,
    y: [1, 3]
  }
];
unwrappedData = [];

for (b in data) {
  var temp = data[b].y.map((foo) => {
    return {
      x: data[b].x,
      y: foo
    }
  })
  unwrappedData = unwrappedData.concat(temp);

}

console.log(unwrappedData);

var svg = d3.select("body").append("svg")
  .attr("width", 100)
  .attr("height", 100)
  .style("margin-top", "58px");

svg.selectAll("circle")
  .data(unwrappedData)
  .enter()
  .append("circle")
  .attr("cx", function(d) {
    return d.x
  })
  .attr("cy", function(d) {
    return d.y
  })
  .attr("r", 2)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Кроме того, атрибуты cx и cy не должны возвращать d.x и d.y вместо этого?

...