Cannot display data in d3.js from local csv file - d3.js

I know that the question has been largely covered but I am still stuck with it so any help is more than appreciated.
I am trying to display some data from a csv file locally on my computer in d3.js script but nothing is displayed. I have tried two solutions so far:
Solution 1:
Some of the answers found online state that the solution is to install a local server. So I installed a portable version of Uniform Server UPX (because I don't have the administrator privileges to install node http server on my computer).
But even when I run the server from the directory where my index.html is located, nothing happens. Here is the code I am using for reading data from the csv file:
d3.csv("data.csv", type, function(error, data) {
x.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.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);
bar.append("text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; });
});
Furthermore, this solution isn't convenient for me because I want the data to be updated automatically from the csv file without having to run a cmd prompt to start the http server...
Solution2
I tried to allow the browser access local files by adding the following line in my head index, without success either:
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<meta http-equiv="Access-Control-Allow-Origin" content="*"/>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<style>
Could you please point out what I should do to solve the problem?
Thanks.

Related

D3Js.v5: ...selectAll(...).data(...).enter is not a function

I'm learning D3 JS, and I'm trying to replicate the D3 bar chart tutorial here. It works as is using d3.v3, but the moment I change the src to d3.d5 by changing:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
//Irrelevant CSS...
</style>
<svg class="chart"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script> //Changed to d3.v5
<script>
var width = 420,
barHeight = 20;
var x = d3.scale.linear()
.range([0, width]);
var chart = d3.select(".chart")
.attr("width", width);
d3.tsv("data.tsv", type, function(error, data) {
x.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.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);
bar.append("text")
.attr("x", function(d) { return x(d.value) - 3; })
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.text(function(d) { return d.value; });
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
I get an error:
Uncaught (in promise) TypeError: chart.selectAll(...).data(...).enter is not a function
I'd rather learn the latest and greatest, which I assume is D3.v5, instead of D3.v3, unless the latter really is the latest stable build. Was there a syntax change in this method chain? because I thought .selectAll(...).data(...).enter would be a pretty "standard" method chain. This has been surprisingly resistant to googling, unfortunately; similar problems are much more complex use-cases with many more degrees of freedom, whereas my question simply involves changing the D3 version.
I see 2 problems with your solution:
Change d3.scale.linear() to d3.scaleLinear()
Change d3.tsv("data.tsv", type, function(error, data) { to d3.tsv("data.tsv").then(function(data) {
Explanation for 2: d3.tsv function returns a promise which needs to be resolved before you can use the data

Trouble loading CSV data in D3

I'm brand new to D3.js, so my apologies in advance if I'm overlooking something obvious, but I cannot for the life of me figure out what's not working here...
I've been inching my way through Scott Murray's Interactive Data Visualization for the Web and I've hit a block at Chapter 7. My goal is to load some simple data from a csv document, parse the first column as Date data, and then display. The head of the csv looks like this...
Date, Amount
9/15/17, 26
11/9/17, 31
11/30/17, 23
12/21/17, 26
2/7/18, 23
I run the code below (which comes directly from the book!) and...none of that seems to be happening. When I enter "dataset" into the console, it only seems to include the final row:
{Date: "01/31/17", Amount: "23"}
Amount: "23"
Date: "01/31/17"
I'm perplexed since, again, the code itself comes from the book. I've been working through previous chapters just fine until now. And yes, I'm running a local server. Any idea what I'm doing wrong here? Thanks very much in advance!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Time scale</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
/* No style rules here yet */
</style>
</head>
<body>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
var padding = 40;
var dataset, xScale, yScale;
//For converting strings to Dates
var parseTime = d3.timeParse("%m/%d/%y");
//Function for converting CSV values from strings to Dates and numbers
var rowConverter = function(d) {
return {
Date: parseTime(d.Date),
Amount: parseInt(d.Amount)
};
}
//Load in the data
d3.csv("time_scale_data.csv", rowConverter, function(data) {
//Copy data into global dataset
dataset = data;
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.Date; }),
d3.max(dataset, function(d) { return d.Date; })
])
.range([padding, w - padding]);
yScale = d3.scaleLinear()
.domain([
d3.min(dataset, function(d) { return d.Amount; }),
d3.max(dataset, function(d) { return d.Amount; })
])
.range([h - padding, padding]);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Generate date labels first, so they are in back
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return formatTime(d.Date);
})
.attr("x", function(d) {
return xScale(d.Date) + 4;
})
.attr("y", function(d) {
return yScale(d.Amount) + 4;
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "#bbb");
//Generate circles last, so they appear in front
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", function(d) {
return xScale(d.Date);
})
.attr("cy", function(d) {
return yScale(d.Amount);
})
.attr("r", 2);
});
</script>
</body>
</html>
Instead of :
d3.csv("time_scale_data.csv", rowConverter, function(data) {
--- your code ---
});
Try this :
d3.csv("time_scale_data.csv", rowConverter).then(data){
--- your code ---
});

Drawing D3 Rectangles

