Public
Edited
May 13
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, -40, width, height]);

// Using the color scheme
const selectedColors = colors; // This comes from the viewof colors form

// Creating bivariate color function
const color = d => {
if (!data.has(d.properties[idAttribute])) return "#636363"; // Default color
const [floodDepth, popDensity] = data.get(d.properties[idAttribute]);
const xIdx = x(popDensity); // Population density quantile (0-2)
const yIdx = y(floodDepth); // Flood depth quantile (0-2)
// Gets the color from the 3x3 matrix
const colorIdx = xIdx + yIdx * 3;
return selectedColors[Math.min(colorIdx, selectedColors.length - 1)] || "#636363";
};

// Add legend (positioned at bottom right)
svg.append(legend)
.attr("transform", `translate(100,500)`);

// Add title
svg.append("text")
.attr("x", width / 2)
.attr("y", -20)
.attr("text-anchor", "middle")
.attr("font-size", "20px")
.attr("font-weight", "bold")
.text("Flood Prone Areas vs Population Density");

// Add subtitle
svg.append("text")
.attr("x", width / 2)
.attr("y", 0)
.attr("text-anchor", "middle")
.attr("font-size", 16)
.attr("font-style", "italic")
.text("Johnson County, Iowa");

// Add data source
svg.append("text")
.attr("x", width / 2)
.attr("y", 0)
.attr("text-anchor", "middle")
.attr("font-size", 12)
.attr("font-style", "italic")
.text("Data: Census 2019-2023 and Iowa Geospatial Data Clearinghouse")
.attr("transform", "translate(-250,650)");

// Add map features
svg.append("g")
.selectAll("path")
.data(topojson.feature(polygons, polygons.objects.johnson_county_fld_dpth).features)
.join("path")
.attr("fill", d => color(d))
.attr("stroke", "black")
.attr("stroke-width", 1)
.attr("stroke-opacity", 0.8)
.attr("d", path)
.append("title")
.text(d => {
const values = data.get(d.properties[idAttribute]) || [0, 0];
return `Block Group: ${d.properties[idAttribute]}
Flood Depth: ${values[0].toFixed(2)} ft
Population Density: ${values[1].toFixed(2)}/sq mi`;
});

return svg.node();
}
Insert cell
// chart = {
// const svg = d3.create("svg")
// .attr("viewBox", [0, -40, width, height]);

// svg.append(legend)
// .attr("transform", "translate(100,500)");

// svg.append("text")
// .attr("x", width / 2) // Centers the title horizontally
// .attr("y", -20) // Adjusts the vertical position
// .attr("text-anchor", "middle") // Aligns the text to the center
// .attr("font-size", "20px") // Sets the font size
// .attr("font-weight", "bold") // Makes the title bold
// .text("Flood Prone Areas vs Population Density"); // The title text

// //this line of codes to add a subtitle
// svg.append("text")
// .attr("x", width / 2)
// .attr("y", 0)
// .attr("text-anchor", "middle")
// .attr("font-size", 16)
// .attr("font-style", "italic")
// .text("Johnson County, Iowa");

// //this line of codes to add another line at the bottom
// svg.append("text")
// .attr("x", width / 2)
// .attr("y", 0)
// .attr("text-anchor", "middle")
// .attr("font-size", 12)
// .attr("font-style", "italic")
// .text("Data: Census 2019 - 2023 and Iowa Geospatial Data Clearinghous")
// .attr("transform", "translate(-250,650)");;

// svg.append("g")
// .selectAll("path")
// .data(topojson.feature(polygons, polygons.objects.johnson_county_fld_dpth).features)
// .join("path")
// .attr("fill", d => color(data.get(d.properties[idAttribute])))
// .attr("stroke", "black") // Set boundary outline color
// .attr("stroke-width", 1) // Adjust thickness of the boundary lines
// .attr("stroke-opacity", 0.8) // Optional: Control transparency of outline
// .attr("d", path)
// .append("title")
// .text(d => `Block Groups ${d.properties[idAttribute]} | ${format(data.get(d.properties[idAttribute]))}`);

