Reputation: 79
I'm attempting to create a bar chart in D3 that replicates this design. The idea is that values can range from -100 to 100 and are displayed alongside each other. The scale must stay as 0-100, with colours being used to indicate whether the number is above or below 0.
I've managed to create a simple bar chart that displays positive numbers but as soon as a negative number is added, the chart breaks. The following code is used to create the x and y axis. Negative values are displayed if the x domain is changed to [-100, 100], but doing so renders the chart in a way that is too different from the original design.
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
x.domain([0, 100])
y.domain(data.map(function(d) { return d.sentiment; }));
Can anyone provide some tips/guidance on producing a graph that looks similar to the provided design, if it's even possible? Link to my current graph can be found in the JSFiddle below:
Many thanks.
Upvotes: 3
Views: 1022
Reputation: 102174
Just use Math.abs()
:
.attr("width", function(d){
return x(Math.abs(d.value));
})
Here is the demo:
var data = [{"sentiment":"Result","value":28},{"sentiment":"Result2","value":-56}]
var margin = {top: 20, right: 20, bottom: 50, left: 70},
width = 850 - margin.left - margin.right,
height = 200 - margin.top - margin.bottom;
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
var x = d3.scaleLinear()
.range([0, width]);
var svg = d3.select("#graph").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
data.forEach(function(d) {
d.value = +d.value;
});
x.domain([0, 100])
y.domain(data.map(function(d) { return d.sentiment; }));
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("width", function(d) {return x(Math.abs(d.value)); } )
.attr("y", function(d) { return y(d.sentiment) + 15; })
.attr("height", y.bandwidth())
.attr("fill", function(d) {
if (d.value <= 0) {
return "#FC4E5C";
} else {
return "#34A232";
}
});
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.call(d3.axisLeft(y));
svg.append("text")
.attr("class", "x label")
.attr("text-anchor", "end")
.attr("x", width - 300)
.attr("y", height + 40)
.text("Sentiment (%)");
.bar {
margin-top: 50px;
height: 30px;
}
text {
fill: black;
font-size: 14px;
}
path {
stroke: black;
}
line {
stroke: black;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<div id="graph">
</div>
Upvotes: 4