Published
Edited
Sep 23, 2021
Insert cell
# Data Visualization_Week 04
## **Scatter Plot Challenge**
Insert cell
languageData = await d3.json(
"https://api.census.gov/data/2019/acs/acs1?get=NAME,B01001_001E,B16001_003E,B16001_006E&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]) / parseInt(state[1]),
spanish: state[3] == null ? 0 : parseInt(state[3]),
spanishPercent: state[3] == null ? 0 : parseInt(state[3]) / parseInt(state[1]),
fipsCode: state[4]
});
}
return data;
}
Insert cell
alphabeticalStates = languageStates.sort((a,b) => d3.ascending(a.name,b.name))
Insert cell
Insert cell
{

const width = 900;
const height = 900;
const margin = 100;

const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height);

const background = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#0E1721");

//grid
const gridX = d3
.scaleLinear()
.domain([0,10])
.range([margin, width-margin]);

const gridY = d3
.scaleLinear()
.domain([0,10])
.range([margin, height-margin]);

for (let i=0 ; i<11 ; i++) {
svg
.append("line")
.attr("x1", margin)
.attr("y1", gridY(i))
.attr("x2", width - margin)
.attr("y2", gridY(i))
.attr("fill", "none")
.attr("stroke", "#ffffff")
.attr("stroke-width", 0.5)
.attr("oppacity" , 0.5);

svg
.append("line")
.attr("x1", gridX(i))
.attr("y1", margin)
.attr("x2", gridX(i))
.attr("y2", height-margin)
.attr("fill", "none")
.attr("stroke", "#ffffff")
.attr("stroke-width", 0.5)
.attr("oppacity" , 0.5);
}
const frenchPerToX = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates, (d) => d.frenchPercent))
.range([margin, width-margin]);
const spanishPerToY = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates, (d) => d.spanishPercent))
.range([height-margin , margin]);
const colorParameter = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates, (d) => d.totalPopulation))
.range([0,1]);
for (let i = 0 ; i < alphabeticalStates.length ; i++) {
svg
.append("circle")
.attr("cx", frenchPerToX(alphabeticalStates[i].frenchPercent))
.attr("cy", spanishPerToY(alphabeticalStates[i].spanishPercent))
.attr("r", 3)
.attr(
"fill",
// "white"
d3.interpolateViridis(
colorParameter(alphabeticalStates[i].totalPopulation)
)
)
.attr("stroke" , "white")
.attr("stroke-width" , .5);
svg
.append("text")
.attr("x",frenchPerToX(alphabeticalStates[i].frenchPercent)+10)
.attr("y",spanishPerToY(alphabeticalStates[i].spanishPercent)+4)
.attr("font-size", 10)
.attr("fill" , "white")
.attr("text-anchor", "start")
.attr("alignment-baseline", "center")
.attr("font-family", "courier")
.text(alphabeticalStates[i].name);

svg
.append("text")
.attr("x", width/2)
.attr("y", margin/2)
.attr("font-size", 18)
.attr("fill" , "white")
.attr("text-anchor", "middle")
.attr("alignment-baseline", "center")
.attr("font-family", "courier")
.text("+ Percentage of Population that speak French compared to Spanish");
svg
.append("text")
.attr("x", margin/2)
.attr("y", margin)
.attr("font-size", 14)
.attr("fill" , "white")
.attr("text-anchor", "end")
.attr("alignment-baseline", "center")
.attr("font-family", "courier")
.text("+ French Percentage")
.attr("transform" , "rotate(-90 "+margin/2+","+margin+")")

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

}
return svg.node();
}
Insert cell
## **Tutorial Practice**
Insert cell
d3 = require("d3@7")
Insert cell
censusData = await d3.json(
"https://api.census.gov/data/2019/acs/acs1?get=NAME,B01001_001E&for=state:*"
)
Insert cell
states = {
const statesData = [];

for (let i = 1; i < censusData.length; i++) {
const state = censusData[i];
statesData.push({
name: state[0],
population: parseInt(state[1]),
fipsCode: state[2]
});
}
return statesData;
}
Insert cell
### **Q: How can I reorganize the order of states according to the fipsCode?**
Insert cell
circlePlot = {

const height = 200;
const margin = 20;

const svg = d3.create("svg").attr("width", width).attr ("height", height);

for (let i=0; i<states.length; i++) {
svg
.append ("circle")
.attr ("cx", i* (width/states.length) + margin)
.attr ("cy", height / 2)
.attr ("r", states[i].population / 1000000)
.attr ("fill", "blue")
.attr ("opacity", 0.5);

svg
.append ("text")
.attr ("x", i* (width/states.length) + margin)
.attr ("y", 50)
.attr ("font-size", 8)
.attr ("text-anchol", "middle")
.text (states[i].name);
}
return svg.node();
}
Insert cell
rectPlot = {
const height = 500;
const margin = 20;

const svg = d3.create("svg").attr ("width", width).attr ("height", height);

for (let i = 0; i < states.length ; i++) {
const rowHeight = (height - margin * 2) / states.length;
svg
.append ("rect")
.attr ("x", 150)
.attr ("y", i * rowHeight + margin)
.attr ("width", states[i].population / 50000)
.attr ("height", height / states.length)
.attr ("fill", "blue");

svg
.append ("text")
.attr ("x", 0)
.attr ("y", i * rowHeight + margin + rowHeight)
.attr ("font-size", 8)
.text (states[i].name);
}
return svg.node();
}
Insert cell
alphabeticalStates2 = states.sort ((a,b) => d3.ascending(a.name, b.name))
Insert cell
{
const width = 800;
const height = 100;
const svg = d3
.create("svg")
.attr("viewbox", [0,0,width,height])
.attr("width", width)
.attr("height", height);
const exampleData = [9, 2, 7.1, 5, 0, 1, 6, 3.15, -3, 13];
const exampleScale = d3
.scaleLinear()
.domain([0,10])
.range([200,600]);

svg
.append("line")
.attr("x1", 200)
.attr("y1", height/2)
.attr("x2", 600)
.attr("y2", height/2)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", "2");
for (let i=0; i<exampleData.length; i++) {
const xPosition = exampleScale(exampleData[i]);
svg
.append ("circle")
.attr ("cx", xPosition)
.attr ("cy", height / 2)
.attr ("r", 5)
.attr ("fill", "orange")
.attr ("stroke", "black")
.attr ("stroke-width", 2);

svg
.append ("text")
.attr ("x", xPosition)
.attr ("y", height/2 -20)
.attr ("font-family", "courier")
.attr ("font-size", 10)
.attr ("text-anchol", "middle")
.text (exampleData[i] + "→" + exampleScale(exampleData[i]));
}
return svg.node();
}

