I am new to d3.js and I am trying to make a chart where people could change the data source on click. To give a concrete example, if I display a country's population over time, I'd like to have a button for each country and when people click on it, it updates the source.
My initial chart is defined here:
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 600 - margin.left - margin.right,
height = 400 - 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")
.ticks(10, "%");
var svg = d3.select(".chart-container").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("./javascripts/data.tsv", type, function(error, data) {
x.domain(data.map(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;
}
And when people click on a button, I'd like to change the source:
function updateData() {
// Get the data again
d3.tsv("./javascripts/data2.tsv", type, function(error, data) {
console.log(data);
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Select the section we want to apply our changes to
var svg = d3.select(".chart-container").transition();
// Make the changes
svg.selectAll(".bar")
.data(data) // here I get: Uncaught TypeError: undefined is not a function
.exit().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); });
});
}
However this is not working. I get the error commented in the code.
What I am doing wrong?
Cheers
Related
I have a set of nested json data:
var data = [{"time":"2016-03-01","values":[{"specimen_count":1,"trap":"S0024", "species":1},{"specimen_count":2,"trap":"S0025", "species":2},{"specimen_count":2,"trap":"S0026", "species":2}]},{"time":"2016-03-15","values":[{"specimen_count":6,"trap":"S0024", "species":6},{"specimen_count":5,"trap":"S0025", "species":4},{"specimen_count":7,"trap":"S0026", "species":6}]}];
And I want to draw a set of grouped bar charts each group representing a time interval and each group with 3 bars, each representing a trap, and the height of the bar is the specimen_count field.
Now I want to add a scatterplot, one dot for each bar and the height of the dot is the species field, using the same scales. But I am having trouble successfully placing the dots on top the the grouped bar chart. I did manage to add a line with the species data, but I can't add the dots using the same logic.
Here is my code:
var margin = {top: 100, right: 20, bottom: 30, left: 40},
width = 600 - 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 xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020","#f4a582","#92c5de"]);
var svg = d3.select('#chart').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 categoriesNames = data.map(function(d) { return d.time; }); // the 5 time periods
var trapNames = data[0].values.map(function(d) { return d.trap; }); // the name of the traps
console.log(trapNames);
x0.domain(categoriesNames);
x1.domain(trapNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(category) { return d3.max(category.values, function(d) { return d.specimen_count; }); })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity','0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight','bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "slice")
.attr("transform",function(d) { return "translate(" + x0(d.time) + ",0)"; });
slice.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) { return x1(d.trap); })
.style("fill", function(d) { return color(d.trap) })
.attr("y", function(d) { return y(0); })
.attr("height", function(d) { return height - y(0); })
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.trap)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.trap));
});
slice.selectAll("rect")
.transition()
.delay(function (d) {return Math.random()*1000;})
.duration(1000)
.attr("y", function(d) { return y(d.specimen_count); })
.attr("height", function(d) { return height - y(d.specimen_count); });
var valueline = d3.svg.line()
.x(function (d) { return x1(d.trap) + x1.rangeBand()/2; })
.y(function (d) { return y(d.species); });
slice.enter()
.append('path')
.attr('class','line')
.style('stroke', "#0571b0")
.style('stroke-width', "3px")
.attr('fill', 'none')
.attr('d', function(d) { return valueline(d.values); });
slice.selectAll('.dot').data(data,function(d){return d.time;})
.enter()
.append("circle")
.attr("class", "dot")
.attr("r",5)
.attr("cx", function(d){
return x1(d.trap) + x1.rangeBand()/2;
})
.attr("cy",function(d){
return y(d.species);
})
.attr("fill","#0571b0");
There error I'm getting from the circle-related code is: d3.min.js:1 Error: attribute cx: Expected length, "NaN".
I think the nested data and the ordinal scale for the bar chart is throwing me off a bit, so it could be that I am not understanding fulling data access in these cases.
Also here is the screenshot of the current graph
If you need the dots on every bar chart, then the data() callback must return a list of bars not a single item. Did you try replacing it with:
slice.selectAll('.dot')
.data(function(d) {
return d.values;
})
.enter()
.append("circle") //... and so on
Doing this will use the existing data object (with 5 bar groups), but render a dot for each bar.
Here it is running:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.17" data-semver="3.5.17" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.js"></script>
</head>
<body>
<div id="chart"></div>
<script>
var data = [{
"time": "2016-03-01",
"values": [{
"specimen_count": 1,
"trap": "S0024",
"species": 1
}, {
"specimen_count": 2,
"trap": "S0025",
"species": 2
}, {
"specimen_count": 2,
"trap": "S0026",
"species": 2
}]
}, {
"time": "2016-03-15",
"values": [{
"specimen_count": 6,
"trap": "S0024",
"species": 6
}, {
"specimen_count": 5,
"trap": "S0025",
"species": 4
}, {
"specimen_count": 7,
"trap": "S0026",
"species": 6
}]
}];
var margin = {
top: 100,
right: 20,
bottom: 30,
left: 40
},
width = 600 - 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 xAxis = d3.svg.axis()
.scale(x0)
.tickSize(0)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var color = d3.scale.ordinal()
.range(["#ca0020", "#f4a582", "#92c5de"]);
var svg = d3.select('#chart').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 categoriesNames = data.map(function(d) {
return d.time;
}); // the 5 time periods
var trapNames = data[0].values.map(function(d) {
return d.trap;
}); // the name of the traps
console.log(trapNames);
x0.domain(categoriesNames);
x1.domain(trapNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(category) {
return d3.max(category.values, function(d) {
return d.specimen_count;
});
})]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.style('opacity', '0')
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.style('font-weight', 'bold')
.text("Value");
svg.select('.y').transition().duration(500).delay(1300).style('opacity', '1');
var slice = svg.selectAll(".slice")
.data(data)
.enter().append("g")
.attr("class", "slice")
.attr("transform", function(d) {
return "translate(" + x0(d.time) + ",0)";
});
slice.selectAll("rect")
.data(function(d) {
return d.values;
})
.enter().append("rect")
.attr("width", x1.rangeBand())
.attr("x", function(d) {
return x1(d.trap);
})
.style("fill", function(d) {
return color(d.trap)
})
.attr("y", function(d) {
return y(0);
})
.attr("height", function(d) {
return height - y(0);
})
.on("mouseover", function(d) {
d3.select(this).style("fill", d3.rgb(color(d.trap)).darker(2));
})
.on("mouseout", function(d) {
d3.select(this).style("fill", color(d.trap));
});
slice.selectAll("rect")
.transition()
.delay(function(d) {
return Math.random() * 1000;
})
.duration(1000)
.attr("y", function(d) {
return y(d.specimen_count);
})
.attr("height", function(d) {
return height - y(d.specimen_count);
});
var valueline = d3.svg.line()
.x(function(d) {
return x1(d.trap) + x1.rangeBand() / 2;
})
.y(function(d) {
return y(d.species);
});
slice
.append('path')
.attr('class', 'line')
.style('stroke', "#0571b0")
.style('stroke-width', "3px")
.attr('fill', 'none')
.attr('d', function(d) {
return valueline(d.values);
});
slice.selectAll('.dot').data(function(d) {
return d.values;
})
.enter()
.append("circle")
.attr("class", "dot")
.attr("r", 5)
.attr("cx", function(d) {
return x1(d.trap) + x1.rangeBand() / 2;
})
.attr("cy", function(d) {
return y(d.species);
})
.attr("fill", "#0571b0");
</script>
</body>
</html>
I have this JSON data
{"1960":"133.55501327769","1961":"134.159118941963","1962":"134.857912280869","1963":"134.504575565342","1964":"134.105211273476","1965":"133.569625896451","1966":"132.675635192775","1967":"131.665502129354","1968":"129.190980115918","1969":"126.736756382819","1970":"124.382808900193","1971":"122.133431342027","1972":"120.020185557559","1973":"118.087531093609","1974":"116.132988067096","1975":"114.100918174437","1976":"111.980005447216","1977":"109.783821762662","1978":"106.033489239906","1979":"102.341720681455","1980":"98.7390023274647","1981":"95.2412508672801","1982":"91.7911923993222","1983":"88.0011769487606","1984":"84.2072557839419","1985":"80.3593225600132","1986":"76.4415956498419","1987":"72.5145803648751","1988":"71.1706639452677","1989":"69.8887679924858","1990":"69.0044133814268","1991":"67.7559924352118","1992":"66.9284506867798","1993":"64.9489678572737","1994":"62.9227777228154","1995":"60.7070695260477","1996":"58.5966308804751","1997":"56.4401276304142","1998":"55.5315395528949","1999":"54.6587808352011","2000":"53.8314102398679","2001":"52.9015276443892","2002":"51.9907926813042","2003":"51.5228563035101","2004":"51.1032496482833","2005":"50.7325902239383","2006":"50.3291352282938","2007":"49.9998514069402","2008":"49.8870459355469","2009":"49.7812066054555","2010":"49.6729747116906","2011":"49.5360469363113","2012":"49.3837446924523","2013":"48.7965576984378","2014":"48.1964180547578","2015":"47.5501940499984","Country Name":"Arab World","Country Code":"ARB","Indicator Name":"Adolescent fertility rate (births per 1,000 women ages 15-19)","Indicator Code":"SP.ADO.TFRT","":""}
which I convert from CSV to JS object.
How do I build a bar chart with d3.js where the key is the X axis and the values are the Y axis?
here's what I came up with
var margin = {top: 20, right: 20, bottom: 70, left: 40},
width = 600 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
// set the ranges
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var y = d3.scale.linear().range([height, 0]);
// define the axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(10);
// add the SVG element
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.queue()
.defer(d3.csv, "http://localhost:8000/HNP_Data.csv")
.defer(d3.csv, "http://localhost:8000/HNP_Series.csv")
.await(analyze);
var dataToVis;
var array = []
function analyze(error,data,series) {
dataToVis = data[2];
console.log(JSON.stringify(dataToVis));
for (var key in dataToVis) {
if(!isNaN(key) && key.length >0) {
var p = new Object;
p.year = key;
p.frequency = p(dataToVis[key]);
array.push(p);
}
}
array.forEach(function(d){
d.year = d.year;
d.frequency = +d.frequency;
});
x.domain(data.map(function(d) { return d.year; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
// add axis
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", 5)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
// Add bar chart
svg.selectAll("bar")
.data(array)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.year); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
}
but I end up with this error.
Error: <rect> attribute y: Expected length, "NaN".
Error: <rect> attribute height: Expected length, "NaN".
I am having an issue using d3 to create a bar chart where the column overflows the and the y axis labels are incorrect. Here is a fiddle http://jsfiddle.net/fajgvj9v/ that shows the issue. The data is parsing the <pre id="data"> tag to simulate a CSV I am using. If you change the value of 'a' to 5000 from 4000 it renders as expected.
<pre id="data">
name,count
a, 4000
b, 500
</pre>
yTitle = "Items";
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 xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var y = d3.scale.linear()
.rangeRound([height, 0]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("#malware_by_os").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() );
console.log(data);
var xLbl = d3.keys(data[0])[0];
var yLbl = d3.keys(data[0])[1];
data.sort(function(a, b) {
return b[yLbl] - a[yLbl];
});
x.domain(data.map(function(d) {
return d[xLbl];
}));
y.domain([0, d3.max(data, function(d) {
return d[yLbl];
})]);
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(yTitle);
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) {
return x(d[xLbl]);
})
.attr("width", x.rangeBand())
.attr("y", function(d) {
return y(d[yLbl]);
})
.attr("height", function(d) {
return height - y(d[yLbl]);
});
The max function needs to convert to a number using +
y.domain([0, d3.max(data, function(d) {
return d[yLbl];
})]);
should be
y.domain([0, d3.max(data, function(d) {
return +d[yLbl];
})]);
I am creating an interactive bar chart in D3. When a button is pressed the data changes.
Here's simplified code for the bar chart:
<svg class="cex"></svg>
<script>
var margin = {top: 20, right: 20, bottom: 60, left: 35},
width = 650 - margin.left - margin.right,
height = 300- margin.top - margin.bottom;
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)
.outerTickSize(0)
.orient("left");
var cex = d3.select(".cex")
.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("/input.csv", function(error, data) {
x.domain(data.map(function(d) { return d.City; }));
y.domain([0, d3.max(data, function(d) { return d.EatIn; })]);
cex.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(60)")
.style("text-anchor", "start");;
cex.append("g")
.attr("class", "y axis")
.call(yAxis);
var bar=cex.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.City); })
.attr("y", function(d) { return y(d.EatIn); })
.attr("height", function(d) { return height - y(d.EatIn); })
.attr("width", x.rangeBand());
});
function type(d) {
d.EatIn = +d.EatIn;
return d;
}
When a button is selected the following update code runs:
function EatOutData() {
d3.csv("/input.csv", function(error, data) {
x.domain(data.map(function(d) { return d.City; }));
y.domain([0, d3.max(data, function(d) { return d.EatOut; })]);
var sel = cex.selectAll("rect")
.data(data);
sel.exit().remove();
sel.enter().append("rect")
sel.attr("class", "bar")
sel.attr("x", function(d) { return x(d.City); })
sel.attr("y", function(d) { return y(d.EatOut); })
sel.attr("height", function(d) { return height - y(d.EatOut); })
sel.attr("width", x.rangeBand());
sel.selectAll("g.y.axis")
.call(yAxis);
sel.selectAll("g.x.axis")
.call(xAxis);
function type(d) {
d.EatOut = +d.EatOut;
return d;
}
}
)};
The update changes the Y variable. So the height of the bar changes but the axis doesn't change and the scale of the two variables are quite different.
There have been a couple other SO posts on this but none seemed to fix it for me. I'm not sure why the y.domain in the update doesn't adjust them. Would really appreciate any suggestions.
You will have to remove the axis (or the text) and draw it again just like you are removing the bars and plotting them again to update data on the axis. Check the working plnkr here.
function EatOutData() {
d3.csv("input2.csv", function(error, data) {
x.domain(data.map(function(d) { console.log(d); return d.City; }));
y.domain([0, d3.max(data, function(d) { return d.EatOut; })]);
var sel = cex.selectAll("rect")
.data(data);
sel.exit().remove();
d3.select(".x.axis").remove();
sel.enter().append("rect")
sel.attr("class", "bar")
sel.attr("x", function(d) { return x(d.City); })
sel.attr("y", function(d) { return y(d.EatOut); })
sel.attr("height", function(d) { return height - y(d.EatOut); })
sel.attr("width", x.rangeBand());
cex.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(60)")
.style("text-anchor", "start");;
sel.selectAll("g.y.axis")
.call(yAxis);
sel.selectAll("g.x.axis")
.call(xAxis);
function type(d) {
d.EatOut = +d.EatOut;
return d;
}
}
)};
I have successfully managed to create a grouped bar chart that displays the various performance stats for soccer players over the course of one season. This data is all loaded from a csv file. I would now like to dynamically change that data whereby when a button is pressed, a new csv file is loaded with the stats corresponding to the next soccer season. I've tried to do this on my own but everytime I try reload the data, the old data as well as the old axis's remain present and the enw data loads ontop of these. It all ends up looking messy. So how do I have the old bars and axises updated in line with the new data? Here is my code:
$(document).ready(function(){
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(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
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 + ")");
d3.csv("SoccerStatsCSV.csv", function(error, data) {
console.log(data);
var playerNames = d3.keys(data[0]).filter(function(key) { return key !== "Attribute"; });
console.log(playerNames);
data.forEach(function(d) {
d.Playerstats = playerNames.map(function(name) { return {name: name, value: +d[name]}; });
console.log(d.Playerstats);
});
x0.domain(data.map(function(d) { return d.Attribute; }));
x1.domain(playerNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.Playerstats, 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("Units");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Attribute) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.Playerstats; })
.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(playerNames.slice())
.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; });
});
//The updating button
d3.select("button")
.on('click',function(){
d3.csv("SoccerStatsCSV2008.csv", function(error, data) {
console.log(data);
var playerNames = d3.keys(data[0]).filter(function(key) { return key !== "Attribute"; });
console.log(playerNames);
data.forEach(function(d) {
d.Playerstats = playerNames.map(function(name) { return {name: name, value: +d[name]}; });
console.log(d.Playerstats);
});
x0.domain(data.map(function(d) { return d.Attribute; }));
x1.domain(playerNames).rangeRoundBands([0, x0.rangeBand()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.Playerstats, 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("Units");
var state = svg.selectAll(".state")
.data(data)
.enter().append("g")
.attr("class", "g")
.attr("transform", function(d) { return "translate(" + x0(d.Attribute) + ",0)"; });
state.selectAll("rect")
.data(function(d) { return d.Playerstats; })
.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(playerNames.slice())
.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; });
});
});
});