admin管理员组

文章数量:1287867

I want to implement a bar chart in D3, but my values on the dx axis are of type Date, data type which the D3 library should accept, but it seems to give me an error like this: attribute width: Expected length, "NaN". This is my code:

<html> 
 <head> 
    <meta charset="utf-8">         
    <title>a bar graph</title> 
 </head> 
 <style>
    .axis path,
    .axis line{
        fill: none;
        stroke: black;
        shape-rendering: crispEdges;
    }

    .axis text {
        font-family: sans-serif;
        font-size: 11px;
    }

    .MyRect {
        fill: steelblue;
    }

    .MyText {
        fill: white;
        text-anchor: middle;
    }
 </style>
    <body>
        <script src=".v4.min.js" charset="utf-8"></script>
        <script>
        var width=400;  
        var height=400; 

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

        var padding = {left:30, right:30, top:20, bottom:20};

        var dataset=[10,20,30,40,33,24,12,5]; 


        var xScale = d3.scaleBand()
                       .domain(d3.range(dataset.length))
                       .range([0, width-padding.left-padding.right]);


        var yScale = d3.scaleLinear()
                       .domain([0,d3.max(dataset)])
                       .range([height-padding.top-padding.bottom,0]);

        var xAxis = d3.axisBottom()
                      .scale(xScale)          

        var yAxis = d3.axisLeft()
                      .scale(yScale)

        var rectPadding=4;  

        var rects = svg.selectAll(".Myrect")
                       .data(dataset)
                       .enter()
                       .append("rect")
                       .attr("class","Myrect")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x",function(d,i){
                            return xScale(i) + rectPadding/2;
                        })
                        .attr("y",function(d){
                            return yScale(d);
                        })
                       .attr("width",xScale.range()- rectPadding)
                       .attr("height",function(d){
                            return height - padding.top - padding.bottom - yScale(d);
                       });
        var texts = svg.selectAll(".MyText")
                       .data(dataset)
                       .enter()
                       .append("text")
                       .attr("class","MyText")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x", function(d,i){
                                return xScale(i) + rectPadding/2;
                        })
                       .attr("y",function(d){
                                return yScale(d);
                        })
                       .attr("dx",function(){
                                return (xScale.range() - rectPadding)/2;
                        })
                       .attr("dy",function(d){
                                return 20;
                        })
                       .text(function(d){
                                return d;
                        });

        svg.append("g")
           .attr("class","axis")
           .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
           .call(xAxis); 

        svg.append("g")
           .attr("class","axis")
           .attr("transform","translate(" + padding.left + "," + padding.top + ")")
           .call(yAxis);
        </script>
    </body> 
</html>

And the another error: attribute dx: Expected length, "NaN". I think it arises from band scales, but after using the introduction of the official, it still can't work. The introduction of the official:

var x = d3.scaleBand()
    .domain(["a", "b", "c"])
    .range([0, width]);

So when I want to call the code, I think it should be used like this in my pasted code:

var texts = svg.selectAll(".MyText")
                       .data(dataset)
                       .enter()
                       .append("text")
                       .attr("class","MyText")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x", function(d,i){
                                return xScale(i) + rectPadding/2;
                        })
                       .attr("y",function(d){
                                return yScale(d);
                        })
                       .attr("dx",function(){
                                return (xScale.range() - rectPadding)/2;
                        })
                       .attr("dy",function(d){
                                return 20;
                        })
                       .text(function(d){
                                return d;
                        });

But it seems to give me two errors. I'm a beginner. Thank you very much!

I want to implement a bar chart in D3, but my values on the dx axis are of type Date, data type which the D3 library should accept, but it seems to give me an error like this: attribute width: Expected length, "NaN". This is my code:

<html> 
 <head> 
    <meta charset="utf-8">         
    <title>a bar graph</title> 
 </head> 
 <style>
    .axis path,
    .axis line{
        fill: none;
        stroke: black;
        shape-rendering: crispEdges;
    }

    .axis text {
        font-family: sans-serif;
        font-size: 11px;
    }

    .MyRect {
        fill: steelblue;
    }

    .MyText {
        fill: white;
        text-anchor: middle;
    }
 </style>
    <body>
        <script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
        <script>
        var width=400;  
        var height=400; 

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

        var padding = {left:30, right:30, top:20, bottom:20};

        var dataset=[10,20,30,40,33,24,12,5]; 


        var xScale = d3.scaleBand()
                       .domain(d3.range(dataset.length))
                       .range([0, width-padding.left-padding.right]);


        var yScale = d3.scaleLinear()
                       .domain([0,d3.max(dataset)])
                       .range([height-padding.top-padding.bottom,0]);

        var xAxis = d3.axisBottom()
                      .scale(xScale)          

        var yAxis = d3.axisLeft()
                      .scale(yScale)

        var rectPadding=4;  

        var rects = svg.selectAll(".Myrect")
                       .data(dataset)
                       .enter()
                       .append("rect")
                       .attr("class","Myrect")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x",function(d,i){
                            return xScale(i) + rectPadding/2;
                        })
                        .attr("y",function(d){
                            return yScale(d);
                        })
                       .attr("width",xScale.range()- rectPadding)
                       .attr("height",function(d){
                            return height - padding.top - padding.bottom - yScale(d);
                       });
        var texts = svg.selectAll(".MyText")
                       .data(dataset)
                       .enter()
                       .append("text")
                       .attr("class","MyText")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x", function(d,i){
                                return xScale(i) + rectPadding/2;
                        })
                       .attr("y",function(d){
                                return yScale(d);
                        })
                       .attr("dx",function(){
                                return (xScale.range() - rectPadding)/2;
                        })
                       .attr("dy",function(d){
                                return 20;
                        })
                       .text(function(d){
                                return d;
                        });

        svg.append("g")
           .attr("class","axis")
           .attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
           .call(xAxis); 

        svg.append("g")
           .attr("class","axis")
           .attr("transform","translate(" + padding.left + "," + padding.top + ")")
           .call(yAxis);
        </script>
    </body> 
