У меня есть данные, структурированные как JSON, которые выглядят следующим образом (реальные данные намного больше, и каждый экземпляр имеет гораздо больше переменных и атрибутов):

var json = [
{
    "CLIN": "1",
    "cost": 257,
},
{
    "CLIN": "1",
    "cost": 846,
},
{
    "CLIN": "2",
    "cost": 162         
},
{
    "CLIN": "2",
    "cost": 984
}]

Вот как выглядит мой JS-код:

   <script>
        var margin = {top: 20, right: 160, bottom: 35, left: 30};

        var width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

        var svg = d3.select('body')
                    .append('svg')
                    .attr('width', width + margin.left + margin.right)
                    .attr('height', height + margin.top + margin.bottom)
                    .append('g')
                    .attr('transform', 'translate('+ margin.left + "," + margin.top + ")");

        var dataByCLIN = d3.nest()
            .key(function(d) {return d.CLIN; })
            .entries(json);

  </script>

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

        var bars = svg.selectAll('rect')
                    .data(dataByCLIN)
                    .enter()
                        .append('rect')
                        .attr('width', function(d) { return d.values.cost; })
                        .attr('height', 10)
                        .attr('y', function(d, i) { return i * 20; });

Если я запустил приведенный ниже код с выбором различных массивов:

console.log(dataByCLIN[0].values[0].cost)

Он возвращает нужные мне значения, но код:

.attr('width', function(d, i, j) { return d[i].values[j].cost; 

Является недействительным. Консоль выдает ошибку

Cannot read property 'values' of undefined

Я знаю, как выбрать нужные мне данные, но не знаю правильного форматирования для передачи этих данных в функцию d3.

0
FRY-9C 25 Май 2018 в 19:22

1 ответ

Лучший ответ

Что вы можете сделать, так это использовать for/forEach для ваших данных dataByCLIN и создать rects внутри каждого цикла следующим образом:

var bars = svg.selectAll('.rects');
dataByCLIN.forEach(function(d,i1) {
  bars.data(d.values).enter().append('rect').attr('class', 'rects')
    .attr('width', function(d) {
      return d.cost;
    })
    .attr('height', 10)
    .attr('y', function(d, i) {
      return (i+i1+i1+1) * 20 - 20;
    });
});

Вот скрипка:

var json = [{
    "CLIN": "1",
    "cost": 257,
  },
  {
    "CLIN": "1",
    "cost": 846,
  },
  {
    "CLIN": "2",
    "cost": 162

  },
  {
    "CLIN": "2",
    "cost": 984
  }
];


var margin = {
  top: 20,
  right: 160,
  bottom: 35,
  left: 30
};

var width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

var svg = d3.select('body')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', 'translate(' + margin.left + "," + margin.top + ")");

var dataByCLIN = d3.nest()
  .key(function(d) {
    return d.CLIN;
  })
  .entries(json);

var bars = svg.selectAll('.rects');
dataByCLIN.forEach(function(d, i1) {
  bars.data(d.values).enter().append('rect').attr('class', 'rects')
    .attr('width', function(d) {
      return d.cost;
    })
    .attr('height', 10)
    .attr('y', function(d, i) {
      return (i + i1 + i1 + 1) * 20 - 20;
    });
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
1
Aditya 25 Май 2018 в 17:27