Published
Edited
Feb 24, 2021
1 fork
5 stars
Also listed in…
X3Dom
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Generate a 3D view of province to add to the choropleth
function province3D(province, party, tooltip) {
let province_code = province.properties.PROVCODE;
let h = 15000 * prov_proportion(province_code, party);

let all_pts = Object.values(province.pts);
let all_triangles = Object.values(province.triangles);
let all_segments = Object.values(province.segments);
let g = d3
.create('group')
.attr('class', `${province_code} province`)
.attr('title', province_code);
let color = province_color(province_code, party);

let pt_strings = all_pts.map(function(pts) {
let pt_string_top = '';
let pt_string_bot = '';
pts.forEach(function(pt) {
pt_string_top = `${pt_string_top}${pt[0]} ${pt[1]} ${h}, `;
pt_string_bot = `${pt_string_bot}${pt[0]} ${pt[1]} 0, `;
});
return pt_string_top + pt_string_bot;
});
all_triangles.forEach(function(triangles, idx) {
let top_coord_string = '';
triangles.forEach(function(t) {
top_coord_string = `${top_coord_string}${t[0]} ${t[1]} ${t[2]} -1 `;
});
let ifsShape = g.append('shape');
let appearance = ifsShape.append('appearance');
appearance.append('material').attr('diffuseColor', color);
let ifs = ifsShape
.append('IndexedFaceSet')
.attr('solid', 'false')
.attr('coordIndex', top_coord_string);
ifs
.append('coordinate')
.attr('class', 'top')
.attr('point', pt_strings[idx]);
});
all_segments.forEach(function(segments, idx) {
let side_coord_string = '';
let outline_coord_string = '';
let n = all_pts[idx].length;
segments.forEach(function(s) {
side_coord_string = `${side_coord_string}${s[0]} ${s[1]} ${s[1] +
n} ${s[0] + n} -1 `;
outline_coord_string = `${outline_coord_string}${s[0]} ${s[1]} -1 `;
});
let ifsShape = g.append('shape');
let appearance = ifsShape.append('appearance');
appearance
.append('material')
.attr('diffuseColor', color)
.attr('shininess', 0.6);
let ifs = ifsShape
.append('IndexedFaceSet')
.attr('solid', 'false')
.attr('coordIndex', side_coord_string);
ifs
.append('coordinate')
.attr('class', 'side')
.attr('point', pt_strings[idx]);
let ilsShape = g.append('shape');
let ils = ilsShape
.append('IndexedLineSet')
.attr('coordIndex', outline_coord_string)
.append('coordinate')
.attr('class', 'outline')
.attr('point', pt_strings[idx]);
});

g.node().onclick = function() {
tooltip
.transition()
.duration(200)
.style("opacity", .9);
tooltip.html(
`${province_code}: ${Math.round(
100 * prov_proportion(province_code, global_party.party)
)}%`
);
};

return g.node();
}
Insert cell
function prov_proportion(prov_code, party) {
let prov_data = voting_data.filter(o => o.province == prov_code);
let total_votes = d3.sum(prov_data.map(o => parseInt(o.votes)));
let party_votes = parseInt(prov_data.filter(o => o.party == party)[0].votes);
return party_votes / total_votes;
}
Insert cell
Insert cell
bounds = {
let all_pts = triangulated_regions.map(r => Object.values(r.pts)).flat(2);
let xs = all_pts.map(xy => xy[0]);
let ys = all_pts.map(xy => xy[1]);
let xmin = d3.min(xs);
let xmax = d3.max(xs);
let ymin = d3.min(ys);
let ymax = d3.max(ys);
return { xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax };
}
Insert cell
FileAttachment("FlagOfCanada.png").url()
Insert cell
triangulated_regions = FileAttachment('provinces_triangulated.json').json()
Insert cell
voting_data = d3.csvParse(
await FileAttachment("party_votes_by_province.csv").text()
)
Insert cell
style = html`<style>
canvas {
outline: none;
}
</style>`
Insert cell
global_party = ({ party: 'Con' })
Insert cell
Insert cell
d3 = require('d3@5')
Insert cell
x3dom = require('x3dom').catch(() => window['x3dom'])
Insert cell
function province_color(province, party) {
let base_color;
if (party.slice(0, 3) == "NDP") {
base_color = d3.schemeCategory10[1];
} else if (party == "Con") {
base_color = d3.schemeCategory10[0];
} else if (party == "Lib") {
base_color = d3.schemeCategory10[3];
} else if (party == "Bloc QC") {
base_color = d3.schemeCategory10[9];
} else if (party == "other") {
base_color = d3.schemeCategory10[2];
}

return d3.interpolate('white', base_color)(prov_proportion(province, party));
}
Insert cell
import { radio } from "@jashkenas/inputs"
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