@dra2020/district-analytics 1.0.6 → 1.0.7

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.
Files changed (75) hide show
  1. package/dist/cli.js +102 -52
  2. package/dist/cli.js.map +1 -1
  3. package/dist/district-analytics.js +102 -52
  4. package/dist/district-analytics.js.map +1 -1
  5. package/lib/HelloWorld.d.ts +3 -0
  6. package/lib/HelloWorld.js +11 -0
  7. package/lib/_api.js +91 -0
  8. package/lib/_api.js.map +1 -0
  9. package/lib/_cli.js +434 -0
  10. package/lib/_cli.js.map +1 -0
  11. package/lib/_data.js +425 -0
  12. package/lib/_data.js.map +1 -0
  13. package/lib/analyze.d.ts +3 -0
  14. package/lib/analyze.js +69 -0
  15. package/lib/analyze.js.map +1 -0
  16. package/lib/api.d.ts +34 -0
  17. package/lib/api.js +117 -0
  18. package/lib/api.js.map +1 -0
  19. package/lib/cli.d.ts +1 -0
  20. package/lib/cli.js +386 -0
  21. package/lib/cli.js.map +1 -0
  22. package/lib/cohesive.d.ts +4 -0
  23. package/lib/cohesive.js +132 -0
  24. package/lib/cohesive.js.map +1 -0
  25. package/lib/compact.d.ts +4 -0
  26. package/lib/compact.js +183 -0
  27. package/lib/compact.js.map +1 -0
  28. package/lib/constants.js +367 -0
  29. package/lib/constants.js.map +1 -0
  30. package/lib/data.js +188 -0
  31. package/lib/data.js.map +1 -0
  32. package/lib/equal.d.ts +4 -0
  33. package/lib/equal.js +59 -0
  34. package/lib/equal.js.map +1 -0
  35. package/lib/features.js +19 -0
  36. package/lib/features.js.map +1 -0
  37. package/lib/geofeature.js +112 -0
  38. package/lib/geofeature.js.map +1 -0
  39. package/lib/index.d.ts +5 -0
  40. package/lib/index.js +11 -0
  41. package/lib/index.js.map +1 -0
  42. package/lib/minority.d.ts +3 -0
  43. package/lib/minority.js +61 -0
  44. package/lib/minority.js.map +1 -0
  45. package/lib/political.d.ts +7 -0
  46. package/lib/political.js +88 -0
  47. package/lib/political.js.map +1 -0
  48. package/lib/preprocess.d.ts +4 -0
  49. package/lib/preprocess.js +101 -0
  50. package/lib/preprocess.js.map +1 -0
  51. package/lib/report.d.ts +14 -0
  52. package/lib/report.js +817 -0
  53. package/lib/report.js.map +1 -0
  54. package/lib/sample.d.ts +1 -0
  55. package/lib/sample.js +32 -0
  56. package/lib/sample.js.map +1 -0
  57. package/lib/scorecard.d.ts +4 -0
  58. package/lib/scorecard.js +237 -0
  59. package/lib/scorecard.js.map +1 -0
  60. package/lib/settings.d.ts +5 -0
  61. package/lib/settings.js +18 -0
  62. package/lib/settings.js.map +1 -0
  63. package/lib/types.d.ts +125 -0
  64. package/lib/types.js +7 -0
  65. package/lib/types.js.map +1 -0
  66. package/lib/utils.d.ts +20 -0
  67. package/lib/utils.js +223 -0
  68. package/lib/utils.js.map +1 -0
  69. package/lib/valid.d.ts +5 -0
  70. package/lib/valid.js +230 -0
  71. package/lib/valid.js.map +1 -0
  72. package/package.json +2 -2
  73. package/src/_api.ts +1 -0
  74. package/src/_data.ts +42 -19
  75. package/src/report.ts +59 -34
package/dist/cli.js CHANGED
@@ -8838,6 +8838,7 @@ class AnalyticsSession {
8838
8838
  report_1.doAnalyzePostProcessing(this);
8839
8839
  }
8840
8840
  catch (_a) {
8841
+ console.log("Exception caught by analyzePlan()");
8841
8842
  return false;
8842
8843
  }
8843
8844
  return true;
@@ -9038,13 +9039,36 @@ class Districts {
9038
9039
  demVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
9039
9040
  repVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "R" /* RepVotes */);
9040
9041
  // Voting-age demographic breakdowns (or citizen voting-age)
