简体   繁体   中英

D3.js - Stacked Barchart from JSON?

I have been trying to recreate this fiddle: https://jsfiddle.net/1c5eqrp3/3/

In the context of a horizontal stacked bar chart that I am building using my data.

 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>

All was going well, until I tried to get it to read the bar1Data I created.

Now, I am getting the following errors:

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

I have been greatly struggling to create a stacked horizontal bar chart using d3.v5. I have been trying various examples using d3.v4 but I have not been able to get them to work. This was the simplest, most light-weight example I have found. But it does not yet include scales (which I shall hopefully put in a little later).

Could you please help me to solve this issue with an explanation?

In .attr('width', function(d){ return d;}) , you're setting the width of the bar to the entire object d . You need to understand that .data(bar1Data) creates one entry per value of bar1Data , and that that value is accessible as d in all those functions. That means that, as soon as you've passed .data(bar1Data) , you shouldn't directly touch that object anymore.

Now, from your data I seem to understand that you want to use the values of all preceding entries to calculate the cumulative sum up to that point. I will implement that in the answer, but would also like to point you towards stack = d3.stack() , which does it for you.

Note also that your values are too large. You need to transform them using a domain, otherwise you get one pixel per dollar (or other unit of money), which means the bars are drawn 100x the width of your monitor to the right.

 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM