DenLilleMand DenLilleMand - 3 months ago 12
CSS Question

d3.js barchart not quite like I want it

Im doing a simple bar chart with d3.js (version 4.1), and i have followed an example from the official documentation. This is my jsfiddle:

My current barchart

This is my code:

html:

<div class="diagram-wrapper">
<div class="barchart">
<div class="header">
<h2>High score</h2>
</div>
<div class="content">

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


Js:

var data = [{
points: 50,
name: "gunnar"
}, {
points: 100,
name: "herp"
}, {
points: 500,
name: "Jacob"
}];

var width = 420,
barHeight = 20;

var x = d3.scaleLinear()
.range([0, width]);

var chart = d3.select(".diagram-wrapper div.barchart div.content")
.append('svg')
.attr("width", width);

x.domain([0, d3.max(data, function(d) {
return d.points;
})]);

chart.attr("height", barHeight * data.length);

var bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * barHeight + ")";
});

bar.append("rect")
.attr("width", function(d) {
return x(d.points);
})
.attr("height", barHeight - 1);

bar.append("text")
.attr("x", function(d) {
return x(d.points) - 3;
})
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) {
return d.points;
});


But all of the examples i can find are from version 3, or they use TSV og SCV data format... What i want is something like this:

Example of what i want

So basically my questions are as follows:


  • How do i turn the bars vertical instead of horizontal?

  • How do i add the names below the bars in the x-axis?

  • How do i add some values to the y-axis, that the points then relate to?



Sorry for all the questions, i really did investigate the docs, but i can't quite wrap my head around it when theres a leak of working examples and blogposts in 4.1

Thanks

Answer

There is no easy way to "flip" an horizontal bar chart to a vertical bar chart... you have to pretty much change almost all the code. Here I'll show the basic steps (Please note that I'm not modifying your code, but creating a new one).

First, the data is the same. Then, we append the SVG:

var width = 400, height = 500;

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

After that, we define the scales. The x axis is now qualitative, while the y axis is quantitative:

var xScale = d3.scaleBand()
  .domain(data.map(function(d){ return d.name}))
  .range([100, width])
  .paddingInner(0.2)
  .paddingOuter(0.2);

var yScale = d3.scaleLinear()
  .domain([0, d3.max(data, function(d){ return d.points})])
  .range([height - 40, 10]);

Then, we bind the data:

var bars = svg.selectAll(".bars")
  .data(data)
  .enter()
  .append("rect");

With the data bounded we append the rectangles. This is the tricky part: notice how we calculate x, y, width and height:

bars.attr("x", function(d){ return xScale(d.name)})
  .attr("y", function(d){ return yScale(d.points)})
  .attr("width", xScale.bandwidth())
  .attr("height", function(d){ return (height - 40) - yScale(d.points)})
  .attr("fill", "steelblue");

And then, the axes:

var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);

svg.append("g").attr("transform", `translate(0,${height-40})`)
  .call(xAxis);

svg.append("g").attr("transform", "translate(100,0)")
  .call(yAxis);

And the fiddle shows the code working: https://jsfiddle.net/gerardofurtado/o1cer41s/

PS: there are some magic numbers in the code. Also, I'm using a template literal that won't work if you use IE.