Insert cell
{
const width = 800;
const height = 100;
const svg = d3
.create("svg")
.attr("viewbox", [0,0,width,height])
.attr("width", width)
.attr("height", height)

const exampleData = [1, 10, 100, 1000, 10000, 100000];

const exampleScale = d3.scaleLog().domain([1,10000]).range([200,600]);

svg
.append("line")
.attr("x1", 200)
.attr("y1", height/2)
.attr("x2", 600)
.attr("y2", height/2)
.attr("stroke", "black")
.attr("stroke-width", "2");

for (let i=0; i<exampleData.length; i++) {
const xPosition = exampleScale(exampleData[i]);

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height/2)
.attr("r",5)
.attr("fill", "orange")
.attr("stroke", "black")
.attr("stroke-width", 2);

svg
.append("text")
.attr("x", xPosition)
.attr("y", height/2-20)
.attr("font-family", "courier")
.attr("font-size", 10)
.text(exampleData[i] + "→" + Math.round(exampleScale(exampleData[i])));
}
return svg.node();
}
Insert cell
{
const width = 800;
const height = 100;
const svg = d3
.create("svg")
.attr("viewbox", [0,0,width,height])
.attr("width", width)
.attr("height", height)

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

const exampleScale = d3.scaleLinear().domain([0,10]).range([600,200]);

svg
.append("line")
.attr("x1", 200)
.attr("y1", height/2)
.attr("x2", 600)
.attr("y2", height/2)
.attr("stroke", "black")
.attr("stroke-width", "2");

for (let i=0; i<exampleData.length; i++) {
const xPosition = exampleScale(exampleData[i]);

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height/2)
.attr("r",5)
.attr("fill", "orange")
.attr("stroke", "black")
.attr("stroke-width", 2);

svg
.append("text")
.attr("x", xPosition)
.attr("y", height/2-20)
.attr("font-family", "courier")
.attr("font-size", 10)
.text(exampleData[i] + "→" + Math.round(exampleScale(exampleData[i])));
}
return svg.node();
}
Insert cell
{
const exampleData = [];
for (let i = 0 ; i < 10 ; i = i + 1) {
exampleData.push(Math.random() * 50);
}

const min = d3.min(exampleData);
const max = d3.max(exampleData);
const mean = d3.mean(exampleData);
const extent = d3.extent(exampleData);
return {
Minimum: min,
Maximum: max,
Average: mean,
Extent: extent,
Data: exampleData
};
}
Insert cell
{
const width = 800;
const height = 100;

const svg = d3
.create("svg")
.attr("viewbox",[0,0,width,height])
.attr("width", width)
.attr("height", height);

const exampleData = [];

for (let i=0 ; i<10 ; i=i+1){
exampleData.push(Math.random() *50);
}

const exampleExtent = d3.extent(exampleData);

const exampleScale = d3.scaleLinear().domain(exampleExtent).range([200,600]);

svg
.append("line")
.attr("x1", 200)
.attr("y1", height/2)
.attr("x2", 600)
.attr("y2", height/2)
.attr("stroke", "black")
.attr("stroke-width", "2");

for (let i=0; i<exampleData.length; i=i+1) {
const xPosition = exampleScale(exampleData[i]);

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height/2)
.attr("r",5)
.attr("fill", "orange")
.attr("stroke", "black")
.attr("stroke-width", 2);

svg
.append("text")
.attr("x", xPosition)
.attr("y", height/2-20)
.attr("font-family", "courier")
.attr("font-size", 10)
.text(exampleData[i].toFixed(1) + "→" + Math.round(exampleScale(exampleData[i].toFixed(1))));
}
return svg.node();

}
Insert cell
{
const parameterScale = d3.scaleLinear().domain([0,10]).range([0,1]);

return d3.interpolateViridis(parameterScale(5));
}
Insert cell
{
const width = 800;
const height = 100;

const svg = d3
.create("svg")
.attr("viewbox", [0,0,width,height])
.attr("width", width)
.attr("height", height);

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

const pixelScale = d3.scaleLinear().domain([0,10]).range([200,600]);

const parameterScale = d3.scaleLinear().domain([1,10]).range([0,1]);

const scaleNames = ["viridis","magma","cividis"];

for (let i=0.25 ; i<=0.75 ; i=i+0.25) {
svg
.append("line")
.attr("x1", 200)
.attr("y1", height * i)
.attr("x2", 600)
.attr("y2", height * i)
.attr("stroke" , "black")
.attr("stroke-width", "2");

svg
.append("text")
.attr("x", 190)
.attr("y", i * height)
.attr("font-family", "courier")
.attr("font-size" , 10)
.attr("text-anchor", "end")
.attr("alignment-baseline", "middle")
.text(scaleNames[i*4-1]);
}

for (let i=0 ; i<exampleData.length ; i=i+1) {
const xPosition = pixelScale(exampleData[i]);

const parameterData = parameterScale(exampleData[i]);

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height * 0.25)
.attr("r", 10)
.attr("fill", d3.interpolateViridis(parameterData))
.attr("stroke", "black")
.attr("stroke-width", "2");

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height * 0.5)
.attr("r", 10)
.attr("fill", d3.interpolateMagma(parameterData))
.attr("stroke", "black")
.attr("stroke-width", "2");