// return svg.node();
// }
Insert cell
//color_scheme = [d3.color("#feedde"), d3.color("#fdbe85"), d3.color("#fd8d3c"), d3.color("#e6550d"),d3.color("#a63603")]
Insert cell
//http://www.joshuastevens.net/cartography/make-a-bivariate-choropleth-map/
schemes = [
{
name: "RdBu",
colors: [
"#e8e8e8", "#e4acac", "#c85a5a",
"#b0d5df", "#ad9ea5", "#985356",
"#64acbe", "#627f8c", "#574249"
]
},
{
name: "BuPu",
colors: [
"#e8e8e8", "#ace4e4", "#5ac8c8",
"#dfb0d6", "#a5add3", "#5698b9",
"#be64ac", "#8c62aa", "#3b4994"
]
},
{
name: "GnBu",
colors: [
"#e8e8e8", "#b5c0da", "#6c83b5",
"#b8d6be", "#90b2b3", "#567994",
"#73ae80", "#5a9178", "#2a5a5b"
]
},
]
Insert cell
labels = ["low", "Moderate", "high"]
Insert cell
n = Math.floor(Math.sqrt(colors.length))
Insert cell
Insert cell
// Define break points based on standard deviation intervals
// breakpoints = [
// meanx - stdDevx, // 1 standard deviation below
// meanx, // Mean value
// meanx + stdDevx, // 1 standard deviation above
// meanx + 2 * stdDevx, // 2 standard deviations above
// ];
Insert cell
//stdDevx = d3.deviation(Array.from(data.values(), d => d[0]));
Insert cell
//meanx = d3.mean(Array.from(data.values(), d => d[0]));
Insert cell
//breakpointsx = x.quantiles();
Insert cell
x = d3.scaleQuantile(Array.from(data.values(), d => d[1]), d3.range(n))
//x = d3.scaleThreshold().domain(breakpoints).range(d3.range(n));
// x = d3.scaleThreshold()
// .domain([10000, 20000, 40578])
// .range(d3.range(4))

// x = d3.scaleQuantile()
// .domain(attribute)
// .range(d3.range(5)); // Number of classes (4)
Insert cell
Insert cell
// //breakpointsy = [
// meany - stdDevy, // 1 standard deviation below
// meany, // Mean value
// meany + stdDevy, // 1 standard deviation above
// meany + 2 * stdDevy // 2 standard deviations above
// ];
Insert cell
//stdDevy = d3.deviation(Array.from(data.values(), d => d[0]));
Insert cell
//meany = d3.mean(Array.from(data.values(), d => d[0]));
Insert cell
//breakpointsy = y.quantiles();
Insert cell
y = d3.scaleQuantile(Array.from(data.values(), d => d[0]), d3.range(n))
//y = d3.scaleThreshold().domain(breakpointsy).range(d3.range(n));
Insert cell
Insert cell
path = d3.geoPath().projection(projection)
Insert cell
Insert cell
//Rotate the map sets the longitude of origin for our UTM projection.
// For Iowa, the rotation no is (94,0)
projection = d3.geoTransverseMercator().rotate([94,0]).fitExtent([[10, 10], [width, height]], polygon_features);
Insert cell
Insert cell
polygon_features = topojson.feature(polygons, polygons.objects.johnson_county_fld_dpth)
Insert cell
Insert cell
data = Object.assign(new Map(d3.csvParse(await FileAttachment("population3.csv").text(), ({GISJOIN, fld_dpth, area_sq_ml, Year, Total_Population}) => [GISJOIN, [+fld_dpth, +Total_Population/+area_sq_ml]])), {title: ["Avg Flood Depth", "Population Density"]})
Insert cell
idAttribute = "GISJOIN"
Insert cell
Insert cell
polygons = FileAttachment("johnson_county_fld_dpth@1.json").json()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
topojson = require("topojson-client@3")
Insert cell
d3 = require("d3@5")
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