@dra2020/district-analytics 10.0.8 → 10.0.11

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 CHANGED
@@ -26,11 +26,14 @@ sr['config'] = config as T.Dict;
26
26
  let s = new DA.AnalyticsSession(sr);
27
27
 
28
28
  let bLog = false;
29
- s.analyzePlan();
29
+ s.analyzePlan(bLog);
30
30
 
31
- // TODO - UPDATE ...
32
- let pa: DA.PlanAnalytics = s.getPlanAnalytics(bLog);
33
- let ds: DA.DistrictStatistics = s.getDistrictStatistics(bLog);
31
+ const statistics: DA.DistrictStatistics = s.getDistrictStatistics();
32
+ const requirements: DA.RequirementsChecklist = s.getRequirementsChecklist();
33
+ const scorecard: DA.Scorecard = s.getPlanScorecard();
34
+ const ratings: DA.Ratings = s.getRatings();
35
+
36
+ const discontiguous = DA.GeoFeatureCollection = s.getDiscontiguousDistrictFeatures();
34
37
 
35
38
  ```
36
39
 
@@ -276,56 +276,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
276
276
  const G = __importStar(__webpack_require__(/*! @dra2020/dra-graph */ "@dra2020/dra-graph"));
277
277
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
278
278
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
279
- // import { isConnected, isEmbedded } from './valid';
280
279
  const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
281
280
  const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
282
281
  // DEBUG COUNTERS
283
282
  let nMissingDataset = 0;
284
283
  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
284
  class Districts {
324
285
  constructor(s, ds) {
325
286
  this._geoProperties = {};
326
287
  this._session = s;
327
288
  this._shapes = ds;
328
- this.statistics = this.initStatistics();
289
+ this.table = this.initTable();
329
290
  }
330
291
  getDistrictShapes() {
331
292
  return this._shapes;
@@ -348,21 +309,44 @@ class Districts {
348
309
  return null;
349
310
  }
350
311
  setGeoProperties(i, p) { this._geoProperties[i] = p; }
351
- numberOfColumns() { return U.countEnumValues(DistrictField); }
352
312
  // +1 for dummy unassigned 0 "district" and +1 for N+1 summary "district" for
353
313
  // state-level values. Real districts are 1–N.
354
314
  numberOfRows() { return this._session.state.nDistricts + 2; }
355
315
  numberOfWorkingDistricts() { return this._session.state.nDistricts + 1; }
356
- // This is the core statistics 2D matrix:
357
- // Fields on the outside, districts on the inside
358
- initStatistics() {
359
- let nRows = this.numberOfRows();
360
- let nCols = this.numberOfColumns();
361
- let outer = U.initArray(nCols, undefined);
362
- for (let i = 0; i < nCols; i++) {
363
- outer[i] = U.initArray(nRows, null);
364
- }
365
- return outer;
316
+ initTable() {
317
+ let nRows = this.numberOfRows(); // # of districts plus unassigned & summary
318
+ const t = {
319
+ totalPop: U.initArray(nRows, null),
320
+ popDevPct: U.initArray(nRows, null),
321
+ bEqualPop: U.initArray(nRows, null),
322
+ bNotEmpty: U.initArray(nRows, null),
323
+ bContiguous: U.initArray(nRows, null),
324
+ bNotEmbedded: U.initArray(nRows, null),
325
+ countySplits: U.initArray(nRows, null),
326
+ demVotes: U.initArray(nRows, null),
327
+ repVotes: U.initArray(nRows, null),
328
+ otherVotes: U.initArray(nRows, null),
329
+ demPct: U.initArray(nRows, null),
330
+ repPct: U.initArray(nRows, null),
331
+ otherPct: U.initArray(nRows, null),
332
+ demSeat: U.initArray(nRows, null),
333
+ totalVAP: U.initArray(nRows, null),
334
+ minorityPop: U.initArray(nRows, null),
335
+ whitePop: U.initArray(nRows, null),
336
+ blackPop: U.initArray(nRows, null),
337
+ hispanicPop: U.initArray(nRows, null),
338
+ pacificPop: U.initArray(nRows, null),
339
+ asianPop: U.initArray(nRows, null),
340
+ nativePop: U.initArray(nRows, null),
341
+ whitePct: U.initArray(nRows, null),
342
+ minorityPct: U.initArray(nRows, null),
343
+ blackPct: U.initArray(nRows, null),
344
+ hispanicPct: U.initArray(nRows, null),
345
+ pacificPct: U.initArray(nRows, null),
346
+ asianPct: U.initArray(nRows, null),
347
+ nativePct: U.initArray(nRows, null)
348
+ };
349
+ return t;
366
350
  }
367
351
  // This is the workhorse computational routine!
368
352
  recalcStatistics(bLog = false) {
@@ -559,36 +543,34 @@ class Districts {
559
543
  }
560
544
  { // UPDATE THE DISTRICT STATISTICS
561
545
  // NOTE - These are set below for both non-empty & empty districts:
562
- // this.statistics[DistrictField.bNotEmpty][i] = bNotEmpty;
563
- // this.statistics[DistrictField.bContiguous][i] = bContiguous;
564
- // this.statistics[DistrictField.bNotEmbedded][i] = bNotEmbedded;
565
- // this.statistics[DistrictField.TotalPop][i] = totalPop;
566
- // this.statistics[DistrictField.bEqualPop][i] = bEqualPop;
567
- this.statistics[DistrictField.PopDevPct][i] = popDevPct;
568
- // 10-22-2020 - Added Other votes
569
- this.statistics[DistrictField.DemVotes][i] = demVotes;
570
- this.statistics[DistrictField.RepVotes][i] = repVotes;
571
- this.statistics[DistrictField.OtherVotes][i] = othVotes;
572
- // this.statistics[DistrictField.TwoPartyVote][i] = totVotes;
573
- this.statistics[DistrictField.DemPct][i] = demPct;
574
- this.statistics[DistrictField.RepPct][i] = repPct;
575
- this.statistics[DistrictField.OtherPct][i] = othPct;
576
- this.statistics[DistrictField.DemSeat][i] = DemSeat;
577
- this.statistics[DistrictField.WhitePop][i] = whitePop;
578
- this.statistics[DistrictField.MinorityPop][i] = minorityPop;
579
- this.statistics[DistrictField.BlackPop][i] = blackPop;
580
- this.statistics[DistrictField.HispanicPop][i] = hispanicPop;
581
- this.statistics[DistrictField.PacificPop][i] = pacificPop;
582
- this.statistics[DistrictField.AsianPop][i] = asianPop;
583
- this.statistics[DistrictField.NativePop][i] = nativePop;
584
- this.statistics[DistrictField.TotalVAP][i] = totalVAP;
585
- this.statistics[DistrictField.WhitePct][i] = whitePct;
586
- this.statistics[DistrictField.MinorityPct][i] = minorityPct;
587
- this.statistics[DistrictField.BlackPct][i] = blackPct;
588
- this.statistics[DistrictField.HispanicPct][i] = hispanicPct;
589
- this.statistics[DistrictField.PacificPct][i] = pacificPct;
590
- this.statistics[DistrictField.AsianPct][i] = asianPct;
591
- this.statistics[DistrictField.NativePct][i] = nativePct;
546
+ // * bNotEmpty;
547
+ // * bContiguous;
548
+ // * bNotEmbedded;
549
+ // * totalPop;
550
+ // * bEqualPop;
551
+ this.table.popDevPct[i] = popDevPct;
552
+ this.table.demVotes[i] = demVotes;
553
+ this.table.repVotes[i] = repVotes;
554
+ this.table.otherVotes[i] = othVotes;
555
+ this.table.demPct[i] = demPct;
556
+ this.table.repPct[i] = repPct;
557
+ this.table.otherPct[i] = othPct;
558
+ this.table.demSeat[i] = DemSeat;
559
+ this.table.whitePop[i] = whitePop;
560
+ this.table.minorityPop[i] = minorityPop;
561
+ this.table.blackPop[i] = blackPop;
562
+ this.table.hispanicPop[i] = hispanicPop;
563
+ this.table.pacificPop[i] = pacificPop;
564
+ this.table.asianPop[i] = asianPop;
565
+ this.table.nativePop[i] = nativePop;
566
+ this.table.totalVAP[i] = totalVAP;
567
+ this.table.whitePct[i] = whitePct;
568
+ this.table.minorityPct[i] = minorityPct;
569
+ this.table.blackPct[i] = blackPct;
570
+ this.table.hispanicPct[i] = hispanicPct;
571
+ this.table.pacificPct[i] = pacificPct;
572
+ this.table.asianPct[i] = asianPct;
573
+ this.table.nativePct[i] = nativePct;
592
574
  }
593
575
  { // ACCUMULATE STATE STATISTICS FROM DISTRICT TOTALS
594
576
  // 10-22-2020 - Added Other votes
@@ -608,60 +590,58 @@ class Districts {
608
590
  }
609
591
  }
610
592
  else { // If a district is empty, zero these results (vs. null)
611
- this.statistics[DistrictField.PopDevPct][i] = popDevPct;
612
- // 10-22-2020 - Added Other votes
613
- this.statistics[DistrictField.DemVotes][i] = 0;
614
- this.statistics[DistrictField.RepVotes][i] = 0;
615
- this.statistics[DistrictField.OtherVotes][i] = 0;
616
- // this.statistics[DistrictField.TwoPartyVote][i] = 0;
617
- this.statistics[DistrictField.DemPct][i] = 0;
618
- this.statistics[DistrictField.RepPct][i] = 0;
619
- this.statistics[DistrictField.OtherPct][i] = 0;
620
- this.statistics[DistrictField.DemSeat][i] = 0;
621
- this.statistics[DistrictField.WhitePop][i] = 0;
622
- this.statistics[DistrictField.MinorityPop][i] = 0;
623
- this.statistics[DistrictField.BlackPop][i] = 0;
624
- this.statistics[DistrictField.HispanicPop][i] = 0;
625
- this.statistics[DistrictField.PacificPop][i] = 0;
626
- this.statistics[DistrictField.AsianPop][i] = 0;
627
- this.statistics[DistrictField.NativePop][i] = 0;
628
- this.statistics[DistrictField.TotalVAP][i] = 0;
629
- this.statistics[DistrictField.WhitePct][i] = 0;
630
- this.statistics[DistrictField.MinorityPct][i] = 0;
631
- this.statistics[DistrictField.BlackPct][i] = 0;
632
- this.statistics[DistrictField.HispanicPct][i] = 0;
633
- this.statistics[DistrictField.PacificPct][i] = 0;
634
- this.statistics[DistrictField.AsianPct][i] = 0;
635
- this.statistics[DistrictField.NativePct][i] = 0;
593
+ this.table.popDevPct[i] = popDevPct;
594
+ this.table.demVotes[i] = 0;
595
+ this.table.repVotes[i] = 0;
596
+ this.table.otherVotes[i] = 0;
597
+ this.table.demPct[i] = 0;
598
+ this.table.repPct[i] = 0;
599
+ this.table.otherPct[i] = 0;
600
+ this.table.demSeat[i] = 0;
601
+ this.table.whitePop[i] = 0;
602
+ this.table.minorityPop[i] = 0;
603
+ this.table.blackPop[i] = 0;
604
+ this.table.hispanicPop[i] = 0;
605
+ this.table.pacificPop[i] = 0;
606
+ this.table.asianPop[i] = 0;
607
+ this.table.nativePop[i] = 0;
608
+ this.table.totalVAP[i] = 0;
609
+ this.table.whitePct[i] = 0;
610
+ this.table.minorityPct[i] = 0;
611
+ this.table.blackPct[i] = 0;
612
+ this.table.hispanicPct[i] = 0;
613
+ this.table.pacificPct[i] = 0;
614
+ this.table.asianPct[i] = 0;
615
+ this.table.nativePct[i] = 0;
636
616
  }
637
617
  { // UPDATE THESE DISTRICT STATISTICS, EVEN WHEN THEY ARE EMPTY
638
- this.statistics[DistrictField.TotalPop][i] = totalPop;
639
- this.statistics[DistrictField.bNotEmpty][i] = bNotEmpty;
640
- this.statistics[DistrictField.bContiguous][i] = bContiguous;
641
- this.statistics[DistrictField.bNotEmbedded][i] = bNotEmbedded;
642
- this.statistics[DistrictField.bEqualPop][i] = bEqualPop;
643
- this.statistics[DistrictField.CountySplits][i] = countySplits;
618
+ this.table.totalPop[i] = totalPop;
619
+ this.table.bNotEmpty[i] = bNotEmpty;
620
+ this.table.bContiguous[i] = bContiguous;
621
+ this.table.bNotEmbedded[i] = bNotEmbedded;
622
+ this.table.bEqualPop[i] = bEqualPop;
623
+ this.table.countySplits[i] = countySplits;
644
624
  }
645
625
  }
646
626
  // UPDATE STATE STATISTICS
647
627
  let summaryRow = this.numberOfRows() - 1;
648
628
  // 10-22-2020 - Added Other votes
649
629
  if (stateTotVote > 0) {
650
- this.statistics[DistrictField.DemVotes][summaryRow] = stateDemVote;
651
- this.statistics[DistrictField.RepVotes][summaryRow] = stateRepVote;
652
- this.statistics[DistrictField.DemPct][summaryRow] = stateDemVote / stateTotVote;
653
- this.statistics[DistrictField.RepPct][summaryRow] = stateRepVote / stateTotVote;
654
- this.statistics[DistrictField.OtherPct][summaryRow] = stateOthVote / stateTotVote;
630
+ this.table.demVotes[summaryRow] = stateDemVote;
631
+ this.table.repVotes[summaryRow] = stateRepVote;
632
+ this.table.demPct[summaryRow] = stateDemVote / stateTotVote;
633
+ this.table.repPct[summaryRow] = stateRepVote / stateTotVote;
634
+ this.table.otherPct[summaryRow] = stateOthVote / stateTotVote;
655
635
  }
656
636
  if (stateVAPPop > 0) {
657
- this.statistics[DistrictField.TotalVAP][summaryRow] = stateVAPPop;
658
- this.statistics[DistrictField.WhitePct][summaryRow] = stateWhitePop / stateVAPPop;
659
- this.statistics[DistrictField.MinorityPct][summaryRow] = stateMinorityPop / stateVAPPop;
660
- this.statistics[DistrictField.BlackPct][summaryRow] = stateBlackPop / stateVAPPop;
661
- this.statistics[DistrictField.HispanicPct][summaryRow] = stateHispanicPop / stateVAPPop;
662
- this.statistics[DistrictField.PacificPct][summaryRow] = statePacificPop / stateVAPPop;
663
- this.statistics[DistrictField.AsianPct][summaryRow] = stateAsianPop / stateVAPPop;
664
- this.statistics[DistrictField.NativePct][summaryRow] = stateNativePop / stateVAPPop;
637
+ this.table.totalVAP[summaryRow] = stateVAPPop;
638
+ this.table.whitePct[summaryRow] = stateWhitePop / stateVAPPop;
639
+ this.table.minorityPct[summaryRow] = stateMinorityPop / stateVAPPop;
640
+ this.table.blackPct[summaryRow] = stateBlackPop / stateVAPPop;
641
+ this.table.hispanicPct[summaryRow] = stateHispanicPop / stateVAPPop;
642
+ this.table.pacificPct[summaryRow] = statePacificPop / stateVAPPop;
643
+ this.table.asianPct[summaryRow] = stateAsianPop / stateVAPPop;
644
+ this.table.nativePct[summaryRow] = stateNativePop / stateVAPPop;
665
645
  }
666
646
  if (bLog) {
667
647
  console.log(`${nMissingDataset} features with missing datasets.`);
@@ -684,40 +664,6 @@ class Districts {
684
664
  }
685
665
  exports.Districts = Districts;
686
666
  // 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
667
  // Wrap data by feature, to abstract the specifics of the internal structure
722
668
  class Features {
723
669
  constructor(s, data, keys) {
@@ -1033,7 +979,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
1033
979
  };
1034
980
  Object.defineProperty(exports, "__esModule", { value: true });
1035
981
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1036
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1037
982
  // NOTE - The active code is below the long multi-line section to be deleted.
1038
983
  // ANALYZE SIMPLE COUNTY & VTD SPLITTING
1039
984
  /*
@@ -1076,7 +1021,9 @@ function doFindCountiesSplitUnexpectedly(s, bLog = false) {
1076
1021
  let countiesSplitUnexpectedly = [];
1077
1022
  // FIRST, ANALYZE THE COUNTY SPLITTING FOR THE PLAN
1078
1023
  // Get the county-district pivot ("splits")
1079
- let countiesByDistrict = s.districts.statistics[D.DistrictField.CountySplits];
1024
+ let countiesByDistrict = s.districts.table.countySplits;
1025
+ // TODO - DELETE???
1026
+ // let countiesByDistrict = s.districts.statistics[D.DistrictField.CountySplits];
1080
1027
  // countiesByDistrict = countiesByDistrict.slice(1, -1);
1081
1028
  // Find the single-county districts, i.e., districts NOT split across counties.
1082
1029
  // Ignore the dummy unassigned 0 and N+1 summary "districts."
@@ -1307,15 +1254,7 @@ exports.scoreKIWYSICompactness = scoreKIWYSICompactness;
1307
1254
  //
1308
1255
  // EQUAL POPULATION
1309
1256
  //
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
1257
  Object.defineProperty(exports, "__esModule", { value: true });
1318
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1319
1258
  // NOTE - This validity check is *derived* and depends on population deviation %
1320
1259
  // being computed (above) and normalized in test log & scorecard generation.
1321
1260
  function doHasEqualPopulations(s, bLog = false) {
@@ -1338,7 +1277,7 @@ function doHasEqualPopulations(s, bLog = false) {
1338
1277
  test['details']['deviation'] = popDevPct;
1339
1278
  test['details']['thresholds'] = popDevTest['details']['scale'];
1340
1279
  // Populate the N+1 summary "district" in district.statistics
1341
- let bEqualPop = s.districts.statistics[D.DistrictField.bEqualPop];
1280
+ let bEqualPop = s.districts.table.bEqualPop;
1342
1281
  let summaryRow = s.districts.numberOfRows() - 1;
1343
1282
  bEqualPop[summaryRow] = test['score'];
1344
1283
  return test;
@@ -1365,7 +1304,6 @@ function __export(m) {
1365
1304
  }
1366
1305
  Object.defineProperty(exports, "__esModule", { value: true });
1367
1306
  __export(__webpack_require__(/*! ./_api */ "./src/_api.ts"));
1368
- __export(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1369
1307
  __export(__webpack_require__(/*! ./results */ "./src/results.ts"));
1370
1308
  __export(__webpack_require__(/*! ./types */ "./src/types.ts"));
1371
1309
 
@@ -1631,7 +1569,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
1631
1569
  Object.defineProperty(exports, "__esModule", { value: true });
1632
1570
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1633
1571
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
1634
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1635
1572
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
1636
1573
  function prepareRequirementsChecklist(s, bLog = false) {
1637
1574
  if (!(s.bPostProcessingDone)) {
@@ -1706,41 +1643,29 @@ function prepareDistrictStatistics(s, bLog = false) {
1706
1643
  if (!(s.bPostProcessingDone)) {
1707
1644
  doAnalyzePostProcessing(s);
1708
1645
  }
1646
+ // Transpose the rows & columns, so rows are districts.
1709
1647
  let dsTable = [];
1710
1648
  for (let i = 0; i < s.districts.numberOfRows(); i++) {
1711
- let rawRow = [
1712
- i,
1713
- s.districts.statistics[D.DistrictField.TotalPop][i],
1714
- s.districts.statistics[D.DistrictField.PopDevPct][i],
1715
- s.districts.statistics[D.DistrictField.bEqualPop][i],
1716
- s.districts.statistics[D.DistrictField.bNotEmpty][i],
1717
- s.districts.statistics[D.DistrictField.bContiguous][i],
1718
- s.districts.statistics[D.DistrictField.bNotEmbedded][i],
1719
- s.districts.statistics[D.DistrictField.DemPct][i],
1720
- s.districts.statistics[D.DistrictField.RepPct][i],
1721
- s.districts.statistics[D.DistrictField.WhitePct][i],
1722
- s.districts.statistics[D.DistrictField.MinorityPct][i],
1723
- s.districts.statistics[D.DistrictField.BlackPct][i],
1724
- s.districts.statistics[D.DistrictField.HispanicPct][i],
1725
- s.districts.statistics[D.DistrictField.PacificPct][i],
1726
- s.districts.statistics[D.DistrictField.AsianPct][i],
1727
- s.districts.statistics[D.DistrictField.NativePct][i],
1728
- s.districts.statistics[D.DistrictField.TotalVAP][i],
1729
- // 10-23-2020 - Added Other vote percentage
1730
- s.districts.statistics[D.DistrictField.OtherPct][i],
1731
- ];
1732
- rawRow[3 /* bEqualPop */] = rawRow[3 /* bEqualPop */];
1733
- rawRow[4 /* bNotEmpty */] = rawRow[4 /* bNotEmpty */];
1734
- rawRow[5 /* bContiguous */] = rawRow[5 /* bContiguous */];
1735
- rawRow[6 /* bNotEmbedded */] = rawRow[6 /* bNotEmbedded */];
1736
- /* TriState
1737
- // NOTE - Until we add three-state support top to bottom in Requirements,
1738
- // map booleans to tri-states here.
1739
- rawRow[DistrictColumn.bEqualPop] = U.mapBooleanToTriState(rawRow[DistrictColumn.bEqualPop]);
1740
- rawRow[DistrictColumn.bNotEmpty] = U.mapBooleanToTriState(rawRow[DistrictColumn.bNotEmpty]);
1741
- rawRow[DistrictColumn.bContiguous] = U.mapBooleanToTriState(rawRow[DistrictColumn.bContiguous]);
1742
- rawRow[DistrictColumn.bNotEmbedded] = U.mapBooleanToTriState(rawRow[DistrictColumn.bNotEmbedded]);
1743
- */
1649
+ let rawRow = {
1650
+ districtID: i,
1651
+ totalPop: s.districts.table.totalPop[i],
1652
+ popDevPct: s.districts.table.popDevPct[i],
1653
+ bEqualPop: s.districts.table.bEqualPop[i],
1654
+ bNotEmpty: s.districts.table.bNotEmpty[i],
1655
+ bContiguous: s.districts.table.bContiguous[i],
1656
+ bNotEmbedded: s.districts.table.bNotEmbedded[i],
1657
+ demPct: s.districts.table.demPct[i],
1658
+ repPct: s.districts.table.repPct[i],
1659
+ othPct: s.districts.table.otherPct[i],
1660
+ whitePct: s.districts.table.whitePct[i],
1661
+ totalVAP: s.districts.table.totalVAP[i],
1662
+ minorityPct: s.districts.table.minorityPct[i],
1663
+ blackPct: s.districts.table.blackPct[i],
1664
+ hispanicPct: s.districts.table.hispanicPct[i],
1665
+ pacificPct: s.districts.table.pacificPct[i],
1666
+ asianPct: s.districts.table.asianPct[i],
1667
+ nativePct: s.districts.table.nativePct[i]
1668
+ };
1744
1669
  let readyRow = U.deepCopy(rawRow);
1745
1670
  dsTable.push(readyRow);
1746
1671
  }
@@ -1819,7 +1744,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
1819
1744
  Object.defineProperty(exports, "__esModule", { value: true });
1820
1745
  const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
1821
1746
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1822
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1823
1747
  const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
1824
1748
  const C = __importStar(__webpack_require__(/*! ./compact */ "./src/compact.ts"));
1825
1749
  // PROFILE A PLAN
@@ -1830,18 +1754,17 @@ function profilePlan(s, bLog = false) {
1830
1754
  const nDistricts = s.state.nDistricts;
1831
1755
  const nCounties = s.counties.nCounties;
1832
1756
  const targetSize = Math.round(s.state.totalPop / nDistricts);
1833
- const popByDistrict = U.deepCopy(s.districts.statistics[D.DistrictField.TotalPop].slice(1, -1));
1757
+ const popByDistrict = U.deepCopy(s.districts.table.totalPop.slice(1, -1));
1834
1758
  const geoPropsByDistrict = makeArrayOfGeoProps(s, bLog);
1835
1759
  const splits = makeNakedCxD(s);
1836
1760
  const summaryRow = s.districts.numberOfRows() - 1;
1837
1761
  // 10-22-2020 - Converted Dem + Rep + Other = Total to two-party vote shares for analytics.
1838
- const demVote = s.districts.statistics[D.DistrictField.DemVotes][summaryRow];
1839
- const repVote = s.districts.statistics[D.DistrictField.RepVotes][summaryRow];
1762
+ const demVote = s.districts.table.demVotes[summaryRow];
1763
+ const repVote = s.districts.table.repVotes[summaryRow];
1840
1764
  const statewideVf = U.trim(demVote / (demVote + repVote), KEEP_DECIMALS);
1841
- // const statewideVf: number = U.trim(s.districts.statistics[D.DistrictField.DemPct][summaryRow], 6);
1842
1765
  let vpiArray = [];
1843
- const demVotes = U.deepCopy(s.districts.statistics[D.DistrictField.DemVotes].slice(1, -1));
1844
- const repVotes = U.deepCopy(s.districts.statistics[D.DistrictField.RepVotes].slice(1, -1));
1766
+ const demVotes = U.deepCopy(s.districts.table.demVotes.slice(1, -1));
1767
+ const repVotes = U.deepCopy(s.districts.table.repVotes.slice(1, -1));
1845
1768
  for (let districtID = 1; districtID <= nDistricts; districtID++) {
1846
1769
  const D = demVotes[districtID - 1];
1847
1770
  const R = repVotes[districtID - 1];
@@ -1849,7 +1772,6 @@ function profilePlan(s, bLog = false) {
1849
1772
  const v = (T > 0) ? U.trim(D / T, KEEP_DECIMALS) : 0;
1850
1773
  vpiArray.push(v);
1851
1774
  }
1852
- // const vpiArray: number[] = U.deepCopy(s.districts.statistics[D.DistrictField.DemPct].slice(1, -1)) as number[];
1853
1775
  const statewideDemographics = getStatewideDemographics(s);
1854
1776
  const demographicsByDistrict = getDemographicsByDistrict(s);
1855
1777
  const profile = {
@@ -1880,7 +1802,7 @@ exports.profilePlan = profilePlan;
1880
1802
  // unassigned precincts & state summary and an extra 0 county. But dra-score takes
1881
1803
  // a simple 1–D x 1–C splits array (zero-based, of course).
1882
1804
  function makeNakedCxD(s, bLog = false) {
1883
- const adornedCxD = s.districts.statistics[D.DistrictField.CountySplits];
1805
+ const adornedCxD = s.districts.table.countySplits;
1884
1806
  let CxD = [];
1885
1807
  // Remove the unassigned & total dummy "districts"
1886
1808
  for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
@@ -1909,13 +1831,13 @@ function getDemographicsByDistrict(s, bLog = false) {
1909
1831
  // Remove the unassigned & total dummy "districts"
1910
1832
  for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
1911
1833
  const districtDemographics = {
1912
- white: U.trim(s.districts.statistics[D.DistrictField.WhitePct][districtID], KEEP_DECIMALS),
1913
- minority: U.trim(s.districts.statistics[D.DistrictField.MinorityPct][districtID], KEEP_DECIMALS),
1914
- black: U.trim(s.districts.statistics[D.DistrictField.BlackPct][districtID], KEEP_DECIMALS),
1915
- hispanic: U.trim(s.districts.statistics[D.DistrictField.HispanicPct][districtID], KEEP_DECIMALS),
1916
- pacific: U.trim(s.districts.statistics[D.DistrictField.PacificPct][districtID], KEEP_DECIMALS),
1917
- asian: U.trim(s.districts.statistics[D.DistrictField.AsianPct][districtID], KEEP_DECIMALS),
1918
- native: U.trim(s.districts.statistics[D.DistrictField.NativePct][districtID], KEEP_DECIMALS)
1834
+ white: U.trim(s.districts.table.whitePct[districtID], KEEP_DECIMALS),
1835
+ minority: U.trim(s.districts.table.minorityPct[districtID], KEEP_DECIMALS),
1836
+ black: U.trim(s.districts.table.blackPct[districtID], KEEP_DECIMALS),
1837
+ hispanic: U.trim(s.districts.table.hispanicPct[districtID], KEEP_DECIMALS),
1838
+ pacific: U.trim(s.districts.table.pacificPct[districtID], KEEP_DECIMALS),
1839
+ asian: U.trim(s.districts.table.asianPct[districtID], KEEP_DECIMALS),
1840
+ native: U.trim(s.districts.table.nativePct[districtID], KEEP_DECIMALS)
1919
1841
  };
1920
1842
  demographicsArray.push(districtDemographics);
1921
1843
  }
@@ -1924,13 +1846,13 @@ function getDemographicsByDistrict(s, bLog = false) {
1924
1846
  function getStatewideDemographics(s, bLog = false) {
1925
1847
  const summaryRow = s.districts.numberOfRows() - 1;
1926
1848
  const demographics = {
1927
- white: U.trim(s.districts.statistics[D.DistrictField.WhitePct][summaryRow], KEEP_DECIMALS),
1928
- minority: U.trim(s.districts.statistics[D.DistrictField.MinorityPct][summaryRow], KEEP_DECIMALS),
1929
- black: U.trim(s.districts.statistics[D.DistrictField.BlackPct][summaryRow], KEEP_DECIMALS),
1930
- hispanic: U.trim(s.districts.statistics[D.DistrictField.HispanicPct][summaryRow], KEEP_DECIMALS),
1931
- pacific: U.trim(s.districts.statistics[D.DistrictField.PacificPct][summaryRow], KEEP_DECIMALS),
1932
- asian: U.trim(s.districts.statistics[D.DistrictField.AsianPct][summaryRow], KEEP_DECIMALS),
1933
- native: U.trim(s.districts.statistics[D.DistrictField.NativePct][summaryRow], KEEP_DECIMALS)
1849
+ white: U.trim(s.districts.table.whitePct[summaryRow], KEEP_DECIMALS),
1850
+ minority: U.trim(s.districts.table.minorityPct[summaryRow], KEEP_DECIMALS),
1851
+ black: U.trim(s.districts.table.blackPct[summaryRow], KEEP_DECIMALS),
1852
+ hispanic: U.trim(s.districts.table.hispanicPct[summaryRow], KEEP_DECIMALS),
1853
+ pacific: U.trim(s.districts.table.pacificPct[summaryRow], KEEP_DECIMALS),
1854
+ asian: U.trim(s.districts.table.asianPct[summaryRow], KEEP_DECIMALS),
1855
+ native: U.trim(s.districts.table.nativePct[summaryRow], KEEP_DECIMALS)
1934
1856
  };
1935
1857
  return demographics;
1936
1858
  }
@@ -1947,9 +1869,9 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
1947
1869
  test['score'] = popDev;
1948
1870
  test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
1949
1871
  // Populate the N+1 summary "district" in district.statistics
1950
- let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
1951
- let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
1952
- let totalVAP = s.districts.statistics[D.DistrictField.TotalVAP];
1872
+ let totalPop = s.districts.table.totalPop;
1873
+ let popDevPct = s.districts.table.popDevPct;
1874
+ let totalVAP = s.districts.table.totalVAP;
1953
1875
  const summaryRow = s.districts.numberOfRows() - 1;
1954
1876
  totalPop[summaryRow] = p.population.targetSize;
1955
1877
  popDevPct[summaryRow] = popDev;
@@ -2303,7 +2225,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
2303
2225
  Object.defineProperty(exports, "__esModule", { value: true });
2304
2226
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
2305
2227
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
2306
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
2307
2228
  //
2308
2229
  // COMPLETE - Are all geo's assigned to a district, and do all districts have
2309
2230
  // at least one geo assigned to them?
@@ -2312,7 +2233,7 @@ function doIsComplete(s, bLog = false) {
2312
2233
  let test = s.getTest(0 /* Complete */);
2313
2234
  // Get the by-district results, including the dummy unassigned district,
2314
2235
  // but ignoring the N+1 summary district
2315
- let bNotEmptyByDistrict = s.districts.statistics[D.DistrictField.bNotEmpty];
2236
+ let bNotEmptyByDistrict = s.districts.table.bNotEmpty;
2316
2237
  bNotEmptyByDistrict = bNotEmptyByDistrict.slice(0, -1);
2317
2238
  // Are all features assigned to districts?
2318
2239
  // Check the dummy district that holds any unassigned features.
@@ -2378,7 +2299,7 @@ function doIsComplete(s, bLog = false) {
2378
2299
  test['details']['emptyDistricts'] = emptyDistricts;
2379
2300
  }
2380
2301
  // Populate the N+1 summary "district" in district.statistics
2381
- let bNotEmpty = s.districts.statistics[D.DistrictField.bNotEmpty];
2302
+ let bNotEmpty = s.districts.table.bNotEmpty;
2382
2303
  let summaryRow = s.districts.numberOfRows() - 1;
2383
2304
  bNotEmpty[summaryRow] = test['score'];
2384
2305
  return test;
@@ -2396,7 +2317,7 @@ function doIsContiguous(s, bLog = false) {
2396
2317
  let test = s.getTest(1 /* Contiguous */);
2397
2318
  // Get the contiguity of each district. Ignore dummy unassigned district
2398
2319
  // and the N+1 summary district.
2399
- let bContiguousByDistrict = s.districts.statistics[D.DistrictField.bContiguous];
2320
+ let bContiguousByDistrict = s.districts.table.bContiguous;
2400
2321
  bContiguousByDistrict = bContiguousByDistrict.slice(1, -1);
2401
2322
  // If any real districts aren't contiguous, mark the plan as not contiguous
2402
2323
  let bMapContiguous = U.andArray(bContiguousByDistrict);
@@ -2414,7 +2335,7 @@ function doIsContiguous(s, bLog = false) {
2414
2335
  test['details'] = { 'discontiguousDistricts': discontiguousDistricts };
2415
2336
  }
2416
2337
  // Populate the N+1 summary "district" in district.statistics
2417
- let bContiguous = s.districts.statistics[D.DistrictField.bContiguous];
2338
+ let bContiguous = s.districts.table.bContiguous;
2418
2339
  let summaryRow = s.districts.numberOfRows() - 1;
2419
2340
  bContiguous[summaryRow] = test['score'];
2420
2341
  return test;
@@ -2437,7 +2358,7 @@ function doIsFreeOfHoles(s, bLog = false) {
2437
2358
  let embeddedDistricts = [];
2438
2359
  // Get the embeddedness of each district. Ignore dummy unassigned district
2439
2360
  // and the N+1 summary district.
2440
- let bNotEmbeddedByDistrict = s.districts.statistics[D.DistrictField.bNotEmbedded];
2361
+ let bNotEmbeddedByDistrict = s.districts.table.bNotEmbedded;
2441
2362
  bNotEmbeddedByDistrict = bNotEmbeddedByDistrict.slice(1, -1);
2442
2363
  let districtID = 1;
2443
2364
  bNotEmbeddedByDistrict.forEach(function (bDistrictNotEmbedded) {
@@ -2453,7 +2374,7 @@ function doIsFreeOfHoles(s, bLog = false) {
2453
2374
  test['details'] = { 'embeddedDistricts': embeddedDistricts };
2454
2375
  }
2455
2376
  // Populate the N+1 summary "district" in district.statistics
2456
- let bNotEmbedded = s.districts.statistics[D.DistrictField.bNotEmbedded];
2377
+ let bNotEmbedded = s.districts.table.bNotEmbedded;
2457
2378
  let summaryRow = s.districts.numberOfRows() - 1;
2458
2379
  bNotEmbedded[summaryRow] = test['score'];
2459
2380
  return test;