Public
Edited
May 6, 2022
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
plot = {
reset;
let value = null;
let svg = d3.create("svg");

let data_total = derived_1990_2019;
let year_period_using = year_period;

let click = 0;

let data_mesh = topojson.mesh(us, us.objects.states);
let data_feature = topojson.feature(us, us.objects.states);
let path = path_us;

let map_using = null;
if(in_or_out == "In"){
map_using = experiment_map_2;
}
else{
map_using = experiment_map;
}

svg.attr("width", 1275)
.attr("height", 775)

// --------------------------------------------------Label and Axis-----------------------------------------------------------------

let label_tweak = function(selection, label, fs) {
selection.attr('text-anchor', 'start')
.attr('font-size', fs)
.attr('font-weight', 'bold')
.attr('fill', d3.hcl(0,0,42))
.text(label)
}

let label_tweak1 = function(selection, label, fs) {
selection.attr('text-anchor', 'end')
.attr('font-size', fs)
.attr('font-weight', 'bold')
.attr('fill', d3.hcl(0,0,42))
.text(label)
}
svg.append('text')
.attr('transform', `translate(575, 35)`)
.call(label_tweak1, 'Interactive Migration Patterns Viewer', '30px')

svg.append('text')
.attr('transform', `translate(1075, 175)`)
.call(label_tweak1, 'Migration Ratio Heatmap(y to x)', '25px')

let line_text = svg.append('text')
.attr('transform', `translate(20, 485)`)
.call(label_tweak, 'Total Migration from 1990-2019', '15px')

let red_line_text = svg.append('text')
.attr('transform', `translate(75, 700)`)
let blue_line_text = svg.append('text')
.attr('transform', `translate(75, 725)`)

let bar_text_blue = svg.append('text')
.attr('transform', `translate(650, 685)`)
.call(label_tweak, 'Top Barplot: Top 5 Origin State', '15px').attr('fill', 'steelblue')
let bar_text_red = svg.append('text')
.attr('transform', `translate(650, 700)`)
.call(label_tweak, 'Bottom Barplot: Top 5 Destination State', '15px').attr('fill', 'red')
let rect = svg.append('rect')
.attr('x', 875)
.attr('y', 675)
.attr('width', 10)
.attr('height', 10)
.attr('fill', 'green')
let bar_text_green = svg.append('text')
.attr('transform', `translate(890, 685)`)
.call(label_tweak, 'Neighboring States', '12px')
let rect1 = svg.append('rect')
.attr('x', 935)
.attr('y', 690)
.attr('width', 10)
.attr('height', 10)
.attr('fill', 'orange')
let bar_text_yellow = svg.append('text')
.attr('transform', `translate(950, 700)`)
.call(label_tweak, 'Neighboring States', '12px')

// --------------------------------------------------Geographic Map-----------------------------------------------------------------

let g = svg.append('g').attr('transform', `translate(40, 45) scale(0.6, 0.6)`);

let regions = g.selectAll()
.classed('regions',true)
.data(data_feature.features)
.enter().append("path")
.attr("d", path)
.attr("fill", d => populationColor(populationByState.get(d.properties.name)))
regions.append("title")
.text(d => `${d.properties.name}`);

let selection_color = d3.hcl(30,30,60);
let selection_color_hover = d3.hcl(220,30,60);
var x = "empty";

g.append("path")
.datum(data_mesh, (a, b) => a !== b)
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-linejoin", "round")
.attr("pointer-events", "none")
.attr("d", path);

// --------------------------------------------------heatmap plot-----------------------------------------------------------------
let margin = options.margin,
width = options.width,
height = options.height,
container = options.container,
showLabels = options.show_labels,
startColor = options.start_color,
endColor = options.end_color,
startColor_blue = options.start_color_blue,
endColor_blue = options.end_color_blue,
highlightCellOnHover = options.highlight_cell_on_hover,
highlightCellColor = options.highlight_cell_color;

let dataValues = data['values'];
let dataLabels = data['labels'];

let maxValue = d3.max(dataValues, function(layer) { return d3.max(layer, function(d) { return d; }); });
let minValue = d3.min(dataValues, function(layer) { return d3.min(layer, function(d) { return d; }); });

let numrows = dataValues.length;
let numcols = dataValues[0].length;
let g_heat = svg.append("g")
.attr("transform", "translate(" + (margin.left + 600) + "," + (margin.top + 150) + ")");

let background = g_heat.append("rect")
.style("stroke", "black")
.style("stroke-width", "2px")
.attr("width", width)
.attr("height", height);

let x_1 = d3.scaleBand()
.domain(d3.range(numcols))
.range([0, width]);

let y = d3.scaleBand()
.domain(d3.range(numrows))
.range([0, height]);

let colorMap = d3.scaleLinear()
.domain([0,1])
.range([startColor, endColor]);
let colorMap_blue = d3.scaleLinear()
.domain([0,1])
.range([startColor_blue, endColor_blue]);

let row = g_heat.selectAll(".row")
.data(dataValues)
.enter().append("g")
.attr("class", "row")
.attr("transform", function(d, i) { return "translate(0," + y(i) + ")"; });

let cell = row.selectAll(".cell")
.data(function(d) { return d; })
.enter().append("g")
.attr("class", "cell")
.attr("transform", function(d, i) { return "translate(" + x_1(i) + ", 0)"; });

cell.append('rect')
.attr("width", width/numcols)
.attr("height", height/numrows)
.style("stroke-width", 0);

cell.append("text")
.attr("dy", ".32em")
.attr("x", x_1.range() / 2)
.attr("y", y.range() / 2)
.style("fill", function(d, i) { return d >= maxValue/2 ? 'white' : 'black'; })
.style("font", "1px times")

row.selectAll(".cell")
.data(function(d, i) { return dataValues[i].map(a => a.ratio); })
.style("fill", color_d=>
{ if(isNaN(color_d))
{return 'white'}
else
{return colorMap_blue(color_d)}});

if(highlightCellOnHover){
cell
.on("mouseover", function(d) {
d3.select(this).style("fill", highlightCellColor);
})
.on("mouseout", function() {
d3.select(this).style("fill", color_d=> { if(isNaN(color_d)){return 'white'} else if(color_d>=0){return colorMap_blue(color_d)
}else if(color_d<0){return colorMap(-color_d)}
});
});
}

if (showLabels){
var labels = g_heat.append('g')
.attr('class', "labels");

var columnLabels = labels.selectAll(".column-label")
.data(dataLabels)
.enter().append("g")
.attr("class", "column-label")
.attr("transform", function(d, i) { return "translate(" + x_1(i) + "," + height + ")"; });

columnLabels.append("line")
.style("stroke", "black")
.style("stroke-width", "1px")
.attr("y2", 5);

columnLabels.append("text")
.attr("x", 0)
.attr("dx", "-0.82em")
.attr("y", y.bandwidth() / 2)
.attr("dy", ".41em")
.attr("text-anchor", "end")
.attr("transform", "rotate(-90)")
.text(function(d, i) { return d; })
.style("font-size", "8px");

var rowLabels = labels.selectAll(".row-label")
.data(dataLabels)
.enter().append("g")
.attr("class", "row-label")
.attr("transform", function(d, i) { return "translate(" + 0 + "," + y(i) + ")"; });

rowLabels.append("line")
.style("stroke", "black")
.style("stroke-width", "1px")
.attr("x1", 0)
.attr("x2", -5)

rowLabels.append("text")
.attr("x", -8)
.attr("y", y.bandwidth() / 2)
.attr("dy", ".32em")
.attr("text-anchor", "end")
.text(function(d, i) { return d; })
.style("font-size", "8px");;

}
// --------------------------------------------------temporal plot-----------------------------------------------------------------
let selected_item = null;

let year_range = 250;

let year_scale = d3.scaleBand()
.domain(year_period_using)
.range([0,year_range])

let pop_scale = d3.scaleLinear()
.domain([0, 127000000])
.range([150, 0])

let mig_scale = d3.scaleLinear()
.domain([2000000, 4600000])
.range([150, 0])

let g_temp = svg.append("g");
let pop_axis = null;
let pop_path = null;
let in_path = null;

g_temp.attr("transform", "translate(" + (margin.left - 20) + "," + (margin.top + 450) + ")");
g_temp.append('rect')
.attr('width', year_range)
.attr('height', 150)
.attr('fill', 'none').attr('stroke', d3.hcl(0,0,30)).attr('stroke-width', .7)

g_temp.append('g')
.classed('axis', true)
.attr('transform', `translate(0,150)`)
.call(d3.axisBottom(year_scale)).selectAll('text').attr("transform", "translate(-15, 15) rotate(-65)")

if(testt == "Population"){

pop_axis = g_temp.append('g')
.classed('axis', true)
.call(d3.axisLeft(pop_scale))

pop_path = g_temp.append("path")
.datum(total_pop)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return year_scale(d.year) })
.y(function(d) { return pop_scale(d.pop) }))
}
else{

pop_axis = g_temp.append('g')
.classed('axis', true)
.call(d3.axisLeft(mig_scale))

pop_path = g_temp.append("path")
.datum(total_migrants)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return year_scale(d.year) })
.y(function(d) { return mig_scale(d.pop) }))
in_path = g_temp.append("path");
}
// --------------------------------------------------Ranking Barplots------------------------------------------------------------------

