I’m attempting to display a basic animated bar-chart using D3 (v7) to my web page. This is being done from within a Django project and so my chart is being fed data from my views.py file. However, the chart only partially displays on the page. The x and y axis lines are displayed, along with the axis labels. Here is my error message:
Error: <rect> attribute height: Expected length, "NaN".
Here is the relevant part of my html template:
<div id="chart-container"></div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script type="text/javascript">
const data = JSON.parse('{{ assign_levels|safe }}');
const margin = {top: 10, right: 30, bottom: 140, left: 60};
const width = 400 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
const svg = d3.select("#chart-container")
.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})`);
const x = d3.scaleBand()
.range([0, width])
.domain(data.map(d => d.level_assign))
.padding(0.3);
const y = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(data, d => d.count)]);
svg.append("g")
.call(d3.axisLeft(y));
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", d => x(d.level_assign))
.attr("width", x.bandwidth())
.attr("y", height)
.attr("height", 0)
.attr("fill", "#5F9EA0")
.transition()
.duration(1000)
.delay((d, i) => i * 100)
.attr("y", d => y(d.count))
.attr("height", d => height - y(d.count));
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "rotate(-45)")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em");
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Study Count");
svg.append("text")
.attr("x", (width + margin.left + margin.right) / 2)
.attr("y", margin.top / 2)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text("Level of Assignment");
</script>
And here is the code I am inputting to the chart:
[["Class", 36], ["School - cluster", 6], ["Individual", 20], ["N", 1], ["School - multi-site", 9], ["Not provided/ not available", 4], ["Region or district", 1]]
I can’t understand why the error message is telling me that it has received a "NaN" for height as I can see that the height has been set in absolute terms e.g. 500.
2
Answers
The Python
pandas
dataframe returnsNaN
for empty results (short for “Not a Number”). You can change it by using thefillna
method on your dataframe:df = df.fillna('')
This should solve the problem downstream for display issues, but you’ll have to dig a bit deeper to find why it is being passed for height.
You’re passing an array of arrays as data but the D3 code expects an array of objects with specific keys.
I tried to convert the data format into an array of objects.
You need to update your code slightly to achieve this. Check the code below:
This will convert your data to this format instead of a list of arrays.
Here is an example with full code: