D3.js - Stacked Barchart จาก JSON?
ฉันพยายามสร้างซอนี้ขึ้นมาใหม่: https://jsfiddle.net/1c5eqrp3/3/
ในบริบทของแผนภูมิแท่งแบบเรียงซ้อนแนวนอนที่ฉันสร้างโดยใช้ข้อมูลของฉัน
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>
ทุกอย่างเป็นไปได้ด้วยดีจนกระทั่งฉันพยายามอ่าน bar1Data ที่ฉันสร้างขึ้น
ตอนนี้ฉันได้รับข้อผิดพลาดต่อไปนี้:
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 ฉันได้ลองใช้ตัวอย่างต่างๆโดยใช้ d3.v4 แต่ไม่สามารถใช้งานได้ นี่เป็นตัวอย่างที่เรียบง่ายและมีน้ำหนักเบาที่สุดที่ฉันพบ แต่ยังไม่รวมตาชั่ง (ซึ่งฉันหวังว่าจะใส่ในภายหลัง)
คุณช่วยฉันแก้ปัญหานี้พร้อมคำอธิบายได้ไหม
คำตอบ
ในคุณกำลังตั้งความกว้างของแถบกับวัตถุทั้งหมด.attr('width', function(d){ return d;})
d
คุณต้องเข้าใจว่า.data(bar1Data)
สร้างหนึ่งรายการต่อค่าของbar1Data
และค่านั้นสามารถเข้าถึงได้เช่นเดียวกับd
ในฟังก์ชันเหล่านั้นทั้งหมด นั่นหมายความว่าทันทีที่คุณผ่านไป.data(bar1Data)
คุณไม่ควรสัมผัสวัตถุนั้นโดยตรงอีกต่อไป
จากข้อมูลของคุณฉันดูเหมือนจะเข้าใจแล้วว่าคุณต้องการใช้ค่าของรายการก่อนหน้าทั้งหมดเพื่อคำนวณผลรวมสะสมจนถึงจุดนั้น ฉันจะนำสิ่งนั้นไปใช้ในคำตอบ แต่ก็อยากจะชี้ให้คุณเห็นstack = d3.stack()
ซึ่งมันก็เพื่อคุณ
โปรดทราบด้วยว่าค่าของคุณใหญ่เกินไป คุณต้องแปลงโดยใช้โดเมนมิฉะนั้นคุณจะได้รับหนึ่งพิกเซลต่อหนึ่งดอลลาร์ (หรือหน่วยเงินอื่น ๆ ) ซึ่งหมายความว่าแถบจะดึงความกว้างของจอภาพไปทางขวา 100 เท่า
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>