d3 tsv not working with django - javascript

I know this question is asked multiple times, but my problem seems to be unique:
my django view:
def data(request):
event = Event.objects.get(pk=request.GET.get('epk'))
occurrences = event.occurrences.all()
response = HttpResponse(content_type='text/tsv')
response['Content-Disposition'] = 'filename="data.tsv"'
response.write('date\tclose\n')
for occ in occurrences:
response.write('%s\t%s\n' % (occ.timestamp.strftime('%Y-%m-%d %H:%M:%S'), occ.counter))
return response
and js:
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%Y-%m-%d %H:%M:%S");
var x = d3.scaleTime().rangeRound([0, width]);
var y = d3.scaleLinear().rangeRound([height, 0]);
var line = d3.line().x(function (d) {
return x(d.date);
}).y(function (d) {
return y(d.close);
});
d3.tsv("{% url 'data' %}?epk={{ event.id }}", function (d) {
d.date = parseTime(d.date);
d.close = +d.close;
return d;
}, function (error, data) {
console.log(data); // ----> the screenshot at the bottom
if (error) throw error;
x.domain(d3.extent(data, function (d) {
return d.date;
}));
y.domain(d3.extent(data, function (d) {
return d.close;
}));
g.append("g")
.attr("transform", "translate(0," + 1 + ")")
.call(d3.axisBottom(x)) // <---- error place
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Occurs");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
});
</script>
content of tsv file I get from my django view is:
date close
2017-02-12 14:07:14 1
2017-02-12 14:07:35 1
2017-02-12 17:12:14 1
2017-02-12 17:23:40 1
2017-02-12 17:51:52 1
2017-02-13 04:15:58 1
the worst part is that it is working on plunker: http://plnkr.co/edit/Moyyawptt8lY0pLBDQDr?p=preview
but in my code, something is wrong. I just dont know where to debug, since the error message is so horribly unclear.
can someone please help me out? it would be the greatest help to humanity!
this is the screenshot from the console.log(data);

Related

How to do line graph from CSV into HTML

My code now looks like this:
<!DOCTYPE html>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
d3.tsv("data.tsv", function(d) {
d.date = parseTime(d.date);
d.close = +d.close;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
});
</script>
Now I would like to redo it to upload CSV file right there on this page and to read data from there.
The file is going to be a table with two columns: first one is going to be a column with dates, but the second one - with numbers, with which the graph will be built.
Now I also tried doing it like this:
<!DOCTYPE html>
<html lang="lv"><head>
<title>HTML formas</title>
<meta charset="UTF-8">
</head>
<body>
<p>Norādi datni</p>
<input type="file" id="datne" onchange="datnesApstrade()">
<p>Ielasītie dati</p>
<pre id="rezultats"></pre>
<script>
function datnesApstrade(){
var fr=new FileReader();
fr.onload=function(){
apstradat( fr.result );
}
f = document.getElementById("datne");
fr.readAsText(f.files[0]);
}
function apstradat( dati ) {
document.getElementById('rezultats')
.textContent=dati;
var rindas = dati.split("\n");
//document.getElementById('rezultats').textContent="Rindas:"+rindas.length;
//alert( "In file is " + rindas.length + " lines" );
var r, i, c, co2 = [];
// pirmā rindā ir tabulas galva, tāpēc to nelasām
for( r=1; r<rindas.length; r=r+1 ) {
c = rindas[r].split(",");
co2.push( Number(c[1]) );
}
var rl = rindas.length-2;
for (i=1; i<rl; i=i+1){
document.getElementById('rezultats').textContent=co2[i];
}
}
</script>
</body></html>
But I don't know how to modify it to achieve my goal. Please help!

Scale d3 x axis(time) to zero

I am making a chart using d3 and time data.
However, its scale is wrong.
It is a simple example.
Code is below:
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 50},
width = svg.attr("width"),
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%H:%M:%S");
var x = d3.scaleTime().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
d3.csv("data.csv", function(d) {
d.date = parseTime(d.date);
d.close = +parseFloat(d.close);
return d;
}, function(error, data) {
if (error) throw error;
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain");
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("dy", "0.71em")
.attr("y",2)
.attr("text-anchor", "end");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
});
Data is:
date,close
00:00:00,0.00
03:00:00,10
06:00:00,20
09:00:00,30
12:00:00,40
15:00:00,50
18:00:00,60
21:00:00,70
The point midnight,0 is wrong. It should be at 0,0.
Instead, it generates this:
How can it fit the chart correctly (starting at 0,0)?
Link to the Codepen:
https://codepen.io/jaqueline-passos/pen/mGpexG/

