sprucegoose
sprucegoose

Reputation: 610

d3 bar chart using rangeRoundBands - why is there outer padding?

I'm creating a bar chart using an ordinal scale for the x axis, and using rangeRoundBands. I'm following this example: https://bl.ocks.org/mbostock/3885304

However, my chart has outer padding -- big spaces at the beginning and end of the axis, where I'd like the bars to fully extend. The screen shot below shows the spaces I'm referring to circled in red.

screenshot of bar chart

How can I remove these spaces? I need my margins and the svg width and height to remain the same.

Here is a Plunker with the chart as it is now: https://plnkr.co/edit/gMw7jvieKSlFbHLTNY9o?p=preview

Code is also below:

<!doctype html>
    <html>
    <head>
        <style>
        .axis path{
            fill: none;
            stroke: #cccccc;
            stroke-width: 2px;
        }
        .x.axis text{
            display:none;
        }
        .bar{
            fill: blue;
        }
        body{
            font-family:Helvetica, Arial, sans-serif;
        }
        </style>
    </head>
    <body>
    <div id="barchart"></div>

    <script src="https://d3js.org/d3.v3.min.js"></script>

    <script>

    var margin = {top: 20, right: 0, bottom: 50, left: 300},
        width = 800 - margin.left - margin.right;
            height = 465 - margin.top - margin.bottom;

    var x = d3.scale.ordinal()
                .rangeRoundBands([0, width], .5);
    var y = d3.scale.linear().range([height, 0]);

    var yAxis = d3.svg.axis().scale(y)
        .orient("left").ticks(5);

    var xAxis = d3.svg.axis().scale(x)
            .orient("bottom");

    var barsvg = d3.select("#barchart")
        .append("svg")
            .attr("width", width + margin.left + margin.right)
            .attr("height", height + margin.top + margin.bottom)
        .append("g")
            .attr("class", "barchartbox")
            .attr("transform",
            "translate(" + margin.left + "," + margin.top + ")");

    // Get the data
      d3.json("population.json", function(error, data1) {

        x.domain(data1.map(function(d) { return d.country; }));
      y.domain([0, d3.max(data1, function(d) { return d.value; })]);

      barsvg.selectAll(".axis").remove();

      // Add the Y Axis
      barsvg.append("g")
          .attr("class", "y axis")
          .call(yAxis);

      // Add the X Axis
      barsvg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis);

      var bars = barsvg.selectAll(".bar")
          .data(data1);

        bars.enter().append("rect")
          .attr("class", "bar")
          .attr("x", function(d) { return x(d.country); })
          .attr("width", x.rangeBand())
          .attr("y", function(d) {return y(d.value); })
          .attr("height", function(d) { return height - y(d.value); });

        bars.exit().remove();

    });


    </script>
    </body>
    </html>

Upvotes: 4

Views: 3924

Answers (2)

Cyril Cherian
Cyril Cherian

Reputation: 32327

You doing.

   var x = d3.scale.ordinal()
                .rangeRoundBands([0, width], .5);

Instead use rangeBands.

var x = d3.scale.ordinal()
             .rangeBands([0, width], .5);

working code here

Upvotes: 7

Gilsha
Gilsha

Reputation: 14589

It is specified in the d3 document that while using rangeRoundBands, rounding introduces additional outer padding which is, on average, proportional to the length of the domain.

For example, for a domain of size 50, an additional 25px of outer padding on either side may be required. Modifying the range extent to be closer to a multiple of the domain length may reduce the additional padding.

Reference: rangeRoundBands

So the solution would be to use following lines after setting the x axis domain:

var mult = Math.max (1, Math.floor (width / x.domain().length));
x.rangeRoundBands ([0, (x.domain().length * mult)], 0.1, 0);

Upvotes: 3

Related Questions