JavaScript , D3 bar graph error - javascript

This is the script/html i am not sure what the problem here is the error I keep arriving at is. I messed around with the y and heigh variables but i am unable to get to a solution. Changed the parameters, changed values but of no avail. Please assist.
Error: Invalid value for attribute y="NaN"
Error: Invalid value for attribute height="NaN"
This is the ERRORS
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
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")
.ticks(1)
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(1.0);
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.csv("Unemployment.csv", type, function(error, data) {
if (error) throw error;
x.domain([0, d3.max(data, function(d) { return d.letter; })]);
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
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.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
});
function type(d) {
d.frequency = +d.frequency;
return d;
}
</script>
Ward,Unemployment
1,4.5
2,4.3
3,4.0
4,5.7
5,7.9
6,5.2
7,11.0
8,14.2

If you log your data after the d3.csv("Unemployment.csv", type, function(error, data) { call you would see that it will contain an array of object with the keys Ward and Unemployment.
However, in several cases such as:
x.domain([0, d3.max(data, function(d) { return d.letter; })]);
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
And
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
your code expects the letter and frequency keys to be present.
Changing these to ward and unemployment would solve this issue

Related

how to connect d3.js and solr json response?

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style>
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<!--/* adding d3.js lib*/-->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://d3js.org/d3-dsv.v1.min.js"></script>
<script src="https://d3js.org/d3-fetch.v1.min.js"></script>
<script>
var margin = { top: 20, right: 20, bottom: 70, left: 40 },
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickFormat(d3.num);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
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 + ")");
/* my data on json server
d3.json("https://api.myjson.com/bins/xya14", function (error, data)
{
alert(data);
data.forEach(function (d) {
d.num = d.num;
d.value = +d.value;
alert(d.value);
});
x.domain(data.map(function (d) { return d.num; }));
y.domain([0, d3.max(data, function (d) { return d.value; })]);
*/
/* data on solr server*/
d3.json("http://192.168.2.4:8983/solr/vkash_collection/select?q=*:*&omitHeader=true", function (error, data)
{
alert(data);
data.forEach(function (d) {
d.num = d.num;
d.value = +d.value;
alert(d.value);
});
x.domain(data.map(function (d) { return d.num; }));
y.domain([0, d3.max(data, function (d) { return d.value; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "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("Value ($)");
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.style("fill", "steelblue")
.attr("x", function (d) { return x(d.num); })
.attr("width", x.rangeBand())
.attr("y", function (d) { return y(d.value); })
.attr("height", function (d) { return height - y(d.value); });
});
</script>
</body>
I load one json file in solr which is have only two fields num and value.i take this url and use d3.json("solr url",function (data))..but I get nothing on the browser. how to connect d3.js ??
my js code snippet is here:
my solr url response is here:

refactor d3 bar chart to be horizontal bar chart

I was trying to refactor this bar chart in d3 to be a horizontal bar chart. I think I've isolated the three areas that need to be changed:
the original scale declarations:
var x0 = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.1);
var x1 = d3.scale.ordinal();
var y = d3.scale.linear()
.range([height, 0]);
The domain definitions:
x0.domain(data.map(function(d) { return d.deviceType; }));
x1.domain(deviceClass).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.whenPurchased, function(d) { return d.value; }); })]);
the rect appending and positioning:
device.selectAll("rect")
.data(function(d) { return d.whenPurchased; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.device); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.device); });
I can't seem to get the refactoring right and I think that is because I don't exactly get how domain works for x0 and basically not getting that right has a waterfall effect of everything else not working.
I put the full example here: JSFIDDLE
Here's a quick refactor:
var margin = {top: 20, right: 20, bottom: 30, left: 270},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var y0 = d3.scale.ordinal()
.rangeRoundBands([0, height], 0.1);
var y1 = d3.scale.ordinal();
var x = d3.scale.linear()
.range([0, width]);
var color = d3.scale.ordinal()
.range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y0)
.orient("left");
// .tickFormat(d3.format(".2s"));
var svg = d3.select("#deviceown-barchart").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 data = d3.csv.parse( d3.select("pre#data").text() );
var deviceClass = d3.keys(data[0]).filter(function(key) { return key !== "deviceType"; });
data.forEach(function(d) {
d.whenPurchased = deviceClass.map(function(device) { return {device: device, value: +d[device]}; });
});
y0.domain(data.map(function(d) { return d.deviceType; }));
y1.domain(deviceClass).rangeRoundBands([0, y0.rangeBand()]);
x.domain([0, d3.max(data, function(d) { return d3.max(d.whenPurchased, 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");
var device = svg.selectAll(".device")
.data(data)
.enter().append("g")
.attr("class", "device")
.attr("transform", function(d) { return "translate(0," + y0(d.deviceType) + ")"; });
device.selectAll("rect")
.data(function(d) { return d.whenPurchased; })
.enter().append("rect")
.attr("height", y1.rangeBand())
.attr("y", function(d) { return y1(d.device); })
.attr("x", 0)
.style("fill", function(d) { return color(d.device); })
.attr("width", 0)
.transition()
.duration(1500)
.attr("width", function(d) { return x(d.value); });
var legend = svg.selectAll(".legend")
.data(deviceClass.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; });
// });
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.y.axis path {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="deviceown-barchart"></div>
<pre id="data">
deviceType,Within the last 6 months,More than 6 months ago
Netatmo Weather Station,0.14,0.09
Nest Learning Thermostat,0.13,0.14
Philips Hue Connected Bulb,0.13,0.08
Nest Cam,0.12,0.12
Belkin WeMo Switch + Motion,0.09,0.08
Nest Protect,0.08,0.12
Canary,0.08,0.03
Other smart home security device,0.08,0.12
August Smart Lock,0.06,0.07
Other connected home appliance,0.05,0.08
GE/Quirky Aros Smart AC,0.04,0.04
Other smart energy monitor,0,0.03
</pre>
Updated fiddle.

D3 bar charts bar values display is improper

I want to display the bar charts each bar peak value at the outer top of each bar. But as far as i could get is to represent each bar value inside the bar. But thats not what i wanted. As you can see in the image attached the bottom of the x axis is messed up. I think we have to move the svg code out of the data loop and use svg.data(someData).enter() to fix this issue but i tried ways to do it but unsuccessful. Kindly suggest how i can modify the follow code.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.axis {
font: 12px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.chart text {
fill: black;
font: 15px sans-serif;
text-anchor: middle;
}
</style>
<svg class="chart"></svg>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 30, right: 80, bottom: 40, left: 100},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var color = d3.scale.category10();
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .2);
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");
function unit (d) {
count = 0, download = 0;
num = d.value;
while((num) >= 1)
{
num/=10;
++count;
}
switch (count) {
case 4 : download = ((d.value/1000).toFixed(2)) + " MB" ;
break;
case 8 : download = ((d.value/1000 * 1000).toFixed(2)) + " GB" ;
break;
default: download = ((d.value/1000).toFixed(2)) + " MB" ;
}
return download;
}
var chart = d3.select("body").append("svg")
// line = 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 bar;
d3.csv("data.csv", type, function(error, data) {
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
chart.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", 790 )
.attr("y", 15 )
.style("text-anchor", "bottom")
.text("Clients");
chart.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
//.attr("transform", "rotate(-90)")
.attr("y", 1)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Kilo Bytes");
bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; });
bar.append("rect")
.style("fill", function(d) { return color(d.name); })
.attr("y", function(d) { return y(d.value);})
.attr("height", function(d) { return height - y(d.value); })
.attr("width", x.rangeBand());
bar.append("text")
.attr("x", x.rangeBand() / 2 )
.attr("y", function(d) { return y(d.value) + 2 ; })
.attr("dy", "1em")
.attr("text-anchor", "middle")
.attr("font-size", "14px")
.attr("fill", "black")
.text(function(d) { return unit(d); });
});
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
</script>
and the data is in the csv format as below:
name,timesatmp,value
98.226.148.140,1341677167454,1
98.226.148.140,1341677167461,3
98.226.148.141,1341677167916,4
98.226.148.141,1341677167935,6
98.226.148.142,1341677167944,7
98.226.148.142,1341677167945,32
Kindly suggest how i can show the display properly.
First modify your bar charts a little, otherwise no bars will be shown there:
html:
<svg class="chart"></svg>
to
<body class="chart"></body>
js:
bar = chart.selectAll(".bar")
.data(data)
.enter().append("g")
.attr('class', 'bar')
.attr("transform", function(d) { return "translate(" + x(d.name) + ",0)"; });
and for adjusting the peak value, just add a translate as follows:
bar.append("text")
.attr("x", x.rangeBand() / 2 )
.attr("y", function(d) { return y(d.value) + 2 ; })
.attr("dy", "1em")
.attr("text-anchor", "middle")
.attr("font-size", "14px")
.attr("fill", "black")
.attr("transform", function(d) { return "translate(0, -20)"; })
.text(function(d) { return unit(d); });
Rplace:
d3.csv("data.csv", type, function(error, data) {
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
with:
d3.csv("data.csv", type, function(error, data) {
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
var nestedData = d3.nest()
.key(function(d) { return d.name; }).entries(data);
var newData = [];
nestedData.forEach(function(d){
newData.push({name:d.key, value: d3.max(d.values, function(d) {return d.value})});
});

d3.js automatic data update - updateData

I made a simple bar chart using D3.js. The data for the chart is coming from a csv file. I would like for the chart to be updated every 2.5 seconds showing the new data. Right now, after updating the csv file the X and Y axis will update but the bars and mouseover tooltip shows the old values. I have looked at many different examples. Here are a few I have referenced. Anyone know what is going on?
http://mbostock.github.io/d3/tutorial/bar-2.html
http://www.d3noob.org/search?q=update
d3 update data and update graph
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Bar Chart</title>
<style type="text/css">
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
div.tooltip {
position: absolute;
text-align: left;
width: auto;
height: auto;
padding: 2px;
font-family: sans-serif;
font-size: 14px;
background: white;
border: 2;
border-radius: 5px;
pointer-events: none;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 45},
width = 1000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
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")
.tickPadding(5);
//var data = [{"label":"Boone","values":0.8},{"label":"Story","values":0.2},{"label":"Polk","values":0.4}]
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("opacity", 0);
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.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.label = d.label;
d.values = +d.values;
});
x.domain(data.map(function(d) { return d.label; }));
y.domain([0, d3.max(data, function(d) { return d.values; })]);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-0)")
.attr("x", -10)
.attr("y", -16)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Values");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.on("mouseover", function(d) {
div.transition()
.duration(100)
.style("opacity", 1)
.style("left", (d3.event.pageX)+ "px")
.style("top", (d3.event.pageY) + "px");
div.html("<p>Label: " + d.label+ "<br>Value: " + d.values);
d3.select("#tooltip").classed("hidden", false);
})
.attr("class", "bar")
.attr("x", function(d) { return x(d.label); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.values); })
.attr("height", function(d) { return height - y(d.values); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", 30)
.style("text-anchor", "end")
.text("Label");
});
var inter = setInterval(function() {
updateData();
},2500);
function updateData() {
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.label = d.label;
d.values = +d.values;
});
x.domain(data.map(function(d) { return d.label; }));
y.domain([0, d3.max(data, function(d) { return d.values; })]);
var svg = d3.select("body")
var vis = svg.transition();
vis.select(".x.axis")
.duration(750)
.call(xAxis)
vis.select(".y.axis")
.duration(750)
.call(yAxis)
vis.select(".rect")
.duration(750)
.attr(".x", function(d) { return x(d.label); })
.attr(".y", function(d) { return y(d.values); })
});
}
</script>
</body>
</html>

I'm working on d3.js. Why this code doesn't work correctly?

That's the CSV file: http://goo.gl/ZVVjD
I've this problem only for bar chart. The line chart works fine. I don't know how to modify this one.
Please,help me to understand where I'm wrong.
<!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="http://d3js.org/d3.v3.min.js"></script>
<script>
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var formatPercent = d3.format("04d");
//var formatPercent = d3.format(".0%");
var parseDate = d3.time.format("%d-%b-%y-%H:%M:%S").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")
//.tickFormat(formatPercent);
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.csv("data.tsv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
//d.energy = parseInt(d.energy);
d.energy = +d.energy;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.energy; })]);
//y.domain(d3.extent(data, function(d) { return d.energy; }));
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("Energy");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.date); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.energy); })
.attr("height", function(d) { return height - y(d.energy); });
});
</script>
Thank you very much!
I don't believe x.rangeBand() works for time scales. Try replacing it with with a fixed pixel value of 2 or 3.

Categories