Using the layout and scale functions of my d3 icon array plugin to render the senate election battleground.
Based on a chart I made for the FT wedsite
xxxxxxxxxx
<html>
<head>
<title>Simple icon array example</title>
<script src="//d3js.org/d3.v4.0.0-alpha.18.min.js" charset="utf-8"></script>
<script type="text/javascript" src="d3-iconarray.js"></script>
<style type="text/css">
*{
font-family: sans-serif;
letter-spacing: 1px;
}
.R, .I{
fill:#F00;
}
.Solid-Republican{
stroke:#F00;
stroke-width:2;
fill: none;
}
.Likely-Republican{
stroke:#F00;
stroke-width:2;
stroke-dasharray:4 2;
fill: none;
}
.Lean-Republican{
stroke:#F00;
stroke-width:2;
stroke-dasharray:2 4;
fill: none;
}
.Tossup{
stroke:#CCC;
stroke-width:2;
fill: none;
}
.Lean-Democratic{
stroke:#00F;
stroke-width:2;
stroke-dasharray:2 4;
fill: none;
}
.Likely-Democratic{
stroke:#00F;
stroke-width:2;
stroke-dasharray:4 2;
fill: none;
}
.Solid-Democratic{
stroke:#00F;
stroke-width:2;
fill: none;
}
.D{
fill:#00F;
}
.key-element text{
font-size: 12px
}
</style>
</head>
<body>
<h1>2014 US senate election</h1>
<p>This graphic shows the 100 seats of the US senate in the run up to the 2014 election. It indicates which were up for election and what their result was expected to be according to <a href="https://cookpolitical.com/senate/charts/race-ratings/8108">The Cook Political Report</a></p>
<div id="senate-example">
</div>
</body>
<script type="text/javascript">
var order = [
'R',
'Solid Republican',
'Likely Republican',
'Lean Republican',
'Tossup',
'Lean Democratic',
'Likely Democratic',
'Solid Democratic',
'D' ]
var width = 600, height = 400,
margin = {top:20,left:20,bottom:20,right:20};
var plotWidth = width - (margin.left + margin.right);
var svg = d3.select('#senate-example')
.append('svg')
.attr('width',width)
.attr('height', height)
.append('g')
.attr('transform','translate('+margin.left+','+margin.top+')')
d3.csv('data-senate-2014.csv', function(data){
var sorted = data.map(function(d){
if (d.election == "" || d.election == undefined){
d['Cook Political Rating'] = d.encumbentparty;
}
return d;
})
.sort(function(a,b){
return order.indexOf(a['Cook Political Rating']) - order.indexOf(b['Cook Political Rating']);
});
var layout = d3_iconarray.layout()
.height(5)
.widthFirst(false);
var grid = layout(sorted);
var scale = d3_iconarray.scale()
.domain([0, layout.maxDimension(sorted.length)])
.range([0, plotWidth])
.gapInterval(10)
.gapSize(1.5);
svg.selectAll('circle')
.data(grid, function(d){ return d.data.seatid; })
.enter()
.append('circle')
.attr('r',function(d){
if(d.data.election){
return 5
}
return 2
})
.attr('cx',function(d){
return scale(d.position.x);
})
.attr('cy',function(d){
return scale(d.position.y);
})
.attr('class',function(d){
return d.data["Cook Political Rating"].replace(/\s/g,'-')
});
//key
var columns = [
['R','Solid Republican','Likely Republican','Lean Republican'],
['Tossup'],
['D','Solid Democratic','Likely Democratic','Lean Democratic']
];
d3.select('svg').selectAll('g.key-column')
.data(columns).enter()
.append('g')
.attr('class','key-column')
.attr('transform',function(d,i){
return 'translate('+(margin.left + (i*plotWidth/columns.length))+','+ (margin.top*4 + scale(layout.height())) +')';
})
.each(function(columnData){
d3.select(this)
.selectAll('g.key-element')
.data(columnData)
.enter()
.append('g')
.attr('class','key-element')
.attr('transform',function(d,i){
return 'translate(0,'+scale(i)+')';
})
.call(function(parent){
parent.append('circle')
.attr('cy',-5)
.attr('r',function(d){
if(d==='D'||d==='R'){
return 2
}
return 5
})
.attr('class',function(d){
return d.replace(/\s/g,'-')
});
parent.append('text')
.attr('dx', margin.left)
.text(function(d){
if(d==='R') return 'Rep (no election)'
if(d==='D') return 'Dem (no election)'
if(d==='Tossup') return 'Tossup ¯\\_(ツ)_/¯' //added the shrugging guy to make the key look abalanced ¯\_(ツ)_/¯
return d;
})
});
});
});
</script>
</html>
https://d3js.org/d3.v4.0.0-alpha.18.min.js