</html>

And the another error: attribute dx: Expected length, "NaN". I think it arises from band scales, but after using the introduction of the official, it still can't work. The introduction of the official:

var x = d3.scaleBand()
    .domain(["a", "b", "c"])
    .range([0, width]);

So when I want to call the code, I think it should be used like this in my pasted code:

var texts = svg.selectAll(".MyText")
                       .data(dataset)
                       .enter()
                       .append("text")
                       .attr("class","MyText")
                       .attr("transform","translate(" + padding.left + "," + padding.top + ")")
                       .attr("x", function(d,i){
                                return xScale(i) + rectPadding/2;
                        })
                       .attr("y",function(d){
                                return yScale(d);
                        })
                       .attr("dx",function(){
                                return (xScale.range() - rectPadding)/2;
                        })
                       .attr("dy",function(d){
                                return 20;
                        })
                       .text(function(d){
                                return d;
                        });

But it seems to give me two errors. I'm a beginner. Thank you very much!

Share Improve this question asked Nov 22, 2016 at 15:56 CharlieCharlie 3331 gold badge5 silver badges10 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 10

Right now, for the width of the rectangles and the dx of the texts, you're using:

xScale.range() - rectPadding

But xScale.range() returns an array, and array - number will give you a NaN. And you're not getting anywhere with a NaN...

Instead of xScale.range(), which will return an array, you should use:

xScale.bandwidth();

Which not only returns a proper number, but it's also what you're looking for.

Here is your code with that change:

<style>
  .axis path,
  .axis line {
    fill: none;
    stroke: black;
    shape-rendering: crispEdges;
  }
  
  .axis text {
    font-family: sans-serif;
    font-size: 11px;
  }
  
  .MyRect {
    fill: steelblue;
  }
  
  .MyText {
    fill: white;
    text-anchor: middle;
  }
</style>

<body>
  <script src="https://d3js.org/d3.v4.min.js" charset="utf-8"></script>
  <script>
    var width = 400;
    var height = 400;

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

    var padding = {
      left: 30,
      right: 30,
      top: 20,
      bottom: 20
    };

    var dataset = [10, 20, 30, 40, 33, 24, 12, 5];


    var xScale = d3.scaleBand()
      .domain(d3.range(dataset.length))
      .range([0, width - padding.left - padding.right]);


    var yScale = d3.scaleLinear()
      .domain([0, d3.max(dataset)])
      .range([height - padding.top - padding.bottom, 0]);

    var xAxis = d3.axisBottom()
      .scale(xScale)

    var yAxis = d3.axisLeft()
      .scale(yScale)

    var rectPadding = 4;

    var rects = svg.selectAll(".Myrect")
      .data(dataset)
      .enter()
      .append("rect")
      .attr("class", "Myrect")
      .attr("transform", "translate(" + padding.left + "," + padding.top + ")")
      .attr("x", function(d, i) {
        return xScale(i) + rectPadding / 2;
      })
      .attr("y", function(d) {
        return yScale(d);
      })
      .attr("width", xScale.bandwidth() - rectPadding)
      .attr("height", function(d) {
        return height - padding.top - padding.bottom - yScale(d);
      });
    var texts = svg.selectAll(".MyText")
      .data(dataset)
      .enter()
      .append("text")
      .attr("class", "MyText")
      .attr("transform", "translate(" + padding.left + "," + padding.top + ")")
      .attr("x", function(d, i) {
        return xScale(i) + rectPadding / 2;
      })
      .attr("y", function(d) {
        return yScale(d);
      })
      .attr("dx", function() {
        return (xScale.bandwidth() - rectPadding) / 2;
      })
      .attr("dy", function(d) {
        return 20;
      })
      .text(function(d) {
        return d;
      });

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + padding.left + "," + (height - padding.bottom) + ")")
      .call(xAxis);

    svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(" + padding.left + "," + padding.top + ")")
      .call(yAxis);
  </script>
</body>


PS: You don't need rectPadding. Just set the padding in the band scale:

var xScale = d3.scaleBand()
    .domain(d3.range(dataset.length))
    .range([0, width-padding.left-padding.right])
    .padding(0.2);//some value here

I have got the same error when element height for chart is too small due to this code (20px per row)

document.getElementById('chart').style.height = (data.getNumberOfRows() * 20) + 'px';

It was fine for several data items but when I had only a few items I got error. So I fixed it by adding some min-height

<div id="chart" style="width: 100%; min-height: 100px"></div>

本文标签: