I'm new to d3.js. I just set up a local server and i'm trying to load a sample json file into my html file to play around with different visualizations. Nothing will display when i open it in my browser, & I'm getting this error in the console. "Uncaught TypeError: Cannot read property 'length' of null"
See code below. First block is the .html file and the second block is the sample .json. Thanks!
<!doctype html>
<html>
<head>
<title> D3 Arrays </title>
<script src="http://d3js.org/d3.v3.min.js"> </script>
</head>
<body>
<script>
d3.json("mydata.json", function (data) {
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) { return d.age * 10;})
.attr("height", 50)
.attr("y", function (d, i) { return i * 48; })
.attr("fill", "blue")
})
</script>
</body>
</html>
json data
[
{"name": "Judy", "age": 56},
{"name": "Glen", "age": 59},
{"name": "Dave", "age": 23}
]
Uncaught TypeError: Cannot read property 'length' of null
from the message, maybe you did not load the json correctly. you can check the data before
pass it to d3.
d3.json("mydata.json", function (data) {
console.log(data); // check the console output to judge if you get the data
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) { return d.age * 10;})
.attr("height", 50)
.attr("y", function (d, i) { return i * 48; })
.attr("fill", "blue")
})
i copy your code and data to http://jsfiddle.net/x5WzU/ and it works correctly
so:
check your server to check the path of mydata.json
The first argument in the d3.json callback is the error, and the second is the parsed data. If you don't have errors loading or parsing the data, your data variable will be null. You should use:
d3.json('mydata.json', function(error, data) {
if (error) {
console.error(error);
}
// visualization code...
});
Regards,
Related
I don't know why, according to the topojson version (may be) I have:
TypeError: t is undefined
An explanation could be nice! (I use the last version of topojson.)
Here an example of TypeError is undefined (pointing to topojson file)
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="https://unpkg.com/d3#5.0.0/dist/d3.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
</head>
<body>
<svg width="960" height="600"></svg>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var unemployment = d3.map();
var path = d3.geoPath();
var x = d3.scaleLinear()
.domain([1, 10])
.rangeRound([600, 860]);
var color = d3.scaleThreshold()
.domain(d3.range(2, 10))
.range(d3.schemeBlues[9]);
var g = svg.append("g")
.attr("class", "key")
.attr("transform", "translate(0,40)");
g.selectAll("rect")
.data(color.range().map(function(d) {
d = color.invertExtent(d);
if (d[0] == null) d[0] = x.domain()[0];
if (d[1] == null) d[1] = x.domain()[1];
return d;
}))
.enter().append("rect")
.attr("height", 8)
.attr("x", function(d) { return x(d[0]); })
.attr("width", function(d) { return x(d[1]) - x(d[0]); })
.attr("fill", function(d) { return color(d[0]); });
g.append("text")
.attr("class", "caption")
.attr("x", x.range()[0])
.attr("y", -6)
.attr("fill", "#000")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text("Unemployment rate");
g.call(d3.axisBottom(x)
.tickSize(13)
.tickFormat(function(x, i) { return i ? x : x + "%"; })
.tickValues(color.domain()))
.select(".domain")
.remove();
var files = ["https://d3js.org/us-10m.v1.json", "unemployment.tsv"];
var promises1 = d3.json("https://d3js.org/us-10m.v1.json");
var promises2 = d3.tsv("unemployment.tsv");
Promise.all([promises1, promises2]).then(function(us){
console.log(us[0]);
console.log(us[1]);
svg.append("g")
.attr("class", "counties")
.selectAll("path")
.data(topojson.feature(us, us[0].objects.counties).features)
.enter().append("path")
.attr("fill", function(d) { return color(d.rate = unemployment.get(d.id)); })
.attr("d", path)
.append("title")
.text(function(d) { return d.rate + "%"; });
svg.append("path")
.datum(topojson.mesh(us, us[0].objects.states, function(a, b) { return a !== b; }))
.attr("class", "states")
.attr("d", path);
});
</script>
</body>
</html>
My code : https://plnkr.co/edit/EzcZMSEQVzCt4uoYCLIc?p=info
Original (d3js v4 + Topojson v2) : https://bl.ocks.org/mbostock/4060606
Here an another example of TypeError is undefined (pointing to topojson file)
My code : https://plnkr.co/edit/o1wQX3tvIDVxEbDtdVZP?p=preview
The two examples have two separate issues in relation to topojson.
In the first example you update where the topojson is held from us to us[0] due to the change in how files are fetched. However, you haven't quite updated the code to reflect this change:
In Original: .data(topojson.feature(us, us.objects.counties).features)
In Question: .data(topojson.feature(us, us[0].objects.counties).features)
And fixed: .data(topojson.feature(us[0], us[0].objects.counties).features)
Updated plunkr.
However, the issue in the second example is a little different.
topojson.feature requires two parameters, a topology and an object. The topology is the variable holding the json, which you have correct. However, the object is not arcs. The variable holding the topojson has a property called objects, and in that there will always be at least one property representing a feature collection (states, counties, etc). This object (or one of these objects) is what we want.
Here is a snippet of your topojson:
... "objects":{"dep_GEN_WGS84_UTF8":{"type":"GeometryCollection","geometries":[{"arcs ..."
We want topojson.feature(data,data.objects.dep_GEN_WGS84_UTF8).
If making topojson with tools such as mapshaper, the object we want to display is the same as the name of the file used to create it. Generally, a quick word search through the topojson for "object" will also get you to the proper object pretty quick.
The arcs property in a topojson is convenient storage for the pieces that make up the features, not the features themselves.
Updated plunkr.
In both cases the topology parameter passed to topojson.feature won't contain the specified features, generating the same error.
I am new to D3.JS and, as a beginner, I am not sure how to handle a demanding program that will read a lot of data from a csv file and then make customized output based on the input. I am doing some test code in order to get the feel of the Here is the CSV file I am using:
location,age_group_id
USA,34
USA,34
USA,36
AFG,34
AFG,34
AFG,36
AFG,36
And the following code works fine to produce a simple bar graph based on this input:
<doctype html>
<html>
<head>
<title> Test </title>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script>
d3.csv("mydata.csv", function(error, data){
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function (d) { return d.age_group_id * 10} )
.attr("height", 48)
.attr("y", function (d, i){return i * 50} )
.attr("fill", "blue")
})
</script>
</body>
</html>
But what if I wanted to filter this data and only show out put for "location" == USA? I assume I would have to first read the data into a variable but I have yet to find documentation on how this is done. I also assume I will have to first define the display in a section and then load the data into this area.
When you do this:
d3.csv("mydata.csv", function(error, data){
All your CSV is loaded, as an array of objects, in a variable named data.
Thus, you can create a new dataset based on data:
var dataUsa = data.filter(function(d){
return d.location === "USA";
});
And use this dataset in the bars:
canvas.selectAll("rect")
.data(dataUsa)
var country = "USA";
d3.csv("mydata.csv", function(error, data){
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.filter(function(d) { return d.location == country })
.append("rect")
.attr("width", function (d) { return d.age_group_id * 10} )
.attr("height", 48)
.attr("y", function (d, i){return i * 50} )
.attr("fill", "blue")
})
I'm trying to create a bar chart using the json url. With respect to impressions and time. I don't think I'm referencing the data correctly at .data(data) how do I access the impressions field from json file in d3?
var url = "https://script.google.com/macros/s/AKfycbwy56QiQwyfkkaLFWZ33QHVieAHhtLJYNa_AzKcCBr-J7Catgv2/exec?id=1vQsWQPUET20KcgeRKgs5NOOBngqLeUuNTHI1bWi5Et8&sheet=Sheet1";
d3.json(url, function(data) {
console.log(data.Sheet1[0]);
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
canvas.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("width", function(d) {
return d.Impressions
})
.attr("height", 45)
.attr("y", function(d, i) {
return i * 50
})
.attr("fill", "blue")
});
You have to pass an array to the function data(). Thus, since data is an object:
Object {Sheet1: Array[71]}
Your data should be data.Sheet1 instead. Check the demo:
var url = "https://script.google.com/macros/s/AKfycbwy56QiQwyfkkaLFWZ33QHVieAHhtLJYNa_AzKcCBr-J7Catgv2/exec?id=1vQsWQPUET20KcgeRKgs5NOOBngqLeUuNTHI1bWi5Et8&sheet=Sheet1";
d3.json(url, function (data) {
var scale = d3.scale.linear()
.domain([0, d3.max(data.Sheet1, function(d){ return d.Impressions})])
.range([0, 500]);
var canvas = d3.select("body").append("svg")
.attr("width",500)
.attr("height",500)
canvas.selectAll("rect")
.data(data.Sheet1)
.enter()
.append("rect")
.attr("width",function(d){return scale(d.Impressions)})
.attr("height", 6)
.attr("y",function(d,i){return i*7})
.attr("fill","blue")
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
PS: I added a scale to your code.
Using d3, I am reading in 8760 data points (one for each hour of 2013) from a csv into a 2-d array and then trying to create them as circles in an <svg> element. The code successfully imports the data, as I can view it in the browser's console. However, the enter function does not seem to be applying the data to create the circles. No errors are raised.
Code:
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var w = 900, h = 500;
var dataset = [];
d3.csv("Jsorted2.csv", function(error, data) {
dataset = data.map(function(d) { return [ +d["Load"], new Date(d["dtDateTime"]), +d["Month"], +d["Hour"], +d["DayofYear"], +d["NetLoad"]]; });
});
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("circle")
.data( dataset )
.enter()
.append("circle")
.attr("cx", function(d,i) { return i; })
.attr("cy", function(d,i) { return d[0]; })
.attr("r", function(d,i) { return d[5]; });
</script>
The data loads properly:
Browser Inspector Console Screenshot
But the circles are missing:
Browser Inspector Source Screenshot
I have found different errors if I change the initial definition of dataset. If I use
var dataset = [[]];
the data still loads, but now I receive an error when d3 tries the grab the data:
d3.v4.min.js:3 Error: <circle> attribute cy: Expected length, "NaN".
(anonymous function)
# d3.v4.min.js:3Q_
# d3.v4.min.js:6K_
# d3.v4.min.js:6(anonymous function)
# D3test4LD.html:29
And d3 gets a little further in creating the circles:
<svg width="900" height="500">
<circle cx="0" cy="NaN"></circle>
</svg>
Why does d3 not load the data to circles? It appears as if d3 is not passing the data to d as it should, as d[0] has no length. If I cannot get this to work, I'll just write a Javascript for loop to place them myself, but I'd like to figure out why this doesn't work. It looks like a type conversion issue, but I import the data with a +, which is supposed to set the data as a number. I can even test that in the console:
> typeof(dataset[0][0])
"number"
Please do not include a js for loop as a solution.
UPDATE
So, I did solve my problem after researching asynchronous data loading, as per the answer below. For clear and easy future reference, here is one way to code a solution:
setInterval(drawLD, 2000);
function drawLD(){
svg.selectAll("circle")
.data( dataset )
.enter()
.append("circle")
.attr("cx", function(d,i) { return Math.round(i/8760); })
.attr("cy", function(d,i) { return Math.round(d[0]/maxload); })
.attr("r", function(d,i) { return 2; });
}
d3.csv is an asynchronous function. The code that creates the circles is executed before your csv data has returned. Place your d3 code inside the callback.
<script>
var w = 900, h = 500;
var dataset = [];
d3.csv("Jsorted2.csv", function(error, data) {
dataset = data.map(function(d) { return [ +d["Load"], new Date(d["dtDateTime"]), +d["Month"], +d["Hour"], +d["DayofYear"], +d["NetLoad"]]; });
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("circle")
.data( dataset )
.enter()
.append("circle")
.attr("cx", function(d,i) { return i; })
.attr("cy", function(d,i) { return d[0]; })
.attr("r", function(d,i) { return d[5]; });
});
</script>
So I am following along on this tutorial for D3JS, I have used javascript some in the past but I really wanted to broaden my horizons and learn how to make these really awesome data driven websites. Plus I am currently working in a place that will in the future require the DDD model and I want to be up to speed when that comes about. However while following this tutorial I get this crazy error
Error: value of <"rect"> = "NaN", Error:Value of <"text"> = "Nan"
in my inspect console and nothing renders on the page (obviously because it isn't properly getting the data that it needs to display anything), I have tried removing the type function and using the parseInt on the return values in text and rect, as well as leaving the type function and just parsing that value and returning it but nothing seems to be working. I am using a tsv to get the data from and have done everything that the tutorial said to do. Just for giggles I thought hmmm, I have an error, let me try their code. So I copy pasted their code into my code block (not just the pieces that were throwing the error but the entire thing!!!), and got the same error that mine got... hahahahaha now I just want to know what is going on so that I can fix it and move forward with my bar graph extravaganza. any thoughts???
<!DOCTYPE html>
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Stacked Bar Graph</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div class="chart">
<script>
d3.tsv("data.tsv", type, function(data) {
var width = 420,
barHeight = 20;
var x = d3.scale.linear()
.range([ 0, width ])
.domain([ 0, d3.max(data, function(d) {
return d.value;
}) ]);
var chart = d3.select(".chart")
.append("svg")
.attr("width", width)
.attr("height", barHeight * data.length);
var bar = chart.selectAll("g")
.data(data)
.enter()
.append("g")
.attr("transform", function(d, i) {
return "translate(0," + i * barHeight + ")";
});
bar.append("rect").attr("width", function(d) {
return x(d.value);
}).attr("height", barHeight - 1).attr("fill", "steelblue");
bar.append("text").attr("x", function(d) {
return x(d.value) - 3;
}).attr("y", barHeight / 2).attr("dy", ".35em").attr("fill",
"white").attr("font", "10px san-serif").attr("text-anchor",
"end").text(function(d) {
return d.value;
});
});
function type(d) {
d.value = +d.value;
return d;
}
</script>
</div>
data.tsv file
name value
Locke 4
Reyes 8
Ford 15
Jarrah 16
Shepard 23
Kwon 42
Make sure the values in the TSV are separated by tabs, not spaces.