Published
Edited
Mar 26, 2020
4 stars
Also listed in…
Maps
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function* make_choropleth3D() {
let width = 900;
let height = 400;
let container = d3
.create('div')
.style('width', width.toString() + 'px')
.style('height', height.toString() + 'px');

let scene = container
.append('x3d')
.attr('width', width.toString() + 'px')
.attr('height', height.toString() + 'px')
.append('scene');
scene
.append("viewpoint")
.attr("centerOfRotation", "996 64700 0")
.attr("position", "-3065.65419 56723.69512 5351.94013")
.attr("orientation", "0.97625 -0.13632 -0.16837 1.00157");

let T = scene.append('transform');
['VD', 'VP', 'HD', 'HP'].forEach(function(t) {
let G = T.append('group').attr('id', t);
triangulated_counties.forEach(function(c) {
G.append(() => county3D(c, t));
});
});
scene
.select('#VP')
.selectAll('material')
.attr('transparency', 0);

T.attr('scale', '1,1,0.01');
Promises.delay(500).then(function() {
T.transition()
.duration(1000)
.attr('scale', '1,1,1');
});

yield container.node();
x3dom.reload();
}
Insert cell
// Determine height based type
// VD means volume proprtional to density
// VP means volume proportional to population
// HD means height proporitonal to density
// HP means height proporitonal to population

function height(county, type) {
let pop = county.properties.pop;
let A = county.properties.ALAND + county.properties.AWATER;
if (type == 'VD') {
return (3 * 10 ** 15 * pop) / (A * A);
} else if (type == 'VP' || type == 'HD') {
return (3 * 10 ** 6 * pop) / A;
} else if (type == 'HP') {
return (2 * pop) / 10 ** 3;
} else {
return 0;
}
}
Insert cell
function county3D(county, type) {
let pt_string_top = '';
let pt_string_bot = '';
let h = height(county, type);
county.pts.map(function(pt) {
pt_string_top = `${pt_string_top}${pt[0]} ${pt[1]} ${h}, `;
pt_string_bot = `${pt_string_bot}${pt[0]} ${pt[1]} 0, `;
});
let pt_string = pt_string_top + pt_string_bot;
let top_coord_string = '';
county.triangles.map(function(t) {
top_coord_string = `${top_coord_string}${t[0]} ${t[1]} ${t[2]} -1 `;
});

let n = county.pts.length;
let side_coord_string = '';
county.segments.map(function(s) {
side_coord_string = `${side_coord_string}${s[0]} ${s[1]} ${s[1] +
n} ${s[0] + n} -1 `;
});
let coord_string = `${top_coord_string} ${side_coord_string}`;

let color;
if (type == 'HD' || type == 'VD') {
let density =
county.properties.pop /
(county.properties.ALAND + county.properties.AWATER);
color = d3.interpolateBlues((density / max_density) ** 0.2);
} else if (type == 'HP' || type == 'VP') {
color = d3.interpolateBlues((county.properties.pop / max_pop) ** 0.2);
}
let g = d3.create('group');
let shape = g.append('shape');
let appearance = shape.append('appearance');
appearance
.append('material')
.attr('transparency', 1)
.attr('diffuseColor', color);
let ifs = shape
.append('IndexedFaceSet')
.attr('solid', 'false')
.attr('coordIndex', coord_string);
ifs.append('coordinate').attr('point', pt_string);

return g.node();
}
Insert cell
max_density = d3.max(
triangulated_counties.map(
c => c.properties.pop / (c.properties.ALAND + c.properties.AWATER)
)
)
Insert cell
max_pop = d3.max(triangulated_counties.map(c => c.properties.pop))
Insert cell
triangulated_counties = FileAttachment('nc_triangulated3.json').json()
Insert cell
d3 = require('d3@5')
Insert cell
x3dom = require('x3dom').catch(() => window['x3dom'])
Insert cell
style = html`<style>
canvas {
outline: 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