@mailwoman/tiger 5.6.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Race-by-dot-density builder — the Cooper Center "Racial Dot Map" recipe, from the TIGER DB the
7
+ * `mailwoman tiger` CLI produces.
8
+ *
9
+ * Reads `tabblock20 ⋈ pl_block` (block geometry + Census 2020 P.L. 94-171 table P2 counts) and
10
+ * scatters one dot per `--per` people uniformly at random inside each block, tagged with its
11
+ * race/ethnicity category. Output is NDJSON (one GeoJSON Point Feature per line, with a
12
+ * `tippecanoe` layer hint) ready for `tippecanoe -o race-dots.pmtiles`.
13
+ *
14
+ * Point-in-polygon uses `@turf/boolean-contains` (ships with `@mailwoman/tiger`). The dot is a
15
+ * _representation_, not a record: a random position inside the block it belongs to, standing in
16
+ * for `--per` real people of that category. It says nothing about any individual address.
17
+ *
18
+ * Build the input DB first: mailwoman tiger fetch --state 06 --county 059 --out tiger-oc.db
19
+ * mailwoman tiger redistricting --state 06 --county 059 --out tiger-oc.db
20
+ *
21
+ * Run: node --experimental-strip-types scripts/census/race-dots.ts\
22
+ * --db tiger-oc.db --per 10 --out /tmp/race-dots.ndjson
23
+ */
24
+ import { createWriteStream } from "node:fs";
25
+ import { DatabaseSync } from "node:sqlite";
26
+ import { parseArgs } from "node:util";
27
+ import { dataRootPath } from "@mailwoman/core/utils";
28
+ import booleanContains from "@turf/boolean-contains";
29
+ // Loose scan parity with the retired local argv helpers: unknown flags tolerated.
30
+ const { values: rawValues } = parseArgs({
31
+ options: { db: { type: "string" }, layer: { type: "string" }, out: { type: "string" }, per: { type: "string" } },
32
+ strict: false,
33
+ allowPositionals: true,
34
+ });
35
+ // Typed view: strict:false loosens TS inference, but declared options always parse to their schema type.
36
+ const values = rawValues;
37
+ const DB = values["db"] || dataRootPath("tiger", "tiger-oc.db");
38
+ const OUT = values["out"] || "/tmp/race-dots.ndjson";
39
+ const PER = Number(values["per"] || "10"); // people represented by one dot
40
+ const LAYER = values["layer"] || "dots";
41
+ // The eight P2 categories (columns in pl_block) that partition each block's population.
42
+ const CATEGORIES = ["hispanic", "white", "black", "asian", "aian", "nhpi", "other", "multi"];
43
+ function bbox(rings) {
44
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
45
+ for (const [x, y] of rings[0]) {
46
+ if (x < minX) {
47
+ minX = x;
48
+ }
49
+ if (x > maxX) {
50
+ maxX = x;
51
+ }
52
+ if (y < minY) {
53
+ minY = y;
54
+ }
55
+ if (y > maxY) {
56
+ maxY = y;
57
+ }
58
+ }
59
+ return [minX, minY, maxX, maxY];
60
+ }
61
+ // A block geometry is one or more polygons. Pick a sub-polygon weighted by bbox area, then
62
+ // rejection-sample inside it with a turf containment test (handles holes + winding correctly).
63
+ function randomPointIn(polys, areas, totalArea) {
64
+ let r = Math.random() * totalArea;
65
+ let pick = 0;
66
+ while (pick < polys.length - 1 && (r -= areas[pick]) > 0) {
67
+ pick++;
68
+ }
69
+ const poly = polys[pick];
70
+ const polyFeature = {
71
+ type: "Feature",
72
+ geometry: { type: "Polygon", coordinates: poly },
73
+ properties: {},
74
+ };
75
+ const [minX, minY, maxX, maxY] = bbox(poly);
76
+ for (let tries = 0; tries < 60; tries++) {
77
+ const x = minX + Math.random() * (maxX - minX);
78
+ const y = minY + Math.random() * (maxY - minY);
79
+ const pt = { type: "Feature", geometry: { type: "Point", coordinates: [x, y] }, properties: {} };
80
+ if (booleanContains(polyFeature, pt))
81
+ return [x, y];
82
+ }
83
+ return null;
84
+ }
85
+ const db = new DatabaseSync(DB, { readOnly: true });
86
+ const rows = db
87
+ .prepare(`SELECT b.geometry AS geometry, ${CATEGORIES.map((c) => `p.${c} AS ${c}`).join(", ")}
88
+ FROM tabblock20 b JOIN pl_block p ON b.GEOID = p.GEOID
89
+ WHERE p.pop_total > 0`)
90
+ .all();
91
+ db.close();
92
+ const out = createWriteStream(OUT);
93
+ const totals = new Map();
94
+ let dots = 0, skipped = 0;
95
+ for (const row of rows) {
96
+ let geom;
97
+ try {
98
+ geom = JSON.parse(row.geometry);
99
+ }
100
+ catch {
101
+ continue;
102
+ }
103
+ const polys = geom.type === "Polygon" ? [geom.coordinates] : geom.coordinates;
104
+ const areas = polys.map((p) => {
105
+ const [a, b, c, d] = bbox(p);
106
+ return Math.max((c - a) * (d - b), 1e-12);
107
+ });
108
+ const totalArea = areas.reduce((s, a) => s + a, 0);
109
+ for (const cat of CATEGORIES) {
110
+ const people = row[cat];
111
+ if (people <= 0)
112
+ continue;
113
+ const exact = people / PER;
114
+ const n = Math.floor(exact) + (Math.random() < exact - Math.floor(exact) ? 1 : 0);
115
+ for (let k = 0; k < n; k++) {
116
+ const pt = randomPointIn(polys, areas, totalArea);
117
+ if (!pt) {
118
+ skipped++;
119
+ continue;
120
+ }
121
+ out.write(JSON.stringify({
122
+ type: "Feature",
123
+ tippecanoe: { layer: LAYER },
124
+ properties: { cat },
125
+ geometry: { type: "Point", coordinates: [Math.round(pt[0] * 1e5) / 1e5, Math.round(pt[1] * 1e5) / 1e5] },
126
+ }) + "\n");
127
+ dots++;
128
+ totals.set(cat, (totals.get(cat) ?? 0) + 1);
129
+ }
130
+ }
131
+ }
132
+ out.end();
133
+ console.error(`[done] ${dots} dots from ${rows.length} blocks (1 dot ≈ ${PER} people); ${skipped} skipped`);
134
+ for (const [cat, n] of [...totals.entries()].sort((a, b) => b[1] - a[1])) {
135
+ console.error(` ${n.toString().padStart(7)} ${cat}`);
136
+ }
137
+ //# sourceMappingURL=race-dots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"race-dots.js","sourceRoot":"","sources":["../../tools/race-dots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Minimal static file server that honours HTTP Range requests (206) — Python's `http.server` does
7
+ * not, and PMTiles reads via Range, so it can't be served by it. Used to preview/render a local
8
+ * `.pmtiles` tileset (e.g. the race-dot map). Not for production; the deployed tiles go through
9
+ * the tile worker.
10
+ *
11
+ * Run: node scripts/census/serve-range.ts [dir=/tmp] [port=8899]
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=serve-range.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve-range.d.ts","sourceRoot":"","sources":["../../tools/serve-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @copyright Sister Software
3
+ * @license AGPL-3.0
4
+ * @author Teffen Ellis, et al.
5
+ *
6
+ * Minimal static file server that honours HTTP Range requests (206) — Python's `http.server` does
7
+ * not, and PMTiles reads via Range, so it can't be served by it. Used to preview/render a local
8
+ * `.pmtiles` tileset (e.g. the race-dot map). Not for production; the deployed tiles go through
9
+ * the tile worker.
10
+ *
11
+ * Run: node scripts/census/serve-range.ts [dir=/tmp] [port=8899]
12
+ */
13
+ import { createReadStream, statSync } from "node:fs";
14
+ import { createServer } from "node:http";
15
+ import { extname, join, normalize } from "node:path";
16
+ import { parseArgs } from "node:util";
17
+ const { positionals } = parseArgs({ allowPositionals: true, strict: false });
18
+ const DIR = positionals[0] || "/tmp";
19
+ const PORT = Number(positionals[1] || 8899);
20
+ const TYPES = {
21
+ ".html": "text/html; charset=utf-8",
22
+ ".json": "application/json",
23
+ ".pmtiles": "application/octet-stream",
24
+ ".pbf": "application/x-protobuf",
25
+ ".png": "image/png",
26
+ };
27
+ createServer((req, res) => {
28
+ const rel = normalize(decodeURIComponent((req.url || "/").split("?")[0])).replace(/^(\.\.[/\\])+/, "");
29
+ const path = join(DIR, rel);
30
+ let st;
31
+ try {
32
+ st = statSync(path);
33
+ }
34
+ catch {
35
+ res.writeHead(404);
36
+ return res.end("not found");
37
+ }
38
+ const type = TYPES[extname(path)] || "application/octet-stream";
39
+ const base = { "Content-Type": type, "Accept-Ranges": "bytes", "Access-Control-Allow-Origin": "*" };
40
+ const range = req.headers.range;
41
+ const m = range && /bytes=(\d+)-(\d*)/.exec(range);
42
+ if (m) {
43
+ const start = Number(m[1]);
44
+ const end = m[2] ? Number(m[2]) : st.size - 1;
45
+ res.writeHead(206, {
46
+ ...base,
47
+ "Content-Range": `bytes ${start}-${end}/${st.size}`,
48
+ "Content-Length": end - start + 1,
49
+ });
50
+ createReadStream(path, { start, end }).pipe(res);
51
+ }
52
+ else {
53
+ res.writeHead(200, { ...base, "Content-Length": st.size });
54
+ createReadStream(path).pipe(res);
55
+ }
56
+ }).listen(PORT, () => console.error(`range server: ${DIR} on http://localhost:${PORT}`));
57
+ //# sourceMappingURL=serve-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve-range.js","sourceRoot":"","sources":["../../tools/serve-range.ts"],"names":[],"mappings":"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"}