var abvToName = { "AL": "Alabama", "AK": "Alaska", "AS": "American Samoa", "AZ": "Arizona", "AR": "Arkansas", "CA": "California", "CO": "Colorado", "CT": "Connecticut", "DE": "Delaware", "DC": "Dist. of Col.", "FM": "Federated States Of Micronesia", "FL": "Florida", "GA": "Georgia", "GU": "Guam", "HI": "Hawaii", "ID": "Idaho", "IL": "Illinois", "IN": "Indiana", "IA": "Iowa", "KS": "Kansas", "KY": "Kentucky", "LA": "Louisiana", "ME": "Maine", "MH": "Marshall Islands", "MD": "Maryland", "MA": "Massachusetts", "MI": "Michigan", "MN": "Minnesota", "MS": "Mississippi", "MO": "Missouri", "MT": "Montana", "NE": "Nebraska", "NV": "Nevada", "NH": "New Hampshire", "NJ": "New Jersey", "NM": "New Mexico", "NY": "New York", "NC": "North Carolina", "ND": "North Dakota", "MP": "Northern Mariana Islands", "OH": "Ohio", "OK": "Oklahoma", "OR": "Oregon", "PW": "Palau", "PA": "Pennsylvania", "PR": "Puerto Rico", "RI": "Rhode Island", "SC": "South Carolina", "SD": "South Dakota", "TN": "Tennessee", "TX": "Texas", "UT": "Utah", "VT": "Vermont", "VI": "Virgin Islands", "VA": "Virginia", "WA": "Washington", "WV": "West Virginia", "WI": "Wisconsin", "WY": "Wyoming" } var states = [] d3.select("#grid").text().split("\n").forEach(function(line, i) { var re = /\w+/g, m; while (m = re.exec(line)) states.push({ name: m[0], x: m.index / 3, y: i, fullName: abvToName[m[0]] }); }); d3.csv('byState.csv', function(stateData){ flatData = [] stateData.forEach(function(d){ var values = d3.entries(d).filter(function(d, i){ d.value = +d.value.replace(',', '').replace(',', '') return d.key != 'state' && i > -10 }) var total = d3.sum(values, ƒ('value')) var prevPercent = 0 values.forEach(function(d, i){ d.percent = d.value/total prevPercent += d.percent d.prevPercent = prevPercent d.i = i flatData.push(d) }) var m = _.findWhere(states, {fullName: d.state.trim()}) if (!m) return m.values = values m.yPercent = _.findWhere(values, {key: '35-39'}).prevPercent m.oPercent = 1 - _.findWhere(values, {key: '70-74'}).prevPercent }) d3.select('body').append('h3').text('Percent Old, Middle Aged, and Young Drives') var svg = d3.select("body").append('svg') .attr({width: 960, height: 500}), width = +svg.attr("width"), height = +svg.attr("height"); var gridWidth = d3.max(states, function(d) { return d.x; }) + 1, gridHeight = d3.max(states, function(d) { return d.y; }) + 1, cellSize = 60, smCellSize = cellSize - 10 var state = svg.append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .selectAll(".state") .data(states) .enter().append("g.state") .attr("transform", function(d) { return "translate(" + (d.x - gridWidth / 2) * cellSize + "," + (d.y - gridHeight / 2) * cellSize + ")"; }); state.append("rect") .attr("x", -cellSize / 2) .attr("y", -cellSize / 2) .attr("width", cellSize) .attr("height", cellSize); state.append('g').translate([-smCellSize/2, smCellSize/2]) .dataAppend(ƒ('values'), 'rect.bar') .attr('width', smCellSize) .attr('height', function(d){ return d.percent*smCellSize }) .attr('y', function(d){ return -d.prevPercent*smCellSize }) .style('fill', function(d, i){ return colorbrewer.Purples[3][Math.round(i/5)] }) state.append("text") .attr("dy", ".35em") .text(function(d) { return d.name; }); d3.select('body').append('h3').text('Percent Old Drivers') var svg = d3.select("body").append('svg') .attr({width: 960, height: 500}), width = +svg.attr("width"), height = +svg.attr("height"); var gridWidth = d3.max(states, function(d) { return d.x; }) + 1, gridHeight = d3.max(states, function(d) { return d.y; }) + 1, cellSize = 60, smCellSize = cellSize - 4 var state = svg.append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .selectAll(".state") .data(states) .enter().append("g.state") .attr("transform", function(d) { return "translate(" + (d.x - gridWidth / 2) * cellSize + "," + (d.y - gridHeight / 2) * cellSize + ")"; }); var underColor = d3.scale.quantile() .domain(states.map(ƒ('oPercent'))) .range(colorbrewer.Purples[5]) state.append("rect") .attr("x", -smCellSize / 2) .attr("y", -smCellSize / 2) .attr("width", smCellSize) .attr("height", smCellSize) .style('fill', ƒ('oPercent', underColor)) state.append("text") .attr("dy", ".35em") .text(function(d) { return d.name; }); d3.select('body').append('h3').text('Percent Young Drivers') var svg = d3.select("body").append('svg') .attr({width: 960, height: 500}), width = +svg.attr("width"), height = +svg.attr("height"); var gridWidth = d3.max(states, function(d) { return d.x; }) + 1, gridHeight = d3.max(states, function(d) { return d.y; }) + 1, cellSize = 60, smCellSize = cellSize - 4 var state = svg.append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")") .selectAll(".state") .data(states) .enter().append("g.state") .attr("transform", function(d) { return "translate(" + (d.x - gridWidth / 2) * cellSize + "," + (d.y - gridHeight / 2) * cellSize + ")"; }); var underColor = d3.scale.quantile() .domain(states.map(ƒ('yPercent'))) .range(colorbrewer.Purples[5]) state.append("rect") .attr("x", -smCellSize / 2) .attr("y", -smCellSize / 2) .attr("width", smCellSize) .attr("height", smCellSize) .style('fill', ƒ('yPercent', underColor)) state.append("text") .attr("dy", ".35em") .text(function(d) { return d.name; }); d3.select('body').append('h3').text('Percent Young Drivers v. Percent Old Drivers') var c = d3.conventions() c.x.domain(d3.extent(states, ƒ('yPercent'))) c.y.domain(d3.extent(states, ƒ('oPercent'))) c.drawAxis() c.svg.dataAppend(states, 'text.state') .text(ƒ('name')) .attr('x', ƒ('yPercent', c.x)) .attr('y', ƒ('oPercent', c.y)) .attr('dy', '.33em') d3.select('body').append('h3').text('Outliers By Age') var byAge = d3.nest().key(ƒ('i')).map(flatData) d3.values(byAge).forEach(function(d){ var mean = d3.mean(d, ƒ('percent')) d.forEach(function(d){ d.ageRatio = d.percent/mean }) var maxAgeDiff = d3.max(d, ƒ('ageRatio', Math.abs)) var minAgeDiff = d3.min(d, ƒ('ageRatio', Math.abs)) var color = d3.scale.linear() .domain([minAgeDiff, 1, maxAgeDiff]) .range(['red', 'yellow', 'green']) var num = d3.scale.linear() .domain([minAgeDiff, 1, maxAgeDiff]) .range([-1, 0, 1]) d.forEach(function(d){ d.ageRatioColor = color(d.ageRatio) d.ageRatioNum = num(d.ageRatio) }) }) states.forEach(function(state){ // state.maxGroupI = _.sortBy(state.values, 'ageRatioNum')[0].i state.maxGroupI = _.last(_.sortBy(state.values, 'ageRatioNum')).i // state.maxGroupI = d3.sum(state.values.map(function(d){ // return d.i*d.percent*d.percent*d.percent })) }) var c = d3.conventions({height: 800}) c.x.domain([0, states[0].values.length]) c.y.domain([0, states.length]) stateGs = c.svg.dataAppend(_.sortBy(states, 'maxGroupI'), 'g') .translate(function(d, i){ return [0, c.y(i)] }) stateGs.dataAppend(ƒ('values'), 'rect') .attr('height', c.y(0) - c.y(1)) .attr('width', c.x(1) - c.x(0)) .attr('x', function(d, i){ return c.x(i) }) .attr('fill', ƒ('ageRatioColor')) .call(d3.attachTooltip) stateGs.append('text') .text(ƒ('name')) .attr('dy', '.76em') .style('font-family', 'monospace') d3.select(self.frameElement).style("height", innerHeight + "px"); })