D3 chart with JSON web service - json

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) {

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.

The values on x-axis are descending values on grouped bar chart using d3.js

I have transformed the vertical grouped bar chart from horizontal grouped bar chart. I have taken the code from the site https://bl.ocks.org/mbostock/3887051. The problem is when I have transformed horizontal to vertical axis the values on x-axis are not ascending but they are descending i.e., the values are 10M, 8M, 6M, 4M etc....I am not sure where I have made a mistake.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 50, left: 140},
width = 800 - margin.left - margin.right,
height = 900 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0],.1);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(y)
.orient("top").ticks(5);
var yAxis = d3.svg.axis()
.scale(x0)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("height", width + margin.left + margin.right)
.attr("width", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
d3.csv("data.csv", function(error, data) {
if (error) throw error;
var ageNames = d3.keys(data[0]).filter(function(key) { return key !== "State"; });
data.forEach(function(d) {
d.ages = ageNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.State; }));
x1.domain(ageNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.ages, function(d) { return d.value; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0,0)")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "translate(0," + height + ")")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "state")
.attr("transform", function(d) { return "translate(0," + x0(d.State) + ")"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("height", x1.rangeBand())
.attr("y", function(d) { return x1(d.name); })
//.attr("x", function(d) { return y(d.value); })
.attr("width", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(ageNames.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 10)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 14)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
</script>
You y-scale which is used on your x-axis is defined as:
var y = d3.scale.linear()
.range([height, 0] , 0.1);
This runs it in reverse and should be:
var y = d3.scale.linear()
.range([0, height] , 0.1);

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 Bar Chart not showing up or giving me any errors to work from

Ok, so I'm trying to make a d3 chart, but when I do nothing shows up. Here is how my data is coming out in the JSON:
[{"Commodity":"Base","num_complete_print":"3","num_incomplete_print":15},{"Commodity":"Blade","num_complete_print":"1","num_incomplete_print":53},{"Commodity":"DTE","num_complete_print":"1","num_incomplete_print":17},{"Commodity":"HUB","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"MH","num_complete_print":"0","num_incomplete_print":"18"},{"Commodity":"Mid","num_complete_print":"0","num_incomplete_print":18},{"Commodity":"Top","num_complete_print":"0","num_incomplete_print":18}]
Here is my javascript....
<script type="text/javascript">
var margin = {top: 20, right: 20, bottom: 100, left: 100},
width = 750 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width-100], .1); //width-100 to make room for the legend.
var y = d3.scale.linear()
.rangeRound([height, 0]);
var color = d3.scale.ordinal()
//.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
//.range(["#1f77b4", "#ff7f0e","d62728"]); //blue, orange, red
//color code for Progress Report
.range(["#00FFFF","#00FF00","#990099","#FF0000","#FFFF00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("#area_progress_report").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
var data = <?php echo json_encode($dataset_progress001); ?>;
//d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Commodity"; }));
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
d.total = d.ages[d.ages.length - 1].y1;
});
//use this to sort the bars from largest to smallest
//data.sort(function(a, b) { return b.total - a.total; });
x.domain(data.map(function(d) { return d.Commodity; }));
y.domain([0, d3.max(data, function(d) { return d.total; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text") //added this line through rotate to change orientation of x axis
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-1em")
.attr("transform", function(d) {
return "rotate(-90)"
});
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("Population");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x(d.Commodity) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.ages; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(color.domain().slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
//Added y label 10/28
svg.append("text")
.attr("class", "y label")
.attr("text-anchor", "end")
.attr("y", -60)
.attr("x",-190)
.attr("dy", ".75em")
.attr("transform", "rotate(-90)")
.text("Number Of Components");
</script>
And of course in my body I have this
<div id="area_progress_report"></div>
What am I doing wrong? I include the d3 locally...
<meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!-- added to try to avoid the d3 is not valid -->
<script type="text/javascript" src="d3-master/d3.v3.js"></script> <!-- load the d3.js library -->
<script type="text/javascript" src="d3-master/d3.v3.min.js"></script> <!-- load the d3.js library -->
Seems to work for me:
http://jsfiddle.net/wqHqP/
I simply replaced the line:
var data = <?php echo json_encode($dataset_progress001); ?>;
with your output JSON.

D3 Comparison bar chart

var data = [
{"Month":"2013/12","Name":"John","EC":344},
{"Month":"2013/12","Name":"Smith","EC":249},
{"Month":"2013/12","Name":"Mary","EC":161},
{"Month":"2013/11","Name":"John","EC":128},
{"Month":"2013/11","Name":"Smith","EC":125},
{"Month":"2013/11","Name":"Mary","EC":117}
];
I have json data for 3 people John, Smith & Mary for the month of 2013/11 and 2013/12. I want to draw d3 bar chart to compare the data of each person for the month 2013/11 and 2013/12 by representing each person with different bar color for both months. The same set of colors will be used for each person for both months.
How do I group by Name and draw bars for their count (EC) for both the month(11 &12) of the same person. I only get one bar but the other bar does not come up for each person. My code is in jsfiddle http://jsfiddle.net/4gY8H/. Can you please help me figure out what I am missing?
var data=[{"Name":"Katte","Month":"2013/11","ExamCount":"30"},{"Name":"Borsh","Month":"2013/11","ExamCount":"130"},{"Name":"Broer","Month":"2013/11","ExamCount":"320"},{"Name":"John","Month":"2013/11","ExamCount":"60"},
{"Name":"Katte","Month":"2013/12","ExamCount":"130"},{"Name":"Borsh","Month":"2013/12","ExamCount":"1130"},{"Name":"Broer","Month":"2013/12","ExamCount":"3120"},{"Name":"John","Month":"2013/12","ExamCount":"610"}];
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range(["rgba(11,94,215,.8)", "rgba(245, 143, 8, 0.8)", "rgba(0, 167, 188, 0.8)", "rgba(223, 40, 35, 0.8)", "rgba(153, 44, 150, 0.8)", "rgba(124, 189, 42, 0.8)", "rgba(37, 47, 71, 0.8)","rgba(153, 0, 51, 0.8)", "rgba(153, 51, 51, 0.8)", "rgba(92, 0, 92, 0.8)"]);
var xAxis = d3.svg.axis()
.scale(x0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
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 months = d3.keys(data[0]).filter(function(key) { return key !== "Name"; });
console.log(months);
data.forEach(function(d) {
d.month = months.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Name; }));
x1.domain(months).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.month, 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")
.text("Exam Count");
var person = svg.selectAll(".person")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Name) + ",0)"; });
person.selectAll("rect")
.data(function(d) { return d.month; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
var legend = svg.selectAll(".legend")
.data(months.slice().reverse())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
</script>
The problem is you basically copied this example, but the data format is different.
For example, you do:
var months = d3.keys(data[0]).filter(function(key) { return key !== "Name"; });
With your data that returns ["Month", "ExamCount"] instead of the months.
In your case, you could use:
var months = d3.set(data.map(function(line) { return line.Month; })).values();
which returns ["2013/11", "2013/12"]
There are other examples. Why do you have 8 colors if you only need 2?
And the entire data binding part (when you create a rect for every data line) is wrong for your data structure, you should try to write it from scratch instead of trying to adapt the one from the example (which has data in CSV format, very different).
Here is a working JSFiddle: http://jsfiddle.net/bxW9T/17/