Public
Edited
May 18, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data
Insert cell
curData = data.filter(d => d.State == state & d.Scenario == scenario & d.StatePctRecorded == statePctRecorded)
Insert cell
curStateData = ({
'DemVotes': d3.sum(curData, d=> +d.DemVotes),
'RepVotes': d3.sum(curData, d=> +d.RepVotes),
'TotalVoters': d3.sum(curData, d=> (+d.DemVotes) + (+d.RepVotes) + (+d.RemainingVotes))
})
Insert cell
curStateShape = stateShapes.features.filter(d => d.id == states.get(state).FIPS)
Insert cell
curCountyShapes = countyShapes.features.filter(d => d.id.slice(0,2) == states.get(state).FIPS)
Insert cell
curCountyShapes
Insert cell
shapesWithDataCounty = curCountyShapes // Counties for current state selected
.map(s => {
let curCountyResults = curData.filter(d=> d.FIPS == s.id)[0]
let curColor = curCountyResults && +curCountyResults.DemVotes == +curCountyResults.RepVotes ? '#ccc' :
curCountyResults && +curCountyResults.DemVotes > +curCountyResults.RepVotes ? '#2e74c0' :
'#cb454a';
let colRamp = d3.scaleLinear().domain([0, 1]).range(["#2e74c0", "#cb454a"])
let curColorRamped = colRamp(+curCountyResults.RepVotes / (+curCountyResults.DemVotes + +curCountyResults.RepVotes))
return ({
...s,
...curCountyResults,
color: curColor,
colorRamped: curColorRamped,
centroid: turf.centroid(s),
TotalVoters: (+curCountyResults.DemVotes) + (+curCountyResults.RepVotes) + (+curCountyResults.RemainingVotes)
})
})
Insert cell
colRamp = d3.scaleLinear().domain([0, 1]).range(["#2e74c0", "#cb454a"])
Insert cell
colRamp(0.75)
Insert cell
curStateCities = stateCitiesGeo.get(state)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
packedDotRadius = ( 0.037 * width * mapScale )* (1.5 / 30 ) // radius for inner dot. Should probably change it to function of max donut size
Insert cell
maxPackedDots = 208 // number of dots to put in the biggest County.
Insert cell
packedDotPop = // population associated with 1 dot it biggest County.
d3.max(shapesWithDataCounty, d=> d.TotalVoters) / maxPackedDots
Insert cell
pack = (data,outerRadius) => d3.pack()
.size([outerRadius*2, outerRadius*2])
.padding(1)
.radius(d=> d3.min([packedDotRadius, outerRadius]))
(d3.hierarchy(data));
Insert cell
circlePackData =
circles.map( d=> {
let packedDotCount = d3.max([1, Math.round(d.TotalVoters / packedDotPop)]) // d3.max to ensure dots > 0
let countyPack = pack( {children:d3.range(packedDotCount)}, d.r)
return {
r: countyPack.children.length > 1 ? countyPack.r : d.r,
x: d.x,
y: d.y,
children: countyPack.children.map(c => ({x: c.x, y: c.y, r: c.r, col: circlePackDotColor(d.DemVotes, d.RepVotes, d.TotalVoters)}))
} ;
})
Insert cell
circlePackDotColor = (demVoters, repVoters, totalVoters, colorScale = ({dem: "#2e74c0", rep: "#cb454a", remaining: '#BBB' })) => {
let rand = Math.random()
if (rand < +demVoters / +totalVoters ) {
return colorScale.dem
} else if (rand < (+demVoters + +repVoters)/ +totalVoters) {
return colorScale.rep
} else {
return colorScale.remaining
}
}
Insert cell
Insert cell
curProps = countyPartyProps.get(state).get(scenario).get(statePctRecorded)
Insert cell
dotPop = // population associated with 1 dot.
d3.sum(shapesWithDataCounty, d=> d.TotalVoters) / curDots.length
Insert cell
dotColor = function(propArray, randNum, colorScale = ({dem: "#2e74c0", rep: "#cb454a", remaining: '#fbf418' })) {
if(+randNum < +propArray[0]){
return colorScale.dem
} else if(+randNum < +propArray[1]) {
return colorScale.rep
} else {
return colorScale.remaining
}
}
Insert cell
curDots = stateDots.get(state)
.map( d => {
return {coordsProjected: projection(d.coords),
color: dotColor(curProps.get(d.FIPS), d.rand)
}
})
Insert cell
proportionToHex = x => (Math.round(x * 255)).toString(16);
Insert cell
proportionToHex(0.75)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mapScale = (sidebarPlotPixels > 0.12 * width ? 1 : 0.75)
Insert cell
height = width * 7/9
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
sidebarPlotPixels = 100
Insert cell
sideBarColOpacityHex = 'B3'
Insert cell
Insert cell
Insert cell
annote1Url = FileAttachment("BubbleAnnot1@1.png").url()
Insert cell
annote2Url = FileAttachment("BubbleAnnot2.png").url()
Insert cell
annote3Url = FileAttachment("BubbleAnnot3.png").url()
Insert cell
annote4Url = FileAttachment("BubbleAnnot4@2.png").url()
Insert cell
annoteDonut = FileAttachment("annoteDonut2.png").url()
Insert cell
annotePackedDot = FileAttachment("annotePackedDot.png").url()
Insert cell
Insert cell
d3 = require('d3@6')
Insert cell
topojson = require("topojson-client@3")
Insert cell
turf = require('https://bundle.run/turf@3.0.14')
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more