D3.js - Stacked Barchart dari JSON?
Saya telah mencoba membuat ulang biola ini: https://jsfiddle.net/1c5eqrp3/3/
Dalam konteks diagram batang bertumpuk horizontal yang saya buat menggunakan data saya.
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>
Semua berjalan dengan baik, sampai saya mencoba untuk membaca bar1Data yang saya buat.
Sekarang, saya mendapatkan kesalahan berikut:
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
Saya telah berjuang keras untuk membuat diagram batang horizontal bertumpuk menggunakan d3.v5. Saya telah mencoba berbagai contoh menggunakan d3.v4 tetapi saya belum bisa membuatnya berfungsi. Ini adalah contoh paling sederhana dan paling ringan yang pernah saya temukan. Tapi itu belum termasuk timbangan (yang mudah-mudahan akan saya masukkan nanti).
Bisakah Anda membantu saya menyelesaikan masalah ini dengan penjelasan?
Jawaban
Di .attr('width', function(d){ return d;})
, Anda mengatur lebar bilah ke seluruh objek d
. Anda perlu memahami bahwa .data(bar1Data)
membuat satu entri per nilai bar1Data
, dan nilai itu dapat diakses seperti d
di semua fungsi tersebut. Artinya, begitu Anda melewatinya .data(bar1Data)
, Anda tidak boleh langsung menyentuh benda itu lagi.
Sekarang, dari data Anda, saya sepertinya memahami bahwa Anda ingin menggunakan nilai dari semua entri sebelumnya untuk menghitung jumlah kumulatif hingga titik itu. Saya akan menerapkannya dalam jawaban, tetapi juga ingin mengarahkan Anda ke stack = d3.stack()
, yang melakukannya untuk Anda.
Perhatikan juga bahwa nilai Anda terlalu besar. Anda perlu mengubahnya menggunakan domain, jika tidak, Anda mendapatkan satu piksel per dolar (atau unit uang lainnya), yang berarti batang ditarik 100x lebar monitor Anda ke kanan.
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>