I am a beginner with D3 and JS in general.
I am trying to do a simple rectangle visualisation with a small csv file as a source.
price, units
80.67, 100
80.87, 99
79.34, 47
File, csv are in the same folder.
I am using Python's SimpleHTTPServer to serve locally in this folder.
This is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Data</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
</head>
<body>
<script type="text/javascript">
// load csv from the same directory
d3.csv("test.csv", function (data){
return {
price: +data.price, // convert to number with +
units: +data.units, // convert to number with +
};
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.price; })
.attr("height", 48)
.attr("y", function (d) { return d.units; })
.attr("fill", "blue");
canvas.selectAll("text")
.data(data)
.enter()
.append("text")
.attr("fill", "white")
.attr("y", function (d) { return d.units + 24; })
.text( function (d) { return d.units;})
});
</script>
</body>
I am getting no errors, just a blank page.
What is wrong with this code?
The first thing you do in your callback is to return. None of the code after that is being executed. I'm referring to
return {
price: +data.price, // convert to number with +
units: +data.units, // convert to number with +
};
which should probably be
data.forEach(function(d) {
d.price = +d.price;
d.units = +d.units;
});
The signature of the callback should also be function(error, data) instead of function(data).

how to import data into d3js correctly

I get pretty excited about the D3.js studying and presentation. And I get stuck on the data importing part. I've tried one month now, and couldn't find a solution for it.
If the data is simply pasted in the code, the scripts works perfectly fine. But once I tried to import the data from outside the script. The webpage won't show anything.
Can someone be kind enough to give me a hand?
Here are my scripts and data:
Working version:
<!DOCTYPE html>
<html>
<head>
<charset=utf-8">
<title>Successful Data Comination In Bar Chart</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var dataset = [{"name":"AAA", "age":10},{"name":"BBB", "age":20},{"name":"CCC", "age":30}];
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
canvas.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("width", function (d) { return d.age*10; })
.attr("height", 48)
.attr("y", function (d,i) { return i*50; })
.attr("fill", "gray");
canvas.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("fill", "white")
.attr("x", 2)
.attr("y", function (d,i) { return i*50 +27; })
.text(function (d) { return d.name + " " + d.age; });
</script>
</body>
</html>
Not working version:
<!DOCTYPE html>
<html>
<head>
<charset=utf-8">
<title>Testing Pie Chart</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script>
var dataset = [];
d3.json("mydata.json", function(data) {
dataset = data;
var canvas = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500);
canvas.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("width", function (d) { return d.age*10; })
.attr("height", 48)
.attr("y", function (d,i) { return i*50; })
.attr("fill", "gray");
canvas.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("fill", "white")
.attr("x", 2)
.attr("y", function (d,i) { return i*50 +27; })
.text(function (d) { return d.name + " " + d.age; });
});
</script>
</body>
</html>
The json data named "mydata.json" is like:
[
{"name": "AAA", "age": 10},
{"name": "BBB", "age": 20},
{"name": "CCC", "age": 30}
]
I am new to Stackoverflow, and trying to edit it as I want, but not perfect. Please feel free to let me know if you get confused about the codes. I will explain, cause I really want to solve this. Thanks a lot!
Thanks for tipping me off! Looking forward to your reply keenly!
This is a security feature in browsers known as the same-origin policy. You can view this in action by firing up your browser-of-choice's dev tools and seeing what happens when it tries to fetch your JSON file.
There are various methods to work around this. If you have access to web hosting, throw it up there. Otherwise, choose a method to run a lightweight server locally. The simplest one that people are routinely told is to serve an index.html file in python:
#(in v2.x)
python -m SimpleHTTPServer 8000
#(in v3.x)
python -m http.server 8000
then browsing to localhost:8000. This is explained in slightly more detail on the d3 wiki. For more in-depth explanations and whatnot, I recommend some reading.

d3.js force layout doesn't run

I'm just starting with d3.js and can't get a simple demo to work correctly.
It's tough to debug: If there’s a bug, it often crashes in d3′s minified code with no stack trace. In this case, it doesn’t print any errors to the error console at all.
When I run this code, all my nodes are stuck in position (0,0) instead of being laid out by force(). What's wrong?
<html>
<meta charset="UTF-8">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
$(function() {
var svg = d3.select('#graph').append('svg').attr('width', 900).attr('height', 900)
var myNodes = [{name:'a'}, {name:'b'}, {name:'c'}]
var myLinks = [{source:myNodes[0], target:myNodes[1]}, {source:myNodes[1], target:myNodes[2]}, {source:myNodes[2], target:myNodes[0]}]
svg.append("text").text("myNodes[0].name=" + myNodes[0].name).attr('y', 50)
var force = d3.layout.force().charge(-120).linkDistance(30).size([900, 900])
var link = svg.selectAll("line")
.data(myLinks)
.enter().append("svg:line");
var node = svg.selectAll("circle")
.data(myNodes)
.enter().append("svg:circle")
.attr("r", 6)
.call(force.drag)
force.nodes(myNodes).links(myLinks).start()
});
</script>
</head>
<body>
<div id="graph"></div>
</body>
</html>
Force just handles setting x/y attributes on the nodes and links:
... The initial x and y coordinates, if not already set externally to a valid number, are computed by examining neighboring node..
It does not actually handle updating of the corresponding svg shapes. This you would typically do in the tick event:
Listen to tick events to update the displayed positions of nodes
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
The only other piece missing from your example is setting the style of the lines. By default they have no stroke color so appear invisible. You can either set the color directly on the line, like this:
var link = svg.selectAll("line")
.data(myLinks)
.enter().append("svg:line")
.attr('stroke', 'red')
.attr('stroke-width', 2)
Or make a CSS class for them:
<style>
.link {
stroke: blue;
stroke-width: 1.5px;
}
</style>
And tag them with it when you create them:
var link = svg.selectAll("line")
.data(myLinks)
.enter().append("svg:line")
.attr('class', 'link')

Resources