This page needs to display a graph that reads the data from a CSV file.
I have been following a tutorial on TheCodingTutorials.
I'm also trying to follow the Multi-Column Data tutorial so that i can add the name to the graph. This is where i'm getting lost, the tutorial make it sound easy but i just don't get it. Every time i try to edit the code it errors out.
It works perfectly if you only want to read a single column csv file.
However I want to read a multiple columns csv file.
Also if there is something that could make it better please let me know.
<html>
<head>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
<html>
<head>
<meta http-equiv="Expires" content="-1">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
{
d3.text("data2.csv", function(unparsedData)
{
var data = d3.csv.parseRows(unparsedData);
//Create the SVG graph.
var svg = d3.select("body").append("svg").attr("width", "100%").attr("height", "100%");
var dataEnter = svg.selectAll("rect").data(data).enter();
var graphHeight = 450;
var barWidth = 20;
var barSeparation = 10;
var maxData = 105;
var horizontalBarDistance = barWidth + barSeparation;
var textYOffset = horizontalBarDistance / 2 - 12;
var textXOffset = 20;
var barHeightMultiplier = graphHeight / maxData;
//Draw the bars.
dataEnter.append("rect").attr("y", function(d, i)
{
return i * horizontalBarDistance;
}).attr("x", function(d)
{
return 100;
}).attr("height", function(d)
{
return barWidth;
}).attr("width", function(d)
{
return d * barHeightMultiplier;
});
//Draw the text.
dataEnter.append("text").text(function(d)
{
return d;
}).attr("y", function(d, i)
{
return i * horizontalBarDistance + textXOffset;
}).attr("x");
});
};
}
</script>
</head>
<body onLoad="JavaScript:timedRefresh(10000);">
</body>
</html>
My CSV file now looks like this
names,data
john,78
brad,105
amber,103
james,2
dean,74
pat,45
matt,6
andrew,18
ashley,15
==================================================================================
UPDATE
==================================================================================
Thanks to all your help this is my updated code.
<html>
<head>
<meta http-equiv="Expires" content="-1">
<script type="text/javascript" src=".\JavaScripts\d3.v3.min.js"></script>
<script type="text/javascript">setTimeout(function(){window.location.href='index2.html'},120000);
d3.csv("./data/data.csv", function(data){
//Create the SVG graph.
var svg = d3.select("#graph").append("svg").attr("width", "1800").attr("height", "600");
var dataEnter = svg.selectAll("rect").data(data).enter();
var graphWidth = 800;
var barWidth = 40;
var barSeparation = 30;
var maxData = 2;
var horizontalBarDistance = barWidth + barSeparation;
var textYOffset = 25;
var barXOffset = 260;
var barYOffset = 5;
var numXOffset = 230;
var barHeightMultiplier = graphWidth / maxData;
var fontSize = "30px";
var color = d3.scale.category10();
//Draw the bars.
dataEnter.append("rect")
.attr("fill",function(d,i){return color(i);})
.attr("y", function(d, i){return i * horizontalBarDistance - barYOffset;})
.attr("x", barXOffset)
.attr("height", function(d){return barWidth;})
.attr("width", function(d){return d.data * barHeightMultiplier;});
//Draw the text.
dataEnter.append("text")
.text(function(d){return d.Name;})
.attr("font-size", fontSize)
.attr("font-family", "sans-serif")
.attr("y", function(d, i){return i * horizontalBarDistance + textYOffset;})
.attr("x");
//Draw the numbers.
dataEnter.append("text")
.text(function(d){return d.data;})
.attr("font-size", fontSize)
.attr("font-family", "sans-serif")
.attr("y", function(d, i){return i * horizontalBarDistance + textYOffset;})
.attr("x", numXOffset);
//Draw the Target bar
dataEnter.append("rect")
.attr("fill", "red")
.attr("y", function(d, i){return i * horizontalBarDistance;})
.attr("x", barXOffset + graphWidth)
.attr("height", 70)
.attr("width", 10);
});
</script>
<style type="text/css">
#title {
font-family:sans-serif;
font-size: 50px;
color:#000;
text-decoration: underline;
text-align: center;
width: 100%;
position:relative;
margin-top:20;
}
#graph {
overflow:hidden;
margin-top:40;
}
</style>
</head>
<body>
<div id="title">Graph 1</div>
<div id="graph"></div>
</body>
</html>
Because your data contains a header row as its first row, you should be using d3.csv.parse instead of d3.csv.parseRows. The CSV documentation explains the differences.
The result of parsing will be something that looks like this:
[
{"names": "john", "data": 78},
{"names": "brad", "data": 105},
...
]
So, when you use this data to create your rect elements, you get an object bound to each rect. Then when you use selection.attr or selection.style the d value you are passed will be the bound object. This means you will need to reference the property you want, either as d.names or d.data. Each column in the file will be a different property on the object (as shown above).
One other thing to consider is possibly replacing d3.text with d3.csv to retrieve the file and parse the data in one step.
Related
I made a bar chart from data from a .csv file. I am struggling to make the height of the bar chart. I would like the height to be taken from the data values of a specific column, in this case, the "NO OF RECORDS STOLEN" column in the file.
I have tried things like:
.attr("height", function(d) {return d["NO OF RECORDS STOLEN"];}
but it does not work.
This is my HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Bar Chart | Crime File</title>
<script type="text/javascript" src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<script type="text/javascript">
var dataset = "data_breaches.csv";
var w = 960;
var h = 500;
var barPadding = 1;
var barWidth = w / dataset.length - barPadding;
// create canvas
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// create bar chart
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x", function (d, i) {
return i * (barWidth + barPadding);
})
.attr("y", 0)
.attr("width", barWidth)
.attr("height", 100) // WORKING ON THIS
.attr("fill", function (d) {
return "rgb(200, 50, 50)";
});
// get data
d3.csv(dataset, function (data) {
// convert type from string to integer
data.forEach(function typeConv(d) {
// type conversion from string to number
d["YEAR"] = +d["YEAR"]; // for names with spaces
d["DATA SENSITIVITY"] = +d["DATA SENSITIVITY"];
d["NO OF RECORDS STOLEN"] = +d["NO OF RECORDS STOLEN"];
return d;
});
var arrayLength = data.length;
// fixed, should have been <, not <= bc n-1, not n
for (var i = 0; i < arrayLength; i++) {
var breachesData = data[i];
console.log(breachesData);
}
});
</script>
</body>
</html>
As mentioned in the comment at your question, you need to append the rectangles after the data is loaded. Also I reviewed your code and removed unnecessary parts for clarity. Pay attention to the comments that I've added and let us know if you have any questions. Good luck!
var dataset = "data_breaches.csv";
var w = 960;
var h = 500;
var barPadding = 1;
var barWidth = w / dataset.length - barPadding;
// create canvas
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// get data
d3.csv(dataset, function (data) {
// You need to create a "scale" to convert from your data values to pixels in the screen
var heightBy = "NO OF RECORDS STOLEN"
var scale = d3.scaleLinear()
.domain([0, d3.max(d => d[heightBy])])
.range([0, h])
// create bar chart
svg.selectAll("rect")
.data(data) // "dataset" is the filepath, "data" is the loaded file content
.enter()
.append("rect")
.attr("x", (d, i) => i * (barWidth + barPadding))
.attr("y", d => h - scale(d[heightBy])) // Remember that on SVG y=0 is at the bottom and the rect height grows down
.attr("width", barWidth)
.attr("height", d => scale(d[heightBy]))
.attr("fill", "rgb(200, 50, 50)");
});
I wonder how I can use the data from a database received via Socket.io from a Node.js server for a data visualisation with d3.
I´ve read some posts about using PHP and JSON for that. Do I really need JSON? And how can I do this without the need of PHP? Actually the data received from Socket.io is already stored in the array values_array. But this array is not accepted by d3.
So far I tried a getter function and tried to rewrite the array – without success.
Any advice would be appreciated.
Below you see the client-side HTML-code:
!doctype html>
<html>
<head>
<script src='//code.jquery.com/jquery-1.7.2.min.js'></script>
<script src='//localhost:3000/socket.io/socket.io.js'></script>
<script type="text/javascript" src="d3.v3.min.js"></script>
<script>
window.onload=function(){
var socket = io();
var values_array = new Array();
socket.on('server2browser', function(data) // receive
{
fkt_values_array(data);
});
function fkt_values_array(data)
{
$.each(data, function(i, obj)
{
values_array[i] = obj.numbers;
});
$('#arrayprint_values').text(values_array);
}
setTimeout(function()
{
dynamicData = values_array;
}, Math.random() * 1000);
dynamicData = [22,33,33]; // This works
// dynamicData = values_array; // But I can´t get data from Socket.io into d3
// Data visualisation (d3)
var dataset = dynamicData;
//Width and height
var w = 500;
var h = 200;
var barPadding = 1;
var svg = d3.select("#diagram")
.append("svg")
.attr("width", w)
.attr("height", h);
svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("y", function(d) {
return h - (d * 4); //Höher
})
.attr("width", w / dataset.length - barPadding)
.attr("height", function(d) {
return d * 4;
})
.attr("x", function(d, i) {
return i * (w / dataset.length);
})
.attr("fill", function(d) {
return "rgb(" + (d * 10) + ", 0, " + (d * 10) + ")";
});
svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("x", function(d, i) {
return i * (w / dataset.length) + (w / dataset.length - barPadding) / 2;
})
.attr("y", function(d) {
return h - (d * 4) + 14; //15 is now 14
})
.attr("font-family", "sans-serif")
.attr("font-size", "11px")
.attr("fill", "white")
.attr("text-anchor", "middle");
}
</script>
</head>
<body>
<div id='arrayprint_values'> Placeholder Text</div> // Here the array is successfully printed out
<div id="diagram"> Placeholder </div> // Here the diagram is displayed, but only with static data
</body>
</html>
Well, everything in JavaScript is JSON so it just kind of makes sense to use it.
And you don't need PHP. You seem to already have a Node server up, just use that :). However, your valuesArray is instantiated to an empty list and then reassigned a bunch of times to other objects. You may want to change that to increase code clarity. A possible error source is that D3 expects an array of numbers, but your function is getting strings or JSON. That is, either ["1", "2"] or [{number : 1}, {number : 2}] as opposed to [1,2]. Place console.log(obj.numbers) in fkt_values_array and see what it looks like
I am new in d3.js language. I am trying to built a simple application but I stuck some where. I have a separate .js file jack.js which makes pie chart when you link it with html page.
Problem I want to use that file in every html page with different data. But i cant find the perfect solution of this. whenever page loaded in browser, file load its pie chart visualization. So can you suggest me what should i need to do?
HTML page
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="lib/pie.js"></script>
<script>
dataset = [1,2,3,4,5];
</script>
</head>
<body>
</body>
</html> `
jack.js
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
<body>
<script type="text/javascript" src="lib/pie.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</body>
This way you can do this.
Hi Remove var dataset = [ 5, 10, 20, 45, 6, 25 ]; from jack.js and put them either in your html file like you did in the head of your html file. Call jack.js in the body.
This will ensure that the data is loaded first before jack.js.
Hence your code will look like this
Html
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Pie layout</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script>dataset = [1, 2, 3, 4, 5];</script>
</head>
<body>
<script type="text/javascript" src="lib/pie.js"></script>
</body>
</html>
pie.js
var w = 300;
var h = 300;
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Set up groups
var arcs = svg.selectAll("g.arc")
.data(pie(dataset))
.enter()
.append("g")
.attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");
//Draw arc paths
arcs.append("path")
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
//Labels
arcs.append("text")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("text-anchor", "middle")
.text(function(d) {
return d.value;
});
Alternatively, you place wrap you d3 code in a $( document ).ready( //your d3 code here ) http://learn.jquery.com/using-jquery-core/document-ready/
Alternatively
pie.js
$( document ).ready(
// d3 code here
var pie = d3.layout.pie();
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category10();
....
)
I pasted that code to jack.js file
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
//Width and height
var w = 300;
var h = 300;
var dataset = [ 5, 10, 20, 45, 6, 25 ];
var outerRadius = w / 2;
var innerRadius = 0;
var arc = d3.svg.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var pie = d3.layout.pie();
var color = d3.scale.category10();
var svg = d3.select("body").append("svg").attr("width", w)
.attr("height", h);
var arcs = svg.selectAll("g.arc").data(pie(dataset)).enter()
.append("g").attr("class", "arc")
.attr("transform", "translate(" + outerRadius + "," +outerRadius + ")");
arcs.append("path").attr("fill", function(d, i) {
return color(i);})
.attr("d", arc).on("mouseenter", function(d) {
//console.log("mousein")
text = arcs.append("text").attr("transform", arc.centroid(d))
.attr("dy", ".5em").style("text-anchor", "middle")
.style("fill", "blue").attr("class", "on")
.text(d.data.place);})
.on("mouseout", function(d) {
text.remove();});
//Labels
arcs.append("text").attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")"; })
.attr("text-anchor", "middle").text(function(d) {
return d.value;
});</script>
and linked it to my html page.
Problem: This jack.js file is not showing pie chart in HTML page. can any body suggest me what should I need to do?
Is this the behavior you wanted?
plnkr
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script type="text/javascript" src="jack.js"></script>
<h1>Hello Plunker!</h1>
</body>
</html>
Below is the important part of the code:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="firstdoc.css">
<meta charset="utf-8">
<title>Multi-Class Test Error Visualization</title>
<script src="http://d3js.org/d3.v3.js"></script>
<style>
text.title {
font: 20px sans-serif;
font-family: Calibri;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<script type="text/javascript">
w = 400;
h = 400;
barPadding = 1;
top_gap = 100;
left_gap = 50;
var output_format = d3.format("d");
// create svg given the height/width above
var svg = d3.select("body")
.append("svg")
.attr("width", w + left_gap)
.attr("height", h + top_gap);
var labels = [];
var labels2 = [];
d3.text("d3_output.csv", function(error, fulldata) {
labels = d3.csv.parseRows(fulldata);
fulldata = d3.merge(labels);
labels = labels[0];
console.log(labels);
n = labels.length;
fulldata = fulldata.slice(n,fulldata.length);
console.log(fulldata);
svg.selectAll("top.headers")
.data(labels)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("x", function(val, elem_num) {
return ((elem_num%n) * (w / n)) + (w/n)/2 - 2 + left_gap;
})
.attr("y", 90)
.attr("font-family", "sans-serif")
.attr("text-anchor", "middle")
.attr("font-size", "11px")
.attr("fill", "black");
svg.selectAll("left.headers")
.data(labels)
.enter()
.append("text")
.text(function(d) {
return d;
})
.attr("x", 23)
.attr("y", function(val, elem_num) {
return elem_num*(h/n) + (w/n)/2 + 2 + top_gap;})
.attr("font-family", "sans-serif")
.attr("text-anchor", "left")
.attr("font-size", "11px")
.attr("fill", "black");
This code correctly creates a heat map from a CSV file that is 11 x 10, with the first row consisting of the headers.
But now I have a problem that requires two separate headers, which I plan to stick right into the CSV in this format:
Top Headers (10 elements)
Left Headers (10 elements)
Data (10 x 10 matrix)
I've created var labels2 = []; to store the left side headers, but I can't figure out what else to change in the code.
You would assign the second element of the array to your new labels variable and cut fulldata accordingly.
temp = d3.csv.parseRows(fulldata);
fulldata = d3.merge(temp);
labels = temp[0];
labels2 = temp[1];
fulldata = fulldata.slice(labels.length + labels2.length, fulldata.length);