let state_range = 150;

let state_out_scale = d3.scaleBand()
.domain(top_out_name)
.range([0,state_range])

let state_in_scale = d3.scaleBand()
.domain(top_in_name)
.range([0,state_range])

let num_scale = d3.scaleLinear()
.domain([0, 500000])
.range([0, 200])

let g_rank_out = svg.append("g");
let g_rank_in = svg.append("g");
let out_axis = null;
let in_axis = null;
let num_axis = null;

g_rank_out.attr("transform", "translate(" + (margin.left + year_range + 70) + "," + (margin.top + 375) + ")");
g_rank_out.append('rect')
.attr('width', 200)
.attr('height', state_range)
.attr('fill', 'none').attr('stroke', d3.hcl(0,0,30)).attr('stroke-width', .7)

g_rank_in.attr("transform", "translate(" + (margin.left + year_range + 70) + "," + (margin.top + 525) + ")");
g_rank_in.append('rect')
.attr('width', 200)
.attr('height', state_range)
.attr('fill', 'none').attr('stroke', d3.hcl(0,0,30)).attr('stroke-width', .7)

out_axis = g_rank_out.append('g')
.classed('axis', true)
.call(d3.axisLeft(state_out_scale))
in_axis = g_rank_in.append('g')
.classed('axis', true)
.call(d3.axisLeft(state_in_scale))
num_axis = g_rank_in.append('g')
.classed('axis', true)
.attr('transform', `translate(0, ${state_range})`)
.call(d3.axisBottom(num_scale))
num_axis.selectAll('text').attr("transform", "translate(-20, 20) rotate(-65)");

