Public
Edited
Nov 6, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ctu_second_submission = FileAttachment("ctu_second_submission.geojson").json()
Insert cell
Insert cell
maldef = FileAttachment("maldef.geojson").json()
Insert cell
maldef_plan = FileAttachment("maldef.csv").csv({ typed: true })
Insert cell
may_17_draft_plan = FileAttachment("may_17_draft_plan.geojson").json()
Insert cell
may_17_plan = FileAttachment("may_17_draft_plan(1).csv").csv({ typed: true })
Insert cell
oct_31_draft_plan = FileAttachment("oct_31_draft_plan.geojson").json()
Insert cell
oct_31_plan = FileAttachment("oct_31_draft_plan.csv").csv({ typed: true })
Insert cell
Insert cell
Insert cell
plurality = (plan) =>
plan
.map(
({
district_name,
percent_white_cvap,
percent_black_cvap,
percent_latino_cvap
}) => ({
district_name,
...Object.entries({
percent_white_cvap,
percent_black_cvap,
percent_latino_cvap
}).reduce((a, b) => (b[1] > a[1] ? b : a))
})
)
.map((d) => ({
district_name: d.district_name,
candidate: new Map([
["percent_white_cvap", "white"],
["percent_black_cvap", "Black"],
["percent_latino_cvap", "Latino"]
]).get(d[0]),
percentage: d[1]
}))
Insert cell
adjusted_mutual_information = (A, B, simplifier = 100000) => {
const contingency = A.features.map((A_polygon) =>
B.features.map((B_polygon) => {
const intersection = turf.intersect(A_polygon, B_polygon);
return intersection
? Math.round(turf.area(intersection) / simplifier)
: 0;
})
);

const total_area = sum(contingency.flat());

const A_areas = A.features.map((polygon) =>
Math.round(turf.area(polygon) / simplifier)
);
const B_areas = B.features.map((polygon) =>
Math.round(turf.area(polygon) / simplifier)
);
const entropy_A = -sum(
A_areas.map((area) => area / total_area).map((p) => p * Math.log(p))
);
const entropy_B = -sum(
B_areas.map((area) => area / total_area).map((p) => p * Math.log(p))
);

const products = A_areas.map((A_area) =>
B_areas.map((B_area) => A_area * B_area)
);

const mutual_information = sum(
zip(contingency.flat(), products.flat()).map(
([intersection, product]) =>
(intersection / total_area) *
(intersection ? Math.log((total_area * intersection) / product) : 0)
)
);

const emi = expected_mutual_information(contingency);
return (mutual_information - emi) / (Math.max(entropy_A, entropy_B) - emi);
}
Insert cell
expected_mutual_information = (contingency) => {
let accumulator = 0;

const row_marginals = contingency.map((row) => sum(row));
const column_marginals = colsum(contingency);
const N = sum(contingency.flat());
for (const a of row_marginals) {
for (const b of column_marginals) {
for (const n of range(Math.max(a + b - N, 1), Math.min(a, b))) {
accumulator +=
(n / N) *
(Math.log(N) + Math.log(n) - Math.log(a) - Math.log(b)) *
Math.exp(
gammaln(a) +
gammaln(b) +
gammaln(N - a) +
gammaln(N - b) -
gammaln(N) -
gammaln(n) -
gammaln(a - n) -
gammaln(b - n) -
gammaln(N - a - b + n)
);
}
}
}
return accumulator;
}
Insert cell
zip = (a, b) => a.map((k, i) => [k, b[i]])
Insert cell
sum = (arr) => arr.reduce((partialSum, a) => partialSum + a, 0)
Insert cell
colsum = (arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b))
Insert cell
range = (start, stop) =>
Array.from({ length: stop - start + 1 }, (value, index) => start + index)
Insert cell
gammaln = (
await import(
"https://cdn.skypack.dev/@stdlib/math-base-special-gammaln@0.1.0?min"
)
).default
Insert cell
import { rewind } from "@fil/rewind"
Insert cell
turf = require("@turf/turf")
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