Public
Edited
Mar 22, 2023
1 fork
Insert cell
Insert cell
proportionalSymbols = {
const svg = d3.create("svg") //This creates my svg "canvas" for my page
.attr("viewBox", [0, 0, width, height]);
// The width and height of the page is defined below as variables.

svg.append("path") // adds basemap of states.
.datum(topojson.feature(basepolygons_states, basepolygons_states.objects.States)) // This is the data for my basemap of states called basepolygons_states. The object within that is called States.
.attr("fill", "#ccc") // The gray color will fill my polygons since this is serving as just a basemap. The color is #ccc and fills in the polygon.
.attr("d", path_basemap); // This adds the attribute path to display the map as the Albers USA projection.
svg.append("path") // This creates the borders between the states.
.datum(topojson.mesh(basepolygons_states, basepolygons_states.objects.States, (a, b) => a !== b)) // The mesh function turns our topojson base polygons of the states into the border lines
.attr("fill", "none") // no fill for the border
.attr("stroke", "white") // stroke color of white
.attr("stroke-linejoin", "round") // border lines will be rounded off
.attr("d", path_basemap); // again adds the attribute path to display the map borders of the states


const legend = svg.append("g") // This function creates the legend element.
.attr("fill", "black") // color of the legend, black
.attr("transform", "translate(825,400)") // I can change where the legend is displayed on my canvas by changing the translate(#,#) portion of the legend. For this case, I have the legend displayed on the bottom left corner in the map.
.attr("text-anchor", "middle") // anchoring the text to the middle of legend symbol
.style("font", "10px sans-serif") // This is the size and font of the legend
.selectAll("g")
.data([1.4, d3.max([...data.values()])])
.join("g");
// The size of the circles displayed on the legend are shown as a manually entered value and the maximum value of the proportional symbols. In this case I took the 1/4 of the maximum value (1.4) and the max value of the number of providers in a city. This is done using the code .data([1.4, d3.max([...data.values()])])

legend.append("circle") // This adds the circles to the legend to be represented as 1/4 of the maximum value and the max value of the number of providers in a city.
.attr("fill", "none") // no fill added
.attr("stroke", "#8856a7") // The color of the outline of the circles in the legend
.attr("cy", d => -radius(d))
.attr("r", radius);
legend.append("text") //This chunk adds text to the legend
.attr("y", d => -2 * radius(d))
.attr("dy", "1.3em") // This changes the position of the text in the circle
.text(format);


svg.append("g") // This is how the point symbols are added to the map.
.attr("fill", "#8856a7") // This is the color I want to fill my points with (that will be shown as the proportional symbol).
.attr("fill-opacity", 0.5) // Fill transparency for my points. It is currently at 50%
.attr("stroke", "#252525") // This is the color of the outline for the point symbol.
.attr("stroke-width", 0.5) // This is the thickness of the point symbol outline.
.selectAll("circle") // The point symbols will be represented as a circle.
.data(points.features // This gathers the features from my data calls points. It goes through each shape and takes the ID (That is PLACEFIPS) and returns the value and assigns it to the point.
.map(d => (d.value = data.get(d.properties.PLACEFIPS), d))
.sort((a, b) => b.value - a.value)) // The sort function orders the circles by size and then the larger circles are displayed in the back so that the small circles, if they overlap with the larger circles can be seen.
.join("circle")
.attr("transform", d => `translate(${path_points.centroid(d)})`) //This finds the centroid of the circle and shows the circle right in the center of point.
.attr("r", d => radius(data.get(d.properties.PLACEFIPS))) // Once the value of the average family size has been returned, it will assign the point as radius size depending upon the value and the size of canvas. It assigns it an attribute "r" which is the radius of the circle
.append("title")
.text(d => `${d.properties.NAME} : ${format(d.value)}`); // When the reader hovers over the point (city,state), the ID of the point and the value of the average family size of that point is displayed.


return svg.node();
}
Insert cell
height = 610
Insert cell
Insert cell
width = 975
Insert cell
Insert cell
path_points = d3.geoPath().projection(projection)
Insert cell
Insert cell
path_basemap = d3.geoPath().projection(projection)
Insert cell
Insert cell
projection = d3.geoAlbers()
Insert cell
Insert cell
format = d3.format(",.2s")
Insert cell
Insert cell
d3.max([...data.values()])
Insert cell
Insert cell
radius(5.7)
Insert cell
Insert cell
radius(1623410)
Insert cell
Insert cell
//proportional symbols
radius = d3.scaleSqrt([0, d3.max([...data.values()])], [0, 25])
Insert cell
Insert cell
data.get(1623410)
Insert cell
Insert cell
data = Object.assign(new Map(csv_data))
Insert cell
Insert cell
csv_data = d3.csvParse(await FileAttachment("USA_Major_Cities.csv").text(), ({PLACEFIPS, AVE_FAM_SZ, NAME}) => [PLACEFIPS, +AVE_FAM_SZ])
Insert cell
Insert cell
//import the point data (geojson)
points = FileAttachment("USA_Major_Cities@1.geojson").json()
Insert cell
Insert cell
basepolygons_states = FileAttachment("States.json").json()
Insert cell
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