svg
.append("circle")
.attr("cx", xPosition)
.attr("cy", height * 0.75)
.attr("r", 10)
.attr("fill", d3.interpolateCividis(parameterData))
.attr("stroke", "black")
.attr("stroke-width", "2");

}
return svg.node();
}
Insert cell
viewof moonPhase = Inputs.range([0.0,1.0],{label: "Moon Phase", value: 0.5})
Insert cell
{
if(moonPhase >= 0.93) {
return "🌕";
} else if (moonPhase >= 0.79) {
return "🌖";
} else if (moonPhase >= 0.65){
return "🌗";
} else if (moonPhase >= 0.51){
return "🌘";
} else if (moonPhase >= 0.37){
return "🌑";
} else if (moonPhase >= 0.23){
return "🌒";
} else if (moonPhase >= 0.09){
return "🌓";
} else {
return "🌕";
}
}
Insert cell
viewof booleanSlider = Inputs.range([0.0,1.0],{
label: "Larger than .5?",
value: 0.5})
Insert cell
booleanSlider > 0.5
Insert cell
viewof distance = Inputs.range([0.0,1.0],{
label:"Distance to Travel",
value:0.5})
Insert cell
viewof time = Inputs.range([0.0,1.0],{
label: "Time Available",
value: 0.5
})
Insert cell
{
if (distance > 0.75 && time < 0.25) {
return "Recommended Transit Method: 🚀"
} else if (distance > 0.5 && time < 0.5) {
return "Recommended Transit Method: 🏎"
} else if (distance > 0.25 && time < 0.75) {
return "Reccomended Transit Method: 🚲"
} else if (distance >= 0 && time <= 1) {
return "Recommended Transit Method: 🛼"
}
}
Insert cell
viewof graphAge = Inputs.range([0.0,100], {
label: "How old are you?",
value: 18,
step: 1
});
Insert cell
{
return graphAge < 21 ? "🍇->🧃" : "🍇->🍷"
}
Insert cell
viewof modulo = Inputs.range([1,9],{
label: "9%",
step: 1
})
Insert cell
9 % modulo
Insert cell
viewof isItEvenOrOdd = Inputs.range([1,9],{
label: "Is it even or odd?",
step: 1,
value: 3
})
Insert cell
isItEvenOrOdd % 2 == 0 ? "even" : "odd"
Insert cell
betterCirclePlot = {
const height = 400;
const margin = 20;

const svg = d3.create("svg").attr("width", width).attr("height", height);

const background = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#eeeeff");

const indexToX = d3
.scaleLinear()
.domain([0,alphabeticalStates2.length])
.range([margin, width-margin]);

const populationToRadius = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates2, (d) => d.population))
.range([2, (width - margin * 2) / alphabeticalStates2.length]);

