D3 update line graph - csv

I created a line graph using a csv file and now I am trying to update this graph using new data from the same csv. However when I open the file in firefox I am getting an error: ReferenceError: updateData is not defined.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3/d3.min.js"></script>
</head>
<body>
<div id="option">
<input name="updateButton"
type="button"
value="Update"
onclick="updateData()" />
</div>
<script type="text/javascript">
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 150},
width = 1000 - margin.left - margin.right,
height = 400 - 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)
.tickFormat(d3.format(".0f"))
.orient("bottom");
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.Year); })
.y(function(d) { return y(d.AttendancePerG); });
// 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("piratesAttendance.csv", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.AttendancePerG = +d.AttendancePerG;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.AttendancePerG; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data))
.attr("stroke", "black")
.attr("stroke-width",2)
.attr("fill","none");
// 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);
function updateData() {
// Get the data again
d3.tsv("pittsburghAttendance", function(error, data) {
data.forEach(function(d) {
d.Year = +d.Year;
d.Attendance = +d.Attendance;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.Year; }));
y.domain([0, d3.max(data, function(d) { return d.Attendance; })]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("class", "line")
.attr("d", valueline(data));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
});
</script>
</body>
</html>

Your function updateData is defined in a callback, so it will not be in the "global" scope of your page, hence you cannot invoke it from the HTML.
Try to simply move its declaration to the beginning (or end) of your <script> tag.
Oh and also your usage of d3.csv seems incorrect.

Related

D3 svg chart can't display in IE

I'm building a website which contains d3 svg to display the bar chart. It can display in Chrome, Firefox, Edge, Safari, but it is not working in IE. I have tried to use canvas method, but it is not working. Then I tried set viewbox for svg, but it is not working as well. Could anyone help me solve this problem?
Here's my d3.js and html code
function homeStats() {
var jsonobj = document.getElementById('stats-data').value;
var data = JSON.parse(jsonobj);
var parentDiv = document.getElementById("home-stats");
function drawbar() {
var margin = { top: 40, right: 20, bottom: 100, left: 40 };
var width = parentDiv.clientWidth - margin.left - margin.right;
var height = parentDiv.clientHeight - margin.top - margin.bottom;
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function (d) {
return "<span style='color:white'>" + d.value + "</span>";
})
d3.selectAll('#home-stats-svg').remove()
var svg = d3.select("#home-stats").append("svg").attr("id", "home-stats-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.call(tip);
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .65);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["#f79944", "#20b5e1"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
var columnNames = d3.keys(data[0]).filter(function (key) { return key !== "Year"; });
data.forEach(function (d) {
d.subGroups = columnNames.map(function (name) { return { name: name, value: +d[name] }; });
});
x0.domain(data.map(function (d) { return d.Year; }));
x1.domain(columnNames).rangeRoundBands([0, 30]);
y.domain([0, d3.max(data, function (d) { return d3.max(d.subGroups, function (d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end");
const rx = 5;
const ry = 5;
var Year = svg.selectAll(".Year")
.data(data)
.enter().append("g")
.attr("class", "Year")
.attr("transform", function (d) { return "translate(" + x0(d.Year) + ",0)"; });
Year.selectAll("rect")
.data(function (d) { return d.subGroups; })
.enter().append("path")
.style("fill", function (d) { return color(d.name); })
.attr("d", item => `
M${x1(item.name)},${y(item.value) + ry}
a${rx},${ry} 0 0 1 ${rx},${-ry}
h${10 - 2 * rx}
a${rx},${ry} 0 0 1 ${rx},${ry}
v${height - y(item.value) - ry}
h${-(10)}Z
`)
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
var legend = svg.selectAll(".legend")
.data(columnNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function (d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 5)
.attr("width", "1vw")
.attr("height", "2vh")
.style("fill", color);
legend.append("text")
.attr("x", width - 7)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function (d) { return d; });
}
drawbar();
}
Html
<div id="home-stats" style="height:50vh; width:45vw">
<input type="hidden" id="stats-data" value=#ViewBag.deaths_json />
<svg id="home-stats-svg" viewBox="0 0 100 100"></svg>
</div>
Since the arrow function expression doesn't support IE browser, we could use babeljs.io to convert this function to ES5 format.

populating the JSON data from spring mvc to d3 chart using request body

I'm tyring to poplulate the data from the server as json into d3 to generate chart.
In server side I generated the JSON object using spring as below, by just populating the data in hashmap and sending the responce through spring responce body.
#RequestMapping("/greeting1")
#ResponseBody
public LinkedHashMap<String, String> greeting1(#RequestParam(value = "name", required = false) String name,
Model model) {
LinkedHashMap<String, String> values = data.populateData();
model.addAttribute("name", values);
return values;
}
In client side I'm populating the data to a div and trying to inject into d3 as below (but dosen't work).
case 1:
var test_data=d3.select("body").selectAll("test_data");
data=test_data.html;
x.domain(data.map(function(d) { return d.x; }));
y.domain(data.map(function(d) { return d.y; }));
The above code is requiring JSON as in the following format.
case 2:
var data = [{x:0,y:0.5},{x:0.1,y:0.8},{x:0.2,y:1.1},{x:1.3,y:1.5},{x:0.4,y:2.5},{x:0.5,y:3.4},{x:0.6,y:4.3}];
x.domain(data.map(function(d) { return d.x; }));
y.domain(data.map(function(d) { return d.y; }));
How shall I generate the JSON in the format specified from the server side ( as in case 2) ?
How shall i capture the div test_data in d3 ?
complete js code for d3 as below.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta charset="utf-8"></meta>
<style>
.axis text {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
fill: none;
stroke-width: 1.5px;
}
.dot {
fill: #fff;
stroke: #000;
}
</style>
<script src="./d3.js"></script>
<script src="./jquery.js"></script>
<script src="./data.tsv"></script>
<script>
$(document).ready(function(){
sendAjax();
});
function sendAjax() {
$.ajax({
url: "/greeting1",
type: 'GET',
/* dataType: 'json',
data: "{\"name\":\"hmkcode\",\"id\":2}",
contentType: 'application/json',
mimeType: 'application/json',*/
success: function(data) {
//alert(data);
$('#test_data').html(data);
//alert($('#test_data').html);
callChart();
},
error:function(data,status,er) {
alert("error: "+data+" status: "+status+" er:"+er);
}
});
}
</script>
</head>
<body>
<p th:text="'Hello, ' + ${name} + '!'" />
<div id="test"></div>
<div id="test_data"></div>
<script>
function callChart()
{
var margin = {top: 40, right: 40, bottom: 40, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 1])
.range([height, 0]);
var z = d3.scale.linear()
.domain([2 / 3, 1]) // D3 3.x tension is buggy!
.range(["brown", "steelblue"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
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.tsv("data.tsv", type, function(error, data) {
// if (error) throw error;
//var test_data=d3.select("body").selectAll("test_data");
//data=test_data.html;
var data = [{x:0,y:0.5},{x:0.1,y:0.8},{x:0.2,y:1.1},{x:1.3,y:1.5},{x:0.4,y:2.5},{x:0.5,y:3.4},{x:0.6,y:4.3}];
x.domain(data.map(function(d) { return d.x; }));
y.domain(data.map(function(d) { return d.y; }));
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
svg.selectAll(".line")
.data(z.ticks(6))
.enter().append("path")
.attr("class", "line")
.attr("d", function(d) { return line.tension(d)(data); })
.style("stroke", z);
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", 3.5);
//});
function type(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
}
</script>
</body>
</html>
My problem is solved by using gson for constructing the Json and the solution provided by #Gerardo Furtado for fetching the div through d3.
#RequestMapping("/greeting")
public String greeting(#RequestParam(value = "name", required = false, defaultValue = "World") String name,
Model model) {
LinkedList<Data.Temp> values = data.populateData();
Gson gson = new Gson();
String output=gson.toJson(values);
model.addAttribute("name",output );
return "greeting";
}
function callChart()
{
var margin = {top: 40, right: 40, bottom: 40, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.domain([0, 1])
.range([0, width]);
var y = d3.scale.linear()
.domain([0, 1])
.range([height, 0]);
var z = d3.scale.linear()
.domain([2 / 3, 1]) // D3 3.x tension is buggy!
.range(["brown", "steelblue"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d) { return x(d.x); })
.y(function(d) { return y(d.y); });
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.tsv("data.tsv", type, function(error, data) {
// if (error) throw error;
//var test_data=d3.select("body").selectAll("test_data");
//data=test_data.html;
var test_data = d3.select("#test_data");
var data = JSON.parse(test_data.text());
x.domain(data.map(function(d) { return d.x; }));
y.domain(data.map(function(d) { return d.y; }));
svg.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis axis--y")
.call(yAxis);
svg.selectAll(".line")
.data(z.ticks(6))
.enter().append("path")
.attr("class", "line")
.attr("d", function(d) { return line.tension(d)(data); })
.style("stroke", z);
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.attr("r", 3.5);
//});
function type(d) {
d.x = +d.x;
d.y = +d.y;
return d;
}
}

Using Ajax for real time graphical display

I am doing a sample project using d3js sample from bl.ocks.org to plot graph. There is a csv file which is continuously updated. My task is to read it every second and update the plot. I tried to look up ajax example to add into the d3. However bl.ocks.org did not have what I needed. Can anyone please let me know a good ajax example which I can integrate with my application.
--> next task is to get csv off and have a restful service to read data. Then it is to be parsed and graph is to be updated periodically.
Thanks in advance!
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// 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.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);
});
</script>
</body>

d3js area chart with json

i'm using the d3js area chart examples with json Chart Link.
the x and y axis are changing when we change the data feeding but no data shown in the graph.but i used a console log.so i saw the datas are already there in the x and y axis.could not figure out why does the data doesn't appear in the chart.
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
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 area = d3.svg.area()
.x(function(d) { return x(d.timeStamp); })
.y0(height)
.y(function(d) {return y(d.memberAverageLoadAverage); });
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 + ")");
var json1=[{"clusterId":"","timeStamp":1437063744524,"memberAverageLoadAverage":51,"memberId":""},
{"clusterId":"","timeStamp":1437069850060,"memberAverageLoadAverage":5,"memberId":""},
{"clusterId":"","timeStamp":1437069910059,"memberAverageLoadAverage":6,"memberId":""},
{"clusterId":"","timeStamp":1437069970060,"memberAverageLoadAverage":15,"memberId":""},
{"clusterId":"","timeStamp":1437070030056,"memberAverageLoadAverage":20,"memberId":""}];
var data = json1;
x.domain(d3.extent(data, function(d) { return d.timeStamp; }));
y.domain([-2, d3.max(data, function(d) { console.info(d.memberAverageLoadAverage); return d.memberAverageLoadAverage; })]);
svg.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("memberAverageLoadAverage");
Any help will be really appreciated.
In
var area = d3.svg.area()
.x(function(d) { return x(d.timeStamp); })
.y0(height)
.y(function(d) {return y(d.memberAverageLoadAverage); });
you should use .y1(...) instead of .y(...).
I think that should do the trick!

D3 chart with JSON web service

I am trying to make the following bar chart from this tutorial. The tutorial utilizes TSV files, but I have modified the code for JSON. I have checked that the endpoint http://localhost:3000/graphs/data from my Node / Express service I created is indeed returning JSON, which can be seen below. The proper D3 libraries are also being included. After checking all this, I cannot get the chart to render.
The goal is to have route on the x-axis and count on the y-axis. Any suggestions would be greatly appreciated.
JSON Response:
[{"route":"9","count":273},{"route":"49","count":242},{"route":"151","count":221},{"route":"8","count":220},{"route":"3","count":213},{"route":"82","count":209},{"route":"79","count":206},{"route":"N5","count":206},{"route":"62","count":206},{"route":"4","count":202}]
Bar Chart Code
<script>
var margin = {top: 40, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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 tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>Count:</strong> <span style='color:red'>" + d.count + "</span>";
})
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.call(tip);
d3.json('http://localhost:3000/graphs/data', type, function(error, data) {
x.domain(data.map(function(d) { return d.route; }));
y.domain([0, d3.max(data, function(d) { return d.count; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.route); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.count); })
.attr("height", function(d) { return height - y(d.count); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.count = +d.count;
return d;
}
</script>
d3.json(), unlike d3.csv(), takes only two arguments, with the second being the callback function. Your call
d3.json('http://localhost:3000/graphs/data', type, function(error, data) {
passes the result of the call to type, not to the anonymous function after that, which is never executed. The call should be
d3.json('http://localhost:3000/graphs/data', function(error, data) {