I got this CSV data (just a sample- it is bigger):
value;count
25;1
28;1
29;3
31;2
34;1
36;1
37;2
I could not find any example which shows line chart without Date function so I modified the example to make linear scales but it does not work. I am trying to make line chart with this code but I get Error: attribute d: Expected number
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// set the ranges
var x = d3.scaleLinear().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
// define the line
var valueline = d3.line()
.x(function(d) { return x(d.value); })
.y(function(d) { return y(d.count); });
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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.csv("exp2.csv", function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.value = +d.value;
d.count = +d.count;
});
// Scale the range of the data
x.domain([0, d3.max(data, function(d) { return d.value; })]);
y.domain([0, d3.max(data, function(d) { return d.count; })]);
// Add the valueline path.
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline);
// Add the X Axis
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add the Y Axis
svg.append("g")
.call(d3.axisLeft(y));
});
As #GerardoFurtado pointed out your data is not csv (ie comma separated) but semi-colon separated. My initial thought was to close this as a duplicate of this question but it looks like the syntax has changed enough in version 4 that I new answer is warranted.
Do this:
// set up a parser
var parser = d3.dsvFormat(';').parse;
// get the data as text
d3.text("exp2.csv", function(error, data) {
if (error) throw error;
// now parse the data
data = parser(data);
// format the data
data.forEach(function(d) {
d.value = +d.value;
d.count = +d.count;
});
...
Here's a full running example.
Related
I am trying to plot a multi-line graph with d3.js but I am getting this error:
Error: attribute d: Expected moveto path command ('M' or 'm'), "function t(t){va…".
I have been stuck at it a while now and tried everything I could think of, to help you in your reflections, Find the code that I use below.
// set the dimensions and margins of the graph
var margin = {top: 10, right: 30, bottom: 30, left: 60},
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
const dateParser = d3.timeFormat("%Y-%m-%d %H:%M:%S");
data.forEach(function(d) {
d.ts = dateParser(new Date(d.ts));
d.value = parseFloat(d.value)
});
// append the svg object to the body of the page
var svg = d3.select("#graph")
.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 + ")");
//Read the data
// group the data: I want to draw one line per group
var sumstat = d3.nest() // nest function allows to group the calculation per level of a factor
.key(function(d) { return d.key;})
.entries(data);
// Add X axis --> it is a date format
var x = d3.scaleLinear()
.domain(d3.extent(data, function(d) { return d.ts; }))
.range([ 0, width ]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(5));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, d3.max(data, function(d) { return +d.value; })])
.range([ height, 0 ]);
svg.append("g")
.call(d3.axisLeft(y));
// color palette
var res = sumstat.map(function(d){ return d.key }) // list of group names
var color = d3.scaleOrdinal()
.domain(res).range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628','#f781bf','#999999'])
// Draw the line
svg.selectAll(".line")
.data(sumstat)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function(d){ return color(d.key) })
.attr("stroke-width", 1.5)
.attr("d", function(d){
return d3.line()
.x(function(d) { return x(d.ts); })
.y(function(d) { return y(d.value); })
})
I cannot figure what I am doing wrong, in case the example I am looking at is this link. I am fairly new to d3 and it is not an easy library to use
When you set the d attribute, you return the line generator itself from the data linking function, but you fail to execute it. Configuring the generator and executing it is a two-step process:
first, contruct and configure the generator (line is a function)
var line = d3.line()
.x(function(d) { return x(d.ts); })
.y(function(d) { return y(d.value); })
then, pass the function to attr(), so it will be executed as line(d)
svg.selectAll(".line")
.data(sumstat)
.enter()
.append("path")
.attr("fill", "none")
.attr("stroke", function(d){ return color(d.key) })
.attr("stroke-width", 1.5)
.attr("d", line)
I am using D3.js to create a simple line graph.
<div>
<h6>Price Over Time</h6>
<div id="priceOverTimeChart"></div>
</div>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 800 - 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(10);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(10);
// 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("#priceOverTimeChart")
.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.csv("data.csv", function(error, 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);
});
The data for the line graph uses the following data format:
26-Apr-12,0.048
25-Apr-12,0.048
24-Apr-12,0.048
I would like to add an optional string to each record so it looks like:
26-Apr-12,0.048, "product 1 launch",
25-Apr-12,0.048, "product 2",
24-Apr-12,0.048, "product 3"
26-Apr-12,0.048, null
25-Apr-12,0.048, null
24-Apr-12,0.048, null
The graph would then look something like this with the labels on it:
Graph with optional labels
How can I accomplish this? Thanks in advance!
Appending texts to the corresponding x, y position will do the trick.
Please refer this working JS Fiddle
svg.append("g").selectAll("text")
.data(data)
.enter()
.append("text")
.attr("x", function(d) { return x(d.date) - paddingForText })
.attr("y", function(d) { return y(d.close) + paddingForText })
.attr("fill", "red")
.text(function(d) { return d.notes });
Here is my code:
// 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-%m-%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.AtTime); })
.y(function(d) { return y(d.Temperature); });
// 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.csv("../datasets/test.csv", function(error, data) {
data.forEach(function(d) {
d.AtTime = parseDate(d.AtTime);
d.Temperature = +d.Temperature;
});
console.log(data);
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.AtTime; }));
y.domain([0, d3.max(data, function(d) { return d.Temperature; })]);
// 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);
});
And the line chat just can not show...Here is my simple csv dataset:
Category,Temperature,Pressure,AtTime
A,76,400,1-1-2014
B,23,239,2-3-2013
C,38.6,378,2-6-2016
D,43.2,289,3-5-2015
E,49,501,3-5-2015
I used console.log(data) to check, and I found that AtTime has null value.... I do not why..Anyone could help me with this? Thanks!
It's one character in your time format string.
//var parseDate = d3.time.format("%d-%m-%y").parse; // lower-case Y expects two digits only
var parseDate = d3.time.format("%d-%m-%Y").parse; // use capital Y for 4 digit years
see https://github.com/d3/d3/wiki/Time-Formatting#format for all the different modifiers
There is a mistake in your dates, I parsed them and ordered them so the line would render correctly.
data.forEach(function(d) {
var dateArr = d.AtTime.split('-');
d.AtTime = new Date(+dateArr[2], +dateArr[1], +dateArr[0]);
d.Temperature = +d.Temperature;
})
data.sort(function(a, b) {
return new Date(b.AtTime) - new Date(a.AtTime);
});
Remove the implicit number cast in your valueLine function:
var valueline = d3.svg.line()
.x(function(d) {
return x(d.AtTime);
})
.y(function(d) {
return y(d.Temperature);
});
And finally if you don't have any css add a stroke to your line so it renders:
svg.append("path")
.attr("class", "line")
.attr('stroke', 'red')
.attr("d", valueline(data));
Working plnkr: https://plnkr.co/edit/ujFDtHkdtC2EeBwJ1foU?p=preview
Fiddle (updating it now): http://jsfiddle.net/hy6r1peb/
I'm attempting to plot points via line graph based on the following data pulled from a JSON API:
var data = {
"january": [
{"total": "31", "date": "2015-01-01"},
{"total": "19", "date": "2015-01-05"},
{"total": "4", "date": "2015-01-10"}
], "error": false, "status": 200
};
This is my code from the d3noobs tutorial. It throws an error on line 1 of d3.js. Where have I gone wrong?
// 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("%Y-%m-%d").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 + ")");
d3.json(URL, function(error, data) {
if (error) return console.warn(error);
else {
data = data.january;
data.forEach(function(d) {
d.date = parseDate(d.date);
d.total = +d.total;
});
}
// 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.total; })]);
// 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 typo'd and had d.close in there when I shouldn't have. Doing this purely to close the question -- all credit goes to Terry for his sharp eyes.
I'm attempting to learn D3 by following some of the simple bl.ock examples. One of the examples uses a CSV file to create a line graph.
I'm using this JSON file to create the path for the graph. The code below outputs the correct data to the console, but when I try to append the data (d.date, d.rain) to the x and y domains, nothing displays.
To the console...
// hold the daily rain total
var daily_rain_total;
// get the data
d3.json("data.json", function(error, data) {
// log the returned object on console unless error
if (error) return console.error(error);
console.log(data);
days = data.data.weather;
// step through each day
days.forEach(function(d) {
hourly = d.hourly;
hourly.forEach(function(h) {
daily_rain_total = daily_rain_total + parseFloat(h.precipMM);
});
d.date = d.date;
console.log(d.date);
d.rain = daily_rain_total.toFixed(2);
console.log(d.rain);
// reset total
daily_rain_total = 0;
});
});
Render a line 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.date); })
.y(function(d) { return y(d.rain); });
// 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 + ")");
// hold the daily rain total
var daily_rain_total;
// get the data
d3.json("data.json", function(error, data) {
// log the returned object on console unless error
if (error) return console.error(error);
console.log(data);
days = data.data.weather;
// step through each day
days.forEach(function(d) {
// step through each hour
hourly = d.hourly;
hourly.forEach(function(h) {
daily_rain_total = daily_rain_total + parseFloat(h.precipMM);
});
d.date = d.date;
console.log(d.date);
d.rain = daily_rain_total.toFixed(2);
console.log(d.rain);
// reset total
daily_rain_total = 0;
});
// 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.rain; })]);
// 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);
});
Any tips are greatly appreciated.