9041
- totalVAP += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
9042
- whitePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
9043
- blackPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */);
9044
- hispanicPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */);
9045
- pacificPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */);
9046
- asianPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */);
9047
- nativePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */);
9042
+ // Guard againt null/NaN values
9043
+ let _totalVAP = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
9044
+ let _whitePop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
9045
+ let _blackPop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */);
9046
+ let _hispanicPop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */);
9047
+ let _pacificPop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */);
9048
+ let _asianPop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */);
9049
+ let _nativePop = outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */);
9050
+ if (_totalVAP)
9051
+ totalVAP += _totalVAP;
9052
+ if (_whitePop)
9053
+ whitePop += _whitePop;
9054
+ if (_blackPop)
9055
+ blackPop += _blackPop;
9056
+ if (_hispanicPop)
9057
+ hispanicPop += _hispanicPop;
9058
+ if (_pacificPop)
9059
+ pacificPop += _pacificPop;
9060
+ if (_asianPop)
9061
+ asianPop += _asianPop;
9062
+ if (_nativePop)
9063
+ nativePop += _nativePop;
9064
+ // TODO - DELETE
9065
+ // totalVAP += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.TotalPop);
9066
+ // whitePop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.WhitePop);
9067
+ // blackPop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.BlackPop);
9068
+ // hispanicPop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.HispanicPop);
9069
+ // pacificPop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.PacificPop);
9070
+ // asianPop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.AsianPop);
9071
+ // nativePop += outerThis._session.features.fieldForFeature(f, Dataset.VAP, FeatureField.NativePop);
9048
9072
  // 4 - MORE ...
9049
9073
  });
9050
9074
  // COMPUTE DERIVED VALUES
