I would like to sum the column elecVotes
and then divide it by the elecVote
of a state that has been clicked on so that I can show the percentage of the electoral vote that state is worth and display it in a dc.numberDisplay
.
This is my data structure:
//updated
ElecVotes.csv:
state,elecVotes,
Alabama,9
Alaska,3
Arkansas,6
Arizona,11
Florida,29
Georgia,16
Iowa,6
Idaho,4
Indiana,11
Kansas,6
Kentucky,8
data.csv:
state,party,votes,winner,elecVote
Alabama,Democratic,725704,1,9
Alabama,Republican,1314431,1,9
Alabama,Libertarian,44211,1,9
Alabama,Green,20276,1,9
Alabama,Other,0,1,9
Alabama,Constitution Party,9341,1,9
Alaska,Democratic,116454,1,3
Alaska,Republican,163387,1,3
Alaska,Libertarian,18725,1,3
Alaska,Green,5735,1,3
Alaska,Constitution Party,3866,1,3
Alaska,Other,10441,1,3
Code:
d3.csv("data.csv", function (data) {
d3.json("us.json", function (json){
data.forEach(function(r) {
r.votes = +r.votes;
r.elecVote = +r.elecVote;
});
var elecVotes = d3.csv.parse("elecVotes")
var elecVotesMap = d3.map()
elecVotes.forEach(function(r){
elecVotesMap.set(r.state, +r.elecVotes)
});
// set up crossfilter on the data.
var ndx = crossfilter(data);
// set up the dimensions
var stateDim = ndx.dimension(function(d) { return d.state; });
var stateDim2 = ndx.dimension(function(d) { return d.state; });
var stateDim3 = ndx.dimension(function(d) { return d.state; });
var partyDim = ndx.dimension(function(d) { return d.party; });
var winnerDim = ndx.dimension(function(d) { return d.winner; });
var elecVotesDim = ndx.dimension(function(d) { return d.elecVote;});
var stateDim4 = ndx.dimension(function(d) { return d.state; }),
group = stateDim4.group().reduceSum(function(d) {return d.elecVote
}),
count = group.top(51);
count[0].key;
count[0].value;
// set up the groups/values
var state = stateDim.group();
var party = partyDim.group().reduceSum(function(d) { return d.votes;});
var party2 = partyDim.group().reduceSum(function(d) { return d.votes;});
var winner = stateDim2.group().reduceSum(function(d) { return d.winner; });
var elecVotes = stateDim3.group().reduceSum(function(d) { return d.elecVote; });
var group = stateDim4.group().reduceSum(function(d) { return d.votes; } )
// the 4 different charts - options are set below for each one.
var pie = dc.pieChart('#chart-pie');
var usmap = dc.geoChoroplethChart("#usmap");
var selectMenu = dc.selectMenu('#select-container');
var percentElec = dc.numberDisplay("#percentage-elec-vote");
var colorScale = d3.scale.ordinal().domain(["Democratic","Republican","Libertarian","Green","Constitution Party","Other"]) //set colour based on party
.range(["#4682B4","#B22222","#DAA520","#228B22","#80f2ee","#D3D3D3"]);
var stateColor = d3.scale.ordinal().domain(["1","2",""]).range(["#B22222","#4682B4","#B2B7B2"]); //set colour based on which party won
selectMenu
.dimension(stateDim3)
.group(state)
.onClick = function() {};
selectMenu.title(function (d){
return d.key;
})
//create pie from to show popular vote for each state
pie
.width(300)
.height(180)
.radius(80)
.dimension(stateDim2)
.group(party)
.legend(dc.legend())
.colors(colorScale)
.innerRadius(10)
.transitionDuration(500)
.filter = function() {};
//number chart to show percentage of electoral vote for each state
percentElec
.group(group)
.formatNumber(d3.format("d"))
.valueAccessor(function(d){ return elecVotesMap.get(d.key); })
//display US map
usmap
.width(900)
.height(500)
.dimension(stateDim)
.group(winner)
.colors(stateColor)
.overlayGeoJson(json.features, "name", function (d) { return d.properties.name; })
// at the end this needs to be called to actually go through and generate all the graphs on the page.
dc.renderAll();
});
});
};
So, to expand on the comments above a bit, here is a fiddle that pretty much shows how I would approach this: https://jsfiddle.net/esjewett/u9dq33v2/1/
This just loads the data from inline in the page.
var elecVotes = d3.csv.parse(document.getElementById("ElecVotes.csv").innerHTML)
var data = d3.csv.parse(document.getElementById("data.csv").innerHTML)
Set up your charts. In this example I am using a rowChart as well as the numberDisplay so that you can see how you need to approach dimension/group design for filtering.
var percentElec = dc.numberDisplay("#percentage-elec-vote");
var states = dc.rowChart("#state-votes")
Set up the Map that you're going to do the lookup of your electoral votes based on the state.
var elecVotesMap = d3.map()
elecVotes.forEach(function(r){
elecVotesMap.set(r.state, +r.elecVotes)
});
Set up your Crossfilter and dimension. Note that we are setting up 2 sets of identical dimensions and groups. Groups do not respect filters on their own dimension, so if you use the same dimension (or groups based on the same dimension) in both charts, it will not filter.
var cf = crossfilter(data)
var dim1 = cf.dimension(function(d) { return d.state; })
var grp1 = dim1.group().reduceSum(function(d) { return +d.votes })
var dim2 = cf.dimension(function(d) { return d.state; })
var grp2 = dim2.group().reduceSum(function(d) { return +d.votes })
Set up the state votes rowChart. You can click on this to restrict to just Alabama or Alaska.
states
.dimension(dim1)
.group(grp1)
Set up the numberDisplay. Note that the numberDisplay will display whatever grp2.top(1)
returns. So if you select more than one state in the rowChart, it will display the state with the most votes (or whatever you have set your grp2.order()
as). If you want to total everything up, wrap your group with an object with a top
method that will return what you want to show, and pass the wrapper to the numberDisplay.
In numberDisplay.valueAccessor
, you have access to both the key and the value of the group. Use the key (the name of the state) to look up the electoral votes for that state. That's what will display.
percentElec
.group(grp2)
.formatNumber(d3.format("d"))
.valueAccessor(function(d){ return elecVotesMap.get(d.key); })
dc.renderAll()