D3.Js- passing data set from C# to javascript does not work

This question is related to the following question that I posted some time ago.
D3.js - line graph is not displayed
I accepted one answer and based on that I did some modifications.
var data = $('#<%=hdnDtArray.ClientID%>').val();
var svg = d3.select("svg"),
margin = { top: 20, right: 20, bottom: 30, left: 50 },
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + ","
+ margin.top + ")");
var parseTime = d3.timeParse("%d-%b-%y");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function (d) { return x(parseTime(d.date)); })
.y(function (d) { return y(d.close); });
x.domain(d3.extent(data, function (d) { return parseTime(d.date); }));
y.domain(d3.extent(data, function (d) { return d.close; }));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
Here, "hdnDtArray" is an hidden input field in asp.net through which I pass the data set to the JavaScript code.
I debugged and found that it looks like the following.
[{"date":"2016.07.19","close":185697.89},
{"date":"2016.07.20","close":185697.89},
{"date":"2016.07.21","close":186601.1},
{"date":"2016.07.22","close":187273.89},
{"date":"2016.07.25","close":186807.74},
{"date":"2016.07.26","close":186893.26},....]
Graph is not displayed and there is this error
Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL…".
And, at the same time what I want Y axis to have is Years, months depending on the context. Like Jan, Feb, Mar etc.
or else, 2015,2016,2017 etc.
or else 2015-12-01,2015-12-02,2015-12-03 etc.
I should be able to pass these data through another array.
Can someone pls help ? I am a newbie to D3.js
The problem here is your specifier. Since your dates are...
"2016.07.19"
... your specifier should be:
var parseTime = d3.timeParse("%Y.%m.%d");
For a list of values for the specifier string, have a look at the API here.
Here is your code with that change only:
var data = [{
"date": "2016.07.19",
"close": 185697.89
}, {
"date": "2016.07.20",
"close": 185697.89
}, {
"date": "2016.07.21",
"close": 186601.1
}, {
"date": "2016.07.22",
"close": 187273.89
}, {
"date": "2016.07.25",
"close": 186807.74
}, {
"date": "2016.07.26",
"close": 186893.26
}]
var svg = d3.select("svg"),
margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var parseTime = d3.timeParse("%Y.%m.%d");
var x = d3.scaleTime()
.rangeRound([0, width]);
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var line = d3.line()
.x(function(d) {
return x(parseTime(d.date));
})
.y(function(d) {
return y(d.close);
});
x.domain(d3.extent(data, function(d) {
return parseTime(d.date);
}));
y.domain(d3.extent(data, function(d) {
return d.close;
}));
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.select(".domain")
.remove();
g.append("g")
.call(d3.axisLeft(y))
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Price ($)");
g.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="300"></svg>

Can't decrease number of ticks in axisBottom

