@dra2020/district-analytics 4.3.6 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -91185,7 +91185,7 @@ function calcMinimalInverseResponsiveness(Vf, r) {
91185
91185
  const bBalanced = isBalanced(Vf);
91186
91186
  const ideal = bBalanced ? 0.1 : 0.2;
91187
91187
  MIR = (1 / r) - ideal;
91188
- MIR = U.trim(MIR);
91188
+ MIR = U.trim(Math.max(MIR, 0.0));
91189
91189
  }
91190
91190
  return MIR;
91191
91191
  }
@@ -101337,7 +101337,6 @@ const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.t
101337
101337
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
101338
101338
  const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
101339
101339
  const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
101340
- // import { doConfigureScales, doAnalyzePostProcessing, RequirementsChecklist} from './results' // TODO - DELETE
101341
101340
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
101342
101341
  const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
101343
101342
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
@@ -101348,7 +101347,6 @@ class AnalyticsSession {
101348
101347
  this.bOneTimeProcessingDone = false;
101349
101348
  this.bPlanAnalyzed = false;
101350
101349
  this.bPostProcessingDone = false;
101351
- // testScales = {} as T.TestScales; TODO - DELETE
101352
101350
  this.tests = {};
101353
101351
  this.title = SessionRequest['title'];
101354
101352
  this.legislativeDistricts = SessionRequest['legislativeDistricts'];
@@ -101359,42 +101357,18 @@ class AnalyticsSession {
101359
101357
  this.features = new D.Features(this, SessionRequest['data'], this.config['datasets']);
101360
101358
  this.plan = new D.Plan(this, SessionRequest['plan']);
101361
101359
  this.districts = new D.Districts(this, SessionRequest['districtShapes']);
101362
- // TODO - DELETE
101363
- // if (this.useLegacy())
101364
- // {
101365
- // console.log("Using legacy district-analytics.")
101366
- // // NOTE: I've pulled these out of the individual analytics to here. Eventually,
101367
- // // we could want them to passed into an analytics session as data, along with
101368
- // // everything else. For now, this keeps branching out of the main code.
101369
- // doConfigureScales(this);
101370
- // }
101371
- // else
101372
- // {
101373
- // console.log("Using dra-score analytics.")
101374
- // // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
101375
- // doConfigureScales(this);
101376
- // }
101377
101360
  }
101378
101361
  processConfig(config) {
101379
101362
  // NOTE - Session settings are required:
101380
101363
  // - Analytics suites can be defaulted to all with [], but
101381
101364
  // - Dataset keys must be explicitly specified with 'dataset'
101382
- // TODO - SCORE: Delete
101365
+ // NOTE - Legacy feature: Always calc everything
101383
101366
  config['suites'] = [0 /* Legal */, 1 /* Fair */, 2 /* Best */];
101384
101367
  // Default the Census & redistricting cycle to 2010
101385
101368
  if (!(U.keyExists('cycle', config)))
101386
101369
  config['cycle'] = 2010;
101387
101370
  return config;
101388
101371
  }
101389
- /* TODO - DELETE
101390
- useLegacy(): boolean
101391
- {
101392
- // TODO - SCORE: Opt-out
101393
- return (U.keyExists('useScore', this.config) && (this.config['useScore'] != null) && (!(this.config['useScore']))) ? true : false;
101394
- // TODO - SCORE: Opt-in
101395
- // return (U.keyExists('useScore', this.config) && (this.config['useScore'])) ? false : true;
101396
- }
101397
- */
101398
101372
  // Using the the data in the analytics session, calculate all the
101399
101373
  // analytics & validations, saving/updating the individual test results.
101400
101374
  analyzePlan(bLog = false, overridesJSON) {
@@ -101402,7 +101376,6 @@ class AnalyticsSession {
101402
101376
  preprocess_1.doPreprocessData(this, bLog);
101403
101377
  analyze_1.doAnalyzeDistricts(this, bLog);
101404
101378
  analyze_1.doAnalyzePlan(this, bLog);
101405
- // TODO - SCORE
101406
101379
  this._profile = score_1.profilePlan(this, bLog);
101407
101380
  this._scorecard = score_1.scorePlan(this, this._profile, bLog, overridesJSON);
101408
101381
  results_1.doAnalyzePostProcessing(this, bLog);
@@ -101417,15 +101390,12 @@ class AnalyticsSession {
101417
101390
  getDistrictStatistics(bLog = false) {
101418
101391
  return results_2.prepareDistrictStatistics(this, bLog);
101419
101392
  }
101420
- // TODO - SCORE
101421
101393
  getPlanProfile(bLog = false) {
101422
101394
  return this._profile;
101423
101395
  }
101424
- // TODO - SCORE
101425
101396
  getPlanScorecard(bLog = false) {
101426
101397
  return this._scorecard;
101427
101398
  }
101428
- // TODO - SCORE
101429
101399
  // NOTE - This assumes that analyzePlan() has been run!
101430
101400
  getRequirementsChecklist(bLog = false) {
101431
101401
  return results_2.prepareRequirementsChecklist(this, bLog);
@@ -101526,21 +101496,10 @@ class AnalyticsSession {
101526
101496
  }
101527
101497
  // NOTE - Not sure why this has to be up here ...
101528
101498
  populationDeviationThreshold() {
101529
- // TODO - DELETE
101530
- // if (this.useLegacy())
101531
- // {
101532
- // return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
101533
- // }
101534
- // else
101535
- // {
101536
101499
  // NOTE - This assumes the plan has been profiled
101537
101500
  const scorer = new Score.Scorer();
101538
101501
  const popdev = scorer.populationDeviationThreshold(this.legislativeDistricts);
101539
101502
  return popdev;
101540
- // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
101541
- // NOTE - The plan may not have been scored yet, i.e., no scorecard yet.
101542
- // return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
101543
- // }
101544
101503
  }
101545
101504
  }
101546
101505
  exports.AnalyticsSession = AnalyticsSession;
@@ -101654,11 +101613,11 @@ class Districts {
101654
101613
  }
101655
101614
  // This is the workhorse computational routine!
101656
101615
  //
101657
- // TODO - OPTIMIZE for getting multiple properties from the same feature?
101658
- // TODO - OPTIMIZE by only re-calc'ing districts that have changed?
101616
+ // NOTE - OPTIMIZE for getting multiple properties from the same feature?
101617
+ // NOTE - OPTIMIZE by only re-calc'ing districts that have changed?
101659
101618
  // In this case, special attention to getting county-splits right.
101660
- // TODO - OPTIMIZE by async'ing this?
101661
- // TODO - Is there a way to do this programmatically off data? Does it matter?
101619
+ // NOTE - OPTIMIZE by async'ing this?
101620
+ // NOTE - Is there a way to do this programmatically off data? Does it matter?
101662
101621
  recalcStatistics(bLog = false) {
101663
101622
  // Initialize debug counters
101664
101623
  nMissingDataset = 0;
@@ -101669,7 +101628,6 @@ class Districts {
101669
101628
  let planByDistrict = this._session.plan.byDistrictID();
101670
101629
  let plan = this._session.plan;
101671
101630
  let graph = this._session.graph;
101672
- // NOTE - SPLITTING
101673
101631
  // Add an extra 0th virtual county bucket for county-district splitting analysis
101674
101632
  let nCountyBuckets = this._session.counties.nCounties + 1;
101675
101633
  // INITIALIZE STATE VALUES THAT WILL BE ACCUMULATED
@@ -101695,7 +101653,6 @@ class Districts {
101695
101653
  // INITIALIZE DISTRICT VALUES THAT WILL BE ACCUMULATED (VS. DERIVED)
101696
101654
  let featurePop;
101697
101655
  let totalPop = 0;
101698
- // NOTE - SPLITTING
101699
101656
  let countySplits = U.initArray(nCountyBuckets, 0);
101700
101657
  let demVotes = 0;
101701
101658
  let repVotes = 0;
@@ -101739,7 +101696,6 @@ class Districts {
101739
101696
  featurePop = outerThis._session.features.fieldForFeature(f, "CENSUS" /* CENSUS */, "Tot" /* TotalPop */);
101740
101697
  // Total district population
101741
101698
  totalPop += featurePop;
101742
- // NOTE - SPLITTING
101743
101699
  // Total population by counties w/in a district,
101744
101700
  // except the dummy unassigned district 0
101745
101701
  if (i > 0)
@@ -101943,7 +101899,7 @@ class Features {
101943
101899
  }
101944
101900
  resetDataset(d, k) {
101945
101901
  this._keys[d] = k;
101946
- // TODO - RECALC: Does anything need to be recalc'd now when a dataset is changed?
101902
+ // NOTE - RECALC: Does anything need to be recalc'd now when a dataset is changed?
101947
101903
  }
101948
101904
  mapGeoIDsToFeatureIDs() {
101949
101905
  for (let i = 0; i < this._session.features.nFeatures(); i++) {
@@ -102058,7 +102014,6 @@ class Plan {
102058
102014
  // return newPlan;
102059
102015
  // }
102060
102016
  invertPlan() {
102061
- // NOTE - UNASSIGNED
102062
102017
  this._planByDistrictID = invertPlan(this._planByGeoID, this._session);
102063
102018
  this.districtIDs = U.getNumericObjectKeys(this._planByDistrictID);
102064
102019
  }
@@ -102074,7 +102029,6 @@ function invertPlan(plan, s) {
102074
102029
  let invertedPlan = {};
102075
102030
  // Add a dummy 'unassigned' district
102076
102031
  invertedPlan[S.NOT_ASSIGNED] = new Set();
102077
- // NOTE - UNASSIGNED
102078
102032
  // The feature assignments coming from DRA do not include unassigned ones.
102079
102033
  // - In the DRA-calling context, there's an analytics session with a reference
102080
102034
  // to the features. Loop over all the features to find the unassigned ones,
@@ -102117,7 +102071,6 @@ class Graph {
102117
102071
  // Ignore the lengths of the shared borders (the values), for now
102118
102072
  // Protect against getting a GEOID that's not in the graph
102119
102073
  if (U.keyExists(node, this._graph)) {
102120
- // NOTE - CONTIGUITY GRAPHS
102121
102074
  // Handle both unweighted & weighted neighbors
102122
102075
  let n = this._graph[node];
102123
102076
  let l = (n instanceof Array) ? n : U.getObjectKeys(n);
@@ -102149,22 +102102,7 @@ exports.Graph = Graph;
102149
102102
  Object.defineProperty(exports, "__esModule", { value: true });
102150
102103
  const valid_1 = __webpack_require__(/*! ./valid */ "./src/valid.ts");
102151
102104
  const equal_1 = __webpack_require__(/*! ./equal */ "./src/equal.ts");
102152
- // import { doPopulationDeviation, doHasEqualPopulations } from './equal'; TODO - DELETE
102153
- // import { doReock, doPolsbyPopper } from './compact'; TODO - DELETE
102154
102105
  const cohesive_1 = __webpack_require__(/*! ./cohesive */ "./src/cohesive.ts");
102155
- /* TODO - DELETE
102156
- import
102157
- {
102158
- doFindCountiesSplitUnexpectedly, doFindSplitVTDs,
102159
- doCountySplitting, doDistrictSplitting
102160
- } from './cohesive';
102161
- import
102162
- {
102163
- doSeatsBias, doVotesBias,
102164
- doResponsiveness, doResponsiveDistricts, doEfficiencyGap
102165
- } from './political';
102166
- import { doMajorityMinorityDistricts } from './minority'
102167
- */
102168
102106
  // Compile district-level info for plan/map-level analytics
102169
102107
  function doAnalyzeDistricts(s, bLog = false) {
102170
102108
  s.districts.recalcStatistics(bLog);
@@ -102176,56 +102114,9 @@ exports.doAnalyzeDistricts = doAnalyzeDistricts;
102176
102114
  // NOTE - I could make this table-driven, but I'm thinking that the explicit
102177
102115
  // calls might make chunking for aync easier.
102178
102116
  function doAnalyzePlan(s, bLog = false) {
102179
- // TODO - DELETE
102180
- // if (s.useLegacy())
102181
- // {
102182
- // // Disable most legacy analytics
102183
- // // Get the requested suites, and only execute those tests
102184
- // let requestedSuites = s.config['suites'];
102185
- // // Tests in the "Legal" suite, i.e., pass/ fail constraints
102186
- // if (requestedSuites.includes(T.Suite.Legal))
102187
- // {
102188
- // s.tests[T.Test.Complete] = doIsComplete(s, bLog);
102189
- // s.tests[T.Test.Contiguous] = doIsContiguous(s, bLog);
102190
- // s.tests[T.Test.FreeOfHoles] = doIsFreeOfHoles(s, bLog);
102191
- // // s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
102192
- // // NOTE - I can't check whether a population deviation is legal or not, until
102193
- // // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
102194
- // // the given type of district (CD vs. LD). The EqualPopulation test is derived
102195
- // // from PopulationDeviation, as part of scorecard or test log preparation.
102196
- // // Create an empty test entry here though ...
102197
- // s.tests[T.Test.EqualPopulation] = s.getTest(T.Test.EqualPopulation) as T.TestEntry;
102198
- // }
102199
- // // Tests in the "Fair" suite
102200
- // if (requestedSuites.includes(T.Suite.Fair))
102201
- // {
102202
- // /* TODO - DELETE
102203
- // s.tests[T.Test.SeatsBias] = doSeatsBias(s, bLog);
102204
- // s.tests[T.Test.VotesBias] = doVotesBias(s, bLog);
102205
- // s.tests[T.Test.Responsiveness] = doResponsiveness(s, bLog);
102206
- // s.tests[T.Test.ResponsiveDistricts] = doResponsiveDistricts(s, bLog);
102207
- // s.tests[T.Test.EfficiencyGap] = doEfficiencyGap(s, bLog);
102208
- // s.tests[T.Test.MajorityMinorityDistricts] = doMajorityMinorityDistricts(s, bLog);
102209
- // */
102210
- // }
102211
- // // Tests in the "Best" suite, i.e., criteria for better/worse
102212
- // if (requestedSuites.includes(T.Suite.Best))
102213
- // {
102214
- // // s.tests[T.Test.Reock] = doReock(s, bLog); TODO - DELETE
102215
- // // s.tests[T.Test.PolsbyPopper] = doPolsbyPopper(s, bLog); TODO - DELETE
102216
- // s.tests[T.Test.UnexpectedCountySplits] = doFindCountiesSplitUnexpectedly(s, bLog);
102217
- // s.tests[T.Test.VTDSplits] = doFindSplitVTDs(s, bLog);
102218
- // // s.tests[T.Test.CountySplitting] = doCountySplitting(s, bLog); TODO - DELETE
102219
- // // s.tests[T.Test.DistrictSplitting] = doDistrictSplitting(s, bLog); TODO - DELETE
102220
- // }
102221
- // }
102222
- // else
102223
- // {
102224
- // TODO - SCORE: Except these. Continue to do these here vs. dra-score.
102225
102117
  s.tests[0 /* Complete */] = valid_1.doIsComplete(s, bLog);
102226
102118
  s.tests[1 /* Contiguous */] = valid_1.doIsContiguous(s, bLog);
102227
102119
  s.tests[2 /* FreeOfHoles */] = valid_1.doIsFreeOfHoles(s, bLog);
102228
- // s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
102229
102120
  // NOTE - I can't check whether a population deviation is legal or not, until
102230
102121
  // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
102231
102122
  // the given type of district (CD vs. LD). The EqualPopulation test is derived
@@ -102234,7 +102125,6 @@ function doAnalyzePlan(s, bLog = false) {
102234
102125
  s.tests[3 /* EqualPopulation */] = s.getTest(3 /* EqualPopulation */);
102235
102126
  s.tests[5 /* UnexpectedCountySplits */] = cohesive_1.doFindCountiesSplitUnexpectedly(s, bLog);
102236
102127
  s.tests[6 /* VTDSplits */] = cohesive_1.doFindSplitVTDs(s, bLog);
102237
- // }
102238
102128
  // Enable a Test Log and Scorecard to be generated
102239
102129
  s.bPlanAnalyzed = true;
102240
102130
  s.bPostProcessingDone = false;
@@ -102277,277 +102167,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
102277
102167
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
102278
102168
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
102279
102169
  // NOTE - The active code is below the long multi-line section to be deleted.
102280
- /* TODO - DELETE
102281
- // CALCULATE ENHANCED SQRT ENTROPY METRIC
102282
-
102283
- export function doCountySplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
102284
- {
102285
- let test = s.getTest(T.Test.CountySplitting) as T.TestEntry;
102286
-
102287
- let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
102288
- let countyTotals = s.counties.totalPopulation;
102289
- let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
102290
-
102291
- let f = calcCountyFractions(CxD, countyTotals);
102292
- let w = calcCountyWeights(countyTotals);
102293
-
102294
- let SqEnt_DC = countySplitting(f, w, bLog);
102295
-
102296
- let CxDreducedC = U.deepCopy(CxD);
102297
- reduceCSplits(CxDreducedC, districtTotals);
102298
-
102299
- let fReduced = calcCountyFractions(CxDreducedC, countyTotals);
102300
- let wReduced = calcCountyWeights(countyTotals);
102301
-
102302
- let SqEnt_DCreduced = countySplitting(fReduced, wReduced, bLog);
102303
-
102304
- test['score'] = SqEnt_DCreduced;
102305
- test['details']['SqEnt_DC'] = SqEnt_DC;
102306
-
102307
- return test;
102308
- }
102309
-
102310
- export function doDistrictSplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
102311
- {
102312
- let test = s.getTest(T.Test.DistrictSplitting) as T.TestEntry;
102313
-
102314
- let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
102315
- let countyTotals = s.counties.totalPopulation;
102316
- let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
102317
-
102318
- let g = calcDistrictFractions(CxD, districtTotals);
102319
- let x = calcDistrictWeights(districtTotals);
102320
-
102321
- let SqEnt_CD = districtSplitting(g, x, bLog);
102322
-
102323
- let CxDreducedD = U.deepCopy(CxD);
102324
- reduceDSplits(CxDreducedD, countyTotals);
102325
-
102326
- let gReduced = calcDistrictFractions(CxDreducedD, districtTotals);
102327
- let xReduced = calcDistrictWeights(districtTotals);
102328
-
102329
- let SqEnt_CDreduced = districtSplitting(gReduced, xReduced, bLog);
102330
-
102331
- test['score'] = SqEnt_CDreduced;
102332
- test['details']['SqEnt_CD'] = SqEnt_CD;
102333
-
102334
- return test;
102335
- }
102336
-
102337
-
102338
- // HELPERS
102339
-
102340
- // Loop over all the county-district combos, skipping the virtual district 0
102341
- // and virtual county 0.
102342
- //
102343
- // NOTE - The county-district splits and the county & district totals may all,
102344
- // in general, be fractional/decimal numbers as opposed to integers, due to
102345
- // dissaggregation & re-aggregation. Hence, comparisons need to approximate
102346
- // equality.
102347
-
102348
- // Consolidate districts (rows) consisting of just one county (column)
102349
- // UP into the dummy district (0).
102350
- function reduceCSplits(CxDreducedC: number[][], districtTotals: number[]): void
102351
- {
102352
- let nD = CxDreducedC.length;
102353
- let nC = CxDreducedC[0].length;
102354
-
102355
- for (let j = 1; j < nC; j++)
102356
- {
102357
- for (let i = 1; i < nD; i++)
102358
- {
102359
- let split_total = CxDreducedC[i][j];
102360
-
102361
- if (split_total > 0)
102362
- {
102363
- if (areRoughlyEqual(split_total, districtTotals[i]))
102364
- {
102365
- CxDreducedC[0][j] += split_total;
102366
- CxDreducedC[i][j] = 0;
102367
- }
102368
- }
102369
- }
102370
- }
102371
- }
102372
-
102373
- // Consolidate whole counties (columns) in a district (row) LEFT into the
102374
- // dummy county (0).
102375
- function reduceDSplits(CxDreducedD: number[][], countyTotals: number[]): void
102376
- {
102377
- let nD = CxDreducedD.length;
102378
- let nC = CxDreducedD[0].length;
102379
-
102380
- for (let i = 1; i < nD; i++)
102381
- {
102382
- for (let j = 1; j < nC; j++)
102383
- {
102384
- let split_total = CxDreducedD[i][j];
102385
-
102386
- if (split_total > 0)
102387
- {
102388
- if (areRoughlyEqual(split_total, countyTotals[j]))
102389
- {
102390
- CxDreducedD[i][0] += split_total;
102391
- CxDreducedD[i][j] = 0;
102392
- }
102393
- }
102394
- }
102395
- }
102396
- }
102397
-
102398
- function calcCountyWeights(countyTotals: number[]): number[]
102399
- {
102400
- let nC: number = countyTotals.length;
102401
- let cTotal: number = U.sumArray(countyTotals);
102402
-
102403
- let w: number[] = U.initArray(nC, 0.0);
102404
-
102405
- for (let j = 0; j < nC; j++)
102406
- {
102407
- w[j] = countyTotals[j] / cTotal;
102408
- }
102409
-
102410
- return w;
102411
- }
102412
-
102413
- function calcDistrictWeights(districtTotals: number[]): number[]
102414
- {
102415
- let nD = districtTotals.length;
102416
- let dTotal: number = U.sumArray(districtTotals);
102417
-
102418
- let x: number[] = U.initArray(nD, 0.0);
102419
-
102420
- for (let i = 0; i < nD; i++)
102421
- {
102422
- x[i] = districtTotals[i] / dTotal;
102423
- }
102424
-
102425
- return x;
102426
- }
102427
-
102428
- function calcCountyFractions(CxDreducedD: number[][], countyTotals: number[]): number[][]
102429
- {
102430
- let nD = CxDreducedD.length;
102431
- let nC = CxDreducedD[0].length;
102432
-
102433
- let f: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
102434
-
102435
- for (let j = 0; j < nC; j++)
102436
- {
102437
- for (let i = 0; i < nD; i++)
102438
- {
102439
- if (countyTotals[j] > 0)
102440
- {
102441
- f[i][j] = CxDreducedD[i][j] / countyTotals[j];
102442
- }
102443
- else
102444
- {
102445
- f[i][j] = 0.0;
102446
- }
102447
- }
102448
- }
102449
-
102450
- return f;
102451
- }
102452
-
102453
- function calcDistrictFractions(CxDreducedC: number[][], districtTotals: number[]): number[][]
102454
- {
102455
- let nD = CxDreducedC.length;
102456
- let nC = CxDreducedC[0].length;
102457
-
102458
- let g: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
102459
-
102460
- for (let j = 0; j < nC; j++)
102461
- {
102462
- for (let i = 0; i < nD; i++)
102463
- {
102464
- if (districtTotals[i] > 0)
102465
- {
102466
- g[i][j] = CxDreducedC[i][j] / districtTotals[i];
102467
- }
102468
- else
102469
- {
102470
- g[i][j] = 0.0;
102471
- }
102472
- }
102473
- }
102474
-
102475
- return g;
102476
- }
102477
-
102478
- // Deal with decimal census "counts" due to disagg/re-agg
102479
- function areRoughlyEqual(x: number, y: number): boolean
102480
- {
102481
- let delta = Math.abs(x - y);
102482
- let result = (delta < S.EQUAL_TOLERANCE) ? true : false;
102483
-
102484
- return result;
102485
- }
102486
-
102487
- // For all districts in a county, sum the split score.
102488
- function countySplitScore(j: number, f: number[][], numD: number, bLog: boolean = false): number
102489
- {
102490
- let e = 0.0;
102491
-
102492
- for (let i = 0; i < numD; i++)
102493
- {
102494
- e += Math.sqrt(f[i][j]);
102495
- }
102496
-
102497
- return e;
102498
- }
102499
-
102500
- // For all counties, sum the weighted county splits.
102501
- function countySplitting(f: number[][], w: number[], bLog: boolean = false): number
102502
- {
102503
- let numC = f[0].length;
102504
- let numD = f.length;
102505
-
102506
- let e = 0.0;
102507
-
102508
- for (let j = 0; j < numC; j++)
102509
- {
102510
- let splitScore = countySplitScore(j, f, numD, bLog);
102511
- e += w[j] * splitScore;
102512
-
102513
- if (bLog) console.log("County splitting =", j, w[j], splitScore, e);
102514
- }
102515
-
102516
- return U.trim(e, 3);
102517
- }
102518
-
102519
- // For all counties in a district, sum the split score.
102520
- function districtSplitScore(i: number, g: number[][], numC: number, bLog: boolean = false): number
102521
- {
102522
- let e = 0.0;
102523
-
102524
- for (let j = 0; j < numC; j++)
102525
- {
102526
- e += Math.sqrt(g[i][j]);
102527
- }
102528
-
102529
- return e;
102530
- }
102531
-
102532
- // For all districts, sum the weighted district splits.
102533
- function districtSplitting(g: number[][], x: number[], bLog: boolean = false): number
102534
- {
102535
- let numC = g[0].length;
102536
- let numD = g.length;
102537
-
102538
- let e = 0.0;
102539
-
102540
- for (let i = 0; i < numD; i++)
102541
- {
102542
- let splitScore = districtSplitScore(i, g, numC, bLog);
102543
- e += x[i] * splitScore;
102544
-
102545
- if (bLog) console.log("District split score =", i, x[i], splitScore, e);
102546
- }
102547
-
102548
- return U.trim(e, 3);
102549
- }
102550
- */
102551
102170
  // ANALYZE SIMPLE COUNTY & VTD SPLITTING
102552
102171
  /*
102553
102172
 
@@ -102711,164 +102330,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
102711
102330
  // NOTE - This file will NOT be empty, when legacy code is deleted.
102712
102331
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
102713
102332
  const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
102714
- // TODO - DELETE
102715
- // Measures of compactness compare district shapes to various ideally compact
102716
- // benchmarks, such as circles. All else equal, more compact districts are better.
102717
- //
102718
- // There are four popular measures of compactness. They either focus on how
102719
- // dispersed or how indented a shapes are.
102720
- //
102721
- // These first two measures are the most important:
102722
- //
102723
- // Reock is the primary measure of the dispersion of district shapes, calculated
102724
- // as “the area of the district to the area of the minimum spanning circle that
102725
- // can enclose the district.”
102726
- //
102727
- // R = A / A(Minimum Bounding Circle)
102728
- // R = A / (π * (D / 2)^2)
102729
- //
102730
- // R = 4A / πD^2
102731
- //
102732
- // where A is the area of the district and D is the diameter of the minimum
102733
- // bounding circle.
102734
- //
102735
- // Polsby-Popper is the primary measure of the indendentation of district shapes,
102736
- // calculated as the “the ratio of the area of the district to the area of a circle
102737
- // whose circumference is equal to the perimeter of the district.”
102738
- //
102739
- // PP = A / A(C)
102740
- //
102741
- // where C is that circle. In other words:
102742
- //
102743
- // P = 2πRc and A(C) = π(P / 2π)^2
102744
- //
102745
- // where P is the perimeter of the district and Rc is the radius of the circle.
102746
- //
102747
- // Hence, the measure simplifies to:
102748
- //
102749
- // PP = 4π * (A / P^2)
102750
- //
102751
- // I propose that we use these two, normalize them, and weight equally to determine
102752
- // our compactness value.
102753
- //
102754
- // These second two measures may be used to complement the primary ones above:
102755
- //
102756
- // Convex Hull is a secondary measure of the dispersion of district shapes, calculated
102757
- // as “the ratio of the district area to the area of the minimum convex bounding
102758
- // polygon (also known as a convex hull) enclosing the district.”
102759
- //
102760
- // CH = A / A(Convex Hull)
102761
- //
102762
- // where a convex hull is the minimum perimeter that encloses all points in a shape,
102763
- // basically the shortest unstretched rubber band that fits around the shape.
102764
- //
102765
- // Schwartzberg is a secondary measure of the degree of indentation of district
102766
- // shapes, calculated as “the ratio of the perimeter of the district to the circumference
102767
- // of a circle whose area is equal to the area of the district.”
102768
- //
102769
- // S = 1 / (P / C)
102770
- //
102771
- // where P is the perimeter of the district and C is the circumference of the circle.
102772
- // The radius of the circle is:
102773
- //
102774
- // Rc = SQRT(A / π)
102775
- //
102776
- // So, the circumference of the circle is:
102777
- //
102778
- // C = 2πRc or C = 2π * SQRT(A / π)
102779
- //
102780
- // Hence:
102781
- //
102782
- // S = 1 (P / 2π * SQRT(A / π))
102783
- //
102784
- // S = (2π * SQRT(A / π)) / P
102785
- //
102786
- // All these measures produce values between 0 and 1, with 0 being the least compact
102787
- // and 1 being the most compact. Sometimes these values are multiplied by 100 to
102788
- // give values between 0 and 100.
102789
- //
102790
- // For each measure, the compactness of a set of Congressional districts is the
102791
- // average of that measure for all the districts.
102792
- //
102793
- /* TODO - DELETE
102794
- // Calculate Reock compactness:
102795
- // reock = (4 * a) / (math.pi * d**2)
102796
- // NOTE - Depends on extractDistrictProperties running first
102797
- export function doReock(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
102798
- {
102799
- let test = s.getTest(T.Test.Reock) as T.TestEntry;
102800
-
102801
- // Calculate Reock scores by district
102802
- let scores: number[] = [];
102803
-
102804
- for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
102805
- {
102806
- let districtProps = s.districts.getGeoProperties(districtID);
102807
- // Guard against no shape and no properties
102808
- if (districtProps)
102809
- {
102810
- let a = districtProps[T.DistrictShapeProperty.Area];
102811
- let d = districtProps[T.DistrictShapeProperty.Diameter];
102812
-
102813
- let reock = (4 * a) / (Math.PI * d ** 2);
102814
-
102815
- // Save each district score
102816
- scores.push(reock);
102817
-
102818
- // Echo the results by district
102819
- if (bLog) console.log("Reock for district", districtID, "=", reock);
102820
- }
102821
- }
102822
-
102823
- // Populate the test entry ... for the shapes that exist!
102824
- let averageReock = U.avgArray(scores);
102825
-
102826
- test['score'] = U.trim(averageReock);
102827
- test['details'] = {}; // TODO - Any details?
102828
-
102829
- return test;
102830
- }
102831
-
102832
- // Calculate Polsby-Popper compactness measures:
102833
- // polsby_popper = (4 * math.pi) * (a / p**2)
102834
- // NOTE - Depends on extractDistrictProperties running first
102835
- export function doPolsbyPopper(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
102836
- {
102837
- let test = s.getTest(T.Test.PolsbyPopper) as T.TestEntry;
102838
-
102839
- // Calculate Polsby-Popper scores by district
102840
- let scores: number[] = [];
102841
-
102842
- for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
102843
- {
102844
- let districtProps = s.districts.getGeoProperties(districtID);
102845
- // Guard against no shape and no properties
102846
- if (districtProps)
102847
- {
102848
- let a = districtProps[T.DistrictShapeProperty.Area];
102849
- let p = districtProps[T.DistrictShapeProperty.Perimeter];
102850
-
102851
- let polsbyPopper = (4 * Math.PI) * (a / p ** 2);
102852
-
102853
- // Save each district score
102854
- scores.push(polsbyPopper);
102855
-
102856
- // Echo the results by district
102857
- if (bLog) console.log("Polsby-Popper for district", districtID, "=", polsbyPopper);
102858
- }
102859
- }
102860
-
102861
- // Populate the test entry ... for the shapes that exist!
102862
- let averagePolsbyPopper = U.avgArray(scores);
102863
-
102864
- test['score'] = U.trim(averagePolsbyPopper);
102865
- test['details'] = {}; // TODO - Any details?
102866
-
102867
- return test;
102868
- }
102869
- */
102870
102333
  // HELPER TO EXTRACT PROPERTIES OF DISTRICT SHAPES
102871
- // TODO - SCORE: Create an array, as opposed to a dict
102334
+ // TODO - Create an array, as opposed to a dict
102872
102335
  function extractDistrictProperties(s, bLog = false) {
102873
102336
  // NOTE - I am assuming that district IDs are integers 1–N
102874
102337
  for (let i = 1; i <= s.state.nDistricts; i++) {
@@ -102945,52 +102408,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
102945
102408
  };
102946
102409
  Object.defineProperty(exports, "__esModule", { value: true });
102947
102410
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
102948
- /* TODO - DELETE
102949
- export function doPopulationDeviation(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
102950
- {
102951
- let test = s.getTest(T.Test.PopulationDeviation) as T.TestEntry;
102952
-
102953
- let targetSize = s.state.totalPop / s.state.nDistricts;
102954
-
102955
- // Compute the min & max district populations
102956
- // ... excluding the dummy the 'unassigned' 0 and N+1 summary "districts"
102957
- let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
102958
- totPopByDistrict = totPopByDistrict.slice(1, -1);
102959
-
102960
- // Remove empty districts
102961
- totPopByDistrict = totPopByDistrict.filter(x => x > 0);
102962
-
102963
- let min = 0;
102964
- let max = 0;
102965
-
102966
- // If there's more than 1 non-empty district, calculate a non-zero deviation
102967
- if (totPopByDistrict.length > 1)
102968
- {
102969
- min = U.minArray(totPopByDistrict);
102970
- max = U.maxArray(totPopByDistrict);
102971
- }
102972
-
102973
- // Calculate the raw population deviation
102974
- let popDev = (max - min) / targetSize;
102975
-
102976
- // Round the raw value to the desired level of precision
102977
- popDev = U.trim(popDev);
102978
-
102979
- // Populate the test entry
102980
- test['score'] = popDev;
102981
- test['details'] = { 'maxDeviation': max - min };
102982
-
102983
- // Populate the N+1 summary "district" in district.statistics
102984
- let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
102985
- let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
102986
- let summaryRow = s.districts.numberOfRows() - 1;
102987
-
102988
- totalPop[summaryRow] = targetSize;
102989
- popDevPct[summaryRow] = popDev;
102990
-
102991
- return test;
102992
- }
102993
- */
102994
102411
  // NOTE - This validity check is *derived* and depends on population deviation %
102995
102412
  // being computed (above) and normalized in test log & scorecard generation.
102996
102413
  function doHasEqualPopulations(s, bLog = false) {
@@ -103117,7 +102534,7 @@ function gfPerimeter(poly) {
103117
102534
  exports.gfPerimeter = gfPerimeter;
103118
102535
  // TODO - POLY: Confirm Cartesian calculations w/ Terry
103119
102536
  // Cloned from polyPerimeter() in 'poly' and revised to use Cartesian distance
103120
- // NOTE: No conversion of degrees to radians!
102537
+ // NOTE - No conversion of degrees to radians!
103121
102538
  function _polygonPerimeter(poly) {
103122
102539
  let polyOptions = { noLatitudeCorrection: true }; // Cartesian distance
103123
102540
  poly = Poly.polyNormalize(poly, polyOptions);
@@ -103156,127 +102573,64 @@ exports.gfDiameter = gfDiameter;
103156
102573
 
103157
102574
  /***/ }),
103158
102575
 
103159
- /***/ "./src/political.ts":
103160
- /*!**************************!*\
103161
- !*** ./src/political.ts ***!
103162
- \**************************/
102576
+ /***/ "./src/minority.ts":
102577
+ /*!*************************!*\
102578
+ !*** ./src/minority.ts ***!
102579
+ \*************************/
103163
102580
  /*! no static exports found */
103164
102581
  /***/ (function(module, exports, __webpack_require__) {
103165
102582
 
103166
102583
  "use strict";
103167
102584
 
103168
102585
  //
103169
- // FAIR/PROPORTIONAL
102586
+ // PROTECTS MINORITIES
103170
102587
  //
102588
+ var __importDefault = (this && this.__importDefault) || function (mod) {
102589
+ return (mod && mod.__esModule) ? mod : { "default": mod };
102590
+ };
103171
102591
  Object.defineProperty(exports, "__esModule", { value: true });
103172
- // NOTE - This file will NOT be empty, when legacy code is deleted.
103173
- const assert_1 = __webpack_require__(/*! assert */ "assert");
103174
- /* TODO - DELETE
103175
- import * as D from './_data'
103176
- import { AnalyticsSession } from './_api';
103177
-
103178
-
103179
- // Partisan analytics need the following data:
103180
- //
103181
- // An "election model" by geo_id, where each item has 4 pieces of data:
103182
- //
103183
- // { geo_id, Democratic votes, Republican votes, Total votes }
103184
- //
103185
- // NOTE: D + R <= Total, because there could be third-party or write-in votes.
103186
- //
103187
- // An election model can simply represent one election, e.g., President 2012,
103188
- // or combine multiple elections in some fashion. An election model is used to
103189
- // computer a single index of the likely partisan weight / lean / preference
103190
- // for the districts in a plan. An election model and the associated index go
103191
- // hand in hand. So much so that the index frequently stands in as the name for
103192
- // both, e.g., Cook's PVI is one example, Nagle's 7s, Hofeller's Formula, NDRC's
103193
- // DPI.
103194
- //
103195
- // I'm labelling this general concept a "Voter Preference Index (VPI)," a
103196
- // conscious +1 letter play on Cook's "PVI" acronymn.
103197
-
103198
-
103199
- // MEASURING BIAS & RESPONSIVENESS (NAGLE'S METHOD)
103200
-
103201
- export function doSeatsBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
103202
- {
103203
- let test = s.getTest(T.Test.SeatsBias) as T.TestEntry;
103204
-
103205
- if (bLog) console.log("TODO - Calculating seats bias ...");
103206
-
103207
- return test;
103208
- }
103209
-
103210
- export function doVotesBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
103211
- {
103212
- let test = s.getTest(T.Test.VotesBias) as T.TestEntry;
103213
-
103214
- if (bLog) console.log("TODO - Calculating votes bias ...");
103215
-
103216
- return test;
102592
+ const majority_minority_json_1 = __importDefault(__webpack_require__(/*! ../static/majority-minority.json */ "./static/majority-minority.json"));
102593
+ const vra5_preclearance_json_1 = __importDefault(__webpack_require__(/*! ../static/vra5-preclearance.json */ "./static/vra5-preclearance.json"));
102594
+ // import stateContacts from '../static/state-contacts.json';
102595
+ // import demographicDefs from '../static/demographic-defns.json';
102596
+ // TODO - 2020: Update/revise this, when the update comes out in September:
102597
+ // Sources for majority-minority info:
102598
+ // - https://en.wikipedia.org/wiki/List_of_majority-minority_United_States_congressional_districts
102599
+ // - http://www.ncsl.org/Portals/1/Documents/Redistricting/Redistricting_2010.pdf (PP. 80–84)
102600
+ // - https://www.justice.gov/crt/jurisdictions-previously-covered-section-5
102601
+ function getMajorityMinority(s) {
102602
+ const xx = s.state.xx;
102603
+ const mMDict = majority_minority_json_1.default;
102604
+ const stateMM = mMDict[xx];
102605
+ return stateMM;
103217
102606
  }
103218
-
103219
- export function doResponsiveness(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
103220
- {
103221
- let test = s.getTest(T.Test.Responsiveness) as T.TestEntry;
103222
-
103223
- if (bLog) console.log("TODO - Calculating responsiveness ...");
103224
-
103225
- return test;
103226
- }
103227
-
103228
- export function doResponsiveDistricts(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
103229
- {
103230
- let test = s.getTest(T.Test.ResponsiveDistricts) as T.TestEntry;
103231
-
103232
- if (bLog) console.log("TODO - Calculating # of responsive districts ...");
103233
-
103234
- return test;
102607
+ exports.getMajorityMinority = getMajorityMinority;
102608
+ function getVRASection5(s) {
102609
+ const xx = s.state.xx;
102610
+ const vraPreDict = vra5_preclearance_json_1.default;
102611
+ const stateVRAPre = vraPreDict[xx];
102612
+ return stateVRAPre;
103235
102613
  }
102614
+ exports.getVRASection5 = getVRASection5;
103236
102615
 
103237
102616
 
103238
- // OTHER MEASURES OF PARTISAN BIAS
103239
-
103240
- // TODO - PARTISAN: This formula might need to be inverted for D vs. R +/-
103241
- // TODO - Normalize the results.
103242
- export function doEfficiencyGap(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
103243
- {
103244
- if (bLog) console.log("TODO - Calculating the efficiency gap ...");
103245
-
103246
- let test = s.getTest(T.Test.EfficiencyGap) as T.TestEntry;
103247
-
103248
- // Get partisan statistics by districts.
103249
- // Use Democratic votes, seats, and shares by convention.
103250
- let DVotes = s.districts.statistics[D.DistrictField.DemVotes];
103251
- let DSeats = s.districts.statistics[D.DistrictField.DemSeat];
103252
- let TPVotes = s.districts.statistics[D.DistrictField.TwoPartyVote];
103253
-
103254
- // Exclude the dummy unassigned '0' and N+1 summary "districts"
103255
- DVotes = DVotes.slice(1, -1);
103256
- DSeats = DSeats.slice(1, -1);
103257
- TPVotes = TPVotes.slice(1, -1);
103258
-
103259
- // Calculate D vote share & D seat share
103260
- let DVoteShare = U.sumArray(DVotes) / U.sumArray(TPVotes);
103261
- let DSeatShare = U.sumArray(DSeats) / s.state.nDistricts;
103262
-
103263
- // Finally, calculate the Efficiency Gap
103264
- let efficiencyGap = (DSeatShare - 0.5) - (2.0 * (DVoteShare - 0.5));
103265
-
103266
- // Round the raw value to the desired level of precision
103267
- efficiencyGap = U.trim(efficiencyGap);
103268
-
103269
- // Populate the test entry
103270
- test['score'] = efficiencyGap;
103271
- // test['normalizedScore'] = 0; // TODO - Normalize the raw score
103272
- test['details'] = {}; // TODO - Add details, if any
102617
+ /***/ }),
103273
102618
 
103274
- return test;
103275
- }
102619
+ /***/ "./src/political.ts":
102620
+ /*!**************************!*\
102621
+ !*** ./src/political.ts ***!
102622
+ \**************************/
102623
+ /*! no static exports found */
102624
+ /***/ (function(module, exports, __webpack_require__) {
103276
102625
 
102626
+ "use strict";
103277
102627
 
103278
- // HELPERS
103279
- */
102628
+ //
102629
+ // FAIR/PROPORTIONAL
102630
+ //
102631
+ Object.defineProperty(exports, "__esModule", { value: true });
102632
+ // NOTE - This file will NOT be empty, when legacy code is deleted.
102633
+ const assert_1 = __webpack_require__(/*! assert */ "assert");
103280
102634
  function fptpWin(demPct) {
103281
102635
  // Vote shares should be fractions in the range [0.0 – 1.0]
103282
102636
  assert_1.strict((demPct <= 1.0) && (demPct >= 0.));
@@ -103314,10 +102668,9 @@ function doPreprocessData(s, bLog = false) {
103314
102668
  if (!s.bOneTimeProcessingDone) {
103315
102669
  doPreprocessCountyFeatures(s, bLog);
103316
102670
  doPreprocessCensus(s, bLog);
103317
- doPreprocessElection(s, bLog);
102671
+ // doPreprocessElection(s, bLog);
103318
102672
  s.bOneTimeProcessingDone = true;
103319
102673
  }
103320
- // NOTE - UNASSIGNED: Made both the planByGeoID & DistrictID are right
103321
102674
  // Invert the plan by district ID
103322
102675
  s.plan.invertPlan();
103323
102676
  // Create a map of geoIDs to feature IDs
@@ -103399,7 +102752,6 @@ function doPreprocessCensus(s, bLog = false) {
103399
102752
  // Loop over the counties
103400
102753
  for (let county in fipsCodes) {
103401
102754
  let fipsCode = fipsCodes[county];
103402
- // NOTE - SPLITTING
103403
102755
  // Skip the dummy county
103404
102756
  if (fipsCode == '000')
103405
102757
  continue;
@@ -103423,10 +102775,10 @@ function doPreprocessCensus(s, bLog = false) {
103423
102775
  s.state.expectedAffected = expectedAffected;
103424
102776
  }
103425
102777
  // PREPROCESS ELECTION RESULTS
103426
- function doPreprocessElection(s, bLog = false) {
103427
- if (bLog)
103428
- console.log("TODO - Preprocessing election data ...");
103429
- }
102778
+ // function doPreprocessElection(s: AnalyticsSession, bLog: boolean = false): void
102779
+ // {
102780
+ // if (bLog) console.log("Preprocessing election data ...");
102781
+ // }
103430
102782
 
103431
102783
 
103432
102784
  /***/ }),
@@ -103459,234 +102811,6 @@ const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"
103459
102811
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
103460
102812
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
103461
102813
  const state_reqs_json_1 = __importDefault(__webpack_require__(/*! ../static/state-reqs.json */ "./static/state-reqs.json"));
103462
- // PLAN ANALYTICS
103463
- /* TODO - DELETE
103464
- export type RequirementsCategory = {
103465
- score: T.TriState;
103466
- metrics: {
103467
- complete: T.TriState;
103468
- contiguous: T.TriState;
103469
- freeOfHoles: T.TriState;
103470
- equalPopulation: T.TriState;
103471
- };
103472
- details: {
103473
- unassignedFeatures: string[]; // A possibly empty list of GEOIDs
103474
- emptyDistricts: number[]; // A possibly empty list of district IDs
103475
- discontiguousDistricts: number[]; // Ditto
103476
- embeddedDistricts: number[]; // Ditto
103477
- populationDeviation: number; // A fraction [0.0 – 1.0] to represent as a %
103478
- deviationThreshold: number; // A fraction [0.0 – 1.0] to represent as a %
103479
- };
103480
- datasets: T.Datasets;
103481
- resources: {
103482
- stateReqs: string;
103483
- };
103484
- };
103485
- */
103486
- /* TODO - DELETE
103487
- export type CompactnessCategory = {
103488
- score: number; // An integer score [0–100]
103489
- metrics: {
103490
- reock: number; // A decimal number [0.0–1.0]
103491
- polsby: number; // A decimal number [0.0–1.0]
103492
- };
103493
- details: {
103494
- // None at this time
103495
- };
103496
- datasets: T.Datasets;
103497
- resources: {
103498
- // None at this time
103499
- };
103500
- };
103501
- */
103502
- /* TODO - DELETE
103503
- export type SplittingCategory = {
103504
- score: number; // An integer score [0–100]
103505
- metrics: {
103506
- sqEnt_DCreduced: number, // A decimal number [1.0 – < 2.0]
103507
- sqEnt_CDreduced: number // A decimal number [1.0 – < 2.0]
103508
- };
103509
- details: {
103510
- countiesSplitUnexpectedly: string[], // A possibly empty list of county names
103511
- unexpectedAffected: number, // A fraction [0.0 – 1.0] to represent as a %
103512
- nSplitVTDs: number, // An integer, possibly 0
103513
- splitVTDs: string[] // A possibly empty list of GEOIDs
103514
- };
103515
- datasets: T.Datasets;
103516
- resources: {
103517
- // None at this time
103518
- };
103519
- };
103520
- */
103521
- /* TODO - DELETE
103522
- export type PartisanCategory = {
103523
- score: number; // An integer score [0–100]
103524
- metrics: {
103525
- partisanBias: 0.15, // TBD
103526
- responsiveness: 2.0 // TBD
103527
- };
103528
- details: {
103529
- // TODO - Need to flesh this out
103530
- };
103531
- datasets: T.Datasets;
103532
- resources: {
103533
- planScore?: string;
103534
- };
103535
- };
103536
- */
103537
- /* TODO - DELETE
103538
- export type MinorityCategory = {
103539
- score: null; // Explicitly NOT scored
103540
- metrics: {
103541
- nBlack37to50: number, // Integer >= 0; two-digit maximum
103542
- nBlackMajority: number, // Ditto
103543
- nHispanic37to50: number, // Ditto
103544
- nHispanicMajority: number, // Ditto
103545
- nPacific37to50: number, // Ditto
103546
- nPacificMajority: number, // Ditto
103547
- nAsian37to50: number, // Ditto
103548
- nAsianMajority: number, // Ditto
103549
- nNative37to50: number, // Ditto
103550
- nNativeMajority: number, // Ditto
103551
- nMinority37to50: number, // Ditto
103552
- nMinorityMajority: number, // Ditto
103553
-
103554
- averageDVoteShare: number // A fraction [0.0 – 1.0] to represent as a %
103555
- };
103556
- details: {
103557
- vap: true, // true = using VAP data; false = CVAP data
103558
- comboCategories: true // true = using combo fields; false = mutually exclusive
103559
- };
103560
- datasets: T.Datasets;
103561
- resources: {
103562
- // TODO - Add these ...
103563
- };
103564
- };
103565
- */
103566
- /* TODO - DELETE
103567
- export type PlanAnalytics = {
103568
- requirements: RequirementsCategory;
103569
- compactness: CompactnessCategory;
103570
- // TODO - Don't show these categories yet
103571
- splitting: SplittingCategory;
103572
- partisan: PartisanCategory;
103573
- minority: MinorityCategory;
103574
- }
103575
- */
103576
- // EXAMPLE
103577
- /* TODO - DELETE
103578
- let sampleRequirements: RequirementsCategory = {
103579
- score: T.TriState.Red,
103580
- metrics: {
103581
- complete: T.TriState.Green,
103582
- contiguous: T.TriState.Red,
103583
- freeOfHoles: T.TriState.Yellow,
103584
- equalPopulation: T.TriState.Red
103585
- },
103586
- details: {
103587
- unassignedFeatures: [],
103588
- emptyDistricts: [],
103589
- discontiguousDistricts: [2],
103590
- embeddedDistricts: [],
103591
- populationDeviation: 0.6748,
103592
- deviationThreshold: 0.75 / 100
103593
- },
103594
- datasets: {
103595
- census: "2010 Census Total Population"
103596
- },
103597
- resources: {
103598
- stateReqs: "https://www.brennancenter.org/sites/default/files/publications/2019_06_50States_FINALsinglepages_20.pdf"
103599
- }
103600
- }
103601
- */
103602
- /* TODO - DELETE
103603
- let sampleCompactness: CompactnessCategory = {
103604
- score: 60,
103605
- metrics: {
103606
- reock: 0.3773,
103607
- polsby: 0.3815
103608
- },
103609
- details: {},
103610
- datasets: {
103611
- shapes: "2010 VTD shapes"
103612
- },
103613
- resources: {}
103614
- }
103615
- */
103616
- /* TODO - DELETE
103617
- let sampleSplitting: SplittingCategory = {
103618
- score: 73,
103619
- metrics: {
103620
- sqEnt_DCreduced: 1.531,
103621
- sqEnt_CDreduced: 1.760
103622
- },
103623
- details: {
103624
- countiesSplitUnexpectedly: [
103625
- "Bladen", "Buncombe", "Catawba", "Cumberland", "Durham", "Guilford", "Iredell", "Johnston", "Pitt", "Rowan", "Wilson"
103626
- ],
103627
- unexpectedAffected: 0.3096,
103628
- nSplitVTDs: 12,
103629
- splitVTDs: ["VTD-01", "VTD-02", "VTD-03", "VTD-04", "VTD-05", "VTD-06", "VTD-07", "VTD-08", "VTD-09", "VTD-10", "VTD-11", "VTD-12"]
103630
- },
103631
- datasets: {},
103632
- resources: {}
103633
- }
103634
- */
103635
- /* TODO - DELETE
103636
- let samplePartisan: PartisanCategory = {
103637
- score: 100,
103638
- metrics: {
103639
- partisanBias: 0.15,
103640
- responsiveness: 2.0
103641
- },
103642
- details: {},
103643
- datasets: {
103644
- election: "2016 Presidential, US Senate, Governor, and AG election results"
103645
- },
103646
- resources: {
103647
- planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
103648
- }
103649
- }
103650
- */
103651
- /* TODO - DELETE
103652
- let sampleMinority: MinorityCategory = {
103653
- score: null,
103654
- metrics: {
103655
- nBlack37to50: 1,
103656
- nBlackMajority: 12,
103657
- nHispanic37to50: 0,
103658
- nHispanicMajority: 0,
103659
- nPacific37to50: 0,
103660
- nPacificMajority: 0,
103661
- nAsian37to50: 0,
103662
- nAsianMajority: 0,
103663
- nNative37to50: 0,
103664
- nNativeMajority: 0,
103665
- nMinority37to50: 0,
103666
- nMinorityMajority: 0,
103667
-
103668
- averageDVoteShare: 0.90
103669
- },
103670
- details: {
103671
- vap: true,
103672
- comboCategories: true
103673
- },
103674
- datasets: {
103675
- vap: "2010 Voting Age Population"
103676
- },
103677
- resources: {}
103678
- }
103679
- */
103680
- /* TODO - DELETE
103681
- export const samplePlanAnalytics: PlanAnalytics = {
103682
- requirements: sampleRequirements,
103683
- compactness: sampleCompactness,
103684
- // TODO - Don't show these categories yet
103685
- splitting: sampleSplitting,
103686
- partisan: samplePartisan,
103687
- minority: sampleMinority
103688
- }
103689
- */
103690
102814
  function prepareRequirementsChecklist(s, bLog = false) {
103691
102815
  if (!(s.bPostProcessingDone)) {
103692
102816
  doAnalyzePostProcessing(s);
@@ -103716,14 +102840,8 @@ function prepareRequirementsChecklist(s, bLog = false) {
103716
102840
  const emptyDistrictsDetail = U.deepCopy(completeTest['details']['emptyDistricts']) || [];
103717
102841
  const discontiguousDistrictsDetail = U.deepCopy(contiguousTest['details']['discontiguousDistricts']) || [];
103718
102842
  const embeddedDistrictsDetail = U.deepCopy(freeOfHolesTest['details']['embeddedDistricts']) || [];
103719
- // TODO - SCORE: DELETE - This code is hooked correctly to use dra-score
103720
- // const scorecard = s._scorecard as Score.Scorecard;
103721
- // const populationDeviation = scorecard.best.populationDeviation.raw;
103722
102843
  const populationDeviationDetail = U.deepCopy(equalPopulationTest['details']['deviation']);
103723
- // console.log("Population deviations =", populationDeviationDetail, populationDeviation);
103724
- // const deviationThreshold = scorecard.best.populationDeviation.notes['threshold'];
103725
102844
  const deviationThresholdDetail = U.trim(s.populationDeviationThreshold());
103726
- // console.log("Population deviation thresholds =", deviationThresholdDetail, deviationThreshold);
103727
102845
  const xx = s.state.xx;
103728
102846
  // TODO - JSON: Is there a better / easier way to work with the variable?
103729
102847
  const stateReqsDict = state_reqs_json_1.default;
@@ -103806,8 +102924,8 @@ function prepareDistrictStatistics(s, bLog = false) {
103806
102924
  s.districts.statistics[D.DistrictField.AsianPct][i],
103807
102925
  s.districts.statistics[D.DistrictField.NativePct][i]
103808
102926
  ];
103809
- // TODO - DASHBOARD: Until we add three-state support top to bottom in
103810
- // requirements/validations, map booleans to tri-states here.
102927
+ // NOTE - Until we add three-state support top to bottom in Requirements,
102928
+ // map booleans to tri-states here.
103811
102929
  rawRow[3 /* bEqualPop */] = U.mapBooleanToTriState(rawRow[3 /* bEqualPop */]);
103812
102930
  rawRow[4 /* bNotEmpty */] = U.mapBooleanToTriState(rawRow[4 /* bNotEmpty */]);
103813
102931
  rawRow[5 /* bContiguous */] = U.mapBooleanToTriState(rawRow[5 /* bContiguous */]);
@@ -103882,24 +103000,6 @@ const populationDeviationDefn = {
103882
103000
  externalType: TestType.Percentage,
103883
103001
  suites: [0 /* Legal */, 2 /* Best */] // Both so EqualPopulation can be assessed
103884
103002
  };
103885
- /* TODO - DELETE
103886
- const reockDefn: T.Dict = {
103887
- ID: T.Test.Reock,
103888
- name: "Reock",
103889
- normalize: true,
103890
- externalType: TestType.Number,
103891
- suites: [T.Suite.Best]
103892
- };
103893
-
103894
- const polsbyPopperDefn: T.Dict = {
103895
- ID: T.Test.PolsbyPopper,
103896
- name: "Polsby-Popper",
103897
- normalize: true,
103898
- externalType: TestType.Number,
103899
- suites: [T.Suite.Best]
103900
- };
103901
- */
103902
- // NOTE - SPLITTING
103903
103003
  const unexpectedCountySplitsDefn = {
103904
103004
  ID: 5 /* UnexpectedCountySplits */,
103905
103005
  name: "Unexpected County Splits",
@@ -103907,7 +103007,6 @@ const unexpectedCountySplitsDefn = {
103907
103007
  externalType: TestType.Percentage,
103908
103008
  suites: [2 /* Best */]
103909
103009
  };
103910
- // NOTE - SPLITTING
103911
103010
  const VTDSplitsDefn = {
103912
103011
  ID: 6 /* VTDSplits */,
103913
103012
  name: "VTD Splits",
@@ -103922,87 +103021,16 @@ const testDefns = {
103922
103021
  [2 /* FreeOfHoles */]: freeOfHolesDefn,
103923
103022
  [3 /* EqualPopulation */]: equalPopulationDefn,
103924
103023
  [4 /* PopulationDeviation */]: populationDeviationDefn,
103925
- // [T.Test.Reock]: reockDefn, TODO - DELETE
103926
- // [T.Test.PolsbyPopper]: polsbyPopperDefn, TODO - DELETE
103927
103024
  [5 /* UnexpectedCountySplits */]: unexpectedCountySplitsDefn,
103928
103025
  [6 /* VTDSplits */]: VTDSplitsDefn,
103929
103026
  };
103930
- /* TODO - DELETE
103931
- // NORMALIZE RAW ANALYTICS
103932
- // Raw numeric analytics, such as population deviation, compactness, etc. are
103933
- // normalized as part of creating a scorecard, so the code to normalize results
103934
- // is encapsulated here.
103935
-
103936
- // Configure scale parameters for normalizing each raw test result.
103937
- // Scales consist of a minimum & a maximum *raw* value. If the values get
103938
- // inverted (to make bigger better), these will switch.
103939
- // This process needs to be separate from the test configuration info above,
103940
- // because some scales need access to the analytics session object.
103941
- export function doConfigureScales(s: AnalyticsSession): void
103942
- {
103943
- // Scale defn for PopulationDeviation
103944
- const CDLimit = 0.75 / 100; // Deviation threshold for CD's
103945
- const LDLimit = 10.00 / 100; // Deviation threshold for LD's
103946
-
103947
- const CDGoodEnough = 0.20 / 100;
103948
- const LDGoodEnough = (CDGoodEnough / CDLimit) * LDLimit;
103949
- const popDevScale = (s.legislativeDistricts) ? [1.0 - LDLimit, 1.0 - LDGoodEnough] : [1.0 - CDLimit, 1.0 - CDGoodEnough];
103950
- // const scale = [1.0 - CDLimit, 1.0 - CDGoodEnough];
103951
-
103952
- s.testScales[T.Test.PopulationDeviation] = { scale: popDevScale, bInvertRaw: true };
103953
-
103954
- s.testScales[T.Test.Reock] = { scale: [0.25, 0.50] };
103955
- s.testScales[T.Test.PolsbyPopper] = { scale: [0.10, 0.50] };
103956
-
103957
- const nDistricts = s.state.nDistricts;
103958
- const nCounties = s.counties.nCounties;
103959
-
103960
- // NOTE - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
103961
- // number of county splits seems too stringent, empirically.
103962
- const allowableCountySplitsMultiplier = 1.5;
103963
- const nAllowableSplits = Math.min(allowableCountySplitsMultiplier * (nDistricts - 1));
103964
- const countySplittingThreshold = ((nAllowableSplits * 1.71) + ((nCounties - nAllowableSplits) * 1.0)) / nCounties;
103965
- const countySplittingScale = [1.0, countySplittingThreshold];
103966
- s.testScales[T.Test.CountySplitting] = { scale: countySplittingScale, bInvertScaled: true };
103967
-
103968
- const districtSplittingThreshold = 1.5;
103969
- const districtSplittingScale = [1.0, districtSplittingThreshold];
103970
- s.testScales[T.Test.DistrictSplitting] = { scale: districtSplittingScale, bInvertScaled: true };
103971
-
103972
- // TODO - More analytics ...
103973
- }
103974
- */
103975
103027
  // Postprocess analytics - Normalize numeric results and derive secondary tests.
103976
103028
  // Do this after analytics have been run and before preparing a test log or scorecard.
103977
103029
  function doAnalyzePostProcessing(s, bLog = false) {
103978
- // TODO - DELETE
103979
- // if (s.useLegacy())
103980
- // {
103981
- // // Normalize the raw scores for all the numerics tests
103982
- // let testResults = U.getNumericObjectKeys(testDefns);
103983
- // for (let testID of testResults)
103984
- // {
103985
- // if (testDefns[testID]['normalize'])
103986
- // {
103987
- // let testResult = s.getTest(testID) as T.TestEntry;
103988
- // let rawScore = testResult['score'] as number;
103989
- // let normalizedScore: number;
103990
- // normalizedScore = U.normalize(rawScore, s.testScales[testID]);
103991
- // testResult['normalizedScore'] = normalizedScore;
103992
- // // Add the scale used to normalize the raw score to the details
103993
- // testResult['details']['scale'] = s.testScales[testID].scale;
103994
- // }
103995
- // }
103996
- // }
103997
- // else
103998
- // {
103999
103030
  // Just populate the normalized population deviation score in the test
104000
103031
  const scorecard = s._scorecard;
104001
103032
  let popDev = s.getTest(4 /* PopulationDeviation */);
104002
103033
  popDev['normalizedScore'] = scorecard.traditionalPrinciples.populationDeviation.normalized;
104003
- // TODO - DELETE
104004
- // test['normalizedScore'] = scorecard.best.populationDeviation.normalized;
104005
- // TODO - SCORE: Add datasets used to details by tab
104006
103034
  const datasets = {
104007
103035
  shapes: S.SHAPES,
104008
103036
  census: U.deepCopy(s.config['descriptions']['CENSUS']),
@@ -104013,12 +103041,10 @@ function doAnalyzePostProcessing(s, bLog = false) {
104013
103041
  scorecard.minority.details['vap'] = datasets.vap;
104014
103042
  scorecard.traditionalPrinciples.details['shapes'] = datasets.shapes;
104015
103043
  scorecard.traditionalPrinciples.details['census'] = datasets.census;
104016
- // TODO - SCORE: Add legacy splits details
104017
103044
  const simpleSplits = s.getTest(5 /* UnexpectedCountySplits */);
104018
103045
  scorecard.traditionalPrinciples.details['unexpectedAffected'] = simpleSplits['score'];
104019
103046
  scorecard.traditionalPrinciples.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
104020
103047
  // NOTE - Add split precincts in dra-client directly
104021
- // }
104022
103048
  // Derive secondary tests
104023
103049
  analyze_1.doDeriveSecondaryTests(s, bLog);
104024
103050
  // Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard
@@ -104052,6 +103078,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
104052
103078
  const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "./node_modules/@dra2020/dra-score/dist/dra-score.bundle.js"));
104053
103079
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
104054
103080
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
103081
+ const M = __importStar(__webpack_require__(/*! ./minority */ "./src/minority.ts"));
104055
103082
  // PROFILE A PLAN
104056
103083
  function profilePlan(s, bLog = false) {
104057
103084
  const state = s.state.xx;
@@ -104157,26 +103184,23 @@ function getStatewideDemographics(s, bLog = false) {
104157
103184
  function scorePlan(s, p, bLog = false, overridesJSON) {
104158
103185
  let scorer = new Score.Scorer();
104159
103186
  const scorecard = scorer.score(p, overridesJSON);
104160
- // TODO - SCORE: Toggle: Before returning, create a dummy population deviation
104161
- // test, for doHasEqualPopulations() to use later. This is preserving the old
104162
- // calling sequence.
103187
+ // Before returning, create a dummy population deviation test, for
103188
+ // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
104163
103189
  let test = s.getTest(4 /* PopulationDeviation */);
104164
- // TODO - SCORE: U.trim(popDev)???
104165
- // const popDev = scorecard.best.populationDeviation.raw;
104166
103190
  // Get the raw population deviation
104167
103191
  const popDev = scorecard.traditionalPrinciples.populationDeviation.raw;
104168
103192
  // Populate the test entry
104169
103193
  test['score'] = popDev;
104170
103194
  test['details'] = { 'maxDeviation': scorecard.traditionalPrinciples.populationDeviation.notes['maxDeviation'] };
104171
- // TODO - DELETE
104172
- // test['details'] = { 'maxDeviation': scorecard.best.populationDeviation.notes['maxDeviation'] };
104173
103195
  // Populate the N+1 summary "district" in district.statistics
104174
103196
  let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
104175
103197
  let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
104176
103198
  let summaryRow = s.districts.numberOfRows() - 1;
104177
103199
  totalPop[summaryRow] = p.populationProfile.targetSize;
104178
103200
  popDevPct[summaryRow] = popDev;
104179
- //
103201
+ // Add minority notes
103202
+ scorecard.minority.details['majorityMinority'] = M.getMajorityMinority(s);
103203
+ scorecard.minority.details['vraPreclearance'] = M.getVRASection5(s);
104180
103204
  return scorecard;
104181
103205
  }
104182
103206
  exports.scorePlan = scorePlan;
@@ -104254,7 +103278,6 @@ function isOutOfState(geoID) {
104254
103278
  return geoID == S.OUT_OF_STATE;
104255
103279
  }
104256
103280
  exports.isOutOfState = isOutOfState;
104257
- // NOTE - UNASSIGNED
104258
103281
  // Get the districtID to which a geoID is assigned
104259
103282
  function getDistrict(plan, geoID) {
104260
103283
  // All geoIDs in a state *should be* assigned to a district (including the
@@ -104309,7 +103332,6 @@ function normalize(rawScore, testScale) {
104309
103332
  let coercedValue = Math.min(Math.max(rawScore, rangeMin), rangeMax);
104310
103333
  // Scale the bounded value w/in the range [0 - (rangeMax - rangeMin)]
104311
103334
  let scaledValue = (coercedValue - rangeMin) / (rangeMax - rangeMin);
104312
- // NOTE - SPLITTING
104313
103335
  // Invert the scaled value if necessary to make bigger = better
104314
103336
  if (testScale.bInvertScaled) {
104315
103337
  scaledValue = 1.0 - scaledValue;
@@ -104508,7 +103530,7 @@ function doIsComplete(s, bLog = false) {
104508
103530
  if (!bAllAssigned) {
104509
103531
  let unassignedDistrict = s.plan.geoIDsForDistrictID(S.NOT_ASSIGNED);
104510
103532
  unassignedFeatures = Array.from(unassignedDistrict);
104511
- unassignedFeatures = unassignedFeatures.slice(0, S.NUMBER_OF_ITEMS_TO_REPORT);
103533
+ // unassignedFeatures = unassignedFeatures.slice(0, S.NUMBER_OF_ITEMS_TO_REPORT);
104512
103534
  }
104513
103535
  // Do all real districts have at least one feature assigned to them?
104514
103536
  let emptyDistricts = [];
@@ -104712,6 +103734,17 @@ function isEmbedded(districtID, geoIDs, plan, graph) {
104712
103734
  exports.isEmbedded = isEmbedded;
104713
103735
 
104714
103736
 
103737
+ /***/ }),
103738
+
103739
+ /***/ "./static/majority-minority.json":
103740
+ /*!***************************************!*\
103741
+ !*** ./static/majority-minority.json ***!
103742
+ \***************************************/
103743
+ /*! exports provided: AL, AK, AZ, AR, CA, CO, CT, DE, FL, GA, HI, ID, IL, IN, IA, KS, KY, LA, ME, MD, MA, MI, MN, MS, MO, MT, NE, NV, NH, NJ, NM, NY, NC, ND, OH, OK, OR, PA, RI, SC, SD, TN, TX, UT, VT, VA, WA, WV, WI, WY, default */
103744
+ /***/ (function(module) {
103745
+
103746
+ module.exports = JSON.parse("{\"AL\":{\"Black\":[7],\"Hispanic\":[],\"Pacific\":[]},\"AK\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"AZ\":{\"Black\":[],\"Hispanic\":[2,4,7],\"Pacific\":[]},\"AR\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"CA\":{\"Black\":[13,37,43],\"Hispanic\":[17,18,20,21,28,31,32,34,35,38,39,43,45,47,51],\"Pacific\":[12,13,14,15,17,18,19,27,34,39,45,47,52]},\"CO\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"CT\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"DE\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"FL\":{\"Black\":[5,20,24],\"Hispanic\":[18,21,25],\"Pacific\":[]},\"GA\":{\"Black\":[2,4,5,13],\"Hispanic\":[],\"Pacific\":[]},\"HI\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[2]},\"ID\":{\"Black\":[],\"Hispanic\":[1],\"Pacific\":[]},\"IL\":{\"Black\":[1,2,7],\"Hispanic\":[4],\"Pacific\":[]},\"IN\":{\"Black\":[7],\"Hispanic\":[],\"Pacific\":[]},\"IA\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"KS\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"KY\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"LA\":{\"Black\":[2],\"Hispanic\":[],\"Pacific\":[]},\"ME\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"MD\":{\"Black\":[4,7],\"Hispanic\":[],\"Pacific\":[]},\"MA\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"MI\":{\"Black\":[13,14],\"Hispanic\":[],\"Pacific\":[]},\"MN\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"MS\":{\"Black\":[2],\"Hispanic\":[],\"Pacific\":[]},\"MO\":{\"Black\":[1,5],\"Hispanic\":[],\"Pacific\":[]},\"MT\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"NE\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"NV\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"NH\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"NJ\":{\"Black\":[10,12],\"Hispanic\":[13],\"Pacific\":[6]},\"NM\":{\"Black\":[],\"Hispanic\":[2,13],\"Pacific\":[]},\"NY\":{\"Black\":[5,8,9,13],\"Hispanic\":[12,16],\"Pacific\":[6,7,10]},\"NC\":{\"Black\":[1,12],\"Hispanic\":[],\"Pacific\":[]},\"ND\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"OH\":{\"Black\":[3,11],\"Hispanic\":[],\"Pacific\":[]},\"OK\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"OR\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"PA\":{\"Black\":[2],\"Hispanic\":[],\"Pacific\":[]},\"RI\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"SC\":{\"Black\":[6],\"Hispanic\":[],\"Pacific\":[]},\"SD\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"TN\":{\"Black\":[9],\"Hispanic\":[],\"Pacific\":[]},\"TX\":{\"Black\":[9,18,33],\"Hispanic\":[15,16,19,20,23,27,28,29,32],\"Pacific\":[]},\"UT\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"VT\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"VA\":{\"Black\":[3],\"Hispanic\":[],\"Pacific\":[]},\"WA\":{\"Black\":[],\"Hispanic\":[3],\"Pacific\":[9]},\"WV\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]},\"WI\":{\"Black\":[4],\"Hispanic\":[],\"Pacific\":[]},\"WY\":{\"Black\":[],\"Hispanic\":[],\"Pacific\":[]}}");
103747
+
104715
103748
  /***/ }),
104716
103749
 
104717
103750
  /***/ "./static/state-reqs.json":
@@ -104725,6 +103758,17 @@ module.exports = JSON.parse("{\"AL\":\"https://www.brennancenter.org/sites/defau
104725
103758
 
104726
103759
  /***/ }),
104727
103760
 
103761
+ /***/ "./static/vra5-preclearance.json":
103762
+ /*!***************************************!*\
103763
+ !*** ./static/vra5-preclearance.json ***!
103764
+ \***************************************/
103765
+ /*! exports provided: AL, AK, AZ, CA, FL, GA, LA, MI, MS, NY, NC, SC, SD, TX, VA, default */
103766
+ /***/ (function(module) {
103767
+
103768
+ module.exports = JSON.parse("{\"AL\":\"all\",\"AK\":\"all\",\"AZ\":\"all\",\"CA\":\"parts\",\"FL\":\"parts\",\"GA\":\"all\",\"LA\":\"all\",\"MI\":\"parts\",\"MS\":\"all\",\"NY\":\"parts\",\"NC\":\"parts\",\"SC\":\"all\",\"SD\":\"parts\",\"TX\":\"all\",\"VA\":\"all\"}");
103769
+
103770
+ /***/ }),
103771
+
104728
103772
  /***/ "./test/_cli.ts":
104729
103773
  /*!**********************!*\
104730
103774
  !*** ./test/_cli.ts ***!
@@ -104828,19 +103872,7 @@ let argv = yargs_1.default
104828
103872
  .example('$0 equal -f foo.geojson', 'Calculate population deviation')
104829
103873
  .demandCommand(1, 'You must specify a command to execute.')
104830
103874
  .command('valid', 'Perform validations.')
104831
- /* TODO - DELETE
104832
- .command('equal', 'Calculate population deviation.')
104833
- .command('compact', 'Calculate compactness.')
104834
- .command('cohesive', 'Calculate cohesiveness.')
104835
- .command('political', 'Assess fairness.')
104836
- .command('minority', 'Count majority-minority districts.')
104837
- */
104838
103875
  .command('analyze', 'API call to analyze a plan.')
104839
- /* TODO - DELETE
104840
- .command('scorecard', 'Analyze plan & generate a scorecard.')
104841
- .command('testlog', 'Analyze plan & generate a testlog.')
104842
- .command('report', 'API call to generate a scorecard.')
104843
- */
104844
103876
  .option('state', {
104845
103877
  alias: 'x',
104846
103878
  describe: 'Specify the state.',
@@ -105057,94 +104089,15 @@ switch (command) {
105057
104089
  let t1 = valid_1.doIsComplete(s);
105058
104090
  let t2 = valid_1.doIsContiguous(s);
105059
104091
  let t3 = valid_1.doIsFreeOfHoles(s);
105060
- // let t4 = doPopulationDeviation(s); TODO - DELETE
105061
104092
  let t5 = equal_1.doHasEqualPopulations(s);
105062
104093
  results_1.doAnalyzePostProcessing(s);
105063
104094
  echoTestResult("Complete:", t1);
105064
104095
  echoTestResult("Contiguous:", t2);
105065
104096
  echoTestResult("Free of holes:", t3);
105066
- // echoTestResult("Population deviation (%):", t4); TODO - DELETE
105067
104097
  echoTestResult("Equal populations:", t5);
105068
104098
  break;
105069
104099
  }
105070
- /* TODO - DELETE: Code moved to dra-score
105071
- case 'equal': {
105072
- doPreprocessData(s);
105073
- doAnalyzeDistricts(s);
105074
-
105075
- t = doPopulationDeviation(s);
105076
- echoTestResult("Population deviation (%):", t);
105077
-
105078
- doAnalyzePostProcessing(s);
105079
- break;
105080
- }
105081
- case 'compact': {
105082
- doPreprocessData(s);
105083
- doAnalyzeDistricts(s);
105084
-
105085
- let t1 = doReock(s, bLog);
105086
- let t2 = doPolsbyPopper(s, bLog);
105087
-
105088
- doAnalyzePostProcessing(s);
105089
-
105090
- echoTestResult("Reock:", t1);
105091
- echoTestResult("Polsby-Popper:", t2);
105092
-
105093
- break;
105094
- }
105095
- case 'cohesive': {
105096
- doPreprocessData(s);
105097
- doAnalyzeDistricts(s);
105098
-
105099
- // NOTE - SPLITTING
105100
- let t1 = doFindCountiesSplitUnexpectedly(s);
105101
- let t2 = doFindSplitVTDs(s);
105102
- let t3 = doCountySplitting(s);
105103
- let t4 = doDistrictSplitting(s);
105104
-
105105
- doAnalyzePostProcessing(s);
105106
-
105107
- echoTestResult("Counties split unexpectedly:", t1);
105108
- echoTestResult("Split VTDs:", t2);
105109
- echoTestResult("County splitting:", t3);
105110
- echoTestResult("District splitting:", t4);
105111
-
105112
- break;
105113
- }
105114
- case 'political': {
105115
- doPreprocessData(s);
105116
- doAnalyzeDistricts(s);
105117
-
105118
- let t1 = doSeatsBias(s);
105119
- let t2 = doVotesBias(s);
105120
- let t3 = doResponsiveness(s);
105121
- let t4 = doResponsiveDistricts(s);
105122
- let t5 = doEfficiencyGap(s);
105123
-
105124
- doAnalyzePostProcessing(s);
105125
-
105126
- // echoTestResult("Seats Bias:", t1); TODO
105127
- // echoTestResult("Votes Bias:", t2); TODO
105128
- // echoTestResult("Responsiveness:", t3); TODO
105129
- // echoTestResult("Responsive Districts:", t4); TODO
105130
- echoTestResult("Efficiency gap (%):", t5);
105131
-
105132
- break;
105133
- }
105134
- case 'minority': {
105135
- doPreprocessData(s);
105136
- doAnalyzeDistricts(s);
105137
-
105138
- let t1 = doMajorityMinorityDistricts(s);
105139
-
105140
- doAnalyzePostProcessing(s);
105141
-
105142
- // echoTestResult("Majority-Minority Districts:", t1); TODO
105143
-
105144
- break;
105145
- }
105146
- */
105147
- // TODO - SCORE: Update this w/ scoring info
104100
+ // TODO - Update this w/ scoring info
105148
104101
  case 'analyze': {
105149
104102
  s.analyzePlan(bLog);
105150
104103
  // let planAnalytics = s.getPlanAnalytics(bLog);