Public
Edited
Mar 9, 2023
1 fork
1 star
Insert cell
Insert cell
usHexMap(sample_data, {
topojson: topojson,
stateCodesWithNames: stateCodesWithNames
})
Insert cell
function usHexMap (data, {
topojson = null,
stateCodesWithNames = null,
colorRange = ['#eee','#23c17c','#4f8fe6', '#6f0043', '#eee'], // low to high
colorDomain = [0, 50, 75, 100],
f = d3.format('.1f'), // round to 1 decimal
height = 600, // svg height (without margins)
margin = {top: 5, right: 10, bottom: 5, left: 10} // svg margins/padding
} = {}) {

// set the dimensions and margins of the graph
const w = width - margin.left - margin.right;
const h = height - margin.top - margin.bottom;

const svg = DOM.svg(width, height);
const sel = d3.select(svg)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);

const tiles = topojson.feature(tilegram, tilegram.objects.tiles);

const transform = d3.geoTransform({
point: function (x, y) { return this.stream.point(x, -y) }
});

const path = d3.geoPath().projection(transform);

const g = sel.append('g')
.attr('transform', 'translate(-350,' + (h-10) + ')');

const thresholdScale = d3.scaleThreshold()
.domain(colorDomain)
.range(colorRange);

const borders = g.selectAll('path')
.data(tiles.features)
.join('path')
.attr('d', path)
.attr('class', 'border')
.attr('fill', d => {
const state = d.properties.state;
const datum = _.find(data, o => o.code === state);
return thresholdScale(datum.value)
})
.attr('stroke', '#fff')
.attr('stroke-width', 4)
.on('click', (e, d) => console.log('d', d));
borders.on('mouseover', function (e, d) {
const state = d.properties.state;
const datum = _.find(data, o => o.code === state);
const label = _.find(stateCodesWithNames, o => o.code === state);
sel.select('text.info').text(`${label.state} ${f(datum.value)}`);
});

// add some labels
g.selectAll('.state-label')
.data(tiles.features)
.join('text')
.attr('class', d => 'state-label state-label-' + d.id)
.attr('transform', d => `translate(${path.centroid(d)})`)
.attr('dy', '.35em')
//.attr('dx', '-10px')
.text(d => d.properties.state);

// output some info
sel.append('text')
.attr('y', 20)
.attr('x', -10)
.attr('class', 'info');

// have a legend
const legend = sel.append('g')
.attr('class', 'legend-wrap')
.attr('transform', `translate(${(w- 300)},${(h-10)})`)
.selectAll('g.legend')
.attr('class', 'legend')
.data(colorDomain)
.join('g')
.attr('class', 'legend')
legend.append('rect')
.attr('x', (d, i) => i * 80)
.attr('fill', (d, i) => thresholdScale(d) )
.attr('width', 80)
.attr('height', 10);

legend.append('text')
.attr('x', (d, i) => i * 80 + 40)
.attr('y', -5)
.attr('text-anchor', 'middle')
.text(d => `> ${d}`);

return svg;

}
Insert cell
Insert cell
Insert cell
Insert cell
// dummy data
sample_data = stateCodesWithNames.map(d => {
return {
code: d.code,
value : _.random(1, 98.5)
}
})
Insert cell
topojson = require('topojson')
Insert cell
<!-- css not required for chart -->
<hr>
<link href="https://fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet">
<style>
text {
font-family:'Space Mono',monospace;
}
.border:hover {
fill: #d1bd19;
cursor: pointer;
}

.state-label {
fill: #fff;
fill-opacity: .9;
letter-spacing: 1px;
font-size: 18px;
font-weight: 600;
text-anchor: middle;
pointer-events: none;
}
</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