Reputation: 1044
I have a quick question. I am trying to determine the height in pixels of a chart bar. This is for a D3 implementation, and my chart has a logarithmic y-axis.
I have tried various computations but cannot seem to calculate the height of the bar so that it connects the Y value with the x-Axis.
The picture below should provide a visual illustration of what I am trying to do. Right now I can't seem to get it right ... I think this is essentially a problem in maths, not so much D3. Thank you!
*** EDIT ****
This is the y axis scale that I am using:
var y = d3.scale.log()
.range([height, 0])
.domain([d3.min(sampleData, function(d) {
return d.y;
}),
d3.max(sampleData, function(d) {
return d.y;
})
]);
Upvotes: 3
Views: 1628
Reputation: 102218
I'm still not sure about your problem, because the actual height of the bar is being calculated by the very scale you use to append the rectangles. And, if you're in fact appending the rectangles, you're already setting the height
attribute!
Let's see an example. This is a bar chart using your log scale (I'm using D3 v4 here, but the principle is the same) and this fake data:
var data = [2000, 5000, 3000, 8000, 1500];
As you can see, there is a minimum and a maximum. I put a padding of 20px in the scale:
var yScale = d3.scaleLog()
.range([height - padding, padding])
.domain([d3.min(data), d3.max(data)]);
So, our first value in the range is h - padding
and our last value is just padding
. Here is the chart:
var width = 300,
height = 400,
padding = 20;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var data = [2000, 5000, 3000, 8000, 1500];
var xScale = d3.scaleBand()
.range([50, width])
.domain(d3.range(data.length))
.padding(0.2);
var yScale = d3.scaleLog()
.range([height - padding, padding])
.domain([d3.min(data), d3.max(data)]);
var bars = svg.selectAll("foo")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("width", xScale.bandwidth())
.attr("height", d => height - padding - yScale(d))
.attr("y", d => yScale(d))
.attr("fill", "teal");
var gX = svg.append("g")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(d3.axisBottom(xScale));
var gY = svg.append("g")
.attr("transform", "translate(50,0)")
.call(d3.axisLeft(yScale));
<script src="//d3js.org/d3.v4.min.js"></script>
Suppose you want to calculate the height of the first bar. We can see, by inspecting the DOM, that its height is 61.867984771728516
pixels:
var width = 300,
height = 400,
padding = 20;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var data = [2000, 5000, 3000, 8000, 1500];
var xScale = d3.scaleBand()
.range([50, width])
.domain(d3.range(data.length))
.padding(0.2);
var yScale = d3.scaleLog()
.range([height - padding, padding])
.domain([d3.min(data), d3.max(data)]);
var bars = svg.selectAll("foo")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("width", xScale.bandwidth())
.attr("height", d => height - padding - yScale(d))
.attr("y", d => yScale(d))
.attr("fill", "teal");
var gX = svg.append("g")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(d3.axisBottom(xScale));
var gY = svg.append("g")
.attr("transform", "translate(50,0)")
.call(d3.axisLeft(yScale));
console.log(d3.select("rect").node().height.animVal.value)
<script src="//d3js.org/d3.v4.min.js"></script>
But this is simply the first value in the range (height - padding
) minus yScale(2000)
:
var width = 300,
height = 400,
padding = 20;
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var data = [2000, 5000, 3000, 8000, 1500];
var xScale = d3.scaleBand()
.range([50, width])
.domain(d3.range(data.length))
.padding(0.2);
var yScale = d3.scaleLog()
.range([height - padding, padding])
.domain([d3.min(data), d3.max(data)]);
var bars = svg.selectAll("foo")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => xScale(i))
.attr("width", xScale.bandwidth())
.attr("height", d => height - padding - yScale(d))
.attr("y", d => yScale(d))
.attr("fill", "teal");
var gX = svg.append("g")
.attr("transform", "translate(0," + (height - padding) + ")")
.call(d3.axisBottom(xScale));
var gY = svg.append("g")
.attr("transform", "translate(50,0)")
.call(d3.axisLeft(yScale));
console.log(height - padding - yScale(2000))
<script src="//d3js.org/d3.v4.min.js"></script>
Which, by the way, is the value used to set the height of the bars:
.attr("height", d => height - padding - yScale(d))
Upvotes: 2