let bar_out = g_rank_out.selectAll(".bars")
.data(top_5_out_total)

bar_out
.enter()
.append("rect")
.attr("class", "bars")
.attr("x", 0)
.attr("y", function(d) { return state_out_scale(d.origin); })
.attr("width", function(d) { return num_scale(d.num_migrants); })
.attr("height", state_out_scale.bandwidth)
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("fill", "steelblue")

let bar_in = g_rank_in.selectAll(".bars")
.data(top_5_in_total)

bar_in
.enter()
.append("rect")
.attr("class", "bars")
.attr("x", 0)
.attr("y", function(d) { return state_in_scale(d.destination); })
.attr("width", function(d) { return num_scale(d.num_migrants); })
.attr("height", state_in_scale.bandwidth)
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("fill", "red")
// --------------------------------------------------click interaction-----------------------------------------------------------------

regions
.on('click', function(e,d) {
selected_item = d;
if(testt == "Population"){
g.selectAll("path")
.data(data_feature.features)
.attr("fill", da => (populationByState.get(da.properties.name) - populationByState.get(d.properties.name)) >= 0 ?
positiveColor(Math.abs(populationByState.get(da.properties.name) - populationByState.get(d.properties.name))) :
negativeColor(Math.abs(populationByState.get(da.properties.name) - populationByState.get(d.properties.name))));

let storing_pop = [];
for(let i = 0; i < data_total.length; i++){
for(let j = 0; j < data_total[0].length; j = j + 50){
if(data_total[i][j].origin == d.properties.name){
storing_pop.push({year: year_period_using[i], pop: data_total[i][j].origin_population});
break;
}
}
}
let area_scale = d3.scaleLinear()
.domain([0, 17000000])
.range([150, 0]);
pop_axis.call(d3.axisLeft(area_scale));
storing_pop.filter(d => d.pop > 0);
pop_path
.datum(storing_pop)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(a) { return year_scale(a.year) })
.y(function(a) { return area_scale(a.pop) }));
}
else{

line_text.call(label_tweak, 'Total Migration from & to ' + d.properties.name + ' from 1990-2019', '12px')
blue_line_text.call(label_tweak, 'Migration from ' + d.properties.name, '15px').attr('fill', 'steelblue')
red_line_text.call(label_tweak, 'Migration to ' + d.properties.name, '15px').attr('fill', 'red')
g.selectAll("path").data(data_feature.features)
.attr("fill", da => experiment(100*map_using.get(d.properties.name).get(da.properties.name)));
row.selectAll(".cell")
.data(function(de, i) {
if(dataValues[i][0].state == d.properties.name){
return dataValues[i].map(a => a.ratio);
}
else{
return dataValues[i].map(function(a) { return a.dest == d.properties.name ? a.ratio : 0;});
}
})
.style("fill", color_d=>
{ if(isNaN(color_d))
{return 'white'}
else
{return colorMap_blue(color_d)}});
let storing_pop = [];
for(let i = 0; i < data_total.length; i++){
let num = data_total[i]
.filter(a => a.origin == d.properties.name)
.map(d => d.num_migrants).filter(d => d > 0)
.reduce((a, b) => a + b, 0);
let num2 = data_total[i]
.filter(a => a.destination == d.properties.name)
.map(d => d.num_migrants).filter(d => d > 0)
.reduce((a, b) => a + b, 0);
storing_pop.push({year: year_period_using[i], out: num, in: num2});
}
let store_pop_in_out = [storing_pop.map(dat => dat.out),storing_pop.map(dat => dat.in)].flat()
let pop_exts = d3.extent(store_pop_in_out)
let area_scale = d3.scaleLinear()
.domain([0, 1.1*pop_exts[1]])
.range([150, 0]);
pop_axis.call(d3.axisLeft(area_scale));
pop_path
.datum(storing_pop)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return year_scale(d.year) })
.y(function(d) { return area_scale(d.out) }));
in_path
.datum(storing_pop)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return year_scale(d.year) })
.y(function(d) { return area_scale(d.in) }));

let temp_out_top = top_5_out.get(d.properties.name);
let temp_out_name = temp_out_top.map(a => a.destination);
let temp_out_num = temp_out_top.map(a => a.num_migrants);
let temp_in_top = top_5_in.get(d.properties.name);
let temp_in_name = temp_in_top.map(a => a.origin);
let temp_in_num = temp_in_top.map(a => a.num_migrants);
state_out_scale = d3.scaleBand()
.domain(temp_out_name)
.range([0,state_range])

state_in_scale = d3.scaleBand()
.domain(temp_in_name)
.range([0,state_range])

let domain_upper_bound = d3.max([d3.extent(temp_out_num)[1], d3.extent(temp_in_num)[1]]);

num_scale = d3.scaleLinear()
.domain([0, 1.1*domain_upper_bound])
.range([0, 200])

