vinayan
vinayan

Reputation: 1637

D3 Bar Chart with Variable X and Y(variable width and height for bars)

I am trying to draw a bar chart that will have variable width(based on Weight field in json) and height(based on frequency field in json) for bars based on the json data.

currently I am getting some result, but the there is some gap between bars. Seems I am doing the calculations for X or Width wrong.

Can someone point me in the right direction?

https://i.sstatic.net/mD92Z.jpg

The data looks like below.

var data = [{
        "letter": "A",
        "Weight": 10,
        "frequency": 60,
        "xPos": 2.5
    },
    {
        "letter": "B",
        "Weight": 10,
        "frequency": 25,
        "xPos": 15
    },
    {
        "letter": "C",
        "Weight": 20,
        "frequency": 55,
        "xPos": 40
    }
];

i have a codepen for the same below.

https://codepen.io/poorJSDev/pen/vbReOm

Upvotes: 1

Views: 1131

Answers (1)

Coderino Javarino
Coderino Javarino

Reputation: 2896

Since you need to know both current entry weight (for the width), as well as the sum of all previous entries' weights (for the offset), a pie layout seems like an unexpectedly decent fit for the task (since it provides start and end angles for the slices). All you need to do is to map the angle to the width.

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
  </style>
</head>

<body>
  <script>
    // Feel free to change or delete any of the code you see in this editor!
    var svg = d3.select("body").append("svg")
      .attr("width", 500)
      .attr("height", 200)

    var data = [{
      freq: 60,
      weight: 10
    }, {
      freq: 25,
      weight: 10
    }, {
      freq: 55,
      weight: 20
    }];
    
    var xScale = d3.scaleLinear()
    	.domain([0, Math.PI * 2])
    	.range([0, 500]);
    
    var yScale = d3.scaleLinear()
    	.domain([0, 80])
    	.range([200, 0]);
    
    var pie = d3.pie()
    	.sortValues(null)
    	.value(function(d){ return d.weight; });
    var adjustedData = pie(data);
    
    var rects = svg.selectAll('rect')
    	.data(adjustedData);
    
    rects.enter()
    	.append('rect')
    	.style('fill', 'blue')
    	.style('stroke', 'black')
    .merge(rects)
    	.attr('x', function(d) { return xScale(d.startAngle); })
    	.attr('width', function(d) { return xScale(d.endAngle) - xScale(d.startAngle); })
    	.attr('y', function(d) { return yScale(d.data.freq); })
    	.attr('height', function(d) { return yScale(0) - yScale(d.data.freq); });
    
  </script>
</body>

Upvotes: 2

Related Questions