Public
Edited
Mar 2, 2023
Insert cell
md`# GeoVis Assignment 3
Percent White in Colorado Counties`
Insert cell
d3 = require("d3@5")
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
simple = require("simple-statistics@7.0.7/dist/simple-statistics.min.js")
Insert cell
format = d => `${d}%`
Insert cell
topojson = require("topojson-client@3")
//importing the topojson library
Insert cell
Counties = FileAttachment("geo_export_1df364d9-8aeb-46ba-9d4d-d864fc4046a5.json").json()
Insert cell
Colorado_Counties = topojson.feature(Counties, Counties.objects.counties_topojson)
Insert cell
csv_data = d3.csvParse(await FileAttachment("counties_colorado_csv.csv").text(),({geonum, pop, white_nh}) => [+geonum, +white_nh/+pop])
//need to add + to geonum to make into an integer and not string
Insert cell
data = Object.assign(new Map(csv_data), {title: "Percent White"})
Insert cell
data.get(108007)
Insert cell
whitepct = Array.from(csv_data.values(), d => d[1])
Insert cell
Colorbrewer = [d3.color("#c2e699"), d3.color("#78c679"), d3.color("#31a354"),d3.color("#006837")]
//this is where we create our color scheme, here we chose what colors you want to use
// I used 4 classses and we can see each of the 4 different colors represented by [d3.color("#yourcolor")]
Insert cell
naturalbreaks = simple.ckmeans(whitepct, Colorbrewer.length).map(v => v.pop())
//this uses the natural breaks classification and selects how many classes to use based on how many colors defined in the Colorbewer line of code, here I used for colors so by using Colorbrewer.length it uses 4 classes
Insert cell
//more information on sequential scales: https://observablehq.com/@d3/sequential-scales
// color = d3.scaleSequentialQuantile([...data.values()], d3.interpolateBlues)

// color = d3.scaleQuantile()
// .domain(whitepct)
// .range()

color = d3.scaleThreshold()
.domain(naturalbreaks)
.range(Colorbrewer)
Insert cell
width = 975
//width of the canvas for the map, the height and margins can be adjusted below
Insert cell
height = 610
Insert cell
margin = 100
Insert cell
//Rotate the map sets the longitude of origin for our UTM Zone 15N projection.
projection = d3.geoTransverseMercator().rotate([105,0]).fitExtent([[100, 100], [width, height]], Colorado_Counties);
//Here we can rotate the projection so that it is oriented correctly

//d3 reference for projections: https://github.com/d3/d3-geo/blob/master/README.md

//use the following url for specific projection settings: https://github.com/veltman/d3-stateplane
//Use this code to set up the map projection (if different than geographic projection)

//projection = d3.geoAlbers().fitExtent([[margin, margin], [width - margin, height - margin]], Colorado_Counties)

//projection = d3.geoMercator().fitExtent([[margin, margin], [width - margin, height - margin]], counties)
Insert cell
//Using a path generator to project geometry onto the map
path = d3.geoPath().projection(projection);
Insert cell
choropleth = {
const svg = d3.create("svg")
//creating the canvas we will use
//svg - Scalable Vector Graphics, allows us to visualize two-demensional vector graphic (points, lines, and polygons). Lets us add our map and legend onto the 'canvas' as well as moving them around to different places on the 'canvas'
.attr("viewBox", [0, 0, width, height]);
//inserting the canvas
svg.append("g")
.attr("transform", "translate(360,20)")
//legend cordinates, is used to change location of the lengend based on the x and y values
.append(() =>
legend({
color: color,
//this inputs our colors we chose into the legend
title: data.title,
//inputs the title we chose above
width: 260,
//this is the width of the legend
tickFormat: ".2f"
//here we can chose how many decimal places we want in the legend, I chose 2 because it gives a little more information and better shows the max value at .93 where if I only used 1 decimal it would read .9 and you wouldn't know how close to 1 the max value is
})
);

svg.append("g")
//svg is our 'canvas' append is what we are attaching to it (graphics)
.selectAll("path")
.data(Colorado_Counties.features)
//here we read the features from our data (topojson)
.join("path")
.attr("stroke", "black")
//boundary color between states
.attr("stroke-linejoin", "round")
//line type
.attr("stroke-width", 1.05)
//here you can change the thickness of lines between counties
// .attr("fill", function(d){
// console.log(color(data.get(d.properties.FIPS)[0]))
// return color(data.get(d.properties.FIPS)[0]);
// })
.attr("fill", d => color(data.get(d.properties.geonum)))
//here this defines the color for each polygon by reading the geonum from our data, joining geonum with the attribute
//the data needs to be the same, if it is an integar above it can not be string here
.attr("d", path)
.append("title")
.text(d => "whitepct: " + data.get(d.properties.geonum));
//this is what is used to allow us to hover over the data and see the value for that county

return svg.node();
}

//spatial patterns of the map: By looking at the map I don't think there is a ton of spatial patterns present but one to look at is the southern most counties in Colorado, 6 counties all border each other that all have a percent of white people less than .54 (54%). Other than that I don't think there is much else for spatial patterns, maybe you could say the counties toward the center of the state is a pattern, there are quite a few counties in Colorado with a white population percent over 83% and can a lot of them do border each other. But then looking at the eastern side of the state there is no real spatial pattern seen. I think it would be interesting to look more into those southern counties and see why the white population is much lower in that area of the state
Insert cell
data.get(108007)
Insert cell
color(data.get(108007))
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