out_axis.call(d3.axisLeft(state_out_scale))
in_axis.call(d3.axisLeft(state_in_scale))
num_axis.call(d3.axisBottom(num_scale)).selectAll('text').attr("transform", "translate(-20, 20) rotate(-65)")
.style('fill', 'black')


bar_out = g_rank_out.selectAll('.bars').data(temp_out_top);
bar_out.exit().remove();
bar_out
.enter()
.append("rect")
.attr("class", "bars")
.merge(bar_out)
.attr("x", 0)
.attr("y", function(a) { return state_out_scale(a.destination); })
.attr("width", function(a) { return num_scale(a.num_migrants); })
.attr("height", state_out_scale.bandwidth)
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("fill", function(a){
let temp = neighbor_map.get(d.properties.name);
for(let i =0; i < temp.length; i++){
if(temp[i] == a.destination){
return "green";
}
}
return "steelblue";
})

bar_in = g_rank_in.selectAll('.bars').data(temp_in_top);
bar_in.exit().remove();
bar_in
.enter()
.append("rect")
.attr("class", "bars")
.merge(bar_in)
.attr("x", 0)
.attr("y", function(d) { return state_in_scale(d.origin); })
.attr("width", function(d) { return num_scale(d.num_migrants); })
.attr("height", state_in_scale.bandwidth)
.attr("stroke", "white")
.attr("stroke-width", 1.5)
.attr("fill", function(a){
let temp = neighbor_map.get(d.properties.name);
for(let i =0; i < temp.length; i++){
if(temp[i] == a.origin){
return "orange";
}
}
return "red";
})
}
x = d.properties.name;
g.selectAll("path").classed('click',false);
let is_clicked = d3.select(this).classed('click');
let fill_color = selection_color;
d3.select(this).attr('fill', fill_color).classed('click', 1);
})

