I'd like to plot a multi line graph with d3.js.
I have following data, which I get from a database and convert to JSON.
{"items":["itemID01","itemID12","itemID14","itemID15","itemID16"],
"alpha":{
"xvalue":["itemID03","itemID12","itemID14","itemID16"],
"yvalue":[0,0,0,0]},
"beta":{
"xvalue":["itemID03","itemID12","itemID16"],
"yvalue":[0,2,0]},
"gamma":{
"xvalue":["itemID03","itemID12","itemID14","itemID16"],
"yvalue":[9,10,8,9]},
"delta":{
"xvalue":["itemID12","itemID14","itemID16"],
"yvalue":[2,0,2]},
"epsilon":{
"xvalue":["itemID12"],
"yvalue":[3]}}
I got it to work with one line. When I adjusted it to multiple lines, it doesn't show any lines at all. The code is based on this tutorial by d3noob http://www.d3noob.org/2013/01/adding-more-than-one-line-to-graph-in.html
This is my javascript code:
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangePoints([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// get the JSON data
d3.json("getdata.php", function(error, data) {
//console.log(data);
x.domain(data.items);
y.domain([0, d3.max(d3.values(data.gamma.yvalue))]);
// hardcoded for now, use d3.max(data, function(d) { return Math.max(d.alpha.yvalue, d.beta.yvalue, ...); })
// get the array keys
var keys = [];
for (var key in data){
if (data.hasOwnProperty(key) && key !== 'items') {
keys.push(key);
}
}
//console.log(keys);
var valueline = [];
var i = 0;
keys.forEach(function(k) {
valueline[i] = d3.svg.line()
//.defined(function(d) { return (d.xvalue !== null); })
.x(function(d) { return x(d.xvalue); })
.y(function(d) { return y(d.yvalue); });
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline[i](data[k]));
//console.log(data[k]);
i++;
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(-10,0)")
.call(yAxis);
});
I set up a jsfiddle with the code http://jsfiddle.net/5PcPU/
I tried different variations of having svg.append("path") in and out of the foreach loop and just one valueline element or an array. But nothing worked so far
My guess is that the error is close to those lines
.x(function(d) { return x(d.xvalue); })
.y(function(d) { return y(d.yvalue); });
since if I try to do this, I don't get any output
.x(function(d) {
console.log('test');
console.log(d.xvalue);
return x(d.xvalue); })
I could make it work by rearranging the json data. If I use an array of x AND y values instead of one array for the x values and another one for the y values, it plots like I expect it to.
So the data looks like this:
{"items":["itemID01","itemID12","itemID14","itemID15","itemID16"],
"alpha":[{"x":"itemID03","y":0},
{"x":"itemID12","y":0},
{"x":"itemID14","y":0},
{"x":"itemID16","y":0}],
"beta":[{"x":"itemID03","y":0},
{"x":"itemID12","y":2},
{"x":"itemID16","y":0}],
"gamma":[{"x":"itemID03","y":9},
{"x":"itemID12","y":10},
{"x":"itemID14","y":8},
{"x":"itemID16","y":9}],
"delta":[{"x":"itemID12","y":2},
{"x":"itemID14","y":0},
{"x":"itemID16","y":2}],
"epsilon":[{"x":"itemID12","y":3}]}
Related
I'm using angularjs to get data from facebook
I have written following code.
At the backend,it is giving proper output but for $scope.chart variable but at the front end when I log the data it is showing date:null.I'm uploading images for resprctive data.Backend Data Imagefrontend data showing date Null
<script>
function mychart(){
var dom_el = document.querySelector('[ng-controller="myCtrl"]');
var ng_el = angular.element(dom_el);
var ng_el_scope = ng_el.scope();
var data = ng_el_scope.chart;
//var data = chart;
console.log(data);
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
</script>
I have unable draw for the line graph in the d3.js,i wrote some code but enable show the graph,how to draw a line for the given data.I have a problem for the how to parse the data for the given data and draw a lines ffor the given data of code.
var data=[{"key":[2000,1,1,12],"value":1000},{"key":[2000,2,1,12],"value":38965},
[{"key":[2000,7,1,24],"value":289},{"key":[2000,8,1,24],"value":389}
]
var parseDate = d3.time.format("%Y.%m.%d.%H").parse;
var map=data.map(function (d){
return {
key:parseDate((d.key[0])+"."+(d.key[1]+1)+"."+(d.key[2])+"."+(d.key[3]+1)),value:+d.value
}
});
console.log(map);
var margin = {top: 15, right: 20, bottom: 70, left: 85},
width = 440,height = 450;
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom")
var yAxis = d3.svg.axis().scale(y).orient("left")
var line = d3.svg.line()
.x(function(d) { return x(d.key); })
.y(function(d) { return y(d.value); })
.interpolate("cardinal")
var svg = d3.select("body").select("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
x.domain(d3.extent(d3.map(function (d){return d.key;})));
y.domain(d3.extent(d3.map(function (d){return d.key;})));
svg.append("g")
.attr("class", "x axis x-axis")
.attr("transform", "translate(0," + height + ")").attr("fill","steelblue")
.call(xAxis);
svg.append("g").attr("class", "y axis y-axis").attr("fill","steelblue").call(yAxis)
svg.append("path").datum(map).attr("class", "line").attr("d", line);
There seem to be a number of problems with the above code including an extra [ in the data, which should be:
var data=[
{"key":[2000,1,1,12],"value":1000},
{"key":[2000,2,1,12],"value":38965},
{"key":[2000,7,1,24],"value":289},
{"key":[2000,8,1,24],"value":389}
]
Other than that, the way you parse the data seems fine, but there are some issues with the way you set up the chart.
I've created a new line chart using your data here: http://jsfiddle.net/henbox/9etp0xap/, based on this example: http://bl.ocks.org/mbostock/3883245
You'll probably find it easier to modify that jsfiddle rather than to debug the specific issues.
I am trying to create a line graph using D3. The data for the graph is stored in an XML file like this:
XML Code:
<record>
<date_value>1376092800000</date_value>
</record>
JavaScript Code:
var record=xmlDoc.getElementsByTagName("record");
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.xml("values.xml", "application/xml", function(data) {
for(var d = 0; d < record.length; d++){
d.date = parseDate(record[d].getElementsByTagName("date_value")[0].childNodes[0].nodeValue);
d.close += 1;
};
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
I'm having trouble with the part where I get the data. The x value is the date value and the y value should be increased by one each time. With the current code I have no errors, but only the y axis is showing with no data. I would appreciate any suggestions. Thanks!
I am new to d3.js and am trying to graph three lines on the same plot. I'm reading from a tsv file with four columns: time, x, y, and z. This is accelerometer data. I want to plot the x,y,z columns vs time but can't seem to get it. Any suggestions?
function graph(){
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.x); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.y); })
var valueline3 = d3.svg.line()
.x(function(d) { return x(d.time); })
.y(function(d) { return y(d.z); });
// Adds the svg canvas
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.tsv("data/data2.tsv", function(error, data) {
data.forEach(function(d) {
d.time = +d.time;
d.x = +d.x;
d.y = +d.y;
d.z = +d.z;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.time; }));
y.domain([0, d3.max(data, function(d) { return Math.max(d.x, d.y, d.z); })]);
// Add the valueline path.
svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data));
svg.append("path") // Add the valueline path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2(data));
svg.append("path") // Add the valueline path.
.attr("class", "line")
.style("stroke", "green")
.attr("d", valueline3(data));
// Add the X Axis
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
});}
You can add each line one at a time to the canvas but it's not very d3 or efficient. It's much better to organise your data in the appropriate way. So the the main issue is the way that the data's been prepared. In the example that Lar's pointed to the data is nested using this block of code:
var series = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
time: d.time,
score: +d[name]
};
})
};
});
And what this does is to create an array of 3 objects. Each object has a key value pair: name and
an array. In each array is another object which contains the time and score information for plotting. It is this last array of object that is passed to the line generator.
I've created a fiddle, here, that's heavily based on the example that Lar's has pointed to and it's commented throughout. The trick at this stage is to inspect the elements and use console.log
Best of luck.
I'm playing again with d3.js the javascript library. I am able to create a chart with 2 numeric axes but now I want to have one numeric axis and one axis with a date. Unfortunately I'm not able to do this.
First of all, thats the code that is not running:
d3.json('builds.json',
function(data){
var format = d3.time.format("%Y-%m-%d");
data.forEach(function(d) {
d.finished_at = format.parse(d.finished_at);
});
var margin = {top: 40, right: 40, bottom: 40, left: 40},
width = 960,
height = 500;
var x = d3.time.scale()
.domain(d3.extent(data, function(d) { return d.finished_at; }))
.range([0, width - margin.right - margin.left]);
var y = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d.result; }))
.range([height - margin.top - margin.bottom, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) { return x(d.finished_at); })
.attr("cy", function(d) { return y(d.result); })
.attr("r", 6);
svg.append("g") // Render the axis by calling a <g> selection.
.attr("transform", "translate(0," + y.range()[0] + ")") //setzt x-achse an null punkt von y-achse
.call(xAxis);
svg.append("g")
.call(yAxis);
});
The variable finished_at looks like this: "finished_at":"2011-11-20" and I tried to parse it.
But the output is the following:
Can anybody please help me?
The problem likely lies with your data. You will need to confirm that all of the finished_at values in your JSON are in the correct format.
Your code appears to work perfectly well with a small working JSON dataset: http://bl.ocks.org/4162693