Public
Edited
Mar 20, 2023
Insert cell
Insert cell
Insert cell
averageSalaryMap(us)
Insert cell
d3.min(avgTeacherSalary2010)
Insert cell
d3.max(avgTeacherSalary2010)
Insert cell
averageSalaryMap = (us) => {
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, 2400, height]);

const averageTeacherSalaryFileType = "Average Teacher Salary By State in ";

const str = averageTeacherSalaryFileType + averageSalaryYearFilter;

// Info Window Text

const infoWindowText = svg.append("text")
.attr("x", 15)
.attr("y", 15)
.attr("transform", "translate(1010,120)")
.attr("font-size", 20)

let rank;
let topFiveStates;
let bottomFiveStates;

if (str === averageTeacherSalaryFileType + "2010") {
const salary = avgTeacherSalary2010.get(name);
rank = avgTeacherSalaryRank2010.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2010.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2010.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2011") {
const salary = avgTeacherSalary2011.get(name);
rank = avgTeacherSalaryRank2011.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2011.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2011.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2012") {
const salary = avgTeacherSalary2012.get(name);
rank = avgTeacherSalaryRank2012.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2012.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2012.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2013") {
const salary = avgTeacherSalary2013.get(name);
rank = avgTeacherSalaryRank2013.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2013.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2013.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2014") {
const salary = avgTeacherSalary2014.get(name);
rank = avgTeacherSalaryRank2014.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2014.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2014.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2015") {
const salary = avgTeacherSalary2015.get(name);
rank = avgTeacherSalaryRank2015.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2015.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2015.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2016") {
const salary = avgTeacherSalary2016.get(name);
rank = avgTeacherSalaryRank2016.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2016.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2016.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2017") {
const salary = avgTeacherSalary2017.get(name);
rank = avgTeacherSalaryRank2017.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2017.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2017.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
} else if (str === averageTeacherSalaryFileType + "2018") {
const salary = avgTeacherSalary2018.get(name);
rank = avgTeacherSalaryRank2018.get(name);
bottomFiveStates = Array.from(avgTeacherSalaryRank2018.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
.map(([state, rank]) => state);
topFiveStates = Array.from(avgTeacherSalaryRank2018.entries())
.filter(([key, value]) => value > 0)
.sort((a, b) => a[1] - b[1])
.slice(0, 5)
.map(([key, value]) => key);
}
infoWindowText.text(name)
.append("tspan")
.attr("x", 0)
.attr("y", 0)
.attr("dy", "1.2em")
.text("Top 5 Ranked States");

topFiveStates.forEach((state, index) => {
infoWindowText.append("tspan")
.attr("x", 0)
.attr("dy", "1.2em")
.text(`${index + 1}. ${state}`);
});
infoWindowText.append("tspan")
.attr("x", 0)
.attr("y", 170)
.attr("dy", "1.5em")
.text("Bottom 5 Ranked States");
bottomFiveStates.forEach((state, index) => {
infoWindowText.append("tspan")
.attr("x", 0)
.attr("dy", "1.2em")
.text(`${index + 46}. ${state}`);
});

infoWindowText.append("tspan")
.attr("x", 0)
.attr("y", 340)
.attr("dy", "1.5em")
.text("States That Had Teacher Protests:");

// Chloropleth Map Colors
let color;
const salaryLegend = [40000, 50000, 60000, 70000];
color = d3.scaleThreshold()
.domain(salaryLegend)
.range(d3.schemeBlues[4]);

// Add Color Schema Legend
svg.append("g")
.attr("transform", "translate(1000,30)")
.append(function(d) {
if (str== averageTeacherSalaryFileType + "2010"){
// return legend({color, title: avgTeacherSalary2010.title + ` in dollars($)`, width: 600});
return legend({color, title: avgTeacherSalary2010.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2011"){
return legend({color, title: avgTeacherSalary2011.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2012"){
return legend({color, title: avgTeacherSalary2012.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2013"){
return legend({color, title: avgTeacherSalary2013.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2014"){
return legend({color, title: avgTeacherSalary2014.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2015"){
return legend({color, title: avgTeacherSalary2015.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2016"){
return legend({color, title: avgTeacherSalary2016.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2017"){
return legend({color, title: avgTeacherSalary2017.title + ` in dollars($)`, width: 350});
} else if (str== averageTeacherSalaryFileType + "2018"){
return legend({color, title: avgTeacherSalary2018.title + ` in dollars($)`, width: 350});
}
})

// Map Title
svg.append("text")
.attr("x", width / 4)
.attr("y", 0)
.attr("text-anchor", "start")
.style("font-size", "30px")
.style("font-weight", "bold")
.text(str);

// Baseline Map of Nations
svg.append("path")
.datum(nations)
.attr("fill", "black")
.attr("stroke", "none")
.attr("d", path);

// Baseline Map of States
svg.append("path")
.datum(states)
.attr("fill", "none")
.attr("stroke", "none")
.attr("d", path);

// SVG Show or Hide State Information
svg.append("g")
.selectAll("path")
.data(states.features)
.enter()
.append("path")
.attr("d", path)
.attr("fill", function (d) {
if (str === averageTeacherSalaryFileType + "2010") {
return color(avgTeacherSalary2010.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2011") {
return color(avgTeacherSalary2011.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2012") {
return color(avgTeacherSalary2012.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2013") {
return color(avgTeacherSalary2013.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2014") {
return color(avgTeacherSalary2014.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2015") {
return color(avgTeacherSalary2015.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2016") {
return color(avgTeacherSalary2016.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2017") {
return color(avgTeacherSalary2017.get(d.properties.name));
} else if (str === averageTeacherSalaryFileType + "2018") {
return color(avgTeacherSalary2018.get(d.properties.name));
}
})
.attr("stroke", "white")
.on("mouseover", (event, d) => {
const [x, y] = d3.pointer(event);
const padding = 5;
const lengthOfStateName = d.properties.name.length * 10
const name = d.properties.name;

d3.select(event.currentTarget)
.attr("stroke", "black")
.raise();

// Color Density Based on Average Teacher Salary Per State Per Year
if (str === averageTeacherSalaryFileType + "2010") {
const salary = avgTeacherSalary2010.get(name);
const rank = avgTeacherSalaryRank2010.get(name);

const minSalary = d3.min(avgTeacherSalary2010);
const maxSalary = d3.max(avgTeacherSalary2010);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2010 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2010 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2011") {
const salary = avgTeacherSalary2011.get(name);
const rank = avgTeacherSalaryRank2011.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2011 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2011 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2012") {
const salary = avgTeacherSalary2012.get(name);
const rank = avgTeacherSalaryRank2012.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2012 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2012 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2013") {
const salary = avgTeacherSalary2013.get(name);
const rank = avgTeacherSalaryRank2013.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2013 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2013 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2014") {
const salary = avgTeacherSalary2014.get(name);
const rank = avgTeacherSalaryRank2014.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2014 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2014 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2015") {
const salary = avgTeacherSalary2015.get(name);
const rank = avgTeacherSalaryRank2015.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2015 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2015 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2016") {
const salary = avgTeacherSalary2016.get(name);
const rank = avgTeacherSalaryRank2016.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2016 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2016 Average Teacher Salary Available")
.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2017") {
const salary = avgTeacherSalary2017.get(name);
const rank = avgTeacherSalaryRank2017.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2017 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2017 Average Teacher Salary Available")
.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
} else if (str === averageTeacherSalaryFileType + "2018") {
const salary = avgTeacherSalary2018.get(name);
const rank = avgTeacherSalaryRank2018.get(name);
tooltip.select("text")
.text(null)
.append("tspan")
.text(name)
.attr("font-size", "25px")
.append("tspan")
.attr("dy", "1.2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(salary ? `2018 Average Teacher Salary: $${commaSeparated(salary)}` : "No 2018 Average Teacher Salary Available")

.append("tspan")
.attr("dy", "2em")
.attr("font-size", "20px")
.attr("x", 20)
.attr("y", 25)
.attr("text-anchor", "start")
.text(rank ? `Rank: ${rank}` : "");
}

const textLength = tooltip.select('text').node().getComputedTextLength();

tooltip.select("rect")
.attr("width", textLength)
.attr("height", 80)
tooltip.attr("transform", `translate(${x},${y})`);
tooltip.select("rect")
.attr("width", textLength)
.attr("x")
tooltip.style("display", "block");
})
.on("mouseout", (event, d) => {
tooltip.style("display", "none")

d3.select(event.currentTarget)
.attr("stroke", "white")
.lower();
});

// Right Side Info Window
const infoWindow = svg
.append("rect")
.attr("transform", "translate(1000,100)")
.attr("width", 364)
.attr("height", 500)
.attr("fill", "none")
.attr("stroke", "black")
.raise();

// Tooltip
const rect = svg
.append("rect")
.attr("id", "tooltip-box")
.attr("height", 80)

const stateName = svg.append("text")
.attr("y", 20)
.attr("stroke", "black")
.attr("alignment-baseline", "middle");

const tooltip = svg
.append("g")
.attr("class", "tooltip")
.style("display", "none");

tooltip.append("rect")
.attr("width", 100)
.attr("height", 80)
.attr("fill", "white")
.attr("stroke", "black")
tooltip.append("text")
.attr("y", 25)
.attr("x", 20)
.attr("text-anchor", "start")
.text("");
return svg.node();
}
Insert cell
Insert cell
width = 2000
Insert cell
height = 600
Insert cell
// TopoJSON Map Data for the United States
us = FileAttachment("states-albers-10m.json").json()
Insert cell
Insert cell
avgTeacherSalaryRank2010 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2010.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2010"})
Insert cell
avgTeacherSalaryRank2011 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2011.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2011"})
Insert cell
avgTeacherSalaryRank2012 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2012.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2012"})
Insert cell
avgTeacherSalaryRank2013 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2013.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2013"})
Insert cell
avgTeacherSalaryRank2014 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2014.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2014"})
Insert cell
avgTeacherSalaryRank2015 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2015.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2015"})
Insert cell
avgTeacherSalaryRank2016 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2016.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2016"})
Insert cell
avgTeacherSalaryRank2017 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2017.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2017"})
Insert cell
avgTeacherSalaryRank2018 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2018.csv").text(), ({state, rank}) => [state, +rank])), {title: "Average Teacher Salary Rank By State in 2018"})
Insert cell
Insert cell
avgTeacherSalary2010 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2010.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2010"})
Insert cell
avgTeacherSalary2011 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2011.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2011"})
Insert cell
avgTeacherSalary2012 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2012.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2012"})
Insert cell
avgTeacherSalary2013 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2013.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2013"})
Insert cell
avgTeacherSalary2014 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2014.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2014"})
Insert cell
avgTeacherSalary2015 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2015.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2015"})
Insert cell
avgTeacherSalary2016 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2016.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2016"})
Insert cell
avgTeacherSalary2017 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2017.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2017"})
Insert cell
avgTeacherSalary2018 = Object.assign(new Map(d3.csvParse(await FileAttachment("avgTeacherSalary2018.csv").text(), ({state, avg_teacher_salary}) => [state, +avg_teacher_salary])), {title: "Average Teacher Salary By State in 2018"})
Insert cell
Insert cell
d3 = require('d3@7', 'd3-geo@2', 'd3-dsv', 'd3-selection');
Insert cell
d3_annotation = require("https://cdnjs.cloudflare.com/ajax/libs/d3-annotation/2.3.0/d3-annotation.min.js")
Insert cell
projection = d3.geoAlbersUsa().scale(1300).translate([487.5, 305])
Insert cell
path = d3.geoPath()
Insert cell
states = topojson.feature(us, us.objects.states, (a, b) => a !== b);
Insert cell
nations = topojson.feature(us, us.objects.nation);
Insert cell
topojson = require("topojson-client@3")
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
import {select} from "@jashkenas/inputs"
Insert cell
import {Scrubber} from "@mbostock/scrubber"
Insert cell
commaSeparated = d3.format(",")
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