// --------------------------------------------------hover interaction-----------------------------------------------------------------
regions
.on('mouseover', function(e,d) {
let fill_color = selection_color_hover;
d3.select(this).attr('fill', fill_color);
if(selected_item == null){
row.selectAll(".cell")
.data(function(de, i) {
if(dataValues[i][0].state == d.properties.name){
return dataValues[i].map(a => a.ratio);
}
else{
return dataValues[i].map(function(a) { return a.dest == d.properties.name ? a.ratio : 0;});
}
})
.style("fill", color_d=>
{ if(isNaN(color_d))
{return 'white'}
else
{return colorMap_blue(color_d)}});
}
else{
line_text.call(label_tweak,
'Migration between ' + d.properties.name + ' and ' + selected_item.properties.name + ' from 1990-2019', '12px')
blue_line_text.call(label_tweak,
'Migration from ' + selected_item.properties.name + ' to ' + d.properties.name, '15px')
.attr('fill', 'steelblue')
red_line_text.call(label_tweak,
'Migration from ' + d.properties.name + ' to ' + selected_item.properties.name, '15px')
.attr('fill', 'red')
row.selectAll(".cell")
.data(function(de, i) {
if(dataValues[i][0].state == d.properties.name){
return dataValues[i].map(a => a.ratio);
}else if(dataValues[i][0].state == selected_item.properties.name){
return dataValues[i].map(a => a.ratio);
}
else{
return dataValues[i].map(function(a) { return ((a.dest == d.properties.name)||(a.dest == selected_item.properties.name)
) ? -1*(a.ratio) : NaN;});
}
})
.style("fill", color_d=> { if(isNaN(color_d)){return 'white'} else if(color_d>=0){return colorMap_blue(color_d)
}else if(color_d<0){return colorMap(-color_d)}
});
}
if(selected_item != null && d.properties.name != selected_item.properties.name){
if(testt != "Population"){
let storing_pop = [];
for(let i = 0; i < data_total.length; i++){
let num = data_total[i]
.filter(a => (a.origin == selected_item.properties.name && a.destination == d.properties.name))
.map(a => a.num_migrants/a.origin_population*100).filter(a => a > 0)
.reduce((a, b) => a + b, 0);
let num2 = data_total[i]
.filter(a => (a.origin == d.properties.name && a.destination == selected_item.properties.name))
.map(a => a.num_migrants/a.origin_population*100).filter(a => a > 0)
.reduce((a, b) => a + b, 0);
storing_pop.push({year: year_period_using[i], out: num, in: num2});
}
let store_pop_in_out = [storing_pop.map(dat => dat.out),storing_pop.map(dat => dat.in)].flat()
let pop_exts = d3.extent(store_pop_in_out)
let area_scale = d3.scaleLinear()
.domain([0, 1.1*pop_exts[1]])
.range([150, 0]);
pop_axis.call(d3.axisLeft(area_scale));
pop_path
.datum(storing_pop)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(input) { return year_scale(input.year) })
.y(function(input) { return area_scale(input.out) }));
in_path
.datum(storing_pop)
.attr("fill", "none")
.attr("stroke", "red")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(input) { return year_scale(input.year) })
.y(function(input) { return area_scale(input.in) }));
}
}
})
regions
.on('mouseout', function(e,d) {
let is_clicked = d3.select(this).classed('click');
var fill_color;
if(x=="empty"){
fill_color = d => populationColor(populationByState.get(d.properties.name));
}
else{
if(testt == "Population"){
let temp = (populationByState.get(d.properties.name) - populationByState.get(x)) >= 0 ?
positiveColor(Math.abs(populationByState.get(d.properties.name) - populationByState.get(x))) :
negativeColor(Math.abs(populationByState.get(d.properties.name) - populationByState.get(x)));
fill_color = is_clicked ? selection_color : temp;
}
else{
fill_color = is_clicked ? selection_color : experiment(100*map_using.get(x).get(d.properties.name));
}
}

d3.select(this).attr('fill', fill_color)
});
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
height = 850
Insert cell
Insert cell
populationFormat = d3.format(",d")
Insert cell
populationExtent = d3.extent(populationData_temp.slice(1), d=> +d[1])
Insert cell
Insert cell
populationColor = d3.scaleSequentialLog(populationExtent, d3.interpolateGreens)
Insert cell
positiveColor = d3.scaleSequentialLog(populationExtent, d3.interpolateOranges)
Insert cell
negativeColor = d3.scaleSequentialLog(populationExtent, d3.interpolateBlues)
Insert cell
Insert cell
test = [0, 40]
Insert cell
experiment = d3.scaleSequential(test, d3.interpolateGreens)
Insert cell
cMap = d3.scaleSequential([0, 1], [options.start_color, options.end_color])
Insert cell
cMap_blue = d3.scaleSequential([0, 1], [options.start_color_blue, options.end_color_blue])
Insert cell
Insert cell
path_us = d3.geoPath()
Insert cell
Insert cell
Insert cell
state_codes_file = FileAttachment("state_codes.csv")
Insert cell
state_codes = d3.csvParse(await state_codes_file.text())
Insert cell
state_codes_map = d3.rollup(state_codes, v => v[0].state_name, d => parseInt(d.state_code));
Insert cell
non_state_codes_map = {
let ret = new Map();
ret.set(57, "Foreign");
ret.set(96, "US_and_Foreign");
// This is migration to the US or within the same state
ret.set(97, "US or same state");
ret.set(98, "Foreign");
return ret;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
state_outflow_1819 = FileAttachment("stateoutflow1819.csv")
Insert cell
parsed_1819 = d3.csvParse(await state_outflow_1819.text())
Insert cell
// population map by state code
population_map = d3.rollup(parsed_1819, v => get_population(v), d => parseInt(d.y1_statefips))
Insert cell
// Index 1: the total migration to US,
// Index 2: total foreign migration
// Index 3: total migration within the state
// Index 4: total non-migrants
// Add all values at these indexes to get total tax-paying population
function get_population(v) {
let total = 0;
for (let i = 1; i <= 4; ++i) {
total += parseInt(v[i].n1);
}
return total;
}
Insert cell
// This data is migration data strictly from one state to another state.
derived_1819 = {

let ret = [];
let origin_population = 0;
for (let i = 0; i < parsed_1819.length; ++i) {
let originCode = parseInt(parsed_1819[i].y1_statefips);
let destCode = parseInt(parsed_1819[i].y2_statefips);

// take care of the first couple entries which have codes 96,97,98, and then non-migrants
if (!state_codes_map.has(destCode) || originCode === destCode) {
continue;
}
// let dataPoint = {y1_statefips: parsed_1819[i].y1_statefips, y2_statefips: parsed_1819[i].y2_statefips, y2_state: parsed_1819[i].y2_state};

let dataPoint = {};
dataPoint.origin = state_codes_map.get(originCode);
dataPoint.origin_population = population_map.get(originCode);
dataPoint.destination = state_codes_map.get(destCode);
dataPoint.num_migrants = parseInt(parsed_1819[i].n1);

// take care of data which is unavailble. Set it to 0
if (dataPoint.num_migrants === -1) {
dataPoint.num_migrants = 0;
}
ret.push(dataPoint);
}

return ret;


}
Insert cell
State_names = new Array(us.objects.states.geometries.map(d => [d.properties])).flat().map(d => d[0].name)
Insert cell
countries = topojson.feature(world, world.objects.countries)
Insert cell
derived_data = {
let t = 1991;
let temp = derived_1990_2019[years - t];
return temp;
}
Insert cell
// grouping the toy data based on the origin and distination
grouped_data = d3.rollups(derived_data, v => v[0].num_migrants/v[0].origin_population*100 ,d => d.origin, d => d.destination)
Insert cell
grouped_data_2 = d3.rollups(derived_data, v => v[0].num_migrants/v[0].origin_population*100 ,d => d.destination, d => d.origin)
Insert cell
experiment_map = {
let rows = grouped_data
.map(row => [String(row[0]), new Map(row[1].map(d => [String(d[0]), Number(d[1])]))])
return new Map(rows)
}
Insert cell
experiment_map_2 = {
let rows = grouped_data_2
.map(row => [String(row[0]), new Map(row[1].map(d => [String(d[0]), Number(d[1])]))])
return new Map(rows)
}
Insert cell
us = FileAttachment("data.json").json()
Insert cell
world = FileAttachment("data3.json").json()
Insert cell
populationData_temp = d3.json("https://api.census.gov/data/2018/pep/population?get=GEONAME,POP&for=state:*")
Insert cell
populationByState = {
//removing the title and the last item which is "Puerto Rico" since it is not included in the geographic map
let rows = populationData_temp.slice(1,52)
.map(row => [String(row[0]), Number(row[1])])
return new Map(rows)
}
Insert cell
data_feature = topojson.feature(us, us.objects.states);
Insert cell
Insert cell
Insert cell
Insert cell
raw_1990_2011 = [FileAttachment("state9091out.csv"), FileAttachment("state9192out.csv"), FileAttachment("state9293out.csv"), FileAttachment("state9394out.csv"), FileAttachment("state9495out.csv"), FileAttachment("state9596out.csv"), FileAttachment("state9697out.csv"), FileAttachment("state9798out.csv"), FileAttachment("state9899out.csv"), FileAttachment("state9900out.csv"), FileAttachment("state0001out.csv"), FileAttachment("state0102out (1).csv"), FileAttachment("state0203out.csv"), FileAttachment("state0304out.csv"), FileAttachment("state0405out.csv"), FileAttachment("state0506out.csv"), FileAttachment("stateout0607_parsed@1.csv"), FileAttachment("so0708us_parsed@1.csv"), FileAttachment("stateoutflow0809.csv"), FileAttachment("stateoutflow0910.csv"), FileAttachment("stateoutflow1011.csv")]
Insert cell
// first 2 have 50 less entries because there is no Foreign outflow data for each state
parsed_1990_2011 = {

let arr = [];
for (let i = 0; i < raw_1990_2011.length; ++i) {
let parsed = d3.csvParse(await raw_1990_2011[i].text());
parsed = parsed.filter(function (d) {return (state_codes_map.has(parseInt(d.State_Code_Origin)) ) })
arr.push(parsed);
}

return arr;
}
Insert cell
function get_population1990_2011(v) {
let total = 0;
for (let i = 1; i <= 4; ++i) {
total += parseInt(v[i].Return_Num);
}
return total;
}
Insert cell
populations_1990_1995 = [FileAttachment("population9091out.csv"), FileAttachment("population9192out@1.csv"), FileAttachment("population9293out.csv"), FileAttachment("population9394out.csv"), FileAttachment("population9495out.csv")]
Insert cell
population_maps_1990_1995 = {
let ret = [];
for (let i = 0; i < populations_1990_1995.length; ++i) {
let parsed = d3.csvParse(await populations_1990_1995[i].text());
let mapss = d3.rollup(parsed, v => parseInt(v[0].population), d => parseInt(d.State_Code_Origin));
mapss.delete(57);
ret.push(mapss);
}
return ret;
}
Insert cell
// using get_population
population_maps_1990_2011 = {
let arr = [];
let j = 0;
for (j = 0; j < population_maps_1990_1995.length; ++j) {
arr.push(population_maps_1990_1995[j]);
}
for (let i = j; i < parsed_1990_2011.length; ++i) {
let map = d3.rollup(parsed_1990_2011[i], v => get_population1990_2011(v), d => parseInt(d.State_Code_Origin))
arr.push(map);
}

return arr;
}
Insert cell
// This data is migration data strictly from one state to another state.
function derive1990_2011(migration_data, population_map1) {

let ret = [];
let origin_population = 0;
for (let i = 0; i < migration_data.length; ++i) {
let originCode = parseInt(migration_data[i].State_Code_Origin);
let destCode = parseInt(migration_data[i].State_Code_Dest);

// take care of the first couple entries which have codes 96,97,98, and then non-migrants
if (!state_codes_map.has(destCode) || originCode === destCode) {
continue;
}
let dataPoint = {};
dataPoint.origin = state_codes_map.get(originCode);
dataPoint.origin_population = population_map1.get(originCode);
dataPoint.destination = state_codes_map.get(destCode);
dataPoint.num_migrants = parseInt(migration_data[i].Return_Num);

// take care of data which is unavailble. Set it to 0
if (dataPoint.num_migrants === -1) {
dataPoint.num_migrants = 0;
}
ret.push(dataPoint);
}

return ret;


}
Insert cell
derived_1990_2011 = {

let ret = [];
for (let i = 0; i < parsed_1990_2011.length; ++i) {
let toAdd = derive1990_2011(parsed_1990_2011[i], population_maps_1990_2011[i]);
ret.push(toAdd);
}

return ret;

}
Insert cell
raw_2011_2019 = [FileAttachment("stateoutflow1112.csv"), FileAttachment("stateoutflow1213.csv"), FileAttachment("stateoutflow1314.csv"), FileAttachment("stateoutflow1415.csv"), FileAttachment("stateoutflow1516.csv"), FileAttachment("stateoutflow1617.csv"), FileAttachment("stateoutflow1718.csv"), FileAttachment("stateoutflow1819.csv")]
Insert cell
// first 2 have 50 less entries because there is no Foueign outflow data for each state
parsed_2011_2019 = {

let arr = [];
for (let i = 0; i < raw_2011_2019.length; ++i) {
let parsed = d3.csvParse(await raw_2011_2019[i].text());
arr.push(parsed);
}

return arr;
}
Insert cell
// using get_population
population_maps_2011_2019 = {

let arr = [];
for (let i = 0; i < parsed_2011_2019.length; ++i) {
let map = d3.rollup(parsed_2011_2019[i], v => get_population(v), d => parseInt(d.y1_statefips))
arr.push(map);
}

return arr;
}
Insert cell
derived_1990_2019 = {
let result = [];
let temp = 0;
//if(year_p == "96-19"){
// temp = 5;
//}
for(let i = temp; i < derived_1990_2011.length; i++){
result.push(derived_1990_2011[i]);
}
for(let i = 0; i < derived_2011_2019.length; i++){
result.push(derived_2011_2019[i]);
}
return result;
}
Insert cell
total_pop = {
let arr = [];
let i = 0;
for(i = 0; i < population_maps_1990_2011.length; i++){
let t = Array.from(population_maps_1990_2011[i].values()).filter(d => d > 0).reduce((a, b) => a + b, 0);
arr.push({year: year_period[i], pop: t});
}
for(let j = i; j < population_maps_2011_2019.length + i; j++){
let t = Array.from(population_maps_2011_2019[j-i].values()).filter(d => d > 0).reduce((a, b) => a + b, 0);
arr.push({year: year_period[j], pop: t});
}
return arr;
}
Insert cell
total_migrants = {
let arr = [];
for(let i = 0; i < derived_1990_2019.length; i++){
let t = derived_1990_2019[i].map(d => d.num_migrants).filter(d => d > 0).reduce((a, b) => a + b, 0);
arr.push({year: year_period[i], pop: t});
}
return arr;
}
Insert cell
// This data is migration data strictly from one state to another state.
function derive(migration_data, population_map1) {

let ret = [];
let origin_population = 0;
for (let i = 0; i < migration_data.length; ++i) {
let originCode = parseInt(migration_data[i].y1_statefips);
let destCode = parseInt(migration_data[i].y2_statefips);

// take care of the first couple entries which have codes 96,97,98, and then non-migrants
if (!state_codes_map.has(destCode) || originCode === destCode) {
continue;
}
// let dataPoint = {y1_statefips: parsed_1819[i].y1_statefips, y2_statefips: parsed_1819[i].y2_statefips, y2_state: parsed_1819[i].y2_state};

let dataPoint = {};
dataPoint.origin = state_codes_map.get(originCode);
dataPoint.origin_population = population_map1.get(originCode);
dataPoint.destination = state_codes_map.get(destCode);
dataPoint.num_migrants = parseInt(migration_data[i].n1);

// take care of data which is unavailble. Set it to 0
if (dataPoint.num_migrants === -1) {
dataPoint.num_migrants = 0;
}
ret.push(dataPoint);
}

return ret;


}
Insert cell
derived_2011_2019 = {

let ret = [];
for (let i = 0; i < parsed_2011_2019.length; ++i) {
let toAdd = derive(parsed_2011_2019[i], population_maps_2011_2019[i]);
ret.push(toAdd);
}

return ret;

}

Insert cell
data = {return { values: values, labels: sorted_name }}
Insert cell
test_set = function(list){
let result = [];
for(let i = 0; i < State_names.length; i++){
let temp = list.filter(d => d.origin == State_names[i]);
if(temp[0] == undefined){
continue;
}
temp.push({origin: State_names[i], origin_population: temp[0].origin_population, destination: State_names[i], num_migrants: NaN});
temp.sort(function(a, b) {
var destA = a.destination.toUpperCase();
var destB = b.destination.toUpperCase();
if (destA < destB) {
return -1;
}
if (destA > destB) {
return 1;
}
return 0;
});
temp.map(d => d.ratio = d.num_migrants/d.origin_population*100);
result.push(temp);
}
return result;
}
Insert cell
testtt = test_set(derived_data)
Insert cell
values = testtt.map(d => d.map(a => a = {state: a.origin, dest: a.destination, ratio: a.ratio}))
Insert cell
sorted_name = State_names.sort(function(a, b) {
var aA = a.toUpperCase();
var bB = b.toUpperCase();
if (aA < bB) {
return -1;
}
if (aA > bB) {
return 1;
}
return 0;
});
Insert cell
Insert cell
options = {return {
container: "#Matrix",
show_labels : true,
start_color : d3.hcl(20, 10, 95),
end_color : d3.hcl(20, 80, 10),
start_color_blue : d3.hcl(240, 10, 95),
end_color_blue : d3.hcl(240, 80, 10),

width: 380,
height: 380,
margin: {top: 50, right: 50, bottom: 100, left: 100},
highlight_cell_on_hover: true,
highlight_cell_color: '#2ecc71'
}}
Insert cell
Insert cell
year_period = {
return ["90-91","91-92", "92-93", "93-94", "94-95", "95-96", "96-97", "97-98", "98-99", "99-00", "00-01", "01-02", "02-03", "03-04", "04-05", "05-06", "06-07", "07-08", "08-09", "09-10", "10-11", "11-12", "12-13", "13-14", "14-15", "15-16", "16-17", "17-18", "18-19"];
}
Insert cell
Insert cell
top_5_out = {
let result = new Map();
for(let i = 0; i < State_names.length; i++){
let temp = derived_data.filter(d => d.origin == State_names[i]).sort((a,b) => b.num_migrants - a.num_migrants).slice(0,5);
result.set(State_names[i], temp);
}
return result;
}
Insert cell
top_5_out_total = {
let result = [];
for(let i = 0; i < State_names.length; i++){
let temp = derived_data.filter(d => d.origin == State_names[i]).map(d => d.num_migrants).reduce((a, b) => a + b, 0);
result.push({origin: State_names[i], num_migrants: temp});
}
result = result.sort((a, b) => b.num_migrants - a.num_migrants).slice(0, 5);
return result;
}
Insert cell
top_5_in = {
let result = new Map();
for(let i = 0; i < State_names.length; i++){
let temp = derived_data.filter(d => d.destination == State_names[i]).sort((a,b) => b.num_migrants - a.num_migrants).slice(0,5);
result.set(State_names[i], temp);
}
return result;
}
Insert cell
top_5_in_total = {
let result = [];
for(let i = 0; i < State_names.length; i++){
let temp = derived_data.filter(d => d.destination == State_names[i]).map(d => d.num_migrants).reduce((a, b) => a + b, 0);
result.push({destination: State_names[i], num_migrants: temp});
}
result = result.sort((a, b) => b.num_migrants - a.num_migrants).slice(0, 5);
return result;
}
Insert cell
top_out_name = top_5_out_total.map(d => d.origin)
Insert cell
top_in_name = top_5_in_total.map(d => d.destination)
Insert cell
Insert cell
neighbor_states = [["Florida", "Georgia", "Mississippi", "Tennessee"], [], ["California", "Colorado", "Nevada", "New Mexico", "Utah"], ["Louisiana", "Mississippi", "Missouri", "Oklahoma", "Tennessee", "Texas"], ["Arizona", "Nevada", "Oregon"], ["Arizona", "Kansas", "Nebraska", "New Mexico", "Oklahoma", "Utah", "Wyoming"], ["Massachusetts", "New York", "Rhode Island"], ["Maryland", "New Jersey", "Pennsylvania"], ["Idaho", "Oregon"],["Alabama", "Georgia"], ["Alabama", "Florida", "North Carolina", "South Carolina", "Tennessee"], [], ["Montana", "Nevada", "Oregon", "Utah", "Washington", "Wyoming"], ["Indiana", "Iowa", "Michigan", "Kentucky", "Missouri", "Wisconsin"], ["Illinois", "Kentucky", "Michigan", "Ohio"], ["Illinois", "Minnesota", "Missouri", "Nebraska", "South Dakota", "Wisconsin"], ["Colorado", "Missouri", "Nebraska", "Oklahoma"], ["Illinois", "Indiana", "Missouri", "Ohio", "Tennessee", "Virginia", "West Virginia"], ["Arkansas", "Mississippi", "Texas"], ["New Hampshire"], ["Delaware", "Pennsylvania", "Virginia", "West Virginia"], ["Connecticut", "New Hampshire", "New York", "Rhode Island", "Vermont"], ["Illinois", "Indiana", "Minnesota", "Ohio", "Wisconsin"], ["Iowa", "Michigan", "North Dakota", "South Dakota", "Wisconsin"], ["Alabama", "Arkanssas", "Louisiana", "Tennessee"], ["Arkansas", "Illinois", "Iowa", "Kansas", "Kentucky", "Nebraska", "Oklahoma", "Tennessee"], ["Idaho", "North Dakota", "South Dakota", "Wyoming"], ["Colorado", "Iowa", "Kansas", "Missouri", "South Dakota", "Wyoming"], ["Arizona", "California", "Idaho", "Oregon", "Utah"], ["Maine", "Massachusetts", "Vermont"], ["Delaware", "New York", "Pennsylvania"], ["Arizona", "Colorado", "Oklahoma", "Texas", "Utah"], ["Connecticut", "Massachusets", "New Jersey", "Pennsylvania", "Rhode Island", "Vermont"], ["Georgia", "South Carolina", "Tennessee", "Virginia"], ["Minnesota", "Montana", "South Dakota"], ["Indiana", "Kentucky", "Michigan", "Pennsylvania", "West Virginia"], ["Arkansas", "Colorado", "Kansas", "Missouri", "New Mexico", "Texas"], ["California", "Idaho", "Nevada", "Washington"], ["Delaware", "Maryland", "New Jersey", "New York", "Ohio", "West Virginia"], ["Connecticut", "Massachusetts", "New York"], ["Georgia", "North Carolina"], ["Iowa", "Minnesota", "Montana", "Nebraska", "North Dakota", "Wyoming"], ["Alabama", "Arkansas", "Georgia", "Kentucky", "Mississippi", "Missouri", "North Carolina", "Virginia"], ["Arkansas", "Louisiana", "New Mexico", "Oklahoma"], ["Arizona", "Colorado", "Idaho", "Nevada", "New Mexico", "Wyoming"], ["Massachusetts", "New Hampshire", "New York"], ["Kentucky", "Maryland", "North Carolina", "Tennessee", "West Virginia"], ["Idaho", "Oregon"], ["Kentucky", "Maryland", "Ohio", "Pennsylvania", "Virginia"], ["Illinois", "Iowa", "Michigan, Minnesota"], ["Colorado", "Idaho", "Montana", "Nebraska", "South Dakota", "Utah"]]
Insert cell
neighbor_map = {
let result = new Map();
for(let i = 0; i < state.length; i++){
result.set(state[i], neighbor_states[i]);
}
return result;
}
Insert cell
state = State_names.sort((a, b) => b - a)
Insert cell
Insert cell
import {drawdom} from '91007ee9d5fd152b'
Insert cell
import {legend} from "@d3/color-legend"
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