Public
Edited
Aug 15, 2023
Insert cell
Insert cell
Insert cell
map2 = {
const height = 500;
const svg = d3.select(DOM.svg(width, height));
const g = svg.append("g")
g.selectAll('path.districts').data(fixed)
.enter()
.append("path")
.attr("fill", function(data) {
var party = district_part_affiliation.get(parseInt(data.properties.DISTRICT))[0]
if (party.Party == 'Democratic') {
return d3.interpolateRdBu(.8)
} else {
return d3.interpolateRdBu(0.2)
}
})
.attr("stroke", "black")
.attr("stroke-width", 1)
.on("click", function(d,i){
console.log(d)
})
.attr("d", path)

const zoom = d3.zoom()
.scaleExtent([1, 8])
.extent([[0, 0], [width, height]])
.on("zoom", (event) => g.attr("transform", event.transform));

svg.call(zoom);
return svg.node();

}
Insert cell
annotations_display = {
let collection = labels.collection()
if (collection) {
return collection.annotations
} else {
return "Manually rerun this cell to check the annotation marked by annotation_number"
}
}
Insert cell
annotations = [
{
note: {
label: "",
bgPadding: 20,
title: "Atlanta"
},
//can use x, y directly instead of data
type: d3.annotationCalloutCircle, // this type of annotation draws a line under your label.
data: { county: "DeKalb" },
dx: -127.00057983398438,
dy: -3.0000152587890625,
subject: {
radius: 53.28444388095336,
radiusPadding: 5
},
className: "show-bg"
},
{
note: {
label: "",
bgPadding: 20,
title: "Columbus"
},
//can use x, y directly instead of data
type: d3.annotationCalloutCircle, // this type of annotation draws a line under your label.
data: { county: "Randolph" },
dx: -95.00045776367188,
dy: 6.000030517578125,
subject: {
radius: 32.07111097023835,
radiusPadding: 5
},
className: "show-bg"
},
{
note: {
label: "",
bgPadding: 20,
title: "Savannah"
},
//can use x, y directly instead of data
type: d3.annotationCallout, // this type of annotation draws a line under your label.
data: { county: "Chatham" },
dx: 17.00006103515625,
dy: -19.000091552734375,
className: "show-bg"
},
{
note: {
label: "",
bgPadding: 20,
title: "Augusta"
},
//can use x, y directly instead of data
type: d3.annotationCallout, // this type of annotation draws a line under your label.
data: { county: "Richmond" },
dx: 32.0001220703125,
dy: -19.000091552734375,
className: "show-bg"
},
{
note: {
label: "",
bgPadding: 20,
title: "Macon"
},
//can use x, y directly instead of data
type: d3.annotationCallout, // this type of annotation draws a line under your label.
data: { county: "Bibb" },
dx: -193.0009002685547,
dy: 0,
className: "show-bg"
},
]
Insert cell
getAnnotations = function(annotationList, debug){
/*
Return a list of d3.annotation objects
Arguments
annotationList - a list of dictionaries used to configure each annotation
x: a d3.scale
y: a d3.scale
parseTime: function for turning strings into js dates
formatTime: function for turning js date into a string
debug: a boolean flag
*/
map // reactive hack to force annotations to render whenever the chart is redrawn
let makeLabelAnnotations = d3.annotation()
.editMode(debug) // GLOBAL VARIABLE
.type(d3.annotationLabel) // Adjust this arg to adjust the default annotation styling.
.accessors({
x: d => path.centroid(county_keys.get(d.county)[0].geometry)[0],
y: d => path.centroid(county_keys.get(d.county)[0].geometry)[1] // If you use a new dataset, you may need to update this accessor.
})
.accessorsInverse({
geometry: d => d
})
.annotations(annotationList)
return makeLabelAnnotations
}
Insert cell
labels = getAnnotations(annotations , false)
Insert cell
applyAnnotations = function(annotations, target) {
/*Draws d3.annotation objects onto a designated DOM node */
d3.select(target)
.append("g")
.attr("class", "annotation-group")
.call(annotations)
return annotations
}
Insert cell
applyAnnotations(labels, map)
Insert cell
path = d3.geoPath(projection)
Insert cell
projection = d3.geoMercator()
.fitSize([width, 500],{"type": "FeatureCollection","features":fixed})
Insert cell
fixed = georgia_state_senate.features.map(function(f) {
return turf.rewind(f,{reverse:true});
})
Insert cell
district_part_affiliation = d3.group(district_party, d => d.District)
Insert cell
georgia_senate_current
SELECT District, Party FROM georgia_senate_current
Insert cell
georgia_senate_current.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
georgia_county_votes = d3.group(county_votes, d => d.county_name)
Insert cell
georgia_counties_2020
SELECT county_name, county_fips, candidate, SUM(candidatevotes) as votes, totalvotes FROM georgia_counties_2020
WHERE candidate = 'JOSEPH R BIDEN JR'
GROUP BY county_name, county_fips, candidate, totalvotes

Insert cell
county_votes
Type SQL, then Shift-Enter. Ctrl-space for more options.

Insert cell
georgia_counties_2020.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
county_keys = d3.group(counties.features, d => d.properties.NAME)
Insert cell
counties = Object.keys(georgia_counties.objects).map(key =>
topojson.feature(georgia_counties, georgia_counties.objects[key])
)[0]
Insert cell
topojson.merge(georgia_counties, Object.values(georgia_counties.objects))
Insert cell
georgia_counties = FileAttachment("georgia_counties@1.json").json()
Insert cell
georgia_state_senate = FileAttachment("georgia_state_senate.json").json()
Insert cell
turf = require('https://cdnjs.cloudflare.com/ajax/libs/Turf.js/5.1.5/turf.min.js')
Insert cell
d3_svg_annotation = require("d3-svg-annotation")
Insert cell
d3_base = require("https://d3js.org/d3.v6.min.js")
Insert cell
d3 = {
// Add
const bundle = Object.assign({}, d3_base, d3_svg_annotation);
return bundle;
}
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