Published
Edited
Sep 21, 2021
Insert cell
# Language Scatter Plot
Insert cell
d3 = require("d3@7")
Insert cell
//B01001_001E is Total Population
//B16001_105E is French speaking population
//B16001_003E is Spanish speaking populations

languageData = await d3.json(
"https://api.census.gov/data/2019/acs/acs1?get=NAME,B01001_001E,B16001_006E,B16001_003E&for=state:*"
)
Insert cell
languageStates = {
const data = [];

for (let i = 1; i < languageData.length; i++) {
const state = languageData[i];
data.push({
name: state[0],
totalPopulation: parseInt(state[1]),
french: state[3] == null ? 0 : parseInt(state[2]),
frenchPercent: state[3] == null ? 0 : parseInt(state[2]) / state[1],
spanish: state[3] == null ? 0 : parseInt(state[3]),
spanishPercent: state[3] == null ? 0 : parseInt(state[3]) / state[1],
fipsCode: state[4]
});
}
return data;
}
Insert cell
alphabeticalLanguage = languageStates.sort((a, b) => d3.ascending(a.name, b.name))
Insert cell
{
//svg variables
const width = 900;
const height = 900;
const margin = 100;

//create SVG artboard
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

//background color
const background = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#292C36");

const exampleData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

//create scale to convert data to pixels
const exampleScaleY = d3.scaleLinear().domain([1, 11]).range([100, 800]);
const exampleScaleX = d3.scaleLinear().domain([1, 11]).range([100, 800]);

for (let i = 1; i <= exampleData.length; i = i + 1) {
//draw horizontal line
svg
.append("line")
.attr("x1", margin)
.attr("y1", exampleScaleY(i))
.attr("x2", width-margin)
.attr("y2", exampleScaleY(i))
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "1");

//draw virtical line
svg
.append("line")
.attr("x1", exampleScaleX(i))
.attr("y1", margin)
.attr("x2", exampleScaleX(i))
.attr("y2", height-margin)
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "1");
}

//scales to transform data to relevant visualization values
const frenchRange = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.french))
.range([margin, width-margin]);

const spanishRange = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.spanish))
.range([height-margin, margin ]);

const colorParameter = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.french))
.range([0, 1]);

for (let i = 0; i < alphabeticalLanguage.length; i++) {
//draw circle for each item
svg
.append("circle")
.attr("cx", frenchRange(alphabeticalLanguage[i].french))
.attr("cy", spanishRange(alphabeticalLanguage[i].spanish))
.attr("r", 5)
.attr(
"fill",
d3.interpolateViridis(
colorParameter(alphabeticalLanguage[i].french)
)
)
.attr("opacity", 1);

//add text for each item
svg
.append("text")
.attr("x", frenchRange(alphabeticalLanguage[i].french) + 25)
.attr("y", spanishRange(alphabeticalLanguage[i].spanish) + 4)
.attr("font-size", 8)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "center")
//substring cuts certain characters from a string
.attr("fill", "white")
.text(alphabeticalLanguage[i].name.substring(0, 8));

svg
.append("text")
.attr("x", width - margin)
.attr("y", height - margin / 2)
.text("+ Spanish Percentage")
.attr("text-anchor", "end")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 14);

svg
.append("text")
.attr("x", margin / 2)
.attr("y", margin)
.text("+ French Percentage")
.attr("text-anchor", "end")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 14)
.attr("transform", "rotate(-90 " + margin / 2 + "," + margin + ")");

svg
.append("text")
.attr("x", width / 2)
.attr("y", margin / 2)
.text("Population that Speaks Spanish Compared to French")
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 16);
}
// show visualization in Observable
return svg.node();
}
Insert cell
{
//svg variables
const width = 900;
const height = 900;
const margin = 100;

//create SVG artboard
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);

//background color
const background = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#292C36");

const exampleData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

//create scale to convert data to pixels
const exampleScaleY = d3.scaleLinear().domain([1, 11]).range([100, 800]);
const exampleScaleX = d3.scaleLinear().domain([1, 11]).range([100, 800]);

for (let i = 1; i <= exampleData.length; i = i + 1) {
//draw horizontal line
svg
.append("line")
.attr("x1", margin)
.attr("y1", exampleScaleY(i))
.attr("x2", width-margin)
.attr("y2", exampleScaleY(i))
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "1");

svg
.append("line")
.attr("x1", exampleScaleX(i))
.attr("y1", margin)
.attr("x2", exampleScaleX(i))
.attr("y2", height-margin)
.attr("fill", "none")
.attr("stroke", "grey")
.attr("stroke-width", "1");
}

//scales to transform data to relevant visualization values
// const indexToX = d3
// .scaleLinear()
// .domain([0, alphabeticalLanguage.length])
// .range([margin, width - margin]);

const frenchRangeX = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.frenchPercent))
.range([margin, width-margin]);

const spanishRangeY = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.spanishPercent))
.range([height-margin, margin]);

const colorParameter = d3
.scaleLinear()
.domain(d3.extent(alphabeticalLanguage, (d) => d.french))
.range([0, 1]);
for (let i = 0; i < alphabeticalLanguage.length; i++) {
//draw rect for each item
svg
.append("circle")
.attr("cx", frenchRangeX(alphabeticalLanguage[i].frenchPercent))
.attr("cy", spanishRangeY(alphabeticalLanguage[i].spanishPercent))
.attr("r", 5)
.attr(
"fill",
d3.interpolateViridis(
colorParameter(alphabeticalLanguage[i].french)
)
)
.attr("opacity", 1);

svg
.append("text")
.attr("x", frenchRangeX(alphabeticalLanguage[i].frenchPercent) + 25)
.attr("y", spanishRangeY(alphabeticalLanguage[i].spanishPercent) + 4)
.attr("font-size", 8)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "center")
//substring cuts certain characters from a string
.attr("fill", "white")
.text(alphabeticalLanguage[i].name.substring(0, 8));

svg
.append("text")
.attr("x", width - margin)
.attr("y", height - margin / 2)
.text("+ Spanish Percentage")
.attr("text-anchor", "end")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 14);

svg
.append("text")
.attr("x", margin / 2)
.attr("y", margin)
.text("+ French Percentage")
.attr("text-anchor", "end")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 14)
.attr("transform", "rotate(-90 " + margin / 2 + "," + margin + ")");

svg
.append("text")
.attr("x", width / 2)
.attr("y", margin / 2)
.text("Percentage of Population that Speaks Spanish Compared to French")
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("font-family", "roboto")
.attr("font-size", 16);
}
// show visualization in Observable
return svg.node();
}
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