Sergei Yakovich
Sergei Yakovich

Reputation: 25

How do I make my chart bars align with the chart axis?

My goal is to display a bar chart on the page using sample data. I would like there to be an x and y axis.

I have followed a tutorial on how to create a D3.JS bar chart, which worked fine until I added x and y axis. I would have expected the bar chart to fit inside the axis however the actual result has the barchart outside of the axis.I'm not getting any error messages in the console.

I have tried repositioning the code so that the bar chart is created both before and after the axis with no joy.

var data = [80, 100, 56, 120, 180, 30, 40, 120, 160];

var svgWidth = 500,
  svgHeight = 300,
  barPadding = 5;
var barWidth = (svgWidth / data.length);

var svg = d3.select('svg')
  .attr("width", svgWidth)
  .attr("height", svgHeight);

var barChart = svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("y", function(d) {
    return svgHeight - d
  })
  .attr("height", function(d) {
    return d;
  })
  .attr("width", barWidth - barPadding)
  .attr("transform", function(d, i) {
    var translate = [barWidth * i, 0];
    return "translate(" + translate + ")";
  });

var xScale = d3.scaleLinear()
  .domain([0, d3.max(data)])
  .range([0, svgWidth]);

var yScale = d3.scaleLinear()
  .domain([0, d3.max(data)])
  .range([svgHeight, 0]);

var x_axis = d3.axisBottom().scale(xScale);

var y_axis = d3.axisLeft().scale(yScale);

svg.append("g")
  .attr("transform", "translate(50, 10)")
  .call(y_axis);

var xAxisTranslate = svgHeight - 20;

svg.append("g")
  .attr("transform", "translate(50, " + xAxisTranslate + ")")
  .call(x_axis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="bar-chart"></svg>

Upvotes: 1

Views: 39

Answers (1)

Alex L
Alex L

Reputation: 4241

I tried to change your code as little as possible.

Check out this example for a really clean approach: https://bl.ocks.org/caravinden/d04238c4c9770020ff6867ee92c7dac1

var data = [80, 100, 56, 120, 180, 30, 40, 120, 160];

var svgWidth = 500,
  svgHeight = 300,
  barPadding = 10;
  
const margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 50
};

var svg = d3.select('svg')
  .attr("width", svgWidth)
  .attr("height", svgHeight);
  
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
var barWidth = (width / data.length);

var barChartGroup = svg.append('g')
  .attr("transform", `translate(${margin.left}, ${margin.top})`)

var xScale = d3.scaleBand()
  .domain(data.map((d,i) => i))
  .rangeRound([0, width])
  .padding(barPadding);

var yScale = d3.scaleLinear()
  .domain([0, d3.max(data)])
  .range([height, 0]);
  
var x_axis = d3.axisBottom(xScale);
var y_axis = d3.axisLeft(yScale);

barChartGroup.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("y", function(d) {
    return yScale(d);
  })
  .attr("x", function(d,i) {
    return xScale(i) - (barWidth-barPadding)/2;
  })
  .attr("height", function(d) {
    return height - yScale(d);
  })
  .attr("width", barWidth - barPadding) //xScale.bandwidth()

svg.append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`)
  .call(y_axis);

svg.append("g")
  .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
  .call(x_axis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="bar-chart"></svg>

Output:

enter image description here

Example with array of objects:

var data = [
  {val: 80, name:"A"},
  {val: 100, name:"B"},
  {val: 56, name:"C"},
  {val: 120, name:"D"},
  {val: 180, name:"E"},
  {val: 30, name:"F"},
  {val: 40, name:"G"},
  {val: 120, name:"H"},
  {val: 160, name:"I"}
];

var svgWidth = 500,
  svgHeight = 300,
  barPadding = 10;
  
const margin = {
    top: 20,
    right: 20,
    bottom: 30,
    left: 50
};

var svg = d3.select('svg')
  .attr("width", svgWidth)
  .attr("height", svgHeight);
  
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;
var barWidth = (width / data.length);

var barChartGroup = svg.append('g')
  .attr("transform", `translate(${margin.left}, ${margin.top})`)

var xScale = d3.scaleBand()
  .domain(data.map((d,i) => d.name))
  .rangeRound([0, width])
  .padding(barPadding);

var yScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.val)])
  .range([height, 0]);
  
var x_axis = d3.axisBottom(xScale);
var y_axis = d3.axisLeft(yScale);

barChartGroup.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("y", function(d) {
    return yScale(d.val);
  })
  .attr("x", function(d,i) {
    return xScale(d.name) - (barWidth - barPadding)/2; //barWidth - barPadding
  })
  .attr("height", function(d) {
    return height - yScale(d.val);
  })
  .attr("width", barWidth - barPadding); //xScale.bandwidth()

svg.append("g")
  .attr("transform", `translate(${margin.left}, ${margin.top})`)
  .call(y_axis);

svg.append("g")
  .attr("transform", `translate(${margin.left}, ${height + margin.top})`)
  .call(x_axis);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="bar-chart"></svg>

Output:

enter image description here

Upvotes: 1

Related Questions