D3.js - JSON'dan Yığınlanmış Barchart?

Aug 19 2020

Bu kemanı yeniden yaratmaya çalışıyorum: https://jsfiddle.net/1c5eqrp3/3/

Verilerimi kullanarak oluşturduğum yatay yığılmış çubuk grafik bağlamında.

var bar1Data = [{
    position: 1,
    label: '70k',
    value: 1708026
  },
  {
    position: 2,
    label: '71K - 149K',
    value: 1915059
  },
];

//sort bars based on value
bar1Data = bar1Data.sort(function(a, b) {
  return d3.ascending(a.position, b.position);
})

var colors = ['green', 'blue'];

var bars = d3.select('#bars')
  .append('svg')
  .attr('width', 800)
  .attr('height', 200);

bars.selectAll('rect')
  .data(bar1Data)
  .enter()
  .append('rect')
  .attr('width', function(d) {
    return d;
  })
  .attr('x', function(d, i) {
    return sum(bar1Data.value, 0, i);
  })
  .attr('fill', function(d, i) {
    return colors[i];
  })
  .attr('y', 0)
  .attr('height', 100);

function sum(array, start, end) {
  var total = 0;
  for (var i = start; i < end; i++) total += array[i];
  return total;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="bar"></div>

Oluşturduğum bar1Data'yı okumaya çalışana kadar her şey yolunda gidiyordu.

Şimdi aşağıdaki hataları alıyorum:

Error: <rect> attribute width: Expected length, "[object Object]".
(anonymous) @ d3.js:1211
selection_each @ d3.js:1176
selection_attr @ d3.js:1233
(anonymous) @ bars3.js:23
Promise.then (async)
(anonymous) @ bars3.js:1
bars3.js:33 Uncaught (in promise) TypeError: Cannot read property '0' of undefined
    at sum (bars3.js:33)
    at SVGRectElement.<anonymous> (bars3.js:26)
    at SVGRectElement.<anonymous> (d3.js:1209)
    at Selection.selection_each [as each] (d3.js:1176)
    at Selection.selection_attr [as attr] (d3.js:1233)
    at bars3.js:25

D3.v5 kullanarak yığılmış yatay bir çubuk grafik oluşturmak için büyük çaba harcıyorum. D3.v4 kullanarak çeşitli örnekler deniyordum ama onları çalıştırmayı başaramadım. Bu bulduğum en basit, en hafif örnekti. Ancak henüz ölçekleri içermiyor (umarım biraz sonra koyacağım).

Lütfen bu sorunu bir açıklama ile çözmeme yardım eder misiniz?

Yanıtlar

1 RubenHelsloot Aug 19 2020 at 12:48

İçinde .attr('width', function(d){ return d;}), çubuğun genişliğini tüm nesneye ayarlıyorsunuz d. Bunun .data(bar1Data)değeri başına bir girdi oluşturduğunu bar1Datave bu değerin dtüm bu işlevlerde olduğu gibi erişilebilir olduğunu anlamanız gerekir . Bu .data(bar1Data), yanınızdan geçer geçmez , artık o nesneye doğrudan dokunmamanız gerektiği anlamına gelir .

Şimdi, verilerinizden, o noktaya kadar kümülatif toplamı hesaplamak için önceki tüm girişlerin değerlerini kullanmak istediğinizi anlıyorum. Bunu cevapta uygulayacağım, ama aynı zamanda sizi işaret etmek istiyorum stack = d3.stack(), bu sizin için yapar.

Değerlerinizin çok büyük olduğunu da unutmayın. Bunları bir etki alanı kullanarak dönüştürmeniz gerekir, aksi takdirde dolar başına bir piksel (veya başka bir para birimi) elde edersiniz, bu da çubukların monitörünüzün genişliğinin 100 katı sağa çekildiği anlamına gelir.

var bar1Data = [{
    position: 1,
    label: '70k',
    value: 50
  },
  {
    position: 2,
    label: '71K - 149K',
    value: 40
  },
];

//sort bars based on value
bar1Data = bar1Data.sort(function(a, b) {
  return d3.ascending(a.position, b.position);
})

var colors = ['green', 'blue'];

var bars = d3.select('#bars')
  .append('svg')
  .attr('width', 800)
  .attr('height', 200);

bars.selectAll('rect')
  .data(bar1Data)
  .enter()
  .append('rect')
  .attr('width', function(d) {
    return d.value;
  })
  .attr('x', function(d, i) {
    // Note that I use `.map` here to take only the `.value` attribute
    // from the data and create an array of numbers.
    return sum(bar1Data.map((e) => e.value), 0, i);
  })
  .attr('fill', function(d, i) {
    return colors[i];
  })
  .attr('y', 0)
  .attr('height', 100);

function sum(array, start, end) {
  var total = 0;
  for (var i = start; i < end; i++) total += array[i];
  return total;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id='bars'>
</div>