D3 条形图返回高度为“NaN”。

3
我正在尝试使用D3(v7)在我的网页上显示一个基本的动态条形图。这是在Django项目内完成的,我的图表从views.py文件中获取数据。但是,该图表仅在页面上部分显示。 x和y轴线以及轴标签已显示。以下是我的错误消息:
Error: <rect> attribute height: Expected length, "NaN".

这是我的HTML模板的相关部分:

 <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>

这是我输入到图表中的代码:

[["Class", 36], ["School - cluster", 6], ["Individual", 20], ["N", 1], ["School - multi-site", 9], ["Not provided/ not available", 4], ["Region or district", 1]]

我不明白为什么错误信息告诉我高度接收到了一个"NaN",因为我可以看到高度已经以绝对值的方式设置为500。


你提到了折线图,但你尝试的代码是关于柱状图的。这是打错字了吗? 顺便说一下,我已经添加了我的答案和解决方案。希望这能帮到你。谢谢。 - dostogircse171
这是一个打字错误,谢谢你发现它。我已经接受了你的答案,非常感谢你的帮助。 - Beatdown
2个回答

3

你正在传递一个数组的数组作为数据,但是D3代码期望一个具有特定键的对象数组。 我尝试将数据格式转换为对象数组。

你需要稍微更新一下你的代码才能实现这个。请检查下面的代码:

const rawData = JSON.parse('{{ assign_levels|safe }}');
const data = rawData.map(d => ({level_assign: d[0], count: d[1]}));

这将把您的数据转换为此格式,而不是数组列表。

[
  {"level_assign": "Class", "count": 36},
  {"level_assign": "School - cluster", "count": 6},
  {"level_assign": "Individual", "count": 20},
  {"level_assign": "N", "count": 1},
  {"level_assign": "School - multi-site", "count": 9},
  {"level_assign": "Not provided/ not available", "count": 4},
  {"level_assign": "Region or district", "count": 1}
]

这是一个包含完整代码的示例:

//script.js
const rawData = [
    ["Class", 36],
    ["School - cluster", 6],
    ["Individual", 20],
    ["N", 1],
    ["School - multi-site", 9],
    ["Not provided/ not available", 4],
    ["Region or district", 1],
];

const data = rawData.map((d) => ({
    level_assign: d[0],
    count: d[1]
}));

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");
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>D3 Bar Chart</title>
</head>
<body>
    <div id="chart-container"></div>

    <script src="https://d3js.org/d3.v7.min.js"></script>
    <script src="script.js"></script>
</body>
</html>


1
Python的pandas dataframe在结果为空时返回NaN(“Not a Number”的缩写)。您可以通过在数据框上使用fillna方法来更改它:
df = df.fillna('')
这应该解决下游的显示问题,但您需要深入挖掘为什么会传递高度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接