@dra2020/district-analytics 10.0.9 → 10.1.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.
- package/README.md +7 -4
- package/dist/district-analytics.js +311 -234
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/_api.d.ts +1 -0
- package/dist/src/_data.d.ts +56 -34
- package/dist/src/index.d.ts +1 -1
- package/dist/src/minority.d.ts +2 -0
- package/dist/src/results.d.ts +20 -38
- package/dist/src/score.d.ts +1 -0
- package/dist/src/types.d.ts +0 -5
- package/package.json +1 -1
|
@@ -122,6 +122,8 @@ const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
|
|
|
122
122
|
const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
|
|
123
123
|
const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
124
124
|
const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
125
|
+
// 11-03-2020 - Added for racially polarized voting analysis
|
|
126
|
+
const minority_1 = __webpack_require__(/*! ./minority */ "./src/minority.ts");
|
|
125
127
|
const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "@dra2020/poly"));
|
|
126
128
|
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
127
129
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
@@ -173,6 +175,11 @@ class AnalyticsSession {
|
|
|
173
175
|
}
|
|
174
176
|
return true;
|
|
175
177
|
}
|
|
178
|
+
// 11-03-2020 - Added for racially polarized voting analysis
|
|
179
|
+
// NOTE - This assumes that analyzePlan() has been run!
|
|
180
|
+
analyzeRacialPolarization(id, bLog = false) {
|
|
181
|
+
return minority_1.doAnalyzeRacialPolarization(this, id, bLog);
|
|
182
|
+
}
|
|
176
183
|
// NOTE - This assumes that analyzePlan() has been run!
|
|
177
184
|
getDistrictStatistics(bLog = false) {
|
|
178
185
|
return results_2.prepareDistrictStatistics(this, bLog);
|
|
@@ -276,56 +283,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
276
283
|
const G = __importStar(__webpack_require__(/*! @dra2020/dra-graph */ "@dra2020/dra-graph"));
|
|
277
284
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
278
285
|
const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
|
|
279
|
-
// import { isConnected, isEmbedded } from './valid';
|
|
280
286
|
const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
|
|
281
287
|
const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
|
|
282
288
|
// DEBUG COUNTERS
|
|
283
289
|
let nMissingDataset = 0;
|
|
284
290
|
let nMissingProperty = 0;
|
|
285
|
-
// DISTRICT STATISTICS
|
|
286
|
-
// Indexes for statistics fields in Districts
|
|
287
|
-
// NOTE - Not a const, so the number can be determined dynamically
|
|
288
|
-
var DistrictField;
|
|
289
|
-
(function (DistrictField) {
|
|
290
|
-
DistrictField[DistrictField["TotalPop"] = 0] = "TotalPop";
|
|
291
|
-
DistrictField[DistrictField["PopDevPct"] = 1] = "PopDevPct";
|
|
292
|
-
DistrictField[DistrictField["bEqualPop"] = 2] = "bEqualPop";
|
|
293
|
-
DistrictField[DistrictField["bNotEmpty"] = 3] = "bNotEmpty";
|
|
294
|
-
DistrictField[DistrictField["bContiguous"] = 4] = "bContiguous";
|
|
295
|
-
DistrictField[DistrictField["bNotEmbedded"] = 5] = "bNotEmbedded";
|
|
296
|
-
DistrictField[DistrictField["CountySplits"] = 6] = "CountySplits";
|
|
297
|
-
// 10-22-2020 - Added Other votes
|
|
298
|
-
DistrictField[DistrictField["DemVotes"] = 7] = "DemVotes";
|
|
299
|
-
DistrictField[DistrictField["RepVotes"] = 8] = "RepVotes";
|
|
300
|
-
DistrictField[DistrictField["OtherVotes"] = 9] = "OtherVotes";
|
|
301
|
-
// TwoPartyVote, // Two-party total ()= Dem + Rep) not all votes!
|
|
302
|
-
DistrictField[DistrictField["DemPct"] = 10] = "DemPct";
|
|
303
|
-
DistrictField[DistrictField["RepPct"] = 11] = "RepPct";
|
|
304
|
-
DistrictField[DistrictField["OtherPct"] = 12] = "OtherPct";
|
|
305
|
-
// End - OtherVotes changes
|
|
306
|
-
DistrictField[DistrictField["DemSeat"] = 13] = "DemSeat";
|
|
307
|
-
DistrictField[DistrictField["TotalVAP"] = 14] = "TotalVAP";
|
|
308
|
-
DistrictField[DistrictField["MinorityPop"] = 15] = "MinorityPop";
|
|
309
|
-
DistrictField[DistrictField["WhitePop"] = 16] = "WhitePop";
|
|
310
|
-
DistrictField[DistrictField["BlackPop"] = 17] = "BlackPop";
|
|
311
|
-
DistrictField[DistrictField["HispanicPop"] = 18] = "HispanicPop";
|
|
312
|
-
DistrictField[DistrictField["PacificPop"] = 19] = "PacificPop";
|
|
313
|
-
DistrictField[DistrictField["AsianPop"] = 20] = "AsianPop";
|
|
314
|
-
DistrictField[DistrictField["NativePop"] = 21] = "NativePop";
|
|
315
|
-
DistrictField[DistrictField["WhitePct"] = 22] = "WhitePct";
|
|
316
|
-
DistrictField[DistrictField["MinorityPct"] = 23] = "MinorityPct";
|
|
317
|
-
DistrictField[DistrictField["BlackPct"] = 24] = "BlackPct";
|
|
318
|
-
DistrictField[DistrictField["HispanicPct"] = 25] = "HispanicPct";
|
|
319
|
-
DistrictField[DistrictField["PacificPct"] = 26] = "PacificPct";
|
|
320
|
-
DistrictField[DistrictField["AsianPct"] = 27] = "AsianPct";
|
|
321
|
-
DistrictField[DistrictField["NativePct"] = 28] = "NativePct"; // Display
|
|
322
|
-
})(DistrictField = exports.DistrictField || (exports.DistrictField = {}));
|
|
323
291
|
class Districts {
|
|
324
292
|
constructor(s, ds) {
|
|
325
293
|
this._geoProperties = {};
|
|
326
294
|
this._session = s;
|
|
327
295
|
this._shapes = ds;
|
|
328
|
-
this.
|
|
296
|
+
this.table = this.initTable();
|
|
329
297
|
}
|
|
330
298
|
getDistrictShapes() {
|
|
331
299
|
return this._shapes;
|
|
@@ -348,21 +316,44 @@ class Districts {
|
|
|
348
316
|
return null;
|
|
349
317
|
}
|
|
350
318
|
setGeoProperties(i, p) { this._geoProperties[i] = p; }
|
|
351
|
-
numberOfColumns() { return U.countEnumValues(DistrictField); }
|
|
352
319
|
// +1 for dummy unassigned 0 "district" and +1 for N+1 summary "district" for
|
|
353
320
|
// state-level values. Real districts are 1–N.
|
|
354
321
|
numberOfRows() { return this._session.state.nDistricts + 2; }
|
|
355
322
|
numberOfWorkingDistricts() { return this._session.state.nDistricts + 1; }
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
323
|
+
initTable() {
|
|
324
|
+
let nRows = this.numberOfRows(); // # of districts plus unassigned & summary
|
|
325
|
+
const t = {
|
|
326
|
+
totalPop: U.initArray(nRows, null),
|
|
327
|
+
popDevPct: U.initArray(nRows, null),
|
|
328
|
+
bEqualPop: U.initArray(nRows, null),
|
|
329
|
+
bNotEmpty: U.initArray(nRows, null),
|
|
330
|
+
bContiguous: U.initArray(nRows, null),
|
|
331
|
+
bNotEmbedded: U.initArray(nRows, null),
|
|
332
|
+
countySplits: U.initArray(nRows, null),
|
|
333
|
+
demVotes: U.initArray(nRows, null),
|
|
334
|
+
repVotes: U.initArray(nRows, null),
|
|
335
|
+
otherVotes: U.initArray(nRows, null),
|
|
336
|
+
demPct: U.initArray(nRows, null),
|
|
337
|
+
repPct: U.initArray(nRows, null),
|
|
338
|
+
otherPct: U.initArray(nRows, null),
|
|
339
|
+
demSeat: U.initArray(nRows, null),
|
|
340
|
+
totalVAP: U.initArray(nRows, null),
|
|
341
|
+
minorityPop: U.initArray(nRows, null),
|
|
342
|
+
whitePop: U.initArray(nRows, null),
|
|
343
|
+
blackPop: U.initArray(nRows, null),
|
|
344
|
+
hispanicPop: U.initArray(nRows, null),
|
|
345
|
+
pacificPop: U.initArray(nRows, null),
|
|
346
|
+
asianPop: U.initArray(nRows, null),
|
|
347
|
+
nativePop: U.initArray(nRows, null),
|
|
348
|
+
whitePct: U.initArray(nRows, null),
|
|
349
|
+
minorityPct: U.initArray(nRows, null),
|
|
350
|
+
blackPct: U.initArray(nRows, null),
|
|
351
|
+
hispanicPct: U.initArray(nRows, null),
|
|
352
|
+
pacificPct: U.initArray(nRows, null),
|
|
353
|
+
asianPct: U.initArray(nRows, null),
|
|
354
|
+
nativePct: U.initArray(nRows, null)
|
|
355
|
+
};
|
|
356
|
+
return t;
|
|
366
357
|
}
|
|
367
358
|
// This is the workhorse computational routine!
|
|
368
359
|
recalcStatistics(bLog = false) {
|
|
@@ -559,36 +550,34 @@ class Districts {
|
|
|
559
550
|
}
|
|
560
551
|
{ // UPDATE THE DISTRICT STATISTICS
|
|
561
552
|
// NOTE - These are set below for both non-empty & empty districts:
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
//
|
|
566
|
-
//
|
|
567
|
-
this.
|
|
568
|
-
|
|
569
|
-
this.
|
|
570
|
-
this.
|
|
571
|
-
this.
|
|
572
|
-
|
|
573
|
-
this.
|
|
574
|
-
this.
|
|
575
|
-
this.
|
|
576
|
-
this.
|
|
577
|
-
this.
|
|
578
|
-
this.
|
|
579
|
-
this.
|
|
580
|
-
this.
|
|
581
|
-
this.
|
|
582
|
-
this.
|
|
583
|
-
this.
|
|
584
|
-
this.
|
|
585
|
-
this.
|
|
586
|
-
this.
|
|
587
|
-
this.
|
|
588
|
-
this.
|
|
589
|
-
this.
|
|
590
|
-
this.statistics[DistrictField.AsianPct][i] = asianPct;
|
|
591
|
-
this.statistics[DistrictField.NativePct][i] = nativePct;
|
|
553
|
+
// * bNotEmpty;
|
|
554
|
+
// * bContiguous;
|
|
555
|
+
// * bNotEmbedded;
|
|
556
|
+
// * totalPop;
|
|
557
|
+
// * bEqualPop;
|
|
558
|
+
this.table.popDevPct[i] = popDevPct;
|
|
559
|
+
this.table.demVotes[i] = demVotes;
|
|
560
|
+
this.table.repVotes[i] = repVotes;
|
|
561
|
+
this.table.otherVotes[i] = othVotes;
|
|
562
|
+
this.table.demPct[i] = demPct;
|
|
563
|
+
this.table.repPct[i] = repPct;
|
|
564
|
+
this.table.otherPct[i] = othPct;
|
|
565
|
+
this.table.demSeat[i] = DemSeat;
|
|
566
|
+
this.table.whitePop[i] = whitePop;
|
|
567
|
+
this.table.minorityPop[i] = minorityPop;
|
|
568
|
+
this.table.blackPop[i] = blackPop;
|
|
569
|
+
this.table.hispanicPop[i] = hispanicPop;
|
|
570
|
+
this.table.pacificPop[i] = pacificPop;
|
|
571
|
+
this.table.asianPop[i] = asianPop;
|
|
572
|
+
this.table.nativePop[i] = nativePop;
|
|
573
|
+
this.table.totalVAP[i] = totalVAP;
|
|
574
|
+
this.table.whitePct[i] = whitePct;
|
|
575
|
+
this.table.minorityPct[i] = minorityPct;
|
|
576
|
+
this.table.blackPct[i] = blackPct;
|
|
577
|
+
this.table.hispanicPct[i] = hispanicPct;
|
|
578
|
+
this.table.pacificPct[i] = pacificPct;
|
|
579
|
+
this.table.asianPct[i] = asianPct;
|
|
580
|
+
this.table.nativePct[i] = nativePct;
|
|
592
581
|
}
|
|
593
582
|
{ // ACCUMULATE STATE STATISTICS FROM DISTRICT TOTALS
|
|
594
583
|
// 10-22-2020 - Added Other votes
|
|
@@ -608,60 +597,58 @@ class Districts {
|
|
|
608
597
|
}
|
|
609
598
|
}
|
|
610
599
|
else { // If a district is empty, zero these results (vs. null)
|
|
611
|
-
this.
|
|
612
|
-
|
|
613
|
-
this.
|
|
614
|
-
this.
|
|
615
|
-
this.
|
|
616
|
-
|
|
617
|
-
this.
|
|
618
|
-
this.
|
|
619
|
-
this.
|
|
620
|
-
this.
|
|
621
|
-
this.
|
|
622
|
-
this.
|
|
623
|
-
this.
|
|
624
|
-
this.
|
|
625
|
-
this.
|
|
626
|
-
this.
|
|
627
|
-
this.
|
|
628
|
-
this.
|
|
629
|
-
this.
|
|
630
|
-
this.
|
|
631
|
-
this.
|
|
632
|
-
this.
|
|
633
|
-
this.
|
|
634
|
-
this.statistics[DistrictField.AsianPct][i] = 0;
|
|
635
|
-
this.statistics[DistrictField.NativePct][i] = 0;
|
|
600
|
+
this.table.popDevPct[i] = popDevPct;
|
|
601
|
+
this.table.demVotes[i] = 0;
|
|
602
|
+
this.table.repVotes[i] = 0;
|
|
603
|
+
this.table.otherVotes[i] = 0;
|
|
604
|
+
this.table.demPct[i] = 0;
|
|
605
|
+
this.table.repPct[i] = 0;
|
|
606
|
+
this.table.otherPct[i] = 0;
|
|
607
|
+
this.table.demSeat[i] = 0;
|
|
608
|
+
this.table.whitePop[i] = 0;
|
|
609
|
+
this.table.minorityPop[i] = 0;
|
|
610
|
+
this.table.blackPop[i] = 0;
|
|
611
|
+
this.table.hispanicPop[i] = 0;
|
|
612
|
+
this.table.pacificPop[i] = 0;
|
|
613
|
+
this.table.asianPop[i] = 0;
|
|
614
|
+
this.table.nativePop[i] = 0;
|
|
615
|
+
this.table.totalVAP[i] = 0;
|
|
616
|
+
this.table.whitePct[i] = 0;
|
|
617
|
+
this.table.minorityPct[i] = 0;
|
|
618
|
+
this.table.blackPct[i] = 0;
|
|
619
|
+
this.table.hispanicPct[i] = 0;
|
|
620
|
+
this.table.pacificPct[i] = 0;
|
|
621
|
+
this.table.asianPct[i] = 0;
|
|
622
|
+
this.table.nativePct[i] = 0;
|
|
636
623
|
}
|
|
637
624
|
{ // UPDATE THESE DISTRICT STATISTICS, EVEN WHEN THEY ARE EMPTY
|
|
638
|
-
this.
|
|
639
|
-
this.
|
|
640
|
-
this.
|
|
641
|
-
this.
|
|
642
|
-
this.
|
|
643
|
-
this.
|
|
625
|
+
this.table.totalPop[i] = totalPop;
|
|
626
|
+
this.table.bNotEmpty[i] = bNotEmpty;
|
|
627
|
+
this.table.bContiguous[i] = bContiguous;
|
|
628
|
+
this.table.bNotEmbedded[i] = bNotEmbedded;
|
|
629
|
+
this.table.bEqualPop[i] = bEqualPop;
|
|
630
|
+
this.table.countySplits[i] = countySplits;
|
|
644
631
|
}
|
|
645
632
|
}
|
|
646
633
|
// UPDATE STATE STATISTICS
|
|
647
634
|
let summaryRow = this.numberOfRows() - 1;
|
|
648
635
|
// 10-22-2020 - Added Other votes
|
|
649
636
|
if (stateTotVote > 0) {
|
|
650
|
-
this.
|
|
651
|
-
this.
|
|
652
|
-
this.
|
|
653
|
-
this.
|
|
654
|
-
this.
|
|
637
|
+
this.table.demVotes[summaryRow] = stateDemVote;
|
|
638
|
+
this.table.repVotes[summaryRow] = stateRepVote;
|
|
639
|
+
this.table.demPct[summaryRow] = stateDemVote / stateTotVote;
|
|
640
|
+
this.table.repPct[summaryRow] = stateRepVote / stateTotVote;
|
|
641
|
+
this.table.otherPct[summaryRow] = stateOthVote / stateTotVote;
|
|
655
642
|
}
|
|
656
643
|
if (stateVAPPop > 0) {
|
|
657
|
-
this.
|
|
658
|
-
this.
|
|
659
|
-
this.
|
|
660
|
-
this.
|
|
661
|
-
this.
|
|
662
|
-
this.
|
|
663
|
-
this.
|
|
664
|
-
this.
|
|
644
|
+
this.table.totalVAP[summaryRow] = stateVAPPop;
|
|
645
|
+
this.table.whitePct[summaryRow] = stateWhitePop / stateVAPPop;
|
|
646
|
+
this.table.minorityPct[summaryRow] = stateMinorityPop / stateVAPPop;
|
|
647
|
+
this.table.blackPct[summaryRow] = stateBlackPop / stateVAPPop;
|
|
648
|
+
this.table.hispanicPct[summaryRow] = stateHispanicPop / stateVAPPop;
|
|
649
|
+
this.table.pacificPct[summaryRow] = statePacificPop / stateVAPPop;
|
|
650
|
+
this.table.asianPct[summaryRow] = stateAsianPop / stateVAPPop;
|
|
651
|
+
this.table.nativePct[summaryRow] = stateNativePop / stateVAPPop;
|
|
665
652
|
}
|
|
666
653
|
if (bLog) {
|
|
667
654
|
console.log(`${nMissingDataset} features with missing datasets.`);
|
|
@@ -681,43 +668,75 @@ class Districts {
|
|
|
681
668
|
let countyIndex = this._session.counties.indexFromFIPS(countyFIPS);
|
|
682
669
|
return countyIndex;
|
|
683
670
|
}
|
|
671
|
+
// 11-03-2020 - Added for racially polarized voting analysis
|
|
672
|
+
extractVotesByDemographic(districtID, bLog = false) {
|
|
673
|
+
let whitePts = [];
|
|
674
|
+
let minorityPts = [];
|
|
675
|
+
let blackPts = [];
|
|
676
|
+
let hispanicPts = [];
|
|
677
|
+
let pacificPts = [];
|
|
678
|
+
let asianPts = [];
|
|
679
|
+
let nativePts = [];
|
|
680
|
+
// Gather [demographic %, D %] points for the selected district ID
|
|
681
|
+
let i = districtID;
|
|
682
|
+
// HACK - Because "this" gets ghosted inside the forEach loop below
|
|
683
|
+
let outerThis = this;
|
|
684
|
+
// Get the geoIDs assigned to the district
|
|
685
|
+
// Guard against empty districts
|
|
686
|
+
let geoIDs = this._session.plan.geoIDsForDistrictID(i);
|
|
687
|
+
if (geoIDs && (geoIDs.size > 0)) {
|
|
688
|
+
// ... loop over the geoIDs collecting the points for ecological regression
|
|
689
|
+
geoIDs.forEach(function (geoID) {
|
|
690
|
+
// Skip water-only features
|
|
691
|
+
if (!(U.isWaterOnly(geoID))) {
|
|
692
|
+
// Map from geoID to feature index
|
|
693
|
+
let featureID = outerThis._session.features.featureID(geoID);
|
|
694
|
+
let f = outerThis._session.features.featureByIndex(featureID);
|
|
695
|
+
if (!(f == undefined)) {
|
|
696
|
+
// Calculate the Dem two-party vote
|
|
697
|
+
const featureDem = outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
|
|
698
|
+
const featureRep = outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "R" /* RepVotes */);
|
|
699
|
+
const featureTot = outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "Tot" /* TotalVotes */);
|
|
700
|
+
const pctDem = featureDem / (featureDem + featureRep);
|
|
701
|
+
// Calculate the VAP/CVAP percentages by demographic
|
|
702
|
+
const totalVAP = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
|
|
703
|
+
if (totalVAP > 0) {
|
|
704
|
+
const whitePop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
|
|
705
|
+
const pctWhite = whitePop / totalVAP;
|
|
706
|
+
const minorityPop = totalVAP - whitePop;
|
|
707
|
+
const pctMinority = minorityPop / totalVAP;
|
|
708
|
+
const pctBlack = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */) / totalVAP;
|
|
709
|
+
const pctHispanic = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */) / totalVAP;
|
|
710
|
+
const pctPacific = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */) / totalVAP;
|
|
711
|
+
const pctAsian = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */) / totalVAP;
|
|
712
|
+
const pctNative = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */) / totalVAP;
|
|
713
|
+
whitePts.push({ x: pctWhite, y: pctDem });
|
|
714
|
+
minorityPts.push({ x: pctMinority, y: pctDem });
|
|
715
|
+
blackPts.push({ x: pctBlack, y: pctDem });
|
|
716
|
+
hispanicPts.push({ x: pctHispanic, y: pctDem });
|
|
717
|
+
pacificPts.push({ x: pctPacific, y: pctDem });
|
|
718
|
+
asianPts.push({ x: pctAsian, y: pctDem });
|
|
719
|
+
nativePts.push({ x: pctNative, y: pctDem });
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
return {
|
|
725
|
+
white: whitePts,
|
|
726
|
+
minority: minorityPts,
|
|
727
|
+
black: blackPts,
|
|
728
|
+
hispanic: hispanicPts,
|
|
729
|
+
pacific: pacificPts,
|
|
730
|
+
asian: asianPts,
|
|
731
|
+
native: nativePts
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
// If a district is empty
|
|
735
|
+
return undefined;
|
|
736
|
+
}
|
|
684
737
|
}
|
|
685
738
|
exports.Districts = Districts;
|
|
686
739
|
// CLASSES, ETC. FOR FEATURE & COUNTY DATA
|
|
687
|
-
// Types of datasets by feature
|
|
688
|
-
/* 08-13-2020 - Moved to types.ts
|
|
689
|
-
export const enum Dataset
|
|
690
|
-
{
|
|
691
|
-
SHAPES = "SHAPES",
|
|
692
|
-
CENSUS = "CENSUS",
|
|
693
|
-
VAP = "VAP",
|
|
694
|
-
ELECTION = "ELECTION"
|
|
695
|
-
}
|
|
696
|
-
*/
|
|
697
|
-
/* 08-13-2020 - Moved to types.ts
|
|
698
|
-
export type DatasetKeys = {
|
|
699
|
-
SHAPES: string; // A shapefile
|
|
700
|
-
CENSUS: string; // A total population Census dataset
|
|
701
|
-
VAP: string; // A voting age (or citizen voting age) dataset
|
|
702
|
-
ELECTION: string; // An election dataset
|
|
703
|
-
}
|
|
704
|
-
*/
|
|
705
|
-
// Identifiers of fields for each feature in the datasets
|
|
706
|
-
/* 08-13-2020 - Moved to types.ts
|
|
707
|
-
export const enum FeatureField
|
|
708
|
-
{
|
|
709
|
-
TotalPop = "Tot",
|
|
710
|
-
WhitePop = "Wh",
|
|
711
|
-
BlackPop = "BlC",
|
|
712
|
-
HispanicPop = "His",
|
|
713
|
-
AsianPop = "AsnC",
|
|
714
|
-
PacificPop = "PacC",
|
|
715
|
-
NativePop = "NatC",
|
|
716
|
-
DemVotes = "D",
|
|
717
|
-
RepVotes = "R",
|
|
718
|
-
TotalVotes = "Tot"
|
|
719
|
-
}
|
|
720
|
-
*/
|
|
721
740
|
// Wrap data by feature, to abstract the specifics of the internal structure
|
|
722
741
|
class Features {
|
|
723
742
|
constructor(s, data, keys) {
|
|
@@ -1033,7 +1052,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
1033
1052
|
};
|
|
1034
1053
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1035
1054
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
1036
|
-
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
1037
1055
|
// NOTE - The active code is below the long multi-line section to be deleted.
|
|
1038
1056
|
// ANALYZE SIMPLE COUNTY & VTD SPLITTING
|
|
1039
1057
|
/*
|
|
@@ -1076,7 +1094,9 @@ function doFindCountiesSplitUnexpectedly(s, bLog = false) {
|
|
|
1076
1094
|
let countiesSplitUnexpectedly = [];
|
|
1077
1095
|
// FIRST, ANALYZE THE COUNTY SPLITTING FOR THE PLAN
|
|
1078
1096
|
// Get the county-district pivot ("splits")
|
|
1079
|
-
let countiesByDistrict = s.districts.
|
|
1097
|
+
let countiesByDistrict = s.districts.table.countySplits;
|
|
1098
|
+
// TODO - DELETE???
|
|
1099
|
+
// let countiesByDistrict = s.districts.statistics[D.DistrictField.CountySplits];
|
|
1080
1100
|
// countiesByDistrict = countiesByDistrict.slice(1, -1);
|
|
1081
1101
|
// Find the single-county districts, i.e., districts NOT split across counties.
|
|
1082
1102
|
// Ignore the dummy unassigned 0 and N+1 summary "districts."
|
|
@@ -1307,15 +1327,7 @@ exports.scoreKIWYSICompactness = scoreKIWYSICompactness;
|
|
|
1307
1327
|
//
|
|
1308
1328
|
// EQUAL POPULATION
|
|
1309
1329
|
//
|
|
1310
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
1311
|
-
if (mod && mod.__esModule) return mod;
|
|
1312
|
-
var result = {};
|
|
1313
|
-
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
1314
|
-
result["default"] = mod;
|
|
1315
|
-
return result;
|
|
1316
|
-
};
|
|
1317
1330
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1318
|
-
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
1319
1331
|
// NOTE - This validity check is *derived* and depends on population deviation %
|
|
1320
1332
|
// being computed (above) and normalized in test log & scorecard generation.
|
|
1321
1333
|
function doHasEqualPopulations(s, bLog = false) {
|
|
@@ -1338,7 +1350,7 @@ function doHasEqualPopulations(s, bLog = false) {
|
|
|
1338
1350
|
test['details']['deviation'] = popDevPct;
|
|
1339
1351
|
test['details']['thresholds'] = popDevTest['details']['scale'];
|
|
1340
1352
|
// Populate the N+1 summary "district" in district.statistics
|
|
1341
|
-
let bEqualPop = s.districts.
|
|
1353
|
+
let bEqualPop = s.districts.table.bEqualPop;
|
|
1342
1354
|
let summaryRow = s.districts.numberOfRows() - 1;
|
|
1343
1355
|
bEqualPop[summaryRow] = test['score'];
|
|
1344
1356
|
return test;
|
|
@@ -1365,7 +1377,6 @@ function __export(m) {
|
|
|
1365
1377
|
}
|
|
1366
1378
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1367
1379
|
__export(__webpack_require__(/*! ./_api */ "./src/_api.ts"));
|
|
1368
|
-
__export(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
1369
1380
|
__export(__webpack_require__(/*! ./results */ "./src/results.ts"));
|
|
1370
1381
|
__export(__webpack_require__(/*! ./types */ "./src/types.ts"));
|
|
1371
1382
|
|
|
@@ -1384,10 +1395,19 @@ __export(__webpack_require__(/*! ./types */ "./src/types.ts"));
|
|
|
1384
1395
|
//
|
|
1385
1396
|
// PROTECTS MINORITIES
|
|
1386
1397
|
//
|
|
1398
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
1399
|
+
if (mod && mod.__esModule) return mod;
|
|
1400
|
+
var result = {};
|
|
1401
|
+
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
1402
|
+
result["default"] = mod;
|
|
1403
|
+
return result;
|
|
1404
|
+
};
|
|
1387
1405
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
1388
1406
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
1389
1407
|
};
|
|
1390
1408
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1409
|
+
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
1410
|
+
const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
|
|
1391
1411
|
const majority_minority_json_1 = __importDefault(__webpack_require__(/*! ../static/majority-minority.json */ "./static/majority-minority.json"));
|
|
1392
1412
|
const vra5_preclearance_json_1 = __importDefault(__webpack_require__(/*! ../static/vra5-preclearance.json */ "./static/vra5-preclearance.json"));
|
|
1393
1413
|
// TODO - 2020: Update/revise this, when the update comes out in September:
|
|
@@ -1409,6 +1429,75 @@ function getVRASection5(s) {
|
|
|
1409
1429
|
return stateVRAPre;
|
|
1410
1430
|
}
|
|
1411
1431
|
exports.getVRASection5 = getVRASection5;
|
|
1432
|
+
// 11-03-2020 - Added for racially polarized voting analysis
|
|
1433
|
+
// Analyze the degree of racially polarized voting for a district
|
|
1434
|
+
function doAnalyzeRacialPolarization(s, districtID, bLog = false) {
|
|
1435
|
+
const points = s.districts.extractVotesByDemographic(districtID, bLog);
|
|
1436
|
+
if (points === undefined)
|
|
1437
|
+
return undefined;
|
|
1438
|
+
const nDistricts = s.state.nDistricts;
|
|
1439
|
+
const statewide = score_1.getStatewideDemographics(s, bLog);
|
|
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))
|
|
1447
|
+
return undefined;
|
|
1448
|
+
// At this point, at least one single-race/ethnicity minority demographic needs
|
|
1449
|
+
// to be analyzed, so white & all minorities combined will need to be as well.
|
|
1450
|
+
//
|
|
1451
|
+
// const bDoWhite: boolean = (calcProportionalDistricts(statewide.white, nDistricts) > 0) ? true : false;
|
|
1452
|
+
// const bDoMinority: boolean = (calcProportionalDistricts(statewide.minority, nDistricts) > 0) ? true : false;
|
|
1453
|
+
const result = {
|
|
1454
|
+
white: calcMaxVoteShare(points.white),
|
|
1455
|
+
minority: calcMaxVoteShare(points.minority),
|
|
1456
|
+
black: bDoBlack ? calcMaxVoteShare(points.black) : undefined,
|
|
1457
|
+
hispanic: bDoHispanic ? calcMaxVoteShare(points.hispanic) : undefined,
|
|
1458
|
+
pacific: bDoPacific ? calcMaxVoteShare(points.pacific) : undefined,
|
|
1459
|
+
asian: bDoAsian ? calcMaxVoteShare(points.asian) : undefined,
|
|
1460
|
+
native: bDoNative ? calcMaxVoteShare(points.native) : undefined
|
|
1461
|
+
};
|
|
1462
|
+
return result;
|
|
1463
|
+
}
|
|
1464
|
+
exports.doAnalyzeRacialPolarization = doAnalyzeRacialPolarization;
|
|
1465
|
+
// Cloned from dra-score
|
|
1466
|
+
function calcProportionalDistricts(proportion, nDistricts) {
|
|
1467
|
+
const roundUp = 0.0;
|
|
1468
|
+
const fractional = proportion * nDistricts;
|
|
1469
|
+
const integral = Math.round(fractional + roundUp);
|
|
1470
|
+
return integral;
|
|
1471
|
+
}
|
|
1472
|
+
// https://trentrichardson.com/compute-linear-regressions-in-javascript.html
|
|
1473
|
+
function linearRegression(points) {
|
|
1474
|
+
let result = {};
|
|
1475
|
+
const n = points.length;
|
|
1476
|
+
let sum_x = 0;
|
|
1477
|
+
let sum_y = 0;
|
|
1478
|
+
let sum_xy = 0;
|
|
1479
|
+
let sum_xx = 0;
|
|
1480
|
+
let sum_yy = 0;
|
|
1481
|
+
for (let i = 0; i < n; i++) {
|
|
1482
|
+
const pt = points[i];
|
|
1483
|
+
sum_x += pt.x;
|
|
1484
|
+
sum_y += pt.y;
|
|
1485
|
+
sum_xy += (pt.x * pt.y);
|
|
1486
|
+
sum_xx += (pt.x * pt.x);
|
|
1487
|
+
sum_yy += (pt.y * pt.y);
|
|
1488
|
+
}
|
|
1489
|
+
// y = mx + b
|
|
1490
|
+
result['m'] = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
|
|
1491
|
+
result['b'] = (sum_y - result.m * sum_x) / n;
|
|
1492
|
+
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
|
+
return result;
|
|
1494
|
+
}
|
|
1495
|
+
function calcMaxVoteShare(points) {
|
|
1496
|
+
const { m, b, r2 } = linearRegression(points);
|
|
1497
|
+
const maxVAPPct = 1.0; // 100%
|
|
1498
|
+
const maxDemPct = Math.max(0.0, Math.min(1.0, (m * maxVAPPct) + b));
|
|
1499
|
+
return U.trim(maxDemPct);
|
|
1500
|
+
}
|
|
1412
1501
|
|
|
1413
1502
|
|
|
1414
1503
|
/***/ }),
|
|
@@ -1631,7 +1720,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
1631
1720
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1632
1721
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
1633
1722
|
const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
|
|
1634
|
-
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
1635
1723
|
const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
|
|
1636
1724
|
function prepareRequirementsChecklist(s, bLog = false) {
|
|
1637
1725
|
if (!(s.bPostProcessingDone)) {
|
|
@@ -1706,37 +1794,29 @@ function prepareDistrictStatistics(s, bLog = false) {
|
|
|
1706
1794
|
if (!(s.bPostProcessingDone)) {
|
|
1707
1795
|
doAnalyzePostProcessing(s);
|
|
1708
1796
|
}
|
|
1797
|
+
// Transpose the rows & columns, so rows are districts.
|
|
1709
1798
|
let dsTable = [];
|
|
1710
1799
|
for (let i = 0; i < s.districts.numberOfRows(); i++) {
|
|
1711
|
-
let rawRow =
|
|
1712
|
-
i,
|
|
1713
|
-
s.districts.
|
|
1714
|
-
s.districts.
|
|
1715
|
-
s.districts.
|
|
1716
|
-
s.districts.
|
|
1717
|
-
s.districts.
|
|
1718
|
-
s.districts.
|
|
1719
|
-
s.districts.
|
|
1720
|
-
s.districts.
|
|
1721
|
-
s.districts.
|
|
1722
|
-
s.districts.
|
|
1723
|
-
s.districts.
|
|
1724
|
-
s.districts.
|
|
1725
|
-
s.districts.
|
|
1726
|
-
s.districts.
|
|
1727
|
-
s.districts.
|
|
1728
|
-
s.districts.
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
];
|
|
1732
|
-
/* TriState
|
|
1733
|
-
// NOTE - Until we add three-state support top to bottom in Requirements,
|
|
1734
|
-
// map booleans to tri-states here.
|
|
1735
|
-
rawRow[DistrictColumn.bEqualPop] = U.mapBooleanToTriState(rawRow[DistrictColumn.bEqualPop]);
|
|
1736
|
-
rawRow[DistrictColumn.bNotEmpty] = U.mapBooleanToTriState(rawRow[DistrictColumn.bNotEmpty]);
|
|
1737
|
-
rawRow[DistrictColumn.bContiguous] = U.mapBooleanToTriState(rawRow[DistrictColumn.bContiguous]);
|
|
1738
|
-
rawRow[DistrictColumn.bNotEmbedded] = U.mapBooleanToTriState(rawRow[DistrictColumn.bNotEmbedded]);
|
|
1739
|
-
*/
|
|
1800
|
+
let rawRow = {
|
|
1801
|
+
districtID: i,
|
|
1802
|
+
totalPop: s.districts.table.totalPop[i],
|
|
1803
|
+
popDevPct: s.districts.table.popDevPct[i],
|
|
1804
|
+
bEqualPop: s.districts.table.bEqualPop[i],
|
|
1805
|
+
bNotEmpty: s.districts.table.bNotEmpty[i],
|
|
1806
|
+
bContiguous: s.districts.table.bContiguous[i],
|
|
1807
|
+
bNotEmbedded: s.districts.table.bNotEmbedded[i],
|
|
1808
|
+
demPct: s.districts.table.demPct[i],
|
|
1809
|
+
repPct: s.districts.table.repPct[i],
|
|
1810
|
+
othPct: s.districts.table.otherPct[i],
|
|
1811
|
+
whitePct: s.districts.table.whitePct[i],
|
|
1812
|
+
totalVAP: s.districts.table.totalVAP[i],
|
|
1813
|
+
minorityPct: s.districts.table.minorityPct[i],
|
|
1814
|
+
blackPct: s.districts.table.blackPct[i],
|
|
1815
|
+
hispanicPct: s.districts.table.hispanicPct[i],
|
|
1816
|
+
pacificPct: s.districts.table.pacificPct[i],
|
|
1817
|
+
asianPct: s.districts.table.asianPct[i],
|
|
1818
|
+
nativePct: s.districts.table.nativePct[i]
|
|
1819
|
+
};
|
|
1740
1820
|
let readyRow = U.deepCopy(rawRow);
|
|
1741
1821
|
dsTable.push(readyRow);
|
|
1742
1822
|
}
|
|
@@ -1815,7 +1895,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
1815
1895
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1816
1896
|
const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
|
|
1817
1897
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
1818
|
-
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
1819
1898
|
const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
|
|
1820
1899
|
const C = __importStar(__webpack_require__(/*! ./compact */ "./src/compact.ts"));
|
|
1821
1900
|
// PROFILE A PLAN
|
|
@@ -1826,18 +1905,17 @@ function profilePlan(s, bLog = false) {
|
|
|
1826
1905
|
const nDistricts = s.state.nDistricts;
|
|
1827
1906
|
const nCounties = s.counties.nCounties;
|
|
1828
1907
|
const targetSize = Math.round(s.state.totalPop / nDistricts);
|
|
1829
|
-
const popByDistrict = U.deepCopy(s.districts.
|
|
1908
|
+
const popByDistrict = U.deepCopy(s.districts.table.totalPop.slice(1, -1));
|
|
1830
1909
|
const geoPropsByDistrict = makeArrayOfGeoProps(s, bLog);
|
|
1831
1910
|
const splits = makeNakedCxD(s);
|
|
1832
1911
|
const summaryRow = s.districts.numberOfRows() - 1;
|
|
1833
1912
|
// 10-22-2020 - Converted Dem + Rep + Other = Total to two-party vote shares for analytics.
|
|
1834
|
-
const demVote = s.districts.
|
|
1835
|
-
const repVote = s.districts.
|
|
1913
|
+
const demVote = s.districts.table.demVotes[summaryRow];
|
|
1914
|
+
const repVote = s.districts.table.repVotes[summaryRow];
|
|
1836
1915
|
const statewideVf = U.trim(demVote / (demVote + repVote), KEEP_DECIMALS);
|
|
1837
|
-
// const statewideVf: number = U.trim(s.districts.statistics[D.DistrictField.DemPct][summaryRow], 6);
|
|
1838
1916
|
let vpiArray = [];
|
|
1839
|
-
const demVotes = U.deepCopy(s.districts.
|
|
1840
|
-
const repVotes = U.deepCopy(s.districts.
|
|
1917
|
+
const demVotes = U.deepCopy(s.districts.table.demVotes.slice(1, -1));
|
|
1918
|
+
const repVotes = U.deepCopy(s.districts.table.repVotes.slice(1, -1));
|
|
1841
1919
|
for (let districtID = 1; districtID <= nDistricts; districtID++) {
|
|
1842
1920
|
const D = demVotes[districtID - 1];
|
|
1843
1921
|
const R = repVotes[districtID - 1];
|
|
@@ -1845,7 +1923,6 @@ function profilePlan(s, bLog = false) {
|
|
|
1845
1923
|
const v = (T > 0) ? U.trim(D / T, KEEP_DECIMALS) : 0;
|
|
1846
1924
|
vpiArray.push(v);
|
|
1847
1925
|
}
|
|
1848
|
-
// const vpiArray: number[] = U.deepCopy(s.districts.statistics[D.DistrictField.DemPct].slice(1, -1)) as number[];
|
|
1849
1926
|
const statewideDemographics = getStatewideDemographics(s);
|
|
1850
1927
|
const demographicsByDistrict = getDemographicsByDistrict(s);
|
|
1851
1928
|
const profile = {
|
|
@@ -1876,7 +1953,7 @@ exports.profilePlan = profilePlan;
|
|
|
1876
1953
|
// unassigned precincts & state summary and an extra 0 county. But dra-score takes
|
|
1877
1954
|
// a simple 1–D x 1–C splits array (zero-based, of course).
|
|
1878
1955
|
function makeNakedCxD(s, bLog = false) {
|
|
1879
|
-
const adornedCxD = s.districts.
|
|
1956
|
+
const adornedCxD = s.districts.table.countySplits;
|
|
1880
1957
|
let CxD = [];
|
|
1881
1958
|
// Remove the unassigned & total dummy "districts"
|
|
1882
1959
|
for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
|
|
@@ -1905,13 +1982,13 @@ function getDemographicsByDistrict(s, bLog = false) {
|
|
|
1905
1982
|
// Remove the unassigned & total dummy "districts"
|
|
1906
1983
|
for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
|
|
1907
1984
|
const districtDemographics = {
|
|
1908
|
-
white: U.trim(s.districts.
|
|
1909
|
-
minority: U.trim(s.districts.
|
|
1910
|
-
black: U.trim(s.districts.
|
|
1911
|
-
hispanic: U.trim(s.districts.
|
|
1912
|
-
pacific: U.trim(s.districts.
|
|
1913
|
-
asian: U.trim(s.districts.
|
|
1914
|
-
native: U.trim(s.districts.
|
|
1985
|
+
white: U.trim(s.districts.table.whitePct[districtID], KEEP_DECIMALS),
|
|
1986
|
+
minority: U.trim(s.districts.table.minorityPct[districtID], KEEP_DECIMALS),
|
|
1987
|
+
black: U.trim(s.districts.table.blackPct[districtID], KEEP_DECIMALS),
|
|
1988
|
+
hispanic: U.trim(s.districts.table.hispanicPct[districtID], KEEP_DECIMALS),
|
|
1989
|
+
pacific: U.trim(s.districts.table.pacificPct[districtID], KEEP_DECIMALS),
|
|
1990
|
+
asian: U.trim(s.districts.table.asianPct[districtID], KEEP_DECIMALS),
|
|
1991
|
+
native: U.trim(s.districts.table.nativePct[districtID], KEEP_DECIMALS)
|
|
1915
1992
|
};
|
|
1916
1993
|
demographicsArray.push(districtDemographics);
|
|
1917
1994
|
}
|
|
@@ -1920,16 +1997,17 @@ function getDemographicsByDistrict(s, bLog = false) {
|
|
|
1920
1997
|
function getStatewideDemographics(s, bLog = false) {
|
|
1921
1998
|
const summaryRow = s.districts.numberOfRows() - 1;
|
|
1922
1999
|
const demographics = {
|
|
1923
|
-
white: U.trim(s.districts.
|
|
1924
|
-
minority: U.trim(s.districts.
|
|
1925
|
-
black: U.trim(s.districts.
|
|
1926
|
-
hispanic: U.trim(s.districts.
|
|
1927
|
-
pacific: U.trim(s.districts.
|
|
1928
|
-
asian: U.trim(s.districts.
|
|
1929
|
-
native: U.trim(s.districts.
|
|
2000
|
+
white: U.trim(s.districts.table.whitePct[summaryRow], KEEP_DECIMALS),
|
|
2001
|
+
minority: U.trim(s.districts.table.minorityPct[summaryRow], KEEP_DECIMALS),
|
|
2002
|
+
black: U.trim(s.districts.table.blackPct[summaryRow], KEEP_DECIMALS),
|
|
2003
|
+
hispanic: U.trim(s.districts.table.hispanicPct[summaryRow], KEEP_DECIMALS),
|
|
2004
|
+
pacific: U.trim(s.districts.table.pacificPct[summaryRow], KEEP_DECIMALS),
|
|
2005
|
+
asian: U.trim(s.districts.table.asianPct[summaryRow], KEEP_DECIMALS),
|
|
2006
|
+
native: U.trim(s.districts.table.nativePct[summaryRow], KEEP_DECIMALS)
|
|
1930
2007
|
};
|
|
1931
2008
|
return demographics;
|
|
1932
2009
|
}
|
|
2010
|
+
exports.getStatewideDemographics = getStatewideDemographics;
|
|
1933
2011
|
// SCORE A PLAN
|
|
1934
2012
|
function scorePlan(s, p, bLog = false, overridesJSON) {
|
|
1935
2013
|
let scorer = new Score.Scorer();
|
|
@@ -1943,9 +2021,9 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
|
|
|
1943
2021
|
test['score'] = popDev;
|
|
1944
2022
|
test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
|
|
1945
2023
|
// Populate the N+1 summary "district" in district.statistics
|
|
1946
|
-
let totalPop = s.districts.
|
|
1947
|
-
let popDevPct = s.districts.
|
|
1948
|
-
let totalVAP = s.districts.
|
|
2024
|
+
let totalPop = s.districts.table.totalPop;
|
|
2025
|
+
let popDevPct = s.districts.table.popDevPct;
|
|
2026
|
+
let totalVAP = s.districts.table.totalVAP;
|
|
1949
2027
|
const summaryRow = s.districts.numberOfRows() - 1;
|
|
1950
2028
|
totalPop[summaryRow] = p.population.targetSize;
|
|
1951
2029
|
popDevPct[summaryRow] = popDev;
|
|
@@ -2299,7 +2377,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
2299
2377
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
2300
2378
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
2301
2379
|
const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
|
|
2302
|
-
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
2303
2380
|
//
|
|
2304
2381
|
// COMPLETE - Are all geo's assigned to a district, and do all districts have
|
|
2305
2382
|
// at least one geo assigned to them?
|
|
@@ -2308,7 +2385,7 @@ function doIsComplete(s, bLog = false) {
|
|
|
2308
2385
|
let test = s.getTest(0 /* Complete */);
|
|
2309
2386
|
// Get the by-district results, including the dummy unassigned district,
|
|
2310
2387
|
// but ignoring the N+1 summary district
|
|
2311
|
-
let bNotEmptyByDistrict = s.districts.
|
|
2388
|
+
let bNotEmptyByDistrict = s.districts.table.bNotEmpty;
|
|
2312
2389
|
bNotEmptyByDistrict = bNotEmptyByDistrict.slice(0, -1);
|
|
2313
2390
|
// Are all features assigned to districts?
|
|
2314
2391
|
// Check the dummy district that holds any unassigned features.
|
|
@@ -2374,7 +2451,7 @@ function doIsComplete(s, bLog = false) {
|
|
|
2374
2451
|
test['details']['emptyDistricts'] = emptyDistricts;
|
|
2375
2452
|
}
|
|
2376
2453
|
// Populate the N+1 summary "district" in district.statistics
|
|
2377
|
-
let bNotEmpty = s.districts.
|
|
2454
|
+
let bNotEmpty = s.districts.table.bNotEmpty;
|
|
2378
2455
|
let summaryRow = s.districts.numberOfRows() - 1;
|
|
2379
2456
|
bNotEmpty[summaryRow] = test['score'];
|
|
2380
2457
|
return test;
|
|
@@ -2392,7 +2469,7 @@ function doIsContiguous(s, bLog = false) {
|
|
|
2392
2469
|
let test = s.getTest(1 /* Contiguous */);
|
|
2393
2470
|
// Get the contiguity of each district. Ignore dummy unassigned district
|
|
2394
2471
|
// and the N+1 summary district.
|
|
2395
|
-
let bContiguousByDistrict = s.districts.
|
|
2472
|
+
let bContiguousByDistrict = s.districts.table.bContiguous;
|
|
2396
2473
|
bContiguousByDistrict = bContiguousByDistrict.slice(1, -1);
|
|
2397
2474
|
// If any real districts aren't contiguous, mark the plan as not contiguous
|
|
2398
2475
|
let bMapContiguous = U.andArray(bContiguousByDistrict);
|
|
@@ -2410,7 +2487,7 @@ function doIsContiguous(s, bLog = false) {
|
|
|
2410
2487
|
test['details'] = { 'discontiguousDistricts': discontiguousDistricts };
|
|
2411
2488
|
}
|
|
2412
2489
|
// Populate the N+1 summary "district" in district.statistics
|
|
2413
|
-
let bContiguous = s.districts.
|
|
2490
|
+
let bContiguous = s.districts.table.bContiguous;
|
|
2414
2491
|
let summaryRow = s.districts.numberOfRows() - 1;
|
|
2415
2492
|
bContiguous[summaryRow] = test['score'];
|
|
2416
2493
|
return test;
|
|
@@ -2433,7 +2510,7 @@ function doIsFreeOfHoles(s, bLog = false) {
|
|
|
2433
2510
|
let embeddedDistricts = [];
|
|
2434
2511
|
// Get the embeddedness of each district. Ignore dummy unassigned district
|
|
2435
2512
|
// and the N+1 summary district.
|
|
2436
|
-
let bNotEmbeddedByDistrict = s.districts.
|
|
2513
|
+
let bNotEmbeddedByDistrict = s.districts.table.bNotEmbedded;
|
|
2437
2514
|
bNotEmbeddedByDistrict = bNotEmbeddedByDistrict.slice(1, -1);
|
|
2438
2515
|
let districtID = 1;
|
|
2439
2516
|
bNotEmbeddedByDistrict.forEach(function (bDistrictNotEmbedded) {
|
|
@@ -2449,7 +2526,7 @@ function doIsFreeOfHoles(s, bLog = false) {
|
|
|
2449
2526
|
test['details'] = { 'embeddedDistricts': embeddedDistricts };
|
|
2450
2527
|
}
|
|
2451
2528
|
// Populate the N+1 summary "district" in district.statistics
|
|
2452
|
-
let bNotEmbedded = s.districts.
|
|
2529
|
+
let bNotEmbedded = s.districts.table.bNotEmbedded;
|
|
2453
2530
|
let summaryRow = s.districts.numberOfRows() - 1;
|
|
2454
2531
|
bNotEmbedded[summaryRow] = test['score'];
|
|
2455
2532
|
return test;
|