Published
Edited
Jul 19, 2021
Insert cell
Insert cell
Insert cell
svg = {
// create svg
let svg = d3.create('svg')
.attr('width', 900)
.attr('height', 570)
// create projection
let albersProjection = d3.geoAlbersUsa();
// create path generator
let geoPathGenerator = d3.geoPath(albersProjection)
// append title
svg.append('text')
.attr('transform', 'translate(450,50)')
.attr('text-anchor','middle')
.attr('fill', 'black')
.attr('font-weight', 'bold')
.text("Solar Stations Across the United States")
// append g for map
let g = svg.append('g')
.attr('transform', 'translate(0, 50)')
// append map to g
g.selectAll('path')
.data(statesGeoJson.features)
.enter()
.append('path')
.attr('d', geoPathGenerator)
.attr('fill', '#b0c4d8')
// add a circles group
let circles = svg.append('g')
.attr('transform', 'translate(0,50)')
// append circles to group
circles.selectAll('circle')
.data(stationData)
.enter()
.append('circle')
.attr('transform',d => {
let result = albersProjection(d.loc)
return result !== null ? `translate(${result})` : 'translate(-5,-5)'
})
.attr('r', d => radiusScale(d.elevation))
.attr('fill', d => colorGenerator(d.stationClass + 5))
.attr('opacity', .7)
// append legend
const legendGroup = svg.append('g')
.attr('transform', 'translate(760,400)')
// legend rectangles
const legend = legendGroup
.selectAll('rect')
.data(stationClasses)
.enter()
.append('rect')
.attr('width', 15)
.attr('height',15)
.attr('y', d => legendScale(d))
.attr('fill', (d, i) => colorGenerator(i + 6))
// legend text
legendGroup.append('g')
.selectAll('text')
.data(stationClasses)
.enter()
.append('text')
.text(d => d)
.attr('y', d => legendScale(d) + 13)
.attr('x', 20)
return svg.node();
}
Insert cell
legendScale = d3.scaleBand()
.domain(stationClasses)
.range([0, 80])
Insert cell
// it takes in a number
colorGenerator = d3.scaleOrdinal(stationClasses, d3.schemeCategory10)
Insert cell
stationClasses = [...new Set(stationData.map(st => 'Station Class ' + st.stationClass))]
Insert cell
radiusScale = d3.scaleLinear()
.domain(elevationExtent)
.range([2, 15])
Insert cell
elevationExtent = d3.extent(stationData.map( st => st.elevation))
Insert cell
Insert cell
svg2 = {
// create svg
let svg = d3.create('svg')
.attr('width', 1400)
.attr('height', 400)
.attr('transform', 'translate(0,0)')
// create projection
let albersProjection = d3.geoAlbersUsa().scale(280).translate([150,200])
// create path generator
let geoPathGenerator = d3.geoPath(albersProjection)
// append title
svg.append('text')
.attr('transform', 'translate(10,50)')
.attr('fill', 'black')
.attr('font-weight', 'bold')
.text("Unemployment Rate In the United States 2012 - 2015")
// append g for map
let g = svg.append('g')
.attr('transform', 'translate(0, 50)')

// 2012
let year2012Group = svg.append('g')
.attr('transform', 'translate(0, 50)')
generateUnemploymentMap(year2012Group, geoPathGenerator, '2012');
// 2013
let year2013Group = svg.append('g')
.attr('transform', 'translate(220, 50)')
generateUnemploymentMap(year2013Group, geoPathGenerator, '2013');
// 2014
let year2014Group = svg.append('g')
.attr('transform', 'translate(440, 50)')
generateUnemploymentMap(year2014Group, geoPathGenerator, '2014');
// 2015
let year2015Group = svg.append('g')
.attr('transform', 'translate(660, 50)')
generateUnemploymentMap(year2015Group, geoPathGenerator, '2015');

// append legend
const legendGroup = svg.append('g')
.attr('transform', 'translate(250, 70)')
// legend squares
const legend = legendGroup
.selectAll('rect')
.data([1,2,3,4,5])
.enter()
.append('rect')
.attr('width', 15)
.attr('height',15)
.attr('x', (d, i) => i * 15)
.attr('fill', (d, i) => colorScale(i*2))
// lower unemployment text
svg
.append('text')
.style('font-size', '10px')
.text('Lower Unemployment Rates')
.attr('transform', 'translate(90, 80)')
// Higher Unemployment text
svg
.append('text')
.style('font-size', '10px')
.text('Higher Unemployment Rates')
.attr('transform', 'translate(350, 80)')
// no data legend square
const noData = svg.append('g')
.attr('transform', 'translate(200, 90)')
noData.append('rect')
.attr('width', 15)
.attr('height', 15)
.attr('fill', 'black')
// Counties with no data text
svg
.append('text')
.style('font-size', '10px')
.text('Counties With No Data')
.attr('transform', 'translate(90, 100)')
return svg.node();
}
Insert cell
function generateUnemploymentMap(g, geoPathGenerator, yearText){
// append title to g
g.append('text')
.attr('transform', 'translate(50,100)')
.attr('fill', 'black')
.attr('font-weight', 'bold')
.text(`${yearText}`)
// append counties to map
g.selectAll('path')
.data(countiesGeoJson.features)
.enter()
.append('path')
.attr('d', geoPathGenerator)
.attr('fill', d => {
if(!d[`unemployment${yearText}`]) {
return 'black'
}
return colorScale(d[`unemployment${yearText}`] + 1)
})
}
Insert cell
colorScale = d3.scaleSequential(d3.interpolateReds)
.domain([0, 10])
Insert cell
counties = [...launcnty12,...launcnty13, ...launcnty14, ...launcnty15]
Insert cell
// this function adds unemployment percentaje per year to each county in countiesGeoJson
counties.forEach(county => {
const countyCode = +`${county.StateCode}${county.CountyCode}`
const countyGeoJ = countiesGeoJson.features.find(county => county.id === countyCode)
if(countyGeoJ){
countyGeoJ[`unemployment${county.Year}`] = parseFloat(county.Percent)
}
})
Insert cell
Insert cell
statesGeoJson = FileAttachment("us-states@1.json").json()
Insert cell
Insert cell
Insert cell
launcnty12 = FileAttachment("laucnty12.csv").csv()
Insert cell
launcnty13 = FileAttachment("laucnty13.csv").csv()
Insert cell
launcnty14 = FileAttachment("laucnty14.csv").csv()
Insert cell
launcnty15 = FileAttachment("laucnty15.csv").csv()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more