Sriram
Sriram

Reputation: 83

D3 Bar chart. Values not aligned with Y axis

I am facing an issue while plotting values. The bars go beyond Y-Axis.

<div id = "Bar1">
        <script>

        var margin1 = {top: 40, right: 20, bottom: 30, left: 40},
            width1 = 460 //- margin.left - margin.right,
            height1 = 200 //- margin.top - margin.bottom;

        var formatPercent1 = d3.format("");

        var x1 = d3.scale.ordinal()
            .rangeRoundBands([0, width1], 0);
            //.rangeRoundBands([width1, 0);

        var y1 = d3.scale.linear()
            .range([height1, 0]);

        var xAxis1 = d3.svg.axis()
            .scale(x1)
            .orient("bottom");

        var yAxis1 = d3.svg.axis()
            .scale(y1)
            .orient("left")
            .tickFormat(formatPercent1);

        var tip1 = d3.tip()
          .attr('class', 'd3-tip')
          .offset([-10, 0])
          .html(function(d) {
            return "<strong>Frequency:</strong> <span style='color:red'>" + d.frequency + "</span>";
          })

        var svg1 = d3.select("#Bar1").append("svg")
            .attr("width", width1 + margin1.left + margin1.right)
            .attr("height", height1 + margin1.top + margin1.bottom)
          .append("g")
            .attr("transform", "translate(" + margin1.left + "," + margin1.top + ")");

        svg1.call(tip1);

        d3.tsv(data, type, function(error, data1) {
          x1.domain(data1.map(function(d) { return d.letter; }));
          y1.domain([0, d3.max(data1, function(d) { return d.frequency; })]);

          svg1.append("g")
              .attr("class", "x axis")
              .attr("transform", "translate(0," + height1 + ")")
              .call(xAxis1);

          svg1.append("g")
              .attr("class", "y axis")
              .call(yAxis1)
            .append("text")
              .attr("transform", "rotate(-90)")
              .attr("y", 6)
              .attr("dy", ".71em")
              .style("text-anchor", "end")
              .text("Frequency");

          svg1.selectAll(".bar")
              .data(data1)
            .enter().append("rect")
              .attr("class", "bar")
              .attr("x", function(d) { return x(d.letter); })
              .attr("width", x.rangeBand())
              .attr("y", function(d) { return y(d.frequency); })
              .attr("height", function(d) { return height1 - y(d.frequency); })
              .on('mouseover', tip1.show)
              .on('mouseout', tip1.hide)

        });

        function type(d) {
          d.frequency = +d.frequency;
          return d;
        }

        </script>
    </div>

The CSV:
letter  frequency
django  12
dictionary  33
C   55
D   100
E   90
F   300
G   80
H   10
I   0
J   0

enter image description here Can Anyone please help me out with this code. I am not understanding why this is an issue. The X and Y axis are scaled too. Is there something that i have missed out?

Thanks, Sriram

Upvotes: 1

Views: 841

Answers (1)

veproza
veproza

Reputation: 2994

You must have a mistake elsewhere than in the code you sent. I just put it to JSFiddle and it works correctly:

var tsv = "letter	frequency\n" + 
    "django	12\n" + 
    "dictionary	33\n" + 
    "C	55\n" + 
    "D	100\n" + 
    "E	90\n" + 
    "F	300\n" + 
    "G	80\n" + 
    "H	10\n" + 
    "I	0\n" + 
    "J	0";

var margin1 = {top: 40, right: 20, bottom: 30, left: 40},
    width1 = 460 //- margin.left - margin.right,
    height1 = 200 //- margin.top - margin.bottom;

var formatPercent1 = d3.format("");

var x1 = d3.scale.ordinal()
    .rangeRoundBands([0, width1], 0);
    //.rangeRoundBands([width1, 0);

var y1 = d3.scale.linear()
    .range([height1, 0]);

var xAxis1 = d3.svg.axis()
    .scale(x1)
    .orient("bottom");

var yAxis1 = d3.svg.axis()
    .scale(y1)
    .orient("left")
    .tickFormat(formatPercent1);


var svg1 = d3.select("#Bar1").append("svg")
    .attr("width", width1 + margin1.left + margin1.right)
    .attr("height", height1 + margin1.top + margin1.bottom)
  .append("g")
    .attr("transform", "translate(" + margin1.left + "," + margin1.top + ")");

var data1 = d3.tsv.parse(tsv, type)
x1.domain(data1.map(function(d) { return d.letter; }));
y1.domain([0, d3.max(data1, function(d) { return d.frequency; })]);

svg1.append("g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + height1 + ")")
  .call(xAxis1);

svg1.append("g")
  .attr("class", "y axis")
  .call(yAxis1)
.append("text")
  .attr("transform", "rotate(-90)")
  .attr("y", 6)
  .attr("dy", ".71em")
  .style("text-anchor", "end")
  .text("Frequency");

svg1.selectAll(".bar")
  .data(data1)
.enter().append("rect")
  .attr("class", "bar")
  .attr("x", function(d) { return x1(d.letter); })
  .attr("width", x1.rangeBand())
  .attr("y", function(d) { return y1(d.frequency); })
  .attr("height", function(d) { return height1 - y1(d.frequency); })

function type(d) {
  d.frequency = +d.frequency;
  return d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id='Bar1'></div>

In your snippet, you are referring to x scale as x variable, while you actually save it in x1. The same goes for y and y1 variables. That's corrected in my snippet.

Other than that, I changed the TSV loading from d3.tsv to d3.tsv.parse, but that's just skipping the AJAX fetch of the resource. I also removed the d3.tip tooltip, but again, that shouldn't change the barchart itself.

From the looks of your image, I'd guess you're not converting the frequency to Number but leave it as a String. But that's just a guess, you might want to show the actual code that's giving you trouble.

Upvotes: 1

Related Questions