Public
Edited
Apr 19, 2023
Insert cell
Insert cell
proportionalSymbols = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height]);
// Creates the base map of the graphic. Ties coordinates to US states in this example
svg.append("path")
.datum(topojson.feature(basepolygons, basepolygons.objects.states_simple))
//Determines the color of the base map
.attr("fill", "#ccc")
.attr("d", path_basemap);
// This adds in the state boundaries as a single line. Overlays a mesh layer that represents the states
svg.append("path")
.datum(topojson.mesh(basepolygons, basepolygons.objects.states_simple, (a, b) => a !== b))
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-linejoin", "round")
.attr("d", path_basemap);
// This is creating a legend for the map
const legend = svg.append("g")
.attr("fill", "#777")
.attr("transform", "translate(150,450)")
.attr("text-anchor", "middle")
.style("font", "10px sans-serif")
.selectAll("g")
// Determine breaks shown in the legend.
.data([2e6,1e7, d3.max([...data.values()])])
.join("g");
// This is making the legend be groups of circles because its using the same "r" as the symbol mapping
legend.append("circle")
//This fills the shape
.attr("fill", "none")
// This creates the outside of the shape
.attr("stroke", "#ccc")
.attr("cy", d => -radius(d))
.attr("r", radius);
legend.append("text")
.attr("y", d => -2 * radius(d))
.attr("dy", "1.3em")
.text(format);
// This is how you create your points on the map. the ".attr" allows you to manipulate a graphic's attributes eg: what color it's filled with, the outline's color, etc.
svg.append("g")
//This is the fill color of your point. I chose light brown because it is a 'dirty' which goes well with carbon emissions
.attr("fill", "#c29a5a")
//This determines the opacity of the point. Their not-quite-opaque nature of them allows lower layers to be seen
.attr("fill-opacity", 0.5)
//This is the outline of your point. I chose a darker brown than my fill color to let the circles stand out more
.attr("stroke", "#744700")
.attr("stroke-width", 0.5)
//I chose my data to be a circle because it is gas emissions. It is released in a certain area around the node. The shape/color of your icons should represent your data's information.
.selectAll("circle")
.data(points.features
.map(d => (d.value = data.get(d.properties.GHGRP_ID), d))
.sort((a, b) => b.value - a.value))
//This allows you to display the points value by hovering over it.
.join("circle")
.attr("transform", d =>
//This translates your points to where the point is located and displays the text associated with each node.
`translate(${path_points.centroid(d)})`)
.attr("r", d => radius(data.get(d.properties.GHGRP_ID)))
.append("title")
.text(d => `${d.properties.GHGRP_ID} :
${format(d.value)}`);
return svg.node();
}

// Judging the data, it seems most of the greenhouse gas emitters are in the Eastern US. While there is a diverse set of values, it looks like most "high emitters" are grouped together, most likely around cities.
Insert cell
height = 700
Insert cell
width = 975
Insert cell
path_points = d3.geoPath().projection(projection)
Insert cell
path_basemap = d3.geoPath().projection(projection)
Insert cell
projection = d3.geoAlbers()
Insert cell
format = d3.format(".2s")
Insert cell
radius(20998639)
Insert cell
d3.max([...data.values()])
Insert cell
radius(88371.1)
Insert cell
//This scales the square root of a number with a class within the data. This is good for scaling data with circles because the radius of a circle is sqrt(Radius/pi)
//The first [] within parentheses indicates the input values. The second [] after the comma in the parentheses indicates the output range of the values.
radius = d3.scaleSqrt([0, d3.max([...data.values()])], [0, 15])
Insert cell
//This is a line to test our data variable works
data.get(1000355)
Insert cell
data = Object.assign(new Map(csv_data))
Insert cell
//MAKE SURE YOU ALWAYS SPECIFY INTEGERS. ALL VALUES ARE ASSUMED AS STRING UNLESS OTHERWISE NOTED
csv_data = d3.csvParse(await FileAttachment("GHG_cleaned.csv").text(),({GHGRP_ID, GHGQUANTITY}) => [+GHGRP_ID, +GHGQUANTITY])
Insert cell
//import the point data (json)
points = FileAttachment("GHGwpt.json").json()
Insert cell
//import the polygon base map data
basepolygons = FileAttachment("states_simple.json").json()
Insert cell
simple = require("simple-statistics@7.0.7/dist/simple-statistics.min.js")
Insert cell
topojson = require("topojson-client@3")
Insert cell
d3 = require("d3@5")
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