noblerare
noblerare

Reputation: 11873

In D3 v4, how do I align axes appropriately?

I am using D3 v4. I have a bar graph created with an x-axis using scaleBand(). Now, I have created a y-axis but my issue is that no matter how I position it, it is cutting into the actual bars of the graph.

enter image description here

At the top of my JS file, I have:

var width = 350; var height = 300;

Then, the part where I actually create the Y-axis:

var y = d3.scaleLinear()
      .domain([0, 300000])
      .rangeRound([height, 0]);

var yAxis = d3.axisRight(y);
            yAxis.ticks(6);

chart.append("g")
     .attr("class", "y axis")
     .attr("transform", "translate(" + (width - dist_from_right) + ", 0)")
     .call(yAxis);

As you can see from the picture, the axis stretches the entirety of the height of the SVG, from bottom to top meaning that half of the 0 gets cut off and half off the 300,000 gets cut off.

First question: how do I "squish" (or scale) the y-axis so that it displays within the confines of the SVG?

Next, I want to translate the y-axis so that it is not cutting into my red bar. If I try to use the transform attribute, I can push the axis far to the right of the SVG borders but that means the numbers are off the SVG boundary. I've also tried to increase the width variable but that does nothing because it just stretches out the x-axis proportionally.

Second question: how do I move the y-axis so that it is not cutting into the x-axis and red bar and also remains visible in the SVG window?

Thanks!

Upvotes: 2

Views: 1773

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

In D3, axes are positioned according to the range of corresponding scales. So, you need a "padding" for the ranges. Right now, as your range goes from 0 to height (or vice versa, it doesn't matter), the axis starts at the very beginning of the SVG and ends at its very end.

I see you have a dist_from_right, but I don't know what are you doing with it in your x scale. So, for now, let's suppose you don't have any padding.

First, let's set the paddings:

var paddingLeft = 10, paddingRight = 10, paddingTop = 10, paddingBottom = 10;

Here, 10 is just a given number, change it accordingly.

After that, set the ranges using the paddings:

var y = d3.scaleLinear()
  .domain([0, 300000])
  .rangeRound([height - paddingBottom, paddingTop]);

The same for your x scale:

var x = d3.scaleLinear()
  .domain([0, someValue])
  .rangeRound([paddingLeft, width - paddingRight]);

Then you define the axis:

var xAxis = d3.axisBottom(x);//the same for the y axis

Having the ranges with the paddings, call the axes setting that paddings:

chart.append("g")
 .attr("class", "y axis")
 .attr("transform", "translate(" + (width - paddingRight) + ", 0)")
 .call(yAxis);

And the same for the x axis:

chart.append("g")
 .attr("class", "x axis")
 .attr("transform", "translate(0," + (height - paddingBottom) + ")")
 .call(xAxis);

Here is a working example. I made the SVG light gray and the plotting area white, so you can see the paddings.:

var paddingLeft = 20, paddingRight = 40, paddingTop = 10, paddingBottom = 40;

var width = 300, height = 300;

var chart = d3.select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height)

chart.append("rect")
  .attr("x", paddingLeft)
  .attr("y", paddingTop)
  .attr("width", width - paddingLeft - paddingRight)
  .attr("height", height - paddingTop - paddingBottom)
  .attr("fill", "white");

var y = d3.scaleLinear()
  .domain([0, 100])
  .rangeRound([height - paddingBottom, paddingTop]);

var x = d3.scaleLinear()
  .domain([0, 100])
  .rangeRound([paddingLeft, width - paddingRight]);

var yAxis = d3.axisRight(y);

var xAxis = d3.axisBottom(x);

chart.append("g")
     .attr("class", "y axis")
     .attr("transform", "translate(" + (width - paddingRight) + ", 0)")
     .call(yAxis);

chart.append("g")
     .attr("class", "x axis")
     .attr("transform", "translate(0," + (height - paddingBottom) + ")")
     .call(xAxis);
svg {
  background-color: lightgray;
  }
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 7

Related Questions