@dra2020/district-analytics 10.1.2 → 10.2.2
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.
- package/dist/district-analytics.js +100 -56
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/_api.d.ts +1 -1
- package/dist/src/_data.d.ts +1 -10
- package/dist/src/index.d.ts +0 -1
- package/dist/src/minority.d.ts +1 -2
- package/dist/src/types.d.ts +24 -0
- package/package.json +1 -1
|
@@ -177,8 +177,8 @@ class AnalyticsSession {
|
|
|
177
177
|
}
|
|
178
178
|
// 11-03-2020 - Added for racially polarized voting analysis
|
|
179
179
|
// NOTE - This assumes that analyzePlan() has been run!
|
|
180
|
-
analyzeRacialPolarization(
|
|
181
|
-
return minority_1.doAnalyzeRacialPolarization(this,
|
|
180
|
+
analyzeRacialPolarization(districtID, groups, bLog = false) {
|
|
181
|
+
return minority_1.doAnalyzeRacialPolarization(this, districtID, groups, bLog);
|
|
182
182
|
}
|
|
183
183
|
// NOTE - This assumes that analyzePlan() has been run!
|
|
184
184
|
getDistrictStatistics(bLog = false) {
|
|
@@ -669,7 +669,7 @@ class Districts {
|
|
|
669
669
|
return countyIndex;
|
|
670
670
|
}
|
|
671
671
|
// 11-03-2020 - Added for racially polarized voting analysis
|
|
672
|
-
extractVotesByDemographic(districtID, bLog = false) {
|
|
672
|
+
extractVotesByDemographic(districtID, groups, bLog = false) {
|
|
673
673
|
let whitePts = [];
|
|
674
674
|
let minorityPts = [];
|
|
675
675
|
let blackPts = [];
|
|
@@ -696,39 +696,75 @@ class Districts {
|
|
|
696
696
|
// Calculate the Dem two-party vote
|
|
697
697
|
const featureDem = outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
|
|
698
698
|
const featureRep = outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "R" /* RepVotes */);
|
|
699
|
-
const featureTot = outerThis._session.features.fieldForFeature(f,
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
699
|
+
// const featureTot = outerThis._session.features.fieldForFeature(f, T.Dataset.ELECTION, T.FeatureField.TotalVotes);
|
|
700
|
+
if ((featureDem + featureRep) > 0) {
|
|
701
|
+
const pctDem = featureDem / (featureDem + featureRep);
|
|
702
|
+
// Calculate the VAP/CVAP percentages by demographic
|
|
703
|
+
const totalVAP = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
|
|
704
|
+
if (totalVAP > 0) {
|
|
705
|
+
// Gather all points, for debugging purposes ...
|
|
706
|
+
const whitePop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
|
|
707
|
+
const pctWhite = whitePop / totalVAP;
|
|
708
|
+
const minorityPop = totalVAP - whitePop;
|
|
709
|
+
const pctMinority = minorityPop / totalVAP;
|
|
710
|
+
const pctBlack = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */) / totalVAP;
|
|
711
|
+
const pctHispanic = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */) / totalVAP;
|
|
712
|
+
const pctPacific = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */) / totalVAP;
|
|
713
|
+
const pctAsian = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */) / totalVAP;
|
|
714
|
+
const pctNative = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */) / totalVAP;
|
|
715
|
+
let bGoodPoints = true;
|
|
716
|
+
// bGoodPoints = (Number.isNaN(pctDem)) ? false : true;
|
|
717
|
+
// bGoodPoints = (Number.isNaN(pctWhite)) ? false : true;
|
|
718
|
+
// bGoodPoints = (Number.isNaN(pctMinority)) ? false : true;
|
|
719
|
+
// bGoodPoints = (Number.isNaN(pctBlack)) ? false : true;
|
|
720
|
+
// bGoodPoints = (Number.isNaN(pctHispanic)) ? false : true;
|
|
721
|
+
// bGoodPoints = (Number.isNaN(pctPacific)) ? false : true;
|
|
722
|
+
// bGoodPoints = (Number.isNaN(pctAsian)) ? false : true;
|
|
723
|
+
// bGoodPoints = (Number.isNaN(pctNative)) ? false : true;
|
|
724
|
+
if (bGoodPoints) {
|
|
725
|
+
whitePts.push({ x: pctWhite, y: pctDem });
|
|
726
|
+
minorityPts.push({ x: pctMinority, y: pctDem });
|
|
727
|
+
blackPts.push({ x: pctBlack, y: pctDem });
|
|
728
|
+
hispanicPts.push({ x: pctHispanic, y: pctDem });
|
|
729
|
+
pacificPts.push({ x: pctPacific, y: pctDem });
|
|
730
|
+
asianPts.push({ x: pctAsian, y: pctDem });
|
|
731
|
+
nativePts.push({ x: pctNative, y: pctDem });
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
if (bLog) {
|
|
735
|
+
console.log("NaN value for feature ", featureID);
|
|
736
|
+
console.log("pctDem: ", pctDem);
|
|
737
|
+
console.log("pctWhite: ", pctWhite);
|
|
738
|
+
console.log("pctMinority: ", pctMinority);
|
|
739
|
+
console.log("pctBlack: ", pctBlack);
|
|
740
|
+
console.log("pctHispanic: ", pctHispanic);
|
|
741
|
+
console.log("pctPacific: ", pctPacific);
|
|
742
|
+
console.log("pctAsian: ", pctAsian);
|
|
743
|
+
console.log("pctNative: ", pctNative);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
if (bLog)
|
|
749
|
+
console.log("Total VAP not > 0.");
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
if (bLog)
|
|
754
|
+
console.log("D + R not > 0.");
|
|
720
755
|
}
|
|
721
756
|
}
|
|
722
757
|
}
|
|
723
758
|
});
|
|
759
|
+
// ... but only keep points for the demographics that are going to be analyzed
|
|
724
760
|
return {
|
|
725
761
|
white: whitePts,
|
|
726
|
-
minority: minorityPts,
|
|
727
|
-
black: blackPts,
|
|
728
|
-
hispanic: hispanicPts,
|
|
729
|
-
pacific: pacificPts,
|
|
730
|
-
asian: asianPts,
|
|
731
|
-
native: nativePts
|
|
762
|
+
minority: groups.minority ? minorityPts : [],
|
|
763
|
+
black: groups.black ? blackPts : [],
|
|
764
|
+
hispanic: groups.hispanic ? hispanicPts : [],
|
|
765
|
+
pacific: groups.pacific ? pacificPts : [],
|
|
766
|
+
asian: groups.asian ? asianPts : [],
|
|
767
|
+
native: groups.native ? nativePts : []
|
|
732
768
|
};
|
|
733
769
|
}
|
|
734
770
|
// If a district is empty
|
|
@@ -1407,7 +1443,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
1407
1443
|
};
|
|
1408
1444
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1409
1445
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
1410
|
-
const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
|
|
1411
1446
|
const majority_minority_json_1 = __importDefault(__webpack_require__(/*! ../static/majority-minority.json */ "./static/majority-minority.json"));
|
|
1412
1447
|
const vra5_preclearance_json_1 = __importDefault(__webpack_require__(/*! ../static/vra5-preclearance.json */ "./static/vra5-preclearance.json"));
|
|
1413
1448
|
// TODO - 2020: Update/revise this, when the update comes out in September:
|
|
@@ -1431,33 +1466,36 @@ function getVRASection5(s) {
|
|
|
1431
1466
|
exports.getVRASection5 = getVRASection5;
|
|
1432
1467
|
// 11-03-2020 - Added for racially polarized voting analysis
|
|
1433
1468
|
// Analyze the degree of racially polarized voting for a district
|
|
1434
|
-
function doAnalyzeRacialPolarization(s, districtID, bLog = false) {
|
|
1435
|
-
|
|
1436
|
-
|
|
1469
|
+
function doAnalyzeRacialPolarization(s, districtID, groups, bLog = false) {
|
|
1470
|
+
// Either take take the minorities to analyze in as selections -or- infer them
|
|
1471
|
+
// from the % VAP/CVAP for the district (not the state).
|
|
1472
|
+
if (groups == undefined) {
|
|
1473
|
+
const RPV_THRESHOLD = 0.35; // Using ~ the Bethune–Hill threshold
|
|
1474
|
+
groups = {
|
|
1475
|
+
white: true,
|
|
1476
|
+
minority: false,
|
|
1477
|
+
black: (s.districts.table.blackPct[districtID] > RPV_THRESHOLD) ? true : false,
|
|
1478
|
+
hispanic: (s.districts.table.hispanicPct[districtID] > RPV_THRESHOLD) ? true : false,
|
|
1479
|
+
pacific: (s.districts.table.pacificPct[districtID] > RPV_THRESHOLD) ? true : false,
|
|
1480
|
+
asian: (s.districts.table.asianPct[districtID] > RPV_THRESHOLD) ? true : false,
|
|
1481
|
+
native: (s.districts.table.nativePct[districtID] > RPV_THRESHOLD) ? true : false
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
if (!(groups.black || groups.hispanic || groups.pacific || groups.asian || groups.native))
|
|
1437
1485
|
return undefined;
|
|
1438
|
-
const
|
|
1439
|
-
|
|
1440
|
-
// Which minority groups are big enough that proportional representation would give them one or more seats?
|
|
1441
|
-
const bDoBlack = (calcProportionalDistricts(statewide.black, nDistricts) > 0) ? true : false;
|
|
1442
|
-
const bDoHispanic = (calcProportionalDistricts(statewide.hispanic, nDistricts) > 0) ? true : false;
|
|
1443
|
-
const bDoPacific = (calcProportionalDistricts(statewide.pacific, nDistricts) > 0) ? true : false;
|
|
1444
|
-
const bDoAsian = (calcProportionalDistricts(statewide.asian, nDistricts) > 0) ? true : false;
|
|
1445
|
-
const bDoNative = (calcProportionalDistricts(statewide.native, nDistricts) > 0) ? true : false;
|
|
1446
|
-
if (!(bDoBlack || bDoHispanic || bDoPacific || bDoAsian || bDoNative))
|
|
1486
|
+
const points = s.districts.extractVotesByDemographic(districtID, groups, bLog);
|
|
1487
|
+
if (points === undefined)
|
|
1447
1488
|
return undefined;
|
|
1448
1489
|
// At this point, at least one single-race/ethnicity minority demographic needs
|
|
1449
|
-
// to be analyzed
|
|
1450
|
-
//
|
|
1451
|
-
// const bDoWhite: boolean = (calcProportionalDistricts(statewide.white, nDistricts) > 0) ? true : false;
|
|
1452
|
-
// const bDoMinority: boolean = (calcProportionalDistricts(statewide.minority, nDistricts) > 0) ? true : false;
|
|
1490
|
+
// to be analyzed along with white.
|
|
1453
1491
|
const result = {
|
|
1454
|
-
white:
|
|
1455
|
-
minority:
|
|
1456
|
-
black:
|
|
1457
|
-
hispanic:
|
|
1458
|
-
pacific:
|
|
1459
|
-
asian:
|
|
1460
|
-
native:
|
|
1492
|
+
white: characterizeDemographicVoting(points.white),
|
|
1493
|
+
minority: groups.minority ? characterizeDemographicVoting(points.minority) : undefined,
|
|
1494
|
+
black: groups.black ? characterizeDemographicVoting(points.black) : undefined,
|
|
1495
|
+
hispanic: groups.hispanic ? characterizeDemographicVoting(points.hispanic) : undefined,
|
|
1496
|
+
pacific: groups.pacific ? characterizeDemographicVoting(points.pacific) : undefined,
|
|
1497
|
+
asian: groups.asian ? characterizeDemographicVoting(points.asian) : undefined,
|
|
1498
|
+
native: groups.native ? characterizeDemographicVoting(points.native) : undefined
|
|
1461
1499
|
};
|
|
1462
1500
|
return result;
|
|
1463
1501
|
}
|
|
@@ -1492,11 +1530,17 @@ function linearRegression(points) {
|
|
|
1492
1530
|
result['r2'] = Math.pow((n * sum_xy - sum_x * sum_y) / Math.sqrt((n * sum_xx - sum_x * sum_x) * (n * sum_yy - sum_y * sum_y)), 2);
|
|
1493
1531
|
return result;
|
|
1494
1532
|
}
|
|
1495
|
-
function
|
|
1533
|
+
function characterizeDemographicVoting(points) {
|
|
1496
1534
|
const { m, b, r2 } = linearRegression(points);
|
|
1497
1535
|
const maxVAPPct = 1.0; // 100%
|
|
1498
1536
|
const maxDemPct = Math.max(0.0, Math.min(1.0, (m * maxVAPPct) + b));
|
|
1499
|
-
|
|
1537
|
+
const result = {
|
|
1538
|
+
m: U.trim(m),
|
|
1539
|
+
b: U.trim(b),
|
|
1540
|
+
r2: U.trim(r2),
|
|
1541
|
+
f1: U.trim(maxDemPct)
|
|
1542
|
+
};
|
|
1543
|
+
return result;
|
|
1500
1544
|
}
|
|
1501
1545
|
|
|
1502
1546
|
|