const populationToParameter = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates2, (d)=>d.population))
.range([0,1]);

for (let i=0; i<alphabeticalStates2.length; i++) {
svg
.append("circle")
.attr("cx", indexToX(i))
.attr("cy", height/2)
.attr("r", populationToRadius(alphabeticalStates2[i].population))
.attr("fill", d3.interpolateViridis(populationToParameter(alphabeticalStates2[i].population)))
.attr("opacity", 1);

const labelY = i % 2 == 0 ? height/2 -30 : height/2 +30;

svg
.append("text")
.attr("x",indexToX(i))
.attr("y",labelY +4)
.attr("font-size", 8)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "center")
.attr("font-family", "courier")
.text(states[i].name.substring(0,8));
}
return svg.node();
}
Insert cell
### (d)=>d ??
Insert cell
betterRectPlot = {

const height = 500;
const margin = 20;

const svg = d3.create("svg").attr("width", width).attr("height", height);

const background = svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#eeeeff");

const indexToY = d3
.scaleLinear()
.domain([0,alphabeticalStates2.length])
.range([margin, height-margin]);

const populationToWidth = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates2, (d)=> d.population))
.range([margin, width-margin]);

const populationToParametor = d3
.scaleLinear()
.domain(d3.extent(alphabeticalStates2, (d)=>d.population))
.range([0,1]);

for (let i=0 ; i<alphabeticalStates2.length ; i++) {
const rowHeight = (height-margin *2) / states.length;

svg
.append("rect")
.attr("x",150)
.attr("y", indexToY(i))
.attr("width", populationToWidth(alphabeticalStates2[i].population))
.attr("height", height / alphabeticalStates2.length)
.attr("fill", d3.interpolateMagma(populationToParametor(alphabeticalStates2[i].population)));
svg
.append("text")
.attr("x", margin)
.attr("y",indexToY(i) + height / alphabeticalStates2.length)
.attr("font-size", 8)
.attr("font-family", "helvetica")
.text(states[i].name);
}
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