Public
Edited
May 19, 2023
1 fork
4 stars
Also listed in…
Elections
Maps
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function make_tilegram() {
let div = d3
.create('div')
.style("width", `${map_width}px`)
.style("height", `${height}px`)
.style('overflow', 'hidden');

let svg = div
.append('svg')
.style('overflow', 'hidden')
.attr("viewBox", [0, 0, map_width, height]);

let map_obj, hex_data, boundary_data;
if (map_type == 'Together') {
map_obj = tiles;
hex_data = tiles;
boundary_data = tile_boundaries;
} else if (map_type == 'Broken') {
map_obj = broken_tiles;
hex_data = broken_tiles;
boundary_data = broken_tile_boundaries;
}
let proj = d3
.geoIdentity()
.reflectY(true)
.fitSize([map_width, height], map_obj);

let path = d3.geoPath().projection(proj);

let map = svg.append('g');
map
.selectAll("path.tile")
.data(hex_data.features)
.join("path")
.attr('class', 'tile')
.attr('d', path)
// .style('fill', () => d3.interpolateCool(Math.random()))
.style("fill", function(d) {
let fips = d.id;
let info = info_map.get(fips);
let p;
if (shade_by == "Representation") {
p = info.reps / max_reps;
return d3.interpolateBlues(p ** 0.6);
} else if (shade_by == "Representation change") {
p = (info.change + 2) / 4.1;
return d3.interpolateRdYlGn(p);
}
})
.attr('data-state', d => d.id)
.attr("stroke-width", '1px')
.attr("stroke", "white")
.attr("stroke-linejoin", "round");
map
.selectAll("path.boundary")
.data(boundary_data.features)
.join("path")
.attr('class', 'boundary')
.attr('d', path)
.style('fill', 'black')
.style("fill-opacity", 0)
.attr("stroke-width", '2px')
.attr("stroke", "black")
.attr("stroke-linejoin", "round")
.attr('data-state', d => d.id)
.on('mouseenter', function(evt) {
let copy = this.cloneNode(true);
copy.setAttribute('stroke', 'black');
copy.setAttribute('stroke-width', '6px');
copy.setAttribute('class', 'temp');
copy.addEventListener('mouseleave', function() {
map.selectAll('.temp').remove();
});
let fips = d3.select(evt.target).attr('data-state');
let info = info_map.get(fips);
tippy(copy, {
allowHTML: true,
maxWidth: 420,
theme: 'light',
content: `
<table>
<tr><th>State</th><th>Population</th><th>Representation</th><th>Change</th></tr>
<tr>
<td><span class="td">${info.name}</span></td>
<td><span class="td">${info.pop}</span></td>
<td><span class="td">${info.reps}</span></td>
<td><span class="td">${info.change}</span></td>
</tr>
</table>
`
});
map.append(() => copy);
});

return div.node();
}
Insert cell
height = 0.625 * map_width
Insert cell
map_width = width // < 800 ? width : 800
Insert cell
max_reps = d3.max(Array.from(info_map.values()).map(o => o.reps))
Insert cell
info_map = {
let info_map = new Map();
apportionment_data.forEach(function(o) {
let fips = o.fips;
let name = o.state_name;
let abbr = o.abbr;
let pop = parseInt(o.apportionment_population);
let reps = parseInt(o.reps);
let change = parseInt(o.change);
info_map.set(fips, {
name: name,
abbr: abbr,
pop: pop,
reps: reps,
change: change
});
});
return info_map;
}
Insert cell
apportionment_data = FileAttachment("new_apportionment.csv").csv()
Insert cell
apportionment_data.map((o) => ({ name: o.state_name, abbr: o.abbr }))
Insert cell
broken_tile_boundaries = {
let map_file = await FileAttachment(
"new_congress_broken_boundaries_tilegram.topo.json"
).json();
let boundaries = topojson.feature(map_file, map_file.objects.tiles);
return boundaries;
}
Insert cell
broken_tiles = {
let map_file = await FileAttachment(
"new_congress_broken_tilegram.topo.json"
).json();
let states = topojson.feature(map_file, map_file.objects.tiles);
return states;
}
Insert cell
tile_boundaries = {
let map_file = await FileAttachment(
"new_congress_tilegram_boundaries2.topo@1.json"
).json();
let boundaries = topojson.feature(map_file, map_file.objects.tiles);
return boundaries;
}
Insert cell
tiles = {
let map_file = await FileAttachment("new_congress_tilegram2.topo@1.json").json();
let states = topojson.feature(map_file, map_file.objects.tiles);
return states;
}
Insert cell
import { Radio } from "@observablehq/inputs"
Insert cell
tippy = require("tippy.js@6")
Insert cell
topojson = require("topojson-client@3")
Insert cell
d3 = require('d3@6')
Insert cell
style = html`<link rel="stylesheet" href="${await require.resolve(
`tippy.js/themes/light.css`
)}">`
Insert cell
html`<style>
td,th {
text-align: center;
}
.td {
padding: 20px
}
</style>`
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