@@ -9059,9 +9083,9 @@ class Districts {
9059
9083
  // Total two-party (not total total!) votes, Democratic and Republican vote
9060
9084
  // shares, and Democratic first-past-the-post win (= 1) or loss (= 0).
9061
9085
  let totVotes;
9062
- let demPct = null;
9063
- let repPct = null;
9064
- let DemSeat = null;
9086
+ let demPct = 0;
9087
+ let repPct = 0;
9088
+ let DemSeat = 0;
9065
9089
  totVotes = demVotes + repVotes;
9066
9090
  if (totVotes > 0) {
9067
9091
  demPct = demVotes / totVotes;
@@ -9071,13 +9095,13 @@ class Districts {
9071
9095
  // Total minority VAP
9072
9096
  let minorityPop = totalVAP - whitePop;
9073
9097
  // Voting-age demographic proportions (or citizen voting-age)
9074
- let whitePct = null;
9075
- let minorityPct = null;
9076
- let blackPct = null;
9077
- let hispanicPct = null;
9078
- let pacificPct = null;
9079
- let asianPct = null;
9080
- let nativePct = null;
9098
+ let whitePct = 0;
9099
+ let minorityPct = 0;
9100
+ let blackPct = 0;
9101
+ let hispanicPct = 0;
9102
+ let pacificPct = 0;
9103
+ let asianPct = 0;
9104
+ let nativePct = 0;
9081
9105
  if (totalVAP > 0) {
9082
9106
  whitePct = whitePop / totalVAP;
9083
9107
  minorityPct = minorityPop / totalVAP;
@@ -9180,8 +9204,12 @@ exports.Districts = Districts;
9180
9204
  exports.DatasetDescriptions = {
9181
9205
  D16F: "2016 ACS Total Population",
9182
9206
  D16T: "2016 ACS Voting Age Population",
9183
- E16GPR: "2016 Presidential Election"
9207
+ E16GPR: "2016 Presidential Election",
9208
+ D10F: "2010 Census Total Population",
9209
+ D10T: "2010 Voting Age Population",
9210
+ C16GCO: "2016 Presidential, US Senate, Governor, and AG election results"
9184
9211
  // TODO - What other potential datasets?
9212
+ // MORE ...
9185
9213
  };
9186
9214
  // Wrap data by feature, to abstract the specifics of the internal structure
9187
9215
  class Features {
@@ -9193,7 +9221,8 @@ class Features {
9193
9221
  }
9194
9222
  nFeatures() { return this._data.features.length; }
9195
9223
  featureByIndex(i) { return this._data.features[i]; }
9196
- geoIDForFeature(f) { return f.properties['GEOID']; }
9224
+ // TODO - Generalize this
9225
+ geoIDForFeature(f) { return f.properties['GEOID10']; }
9197
9226
  fieldForFeature(f, dt, fk) {
9198
9227
  let dk = this._keys[dt];
9199
9228
  return _getFeatures(f, dk, fk);
@@ -10313,13 +10342,14 @@ const testDefns = {
10313
10342
  [4 /* PopulationDeviation */]: populationDeviationDefn,
10314
10343
  [5 /* Reock */]: reockDefn,
10315
10344
  [6 /* PolsbyPopper */]: polsbyPopperDefn,
10345
+ // TODO - Flesh out county splits
10316
10346
  [7 /* CountySplits */]: countySplitsDefn,
10317
10347
  [13 /* EfficiencyGap */]: efficiencyGapDefn
10318
10348
  /* TODO - More tests ... */
10319
10349
  };
10320
10350
  // Scorecard category definitions
10321
10351
  const validCategory = {
10322
- catName: "Valid",
10352
+ catName: "Map Validations",
10323
10353
  catTests: [
10324
10354
  { testID: 0 /* Complete */ },
10325
10355
  { testID: 1 /* Contiguous */ },
@@ -10331,7 +10361,8 @@ const validCategory = {
10331
10361
  catPrepareFn: doPrepareValidSection
10332
10362
  };
10333
10363
  const fairCategory = {
10334
- catName: "Fair",
10364
+ // TODO - Change this label
10365
+ catName: "Is the map fair?",
10335
10366
  catTests: [
10336
10367
  {
10337
10368
  testID: 13 /* EfficiencyGap */,
@@ -10347,7 +10378,7 @@ const fairCategory = {
10347
10378
  // multiplied by the associated 'testWeight', and the sum of those is divided
10348
10379
  // by the total weight. Weights don't have to add to 100.
10349
10380
  const bestCategory = {
10350
- catName: "Best",
10381
+ catName: "Traditional Districting Principles",
10351
10382
  catTests: [
10352
10383
  {
10353
10384
  testID: 4 /* PopulationDeviation */,
@@ -10360,11 +10391,12 @@ const bestCategory = {
10360
10391
  {
10361
10392
  testID: 6 /* PolsbyPopper */,
10362
10393
  testWeight: 25
10363
- },
10364
- {
10365
- testID: 7 /* CountySplits */,
10366
- testWeight: 50
10367
10394
  }
10395
+ // TODO - Re-enable, when the metric is implemented
10396
+ // {
10397
+ // testID: T.Test.CountySplits,
10398
+ // testWeight: 50
10399
+ // }
10368
10400
  ],
10369
10401
  catNumeric: true,
10370
10402
  catWeight: undefined,
@@ -10494,31 +10526,46 @@ function doPrepareScorecard(s) {
10494
10526
  // Create and cache a new, unformatted scorecard
10495
10527
  s.scorecard = doGenerateScorecard(s);
10496
10528
  // Create a scorecard header
10497
- blocks.push({ variant: 'h4', text: `Analysis` });
10498
- // Report district statistics
10499
- blocks.push({ variant: 'h5', text: `Individual Districts` });
10500
- let districtStatisticsText = doPrepareDistrictStatistics(s);
10501
- blocks.push(...districtStatisticsText);
10529
+ blocks.push({ variant: 'h4', text: `Analysis - NC 2019 Special Edition` });
10530
+ blocks.push({ variant: 'body1', text: `In response to the recent court ruling in North Carolina and the court's requirement for transparency, we are pleased to provide the general public with early access to this base set of redistricting analytics. Stay tuned for more updates!` });
10531
+ blocks.push({ variant: 'body1', text: `For more details, see our blog post on Medium.` });
10502
10532
  // Prepare each scorecard category
10503
- blocks.push({ variant: 'h5', text: `Overall Plan` });
10533
+ blocks.push({ variant: 'beginExpansion', text: `Overall Plan` });
10504
10534
  let categories = U.getNumericObjectKeys(s.scorecard);
10505
10535
  for (let c of categories) {
10506
10536
  let sectionPrepareFn = scorecardDefn[c]['catPrepareFn'];
10507
10537
  let sectionText = sectionPrepareFn(s, c);
10508
10538
  blocks.push(...sectionText);
10509
10539
  }
10540
+ // blocks.push({ variant: 'body1', text: `` });
10541
+ // blocks.push({ variant: 'body1', text: `There is much more analysis coming of county splitting, partisan fairness, and the opportunity for minority representation! For now, you can glean a lot from the district statistics below.` });
10542
+ blocks.push({ variant: 'endExpansion' });
10543
+ // Report district statistics
10544
+ blocks.push({ variant: 'beginExpansion', text: `Individual Districts` });
10545
+ let districtStatisticsText = doPrepareDistrictStatistics(s);
10546
+ blocks.push(...districtStatisticsText);
10547
+ blocks.push({ variant: 'endExpansion' });
10510
10548
  // Report what datasets were used
10511
10549
  let c = s.config['datasets']["CENSUS" /* CENSUS */];
10512
10550
  let v = s.config['datasets']["VAP" /* VAP */];
10513
10551
  let e = s.config['datasets']["ELECTION" /* ELECTION */];
10514
- blocks.push({ variant: 'body1', text: `Using datasets:` });
10515
- blocks.push({ variant: 'body1', text: `* ${c}: ${D.DatasetDescriptions[c]}` });
10516
- blocks.push({ variant: 'body1', text: `* ${v}: ${D.DatasetDescriptions[v]}` });
10517
- blocks.push({ variant: 'body1', text: `* ${e}: ${D.DatasetDescriptions[e]}` });
10552
+ blocks.push({ variant: 'beginExpansion', text: `About the Data` });
10553
+ blocks.push({ variant: 'body1', text: `These are the 4 datasets used in this analysis:` });
10554
+ // TODO - Get the shape "dataset" from dra-client
10555
+ blocks.push({ variant: 'body1', text: `* Shapes: 2010 VTD shapes` });
10556
+ blocks.push({ variant: 'body1', text: `* Census: ${D.DatasetDescriptions[c]}` });
10557
+ blocks.push({ variant: 'body1', text: `* VAP: ${D.DatasetDescriptions[v]}` });
10558
+ blocks.push({ variant: 'body1', text: `* Elections: ${D.DatasetDescriptions[e]}` });
10559
+ blocks.push({ variant: 'endExpansion' });
10560
+ blocks.push({ variant: 'body1', text: `` });
10561
+ blocks.push({
10562
+ "variant": "link",
10563
+ "text": "Questions or comments?",
10564
+ "label": "analytics@davesredistricting.org",
10565
+ "link": "mailto:analytics@davesredistricting.org"
10566
+ });
10518
10567
  }
10519
10568
  // Otherwise, return a blank scorecard
10520
- // TODO - What dra-client returns from renderAnalyzeCore()
10521
- // return <STV.StaticTextView text={ text } />;
10522
10569
  return text;
10523
10570
  }
10524
10571
  exports.doPrepareScorecard = doPrepareScorecard;
@@ -10534,7 +10581,7 @@ function doPrepareDistrictStatistics(s) {
10534
10581
  else {
10535
10582
  tot = Math.round(tot);
10536
10583
  let dev = fractionToPercentage(s.districts.statistics[D.DistrictField.PopDevPct][d]);
10537
- let bEq = true; // TODO - Set based on population threshold
10584
+ let bEq = s.districts.statistics[D.DistrictField.bEqualPop][d];
10538
10585
  let bC = s.districts.statistics[D.DistrictField.bContiguous][d]
10539
10586
  && s.districts.statistics[D.DistrictField.bNotEmbedded][d];
10540
10587
  let dPct = fractionToPercentage(s.districts.statistics[D.DistrictField.DemPct][d]);
@@ -10605,8 +10652,6 @@ function doPrepareTestLog(s) {
10605
10652
  }
10606
10653
  }
10607
10654
  // Otherwise, return a blank test log
10608
- // TODO - What dra-client returns from renderAnalyzeCore()
10609
- // return <STV.StaticTextView text={ text } />;
10610
10655
  return text;
10611
10656
  }
10612
10657
  exports.doPrepareTestLog = doPrepareTestLog;
@@ -10631,27 +10676,27 @@ function prepareTestEntry(testID, testResult) {
10631
10676
  switch (testType) {
10632
10677
  case TestType.PassFail: {
10633
10678
  scoreText = pfBoolToString(score);
10634
- blocks.push({ variant: 'body1', text: `${testName}: ${scoreText} ${testNameTrailer}` });
10679
+ blocks.push({ variant: 'body1', text: `<b>${testName}</b>: ${scoreText} ${testNameTrailer}` });
10635
10680
  break;
10636
10681
  }
10637
10682
  case TestType.Percentage: {
10638
10683
  score = fractionToPercentage(score);
10639
10684
  if (bNormalize) {
10640
10685
  normalizedScore = testResult['normalizedScore'];
10641
- blocks.push({ variant: 'body1', text: `${testName}: ${normalizedScore} / 100 : ${formatPercentage(score)}% ${testNameTrailer}` });
10686
+ blocks.push({ variant: 'body1', text: `<b>${testName}</b>: ${normalizedScore} / 100 : ${formatPercentage(score)}% ${testNameTrailer}` });
10642
10687
  }
10643
10688
  else {
10644
- blocks.push({ variant: 'body1', text: `${testName}: ${formatPercentage(score)}% ${testNameTrailer}` });
10689
+ blocks.push({ variant: 'body1', text: `<b>${testName}</b>: ${formatPercentage(score)}% ${testNameTrailer}` });
10645
10690
  }
10646
10691
  break;
10647
10692
  }
10648
10693
  case TestType.Number: {
10649
10694
  if (bNormalize) {
10650
10695
  normalizedScore = testResult['normalizedScore'];
10651
- blocks.push({ variant: 'body1', text: `${testName}: ${normalizedScore} / 100 : ${formatNumber(score)} ${testNameTrailer}` });
10696
+ blocks.push({ variant: 'body1', text: `<b>${testName}</b>: ${normalizedScore} / 100 : ${formatNumber(score)} ${testNameTrailer}` });
10652
10697
  }
10653
10698
  else {
10654
- blocks.push({ variant: 'body1', text: `${testName}: ${formatNumber(score)} ${testNameTrailer}` });
10699
+ blocks.push({ variant: 'body1', text: `<b>${testName}</b>: ${formatNumber(score)} ${testNameTrailer}` });
10655
10700
  }
10656
10701
  break;
10657
10702
  }
@@ -10806,7 +10851,8 @@ function doPrepareValidSection(s, c) {
10806
10851
  let testText;
10807
10852
  // Section header
10808
10853
  let stringScore = pfBoolToString(catScore);
10809
- blocks.push({ variant: 'h6', text: `${catName}: ${stringScore}` });
10854
+ blocks.push({ variant: 'beginExpansion', text: `${catName}` });
10855
+ // blocks.push({ variant: 'beginExpansion', text: `${catName} ${stringScore}` });
10810
10856
  // Complete
10811
10857
  testReport = catTests[0 /* Complete */];
10812
10858
  testText = prepareTestEntry(0 /* Complete */, testReport);
@@ -10823,6 +10869,7 @@ function doPrepareValidSection(s, c) {
10823
10869
  testReport = catTests[3 /* EqualPopulation */];
10824
10870
  testText = prepareTestEntry(3 /* EqualPopulation */, testReport);
10825
10871
  blocks.push(...testText);
10872
+ blocks.push({ variant: 'endExpansion' });
10826
10873
  return blocks;
10827
10874
  }
10828
10875
  // TODO - NIY
@@ -10836,12 +10883,13 @@ function doPrepareFairSection(s, c) {
10836
10883
  let blocks = text.data;
10837
10884
  let testText;
10838
10885
  // Section header
10839
- blocks.push({ variant: 'h6', text: `${catName}: ${catScore}` });
10886
+ blocks.push({ variant: 'beginExpansion', text: `${catName} ${catScore} of 100` });
10840
10887
  // TODO - Flesh this out
10841
10888
  // There's only one test: Population Deviation.
10842
10889
  // testReport = catTests[T.Test.PopulationDeviation];
10843
10890
  // testText = prepareTestEntry(T.Test.PopulationDeviation, testReport);
10844
10891
  // blocks.push(...testText);
10892
+ blocks.push({ variant: 'endExpansion' });
10845
10893
  return blocks;
10846
10894
  }
10847
10895
  // This function parses & formats the 'Best' section of a scorecard.
@@ -10854,7 +10902,7 @@ function doPrepareBestSection(s, c) {
10854
10902
  let blocks = text.data;
10855
10903
  let testText;
10856
10904
  // Section header
10857
- blocks.push({ variant: 'h6', text: `${catName}: ${catScore}` });
10905
+ blocks.push({ variant: 'beginExpansion', text: `${catName} (${catScore} of 100)` });
10858
10906
  // Population deviation
10859
10907
  testReport = catTests[4 /* PopulationDeviation */];
10860
10908
  testText = prepareTestEntry(4 /* PopulationDeviation */, testReport);
@@ -10871,9 +10919,11 @@ function doPrepareBestSection(s, c) {
10871
10919
  blocks.push(...reockTestText);
10872
10920
  blocks.push(...polsbyPopperTestText);
10873
10921
  // County splits
10874
- testReport = catTests[7 /* CountySplits */];
10875
- testText = prepareTestEntry(7 /* CountySplits */, testReport);
10876
- blocks.push(...testText);
10922
+ // TODO - Re-enable this, when the county-splitting metric is implemented.
10923
+ // testReport = catTests[T.Test.CountySplits];
10924
+ // testText = prepareTestEntry(T.Test.CountySplits, testReport);
10925
+ // blocks.push(...testText);
10926
+ blocks.push({ variant: 'endExpansion' });
10877
10927
  return blocks;
10878
10928
  }
10879
10929
  // FORMATTING HELPERS