Hayden Allocca Hayden Allocca - 1 month ago 6
ASP.NET (C#) Question

d3 v4 how to add data labels to bar graph

i am working on a d3 graph and i can't seem to get the labels to position onto its corresponding bar in a bar graph. I am using d3 v4.

http://orm-chimera-prod.s3.amazonaws.com/1230000000345/images/idvw_0902.png

this is the desired outcome, the y positioning is ideal in my example however the x position will not move and the data labels are all stuck to the left

<!-- Wrap these elements in the necessary html and bootstrap classes to achieve the desired layout as depicted in the Assignment instructions -->
<div class="flex col-md-2" id="table">
<h2>Annual Sightings Table</h2>
<div class="flex-container" data-ng-app="UFOSightingsApp">
<div class="row">
<div data-ng-controller="UFOSightingsController">
<table class="table table-hover">
<thead>
<tr>
<th>Year</th>
<th>Sighting Count</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="s in sightings">
<td>{{s.sightingYear}}</td>
<td>{{s.sightingCount}}</td>
</tr>
</tbody>

</table>
</div>
</div>
</div>

</div>



<div class="flex col-md-8 col-md-offset-2" id="graph">
<h2>Annual Sightings Graph</h2>
<svg width="100%" height="600px" style="border: 1px solid #000">
</svg>
</div>

<script src="Scripts/d3/d3.js"></script>

<script>
var app = angular.module("UFOSightingsApp", []);

app.controller("UFOSightingsController", function ($scope, $http) {

$http.get("/api/UFOSightings").success(function (data) {
$scope.sightings = data;
});


});



var svg = d3.select("svg");

var svgWidth = svg.style("width");
var svgHeight = svg.style("height");
var width = svgWidth.substring(0, svgWidth.length - 2) - 0;
var height = svgHeight.substring(0, svgHeight.length - 2) - 65;

var xScale = d3.scaleBand()
.range([0, width])
.padding(0.1);


var yScale = d3.scaleLinear()
.range([height, 0]);

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


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




d3.json("SightingData.json", function (error, data) {

if (error) throw error;

data.forEach(function (d) {
d.sightingCount = +d.sightingCount;
d.sightingYear = d.sightingYear;
});

xScale.domain(data.map(function (d) { return d.sightingYear; }));
yScale.domain([0, d3.max(data, function (d) { return d.sightingCount; })]);

//draw the bars
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function (d) { return xScale(d.sightingYear); })
.attr("width", xScale.bandwidth() - 2)
.attr("y", function (d) { return yScale(d.sightingCount); })
.attr("height", function (d) { return height - yScale(d.sightingCount); });

//label the bars
svg.selectAll("text")
.data(data)
.enter()
.append("text")
.text(function (d) { return d.sightingCount; })
.attr("x", function (d) { return xScale(d.sightingYear) + xScale.range() / 2; })
.attr("y", function (d) { return yScale(d.sightingCount) + 12; })
.style("fill", "white");





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


svg.append("g")
.attr("class", "y axis")
.call(yAxis);
//.append("text")
//.attr("transform", "rotate(-90)")
//.attr("y", -36)
//.attr("dy", ".71em")
//.style("text-anchor", "end")
//.text("Salary");

});





</script>




the part i need to work for me that works in many online examples is where "//label the bars" is located

Answer

You're using scaleBand. So, instead of range(), it should be bandwidth():

 svg.selectAll("text")
        .data(data)
        .enter()
        .append("text")
        .text(function (d) { return d.sightingCount; })
        .attr("x", function (d) { return xScale(d.sightingYear) + xScale.bandwidth() / 2; })
        .attr("y", function (d) { return yScale(d.sightingCount) + 12; })
        .style("fill", "white");