Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: <rect> attribute y: Expected length, "NaN"

I am trying to follow this example here for a D3 stacked chart. I've tested it locally and it works fine. I have adapted the code to match my csv dataset, but unfortunately I get issues with the calculation of y and height attributes:

  • Error: attribute y: Expected length, "NaN".
  • Error: attribute height: Expected length, "NaN".

Here is my adapted source code:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Enterprise Elements Analysis - In/Out of Scope</title>
    <script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
    <style type="text/css">
        svg {
            font: 10px sans-serif;
            shape-rendering: crispEdges;
        }

        .axis path,
        .axis line {
            fill: none;
            stroke: #000;
        }

        path.domain {
            stroke: none;
        }

        .y .tick line {
            stroke: #ddd;
        }
  </style>
</head>
<body>
<script type="text/javascript">
// Our D3 code will go here
var ratData = [];

d3.csv("./etcounts.csv", function(d) {
    return {
        type: d.type,
        in_scope: +d.in_scope,
        out_scope: +d.out_scope
    };
}, function(error, rows) {
    data = rows;
    console.log(data);
    createVisualization();
});

function createVisualization() {
    // Setup svg using with margins
    var margin = {bottom: 75, left: 15, right: 85};
    var w = 200 - margin.left - margin.right;
    var h = 175 - margin.bottom;

    // get length of Array
    var arrayLength = data.length; // length of dataset
    var x_axisLength = 100; // length of x-axis in our layout
    var y_axisLength = 100; // length of y-axis in our layout

    var svg = d3.select("body")
        .append("svg")
        .attr("width", w + margin.left + margin.right)
        .attr("height", h + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + ",10)");

    // set up the properties for stack
    var stack = d3.stack()
        .keys(["In Scope", "Out Scope"])
        .order(d3.stackOrderDescending)
        .offset(d3.stackOffsetNone);

    // transpose your data using stack
    var series = stack(data);

    // view the stack
    console.log(series);

    // setup the Y scale
    var yScale = d3.scaleLinear()
        .domain([0, d3.max(series, function(d) {
            return d3.max(d, function(d) {
                return d[1];
            }); 
        })])
        .range([h, 0]);

    // Set some colors into an array
    var colors = ["#dfd6d6", "#d85f41"]; // choose colors

    // Create groups for each series, rect elements for each segment 
    var groups = svg.selectAll("g.type")
        .data(series)
        .enter().append("g")
        .attr("class", "type")
        .style("fill", function(d, i) {
            return colors[i]; // color the rectangles
        });

    // Create the rectangles
    var rect = groups.selectAll("rect")
        .data(function(d) {
            return d;
        })
        .enter()
        .append("rect")
        .attr("x", function(d,i) {
            return i * (x_axisLength/arrayLength) + 30; // Set x coordinate of rectangle to index of data value (i) *25
        })
        .attr("y", function(d) {
            return yScale(d[1]); // set base of rectangle
        })
        .attr("height", function(d) {
            return yScale(d[0]) - yScale(d[1]); // set height of rectangle
        })
        .attr("width", (x_axisLength/arrayLength) - 1) // set width of rectangle
        .on("mouseover", function() {
            tooltip.style("display", null); // hide tooltip
        })
        .on("mousemove", function(d) {
            var xPosition = d3.mouse(this)[0] - 15;
            var yPosition = d3.mouse(this)[1] - 25;
            tooltip.attr("transform", "translate(" + xPosition + "," + yPosition + ")");
            tooltip.select("text").text(d.data.city + ": " + (d[1] - d[0])); // populate tooltip
        })
        .on("mouseout", function() {
            tooltip.style("display", "none");
        });

    // Draw legend
    var legend = svg.selectAll(".legend")
        .data(colors)
        .enter().append("g")
        .attr("class", "legend")
        .attr("transform", function(d, i) { return "translate(" + i * 50 + ", 110)"; });

    legend.append("rect")
        .attr("x", w - 70)
        .attr("width", 18)
        .attr("height", 18)
        .style("fill", function(d, i) {return colors.slice().reverse()[i];});

    legend.append("text")
        .attr("x", w - 49)
        .attr("y", 9)
        .attr("dy", ".35em")
        .style("text-anchor", "start")
        .text(function(d, i) { 
        switch (i) {
            case 0: return "In";
            case 1: return "Out";
        }
    });

    // Prep the tooltip bits, initial display is hidden
    var tooltip = svg.append("g")
        .attr("class", "tooltip")
        .style("display", "none");

    tooltip.append("text")
        .attr("x", 15)
        .attr("dy", "1.2em")
        .style("text-anchor", "middle")
        .attr("font-size", "12px");

    // Create y-axis
    svg.append("line")
        .attr("x1", 30)
        .attr("y1", 0)
        .attr("x2", 30)
        .attr("y2", 100)
        .attr("stroke-width", 2)
        .attr("stroke", "black");

    // y-axis label
    svg.append("text")
        .attr("class", "y label")
        .attr("text-anchor", "middle")
        .text("Elements")
        .attr("transform", "translate(20, 50) rotate(-90)")
        .attr("font-size", "14px")
        .attr("font-family", "'Open Sans', sans-serif");

    // Create x-axis
    svg.append("line")
        .attr("x1", 30)
        .attr("y1", 100)
        .attr("x2", 130)
        .attr("y2", 100)
        .attr("stroke-width", 2)
        .attr("stroke", "black");
}

</script>
</body>
</html>

My Dataset (etcounts.csv) is here:

type,in_scope,out_scope
ERKRS,1,1
KKBER,6,5
KOKRS,1,31
BUKRS,78,143
VKORG,23,13
BWKEY,51,6
EKORG,5,6
WERKS,51,65
LGORT,9,180
SPART,9,3
VTWEG,2,0
PERSA,47,73

Unfortunately my D3/JS skills are not quite up to par, but I would appreciate any help. Thanks - John

like image 807
johnaco Avatar asked Nov 07 '22 16:11

johnaco


1 Answers

Instead of

var stack = d3.stack()
    .keys(["In Scope", "Out Scope"]) <-- there is no key as such
    .order(d3.stackOrderDescending)
    .offset(d3.stackOffsetNone);

it should have been:

var stack = d3.stack()
    .keys(["in_scope", "out_scope"])
    .order(d3.stackOrderDescending)
    .offset(d3.stackOffsetNone);

Reason: there is no keys in your CSV "In Scope", "Out Scope" It should have been "in_scope", "out_scope"

EDIT

For tool tip :

tooltip.select("text").text(d.data.city + ": " + (d[1] - d[0]));

should have been

tooltip.select("text").text(d.data.type + ": " + (d[1] - d[0]));

Reason: There is no data.city in your CSV.

working code here

like image 94
Cyril Cherian Avatar answered Nov 15 '22 12:11

Cyril Cherian