I'm trying to create some bar chart with the U.S. GDP growth. In the x axis, all the YYYY-MM-DD values are shown even though I explicitly set .call(d3.axisBottom(x).ticks(10); What should I do? I tried it with d3.timeYear.every(25) too.
Here's my code:
var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json";
var svg = d3.select("svg"),
margin = {top: 20, right: 20, bottom: 30, left: 40},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var x = d3.scaleBand().rangeRound([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.json(url, function(error, data) {
if (error) throw error;
x.domain(data.data.map(function(d) { return d[0]; }));
y.domain([0, d3.max(data.data, function(d) { return d[1]; })]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(d3.timeYear.every(25)));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(10))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("font-size", "30px")
.attr("font-color", "black")
.attr("dy", "7.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.selectAll(".bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d[0]); })
.attr("y", function(d) { return y(d[1]); })
.attr("width", x.bandwidth())
.attr("height", function(d) { return height - y(d[1]); });
});
You have two problems here. First, you are using a band scale, and d3.timeYear.every(25) will have no effect. But, on top on that, you're using that d3.timeYear.every(25) inside a ticks function, and that won't work.
According to the API:
This method has no effect if the scale does not implement scale.ticks, as with band and point scales. (emphasis mine)
Thus, a possible solution is filtering the band scale's domain inside a tickValues function.
In this example, I'm filtering one tick out of every 20. Also, I'm splitting the string to show only the year:
d3.axisBottom(x).tickValues(x.domain().filter(function(d, i) {
return !(i % 20);
})).tickFormat(function(d) {
return d.split("-")[0]
});
Here is your code with that change:
var url = "https://raw.githubusercontent.com/FreeCodeCamp/ProjectReferenceData/master/GDP-data.json";
var svg = d3.select("svg"),
margin = {
top: 20,
right: 10,
bottom: 30,
left: 50
},
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var x = d3.scaleBand().range([0, width]).padding(0.1),
y = d3.scaleLinear().rangeRound([height, 0]);
d3.json(url, function(error, data) {
if (error) throw error;
x.domain(data.data.map(function(d) {
return d[0];
}));
y.domain([0, d3.max(data.data, function(d) {
return d[1];
})]);
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickValues(x.domain().filter(function(d, i) {
return !(i % 20);
})).tickFormat(function(d) {
return d.split("-")[0]
}))
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y).ticks(10))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("font-size", "30px")
.attr("font-color", "black")
.attr("dy", "7.71em")
.attr("text-anchor", "end")
.text("Frequency");
g.selectAll(".bar")
.data(data.data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d[0]);
})
.attr("y", function(d) {
return y(d[1]);
})
.attr("width", x.bandwidth())
.attr("height", function(d) {
return height - y(d[1]);
});
});
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="400"></svg>

D3 v4 line chart with JSON dates

I've worked on this for a few days now, and I cant really get my line drawn and got some date formating problems I can't crack.
Using this D3 v3 fiddle as inspiration: http://jsfiddle.net/vmvp0zja/ I tried to convert it to D3 v4, but I can't really get my data drawn properly.
I am trying to draw several lines, but I cant even draw one..
Could you take a look and see what I am missing here? Thanks! :)
// JSON data:
var data = [
{"Date":"\/Date(1475272800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475359200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475532000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475618400000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475704800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475791200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475877600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475964000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476050400000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476136800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476223200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476309600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476396000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475532000000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475618400000)\/","Open":2,"Closed":0},
{"Date":"\/Date(1475791200000)\/","Open":9,"Closed":0},
{"Date":"\/Date(1475964000000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475532000000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475618400000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475964000000)\/","Open":0,"Closed":1}]
This is my D3 mess:
// linechart.js
var formatTime = d3.timeFormat("%Y-%m-%d");
data.forEach(function (d) {
var unixToISO = new Date(d.Date.match(/\d+/)[0]*1);
d.Date = formatTime(unixToISO);
d.Open = +d.Open;
d.Closed = +d.Closed;
console.log(d.Date);
return d;
});
var margin = {top: 30, right: 40, bottom: 30, left: 50 },
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var x = d3.scaleTime()
.range([0, width]);
var y0 = d3.scaleLinear()
.range([height, 0]);
// Scale the range of the data
x.domain(d3.extent(data, function (d) { return d.Date; }));
y0.domain([
d3.min(data, function (d) { return Math.min(d.Open); }),
d3.max(data, function (d) { return Math.max(d.Open); })]);
var valueline1 = d3.line()
.x(function (d) { console.log(x(d.Date)); return x(d.Date); })
.y(function (d) { return y(d.Open); });
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 + ")");
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("class", "y axis")
.style("fill", "steelblue")
.call(d3.axisLeft(y0));
svg.append("path") // Add the valueline path.
.data(data)
.attr("class", "line")
.attr("d", valueline1);
Help much appreciated in advance. I am probably overlooking something obvious.
Thank you!
Changes:
data.forEach(function(d) {
var unixToISO = new Date(d.Date.match(/\d+/)[0] * 1);
d.Date = unixToISO; // here
d.Open = +d.Open;
// (...)
var valueline1 = d3.line()
.x(function(d) {
console.log(x(d.Date));
return x(d.Date);
})
.y(function(d) {
return y0(d.Open); // here
});
// (...)
svg.append("path")
.data([data]) // here
.attr("class", "line")
.attr("d", valueline1);
and added x-axis labels with
svg.append("text")
.attr("transform", "translate(" + (width / 2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
BTW, your data is unsorted.
JSFiddle Demo
Docs reference

Categories