Public
Edited
Apr 1
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = Chart()
Insert cell
chart.update_fill(census_collection, d => bgshade(0.00008 * Math.min(d.properties.density, 20000)), title_text)
Insert cell
update_dots(chart.zoomTransform(), chart);
Insert cell
chart.set_transform_callback(update_dots_xform)
Insert cell
bgshade = n => `rgb(0 0 0 / ${n/5})`
Insert cell
Insert cell
Insert cell
function update_dots_xform(transform, chart)
{
var scale = 1 / transform.k;
if (chart[scale_key] == scale) return;
chart[scale_key] = scale;
update_dots(transform, chart);
}
Insert cell
total_amount = census_collection.features.map(geo => 3 * amount_of_dots(geo)).reduce((a, b) => a + b, 0);
Insert cell
scale_preference = dot_size == 'large' ? 1 : dot_size == 'small' ? .6 : .3
Insert cell
function update_dots(transform, chart)
{
var interp = d3.interpolate('#800','#06f');
var scale = 1 / transform.k;
var size = Math.min(2, 1*transform.k) * scale_preference;
var t0 = performance.now()
let points = census_collection.features.map(geo =>
{
var poly = biggest_map_poly(geo);
var n = amount_of_dots(geo);
var pp = makeDots(poly, n,
{distance: size * scale * 1, edgeDistance: 0.5 * scale, maxIterations: 10*n});
if (pp.length == 0 && n > 0) { pp = [d3.polygonCentroid(poly)]; }
pp.pressure = pp.length / n || 0;
return pp
});
var t1 = performance.now()
console.log("time for calculation is", (t1 - t0)*.001, "success rate",
points.map(p => p.length).reduce((a, b) => a + b, 0) /
census_collection.features.map(amount_of_dots).reduce((a, b) => a + b, 0));
// add outlines on area units
chart.map_layer.select(":first-child")
.attr('stroke', sa_type == 1 ? '#fc9' : '#f95')
.attr('stroke-opacity', 0.3)
.attr('stroke-width', sa_type == 1 ? 0.3 : 0.5)
.attr('stroke-linejoin', 'round');
// lazily create our dot layer
if (!chart[dot_key])
chart[dot_key] = chart.img_layer.append('g');
// put dots on it; compensate radius for zoom factor
chart[dot_key]
.selectAll("g")
.data(points)
.join("g")
.attr('fill', dd => interp(dd.pressure))
.attr('stroke', 0)
.selectAll("circle")
.data(dd => dd)
.join("circle")
.attr("pointer-events", "none")
.attr('cx', d => d[0])
.attr('cy', d => d[1])
.attr('r', size * scale);
var t2 = performance.now()
console.log("time for svg update is", (t2 - t1)*.001);
}
Insert cell
function amount_of_dots(d)
{
var number = (d.properties[mode_to_display.key] / 3) >> 0 || 0;
// for population, display larger quanta than just 3, otherwise it really is too crowded.
if (mode_to_display.key == "population") number = Math.round(number / (sa_type == 2 ? 20 : 3));
return number;
}
Insert cell
// Return the outer ring of the largest polygon (most vertices)
function biggest_map_poly(obj)
{
let geo = obj.geometry;
let a = [];
if (geo.type == "MultiPolygon")
{
geo.coordinates.map(poly => {
if (poly[0].length > a.length) { a = poly[0]; }
});
}
else
{
a = geo.coordinates[0];
}
a = a.map(projection);
return a;
}
Insert cell
Insert cell
max_zoom = 6;
Insert cell
census_collection
Insert cell
our_mode_choices = mode_choices.filter(m => m.key != "response").concat([{title: "Population", key: "population"}])
Insert cell
import { Chart , census_collection, title_text, projection, mode_choices, param }
with {sa_type as sa_type, max_zoom as max_zoom, commute_group as commute_group}
from "@roelandschoukens/mode-share-map"
Insert cell
import { makeDots, distPointEdge } from "@floledermann/dot-density-maps-with-d3"
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