@dra2020/district-analytics 6.3.0 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -89099,10 +89099,10 @@ exports.scorePolsbyPopper = scorePolsbyPopper;
89099
89099
  /*!*************************!*\
89100
89100
  !*** ./src/config.json ***!
89101
89101
  \*************************/
89102
- /*! exports provided: partisan, minority, traditionalPrinciples, default */
89102
+ /*! exports provided: partisan, minority, compactness, splitting, popdev, default */
89103
89103
  /***/ (function(module) {
89104
89104
 
89105
- module.exports = JSON.parse("{\"partisan\":{\"bias\":{\"range\":[0,0.2],\"weight\":[50,80]},\"impact\":{\"weight\":[50,0],\"threshold\":4},\"competitiveness\":{\"range\":[0,0.75],\"distribution\":[0.25,0.75],\"simpleRange\":[0.45,0.55],\"weight\":[0,20]},\"bonus\":2,\"weight\":[100,80]},\"minority\":{\"range\":[0.37,0.5],\"distribution\":[0.25,0.75],\"shift\":0.15,\"coalition\":{\"weight\":0.5},\"bonus\":20},\"traditionalPrinciples\":{\"compactness\":{\"reock\":{\"range\":[0.25,0.5],\"weight\":50},\"polsby\":{\"range\":[0.1,0.5],\"weight\":50},\"weight\":[0,50]},\"splitting\":{\"county\":{\"range\":[[1.26,1.68],[1.09,1.45]],\"weight\":50},\"district\":{\"range\":[[1.26,1.68],[1.09,1.45]],\"weight\":50},\"weight\":[0,50]},\"popdev\":{\"range\":[[0.0075,0.002],[0.1,-1]],\"weight\":[0,0]},\"weight\":[0,20]}}");
89105
+ module.exports = JSON.parse("{\"partisan\":{\"bias\":{\"range\":[0,0.2],\"weight\":[50,80]},\"impact\":{\"weight\":[50,0],\"threshold\":4},\"competitiveness\":{\"range\":[0,0.75],\"distribution\":[0.25,0.75],\"simpleRange\":[0.45,0.55],\"weight\":[0,20]},\"bonus\":2},\"minority\":{\"range\":[0.37,0.5],\"distribution\":[0.25,0.75],\"shift\":0.15,\"coalition\":{\"weight\":0.5}},\"compactness\":{\"reock\":{\"range\":[0.25,0.5],\"weight\":50},\"polsby\":{\"range\":[0.1,0.5],\"weight\":50}},\"splitting\":{\"county\":{\"range\":[[1.26,1.68],[1.09,1.45]],\"weight\":50},\"district\":{\"range\":[[1.26,1.68],[1.09,1.45]],\"weight\":50}},\"popdev\":{\"range\":[[0.0075,0.002],[0.1,-1]]}}");
89106
89106
 
89107
89107
  /***/ }),
89108
89108
 
@@ -89118,7 +89118,8 @@ module.exports = JSON.parse("{\"partisan\":{\"bias\":{\"range\":[0,0.2],\"weight
89118
89118
  //
89119
89119
  // THRESHOLDS, SCALES, AND WEIGHTS FOR SCORING MODEL
89120
89120
  //
89121
- // * A layer of functions over config.json, so that they can be overridden dynamically (TODO)
89121
+ // * A layer of functions over config.json, so that they could be overridden dynamically.
89122
+ // That is not implemented yet.
89122
89123
  //
89123
89124
  var __importDefault = (this && this.__importDefault) || function (mod) {
89124
89125
  return (mod && mod.__esModule) ? mod : { "default": mod };
@@ -89160,7 +89161,7 @@ function competitivenessWeight(context, overridesJSON) {
89160
89161
  return cW;
89161
89162
  }
89162
89163
  exports.competitivenessWeight = competitivenessWeight;
89163
- // COMPETITIVENESS - The simple user-facing range, i.e., 45–55%.
89164
+ // The simple user-facing range, i.e., 45–55%.
89164
89165
  function competitiveRange(overridesJSON) {
89165
89166
  const range = config_json_1.default.partisan.competitiveness.simpleRange;
89166
89167
  return range;
@@ -89171,9 +89172,9 @@ function competitiveDistribution(overridesJSON) {
89171
89172
  return dist;
89172
89173
  }
89173
89174
  exports.competitiveDistribution = competitiveDistribution;
89174
- // COMPETITIVENESS - The more complex internal range for normalizing Cdf.
89175
- // COMPETITIVENESS - 06/23/2020 - As part of relaxing the competitive range, I
89176
- // I changed this max from 0.67 to 0.75.
89175
+ // The more complex internal range for normalizing Cdf.
89176
+ // * 06/23/2020 - As part of relaxing the competitive range, I changed this max
89177
+ // from 0.67 to 0.75.
89177
89178
  function overallCompetitivenessRange(overridesJSON) {
89178
89179
  const range = config_json_1.default.partisan.competitiveness.range;
89179
89180
  return range;
@@ -89181,17 +89182,17 @@ function overallCompetitivenessRange(overridesJSON) {
89181
89182
  exports.overallCompetitivenessRange = overallCompetitivenessRange;
89182
89183
  // export function marginalCompetitivenessRange(overridesJSON?: any): number[]
89183
89184
  // {
89184
- // const range = config.partisan.competitiveness.marginal.range;
89185
+ // const range = config.partisan.responsiveness.marginal.range;
89185
89186
  // return range;
89186
89187
  // }
89187
89188
  // export function marginalCompetitivenessWeight(overridesJSON?: any): number
89188
89189
  // {
89189
- // const mcW = config.partisan.competitiveness.marginal.weight;
89190
+ // const mcW = config.partisan.responsiveness.marginal.weight;
89190
89191
  // return mcW;
89191
89192
  // }
89192
89193
  // export function overallCompetitivenessWeight(overridesJSON?: any): number
89193
89194
  // {
89194
- // const ocW = config.partisan.competitiveness.overall.weight;
89195
+ // const ocW = config.partisan.responsiveness.overall.weight;
89195
89196
  // return ocW;
89196
89197
  // }
89197
89198
  // MINORITY
@@ -89215,74 +89216,55 @@ function coalitionDistrictWeight(overridesJSON) {
89215
89216
  return weight;
89216
89217
  }
89217
89218
  exports.coalitionDistrictWeight = coalitionDistrictWeight;
89218
- function minorityBonus(overridesJSON) {
89219
- const bonus = config_json_1.default.minority.bonus;
89220
- return bonus;
89221
- }
89222
- exports.minorityBonus = minorityBonus;
89223
- // TRADITIONAL DISTRICTING PRINCIPLES
89224
- function compactnessWeight(context, overridesJSON) {
89225
- const cW = config_json_1.default.traditionalPrinciples.compactness.weight[context];
89226
- return cW;
89227
- }
89228
- exports.compactnessWeight = compactnessWeight;
89219
+ // COMPACTNESS
89229
89220
  function reockWeight(overridesJSON) {
89230
- const rW = config_json_1.default.traditionalPrinciples.compactness.reock.weight;
89221
+ const rW = config_json_1.default.compactness.reock.weight;
89231
89222
  return rW;
89232
89223
  }
89233
89224
  exports.reockWeight = reockWeight;
89234
89225
  function reockRange(overridesJSON) {
89235
- const range = config_json_1.default.traditionalPrinciples.compactness.reock.range;
89226
+ const range = config_json_1.default.compactness.reock.range;
89236
89227
  return range;
89237
89228
  }
89238
89229
  exports.reockRange = reockRange;
89239
89230
  function polsbyWeight(overridesJSON) {
89240
- const ppW = config_json_1.default.traditionalPrinciples.compactness.polsby.weight;
89231
+ const ppW = config_json_1.default.compactness.polsby.weight;
89241
89232
  return ppW;
89242
89233
  }
89243
89234
  exports.polsbyWeight = polsbyWeight;
89244
89235
  function polsbyRange(overridesJSON) {
89245
- const range = config_json_1.default.traditionalPrinciples.compactness.polsby.range;
89236
+ const range = config_json_1.default.compactness.polsby.range;
89246
89237
  return range;
89247
89238
  }
89248
89239
  exports.polsbyRange = polsbyRange;
89249
- function splittingWeight(context, overridesJSON) {
89250
- const sW = config_json_1.default.traditionalPrinciples.splitting.weight[context];
89251
- return sW;
89252
- }
89253
- exports.splittingWeight = splittingWeight;
89240
+ // SPLITTING
89254
89241
  function countySplittingWeight(overridesJSON) {
89255
- const csW = config_json_1.default.traditionalPrinciples.splitting.county.weight;
89242
+ const csW = config_json_1.default.splitting.county.weight;
89256
89243
  return csW;
89257
89244
  }
89258
89245
  exports.countySplittingWeight = countySplittingWeight;
89259
89246
  function countySplittingRange(d, overridesJSON) {
89260
- const range = config_json_1.default.traditionalPrinciples.splitting.county.range[d];
89247
+ const range = config_json_1.default.splitting.county.range[d];
89261
89248
  return range;
89262
89249
  }
89263
89250
  exports.countySplittingRange = countySplittingRange;
89264
89251
  function districtSplittingWeight(overridesJSON) {
89265
- const dsW = config_json_1.default.traditionalPrinciples.splitting.district.weight;
89252
+ const dsW = config_json_1.default.splitting.district.weight;
89266
89253
  return dsW;
89267
89254
  }
89268
89255
  exports.districtSplittingWeight = districtSplittingWeight;
89269
89256
  function districtSplittingRange(d, overridesJSON) {
89270
- const range = config_json_1.default.traditionalPrinciples.splitting.district.range[d];
89257
+ const range = config_json_1.default.splitting.district.range[d];
89271
89258
  return range;
89272
89259
  }
89273
89260
  exports.districtSplittingRange = districtSplittingRange;
89274
- function popdevWeight(context, overridesJSON) {
89275
- const pdW = config_json_1.default.traditionalPrinciples.popdev.weight[context];
89276
- return pdW;
89277
- }
89278
- exports.popdevWeight = popdevWeight;
89279
89261
  // NOTE - Raw ranges, not inverted (i.e., smaller is better)
89280
89262
  // NOTE - This could be optimized to not calc LD values for CD's (or do it once)
89281
89263
  function popdevRange(bLegislative, overridesJSON) {
89282
- const cdRange = config_json_1.default.traditionalPrinciples.popdev.range[0 /* Congressional */];
89264
+ const cdRange = config_json_1.default.popdev.range[0 /* Congressional */];
89283
89265
  const worstCD = cdRange[exports.BEG];
89284
89266
  const bestCD = cdRange[exports.END];
89285
- const ldRange = config_json_1.default.traditionalPrinciples.popdev.range[1 /* StateLegislative */];
89267
+ const ldRange = config_json_1.default.popdev.range[1 /* StateLegislative */];
89286
89268
  const iRange = bLegislative ? ldRange : cdRange;
89287
89269
  const worst = iRange[exports.BEG];
89288
89270
  const best = bLegislative ? (bestCD / worstCD) * iRange[exports.BEG] : iRange[exports.END];
@@ -89296,17 +89278,6 @@ function popdevThreshold(bLegislative, overridesJSON) {
89296
89278
  return threshold;
89297
89279
  }
89298
89280
  exports.popdevThreshold = popdevThreshold;
89299
- // OVERALL SCORE
89300
- function partisanWeight(context, overridesJSON) {
89301
- const pW = config_json_1.default.partisan.weight[context];
89302
- return pW;
89303
- }
89304
- exports.partisanWeight = partisanWeight;
89305
- function traditionalPrinciplesWeight(context, overridesJSON) {
89306
- const tpW = config_json_1.default.traditionalPrinciples.weight[context];
89307
- return tpW;
89308
- }
89309
- exports.traditionalPrinciplesWeight = traditionalPrinciplesWeight;
89310
89281
 
89311
89282
 
89312
89283
  /***/ }),
@@ -89431,19 +89402,12 @@ const C = __importStar(__webpack_require__(/*! ./config */ "./src/config.ts"));
89431
89402
  const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts");
89432
89403
  const partisan_1 = __webpack_require__(/*! ./partisan */ "./src/partisan.ts");
89433
89404
  function evalMinorityOpportunity(p, bLog = false) {
89434
- // Calculate average Democratic win share
89435
- const VfArray = p.partisanProfile.vfArray;
89436
- const DWins = VfArray.filter(x => x > 0.5);
89437
- const RWins = VfArray.filter(x => x <= 0.5); // Ties credited to R's
89438
- const averageDVf = (DWins.length > 0) ? U.avgArray(DWins) : undefined;
89439
- const averageRVf = (RWins.length > 0) ? U.avgArray(RWins) : undefined;
89440
89405
  // Initialize arrays for results
89441
89406
  const offset = 1; // Don't process 'White'
89442
89407
  const nDemos = 6 /* Total */; // Ditto
89443
89408
  // const nDemos = T.DemographicField.Native + 1 - offset; // Ditto
89444
89409
  const demosByDistrict = p.demographicProfile.mfArrayByDistrict;
89445
89410
  // Initialize the demographic buckets
89446
- // COMPETITIVENESS - 06/23/2020 - And populate the statewide values.
89447
89411
  // Get the statewide minority VAP/CVAP % (ignore 'White')
89448
89412
  const vapPctArray = p.demographicProfile.stateMfArray.slice(1);
89449
89413
  // Determine proportional minority districts by demographic (ignoring'White')
@@ -89486,25 +89450,14 @@ function evalMinorityOpportunity(p, bLog = false) {
89486
89450
  // The # of opportunity districts for each separate demographic and all minorities
89487
89451
  const oD = U.sumArray(opptyByDemo.slice(1)); // Sum individual demos, skipping all minorities
89488
89452
  const cD = opptyByDemo[0 /* Minority */]; // All minorities
89489
- // const cD: number = opptyByDemo[T.DemographicField.Minority - offset]; // All minorities
89490
89453
  // The # of proportional districts for each separate demographic and all minorities
89491
89454
  const pOd = bucketsByDemo[6 /* Total */][4 /* PropSeats */];
89492
89455
  const pCd = bucketsByDemo[0 /* Minority */][4 /* PropSeats */];
89493
- // const pOd: number = bucketsByDemo[T.DemographicField.Total - 1][T.PivotField.PropSeats];
89494
- // const pCd: number = bucketsByDemo[T.DemographicField.Minority - 1][T.PivotField.PropSeats];
89495
- // const pOd: number = U.sumArray(districtsByDemo.slice(1)); // Sum individual demos, skipping all minorities
89496
- // const pCd: number = districtsByDemo[0]; // All minorities
89497
89456
  // Score opportunity
89498
89457
  const score = scoreMinority(oD, pOd, cD, pCd);
89499
89458
  let mS = {
89500
- report: {
89501
- averageDVf: averageDVf,
89502
- averageRVf: averageRVf,
89503
- bucketsByDemographic: bucketsByDemo
89504
- },
89505
- // proportionalOpportunities: pOd,
89459
+ pivotByDemographic: bucketsByDemo,
89506
89460
  opportunityDistricts: oD,
89507
- // proportionalCoalitions: pCd,
89508
89461
  coalitionDistricts: cD,
89509
89462
  score: score,
89510
89463
  details: {}
@@ -89517,14 +89470,13 @@ exports.evalMinorityOpportunity = evalMinorityOpportunity;
89517
89470
  // how minority opportunities are estimated (so that 37% minority shares score
89518
89471
  // like 52% share).
89519
89472
  function scoreMinority(oD, pOd, cD, pCd) {
89520
- // Score minority opportunity [0–100] here; weight it later
89521
- const bonus = 100; // C.minorityBonus();
89473
+ // Score minority opportunity [0–100]
89522
89474
  const cDWeight = C.coalitionDistrictWeight();
89523
89475
  // Cap opportunity & coalition districts
89524
89476
  const oDCapped = Math.min(oD, pOd);
89525
89477
  const cdCapped = Math.min(cD, pCd);
89526
- const opportunityScore = (pOd > 0) ? Math.round((oDCapped / pOd) * bonus) : 0;
89527
- const coalitionScore = (pCd > 0) ? Math.round((cdCapped / pCd) * bonus) : 0;
89478
+ const opportunityScore = (pOd > 0) ? Math.round((oDCapped / pOd) * 100) : 0;
89479
+ const coalitionScore = (pCd > 0) ? Math.round((cdCapped / pCd) * 100) : 0;
89528
89480
  const score = Math.round(Math.min(opportunityScore + cDWeight * Math.max(coalitionScore - opportunityScore, 0), 100));
89529
89481
  return score;
89530
89482
  }
@@ -89565,7 +89517,6 @@ function exceedsMaximumThreshold(Mf) {
89565
89517
  return Mf > threshold;
89566
89518
  }
89567
89519
  function calcProportionalDistricts(proportion, nDistricts) {
89568
- // TODO - Maybe bump up to get a statewide proportion on the bubble to rate one district?
89569
89520
  const roundUp = 0.0;
89570
89521
  const fractional = proportion * nDistricts;
89571
89522
  const integral = Math.round(fractional + roundUp);
@@ -89617,7 +89568,6 @@ class Normalizer {
89617
89568
  }
89618
89569
  // Invert a value in the unit range [0.0–1.0] (so that bigger is better).
89619
89570
  invert() {
89620
- // TODO - DAVID: Can we make this throw an Error and expect that in unit test?
89621
89571
  console.assert(((this.wipNum >= 0.0) && (this.wipNum <= 1.0)), "Inverting: " + S.OUT_OF_RANGE_MSG, this.wipNum);
89622
89572
  this.wipNum = 1.0 - this.wipNum;
89623
89573
  return this.wipNum;
@@ -89641,7 +89591,6 @@ class Normalizer {
89641
89591
  unitize(begin_range, end_range) {
89642
89592
  const min_range = Math.min(begin_range, end_range);
89643
89593
  const max_range = Math.max(begin_range, end_range);
89644
- // TODO - DAVID: Can we make this throw an Error and expect that in unit test?
89645
89594
  console.assert(((this.wipNum >= min_range) && (this.wipNum <= max_range)), "Unitizing: " + S.OUT_OF_RANGE_MSG, this.wipNum);
89646
89595
  const ranged = this.wipNum - min_range;
89647
89596
  this.wipNum = Math.abs(ranged / (end_range - begin_range));
@@ -89651,7 +89600,6 @@ class Normalizer {
89651
89600
  // NOTE - If the range is already such that "bigger is better," then the closer
89652
89601
  // the value is to 1.0 (the best) the *less* it will decay.
89653
89602
  decay(fn = 0 /* Gravity */) {
89654
- // TODO - DAVID: Can we make this throw an Error and expect that in unit test?
89655
89603
  console.assert(((this.wipNum >= 0.0) && (this.wipNum <= 1.0)), "Decaying: " + S.OUT_OF_RANGE_MSG, this.wipNum);
89656
89604
  switch (fn) {
89657
89605
  case 0 /* Gravity */: {
@@ -89665,7 +89613,6 @@ class Normalizer {
89665
89613
  }
89666
89614
  // Translate a value in the unit range to the user-friendly range [0 – 100].
89667
89615
  rescale() {
89668
- // TODO - DAVID: Can we make this throw an Error and expect that in unit test?
89669
89616
  console.assert(((this.wipNum >= 0.0) && (this.wipNum <= 1.0)), "Rescaling: " + S.OUT_OF_RANGE_MSG, this.wipNum);
89670
89617
  this.normalizedNum = Math.round(this.wipNum * S.NORMALIZED_RANGE);
89671
89618
  return this.normalizedNum;
@@ -89702,12 +89649,12 @@ const C = __importStar(__webpack_require__(/*! ./config */ "./src/config.ts"));
89702
89649
  const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts");
89703
89650
  // NOTE - I'm passing T.VfArray's into everything. District indices = array indices.
89704
89651
  // NOTE - I do not (cannot) assume that the values are sorted.
89652
+ // TODO - Revise this.
89705
89653
  // SCORE BIAS & COMPETITIVENESS
89706
89654
  /* SCORECARD FIELDS:
89707
89655
 
89708
89656
  * ??? [statewideV] (V) = the average statewide two-party vote for Democrats
89709
89657
 
89710
-
89711
89658
  * ^S# [bestS] = the Democratic seats closest to proportional
89712
89659
  * ^S% [bestSf] = the corresponding Democratic seat share
89713
89660
  * S! [fptpS] = the estimated number of Democratic seats using first past the post
@@ -89718,7 +89665,7 @@ const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts")
89718
89665
  * BV_50 [bV50] = Votes bias as a fraction
89719
89666
  * decl [decl] = Declination
89720
89667
  * GS [gSym] = Global symmetry
89721
- * ?? [gamma] = TODO
89668
+ * ?? [gamma] = TODO: describe
89722
89669
 
89723
89670
  * EG [EG] = Efficiency gap as a fraction
89724
89671
  * BS_V [bSV] = Seats bias @ <V> (geometric)
@@ -89731,9 +89678,6 @@ const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts")
89731
89678
  * B% [bias] = the bias calculated as S% – ^S%
89732
89679
  * B$ [bias.score] = the bias score normalized [0–100]
89733
89680
 
89734
- * UE# [unearnedS] = the number of unearned seats (R = positive; D = negative)
89735
- * I$ [impact.score] -- the unearned seats normalized [0–100] as impact
89736
-
89737
89681
  * R [bigR] = Overall responsiveness or winner’s bonus
89738
89682
  * r [littleR] = The point responsiveness at V% (the slope of the S(V) curve at <V>)
89739
89683
  * MIR [MIR] = Minimal inverse responsiveness
@@ -89748,70 +89692,60 @@ const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts")
89748
89692
  * Md% [mDf] = the probability that the marginal seats will flip, so S% => ^S%
89749
89693
  * C$ [competitiveness.score] = the competitiveness score normalized [0–100]
89750
89694
 
89751
- * <P$ [score] = the combined partisan score used to compare plans *across* states
89752
- * >P$ [score2] = the combined partisan score used to compare plans *within* a state, along with traditional districting principles
89753
-
89754
89695
  */
89755
89696
  function scorePartisan(Vf, VfArray, options) {
89756
- const bAlternateMetrics = options.alternates;
89697
+ const bAdvanced = options.advanced;
89757
89698
  const bConstrained = options.constrained;
89758
89699
  const shift = options.shift;
89759
89700
  const N = VfArray.length;
89760
89701
  const bestS = bestSeats(N, Vf);
89761
89702
  const bestSf = bestSeatShare(bestS, N);
89762
- const fptpS = bAlternateMetrics ? estFPTPSeats(VfArray) : undefined;
89763
- // NOTE - When not constrained, use the full probability distribution to calc metrics.
89703
+ const fptpS = bAdvanced ? estFPTPSeats(VfArray) : undefined;
89704
+ // When not constrained, use the full probability distribution to calc metrics.
89764
89705
  const range = bConstrained ? C.competitiveDistribution() : undefined;
89765
89706
  const estS = estSeats(VfArray, range);
89766
89707
  const estSf = estSeatShare(estS, N);
89767
- const bias = estBias(estSf, bestSf);
89768
- const biasScore = scorebias(bias, Vf, estSf);
89708
+ const deviation = estDeviation(estSf, bestSf);
89709
+ const proportionalityScore = scoreDeviation(deviation, Vf, estSf);
89769
89710
  const unearnedS = estUnearnedSeats(bestS, estS);
89770
89711
  const impactScore = scoreImpact(unearnedS, Vf, estSf, N);
89771
89712
  // Calculate additional alternate metrics for reference
89772
- // NOTE - Use the uncompressed seat probability function
89773
89713
  const dSVpoints = inferSVpoints(Vf, VfArray, shift);
89774
89714
  const rSVpoints = invertSVPoints(dSVpoints);
89775
- // const dSVpoints = bAlternateMetrics ? inferSVpoints(Vf, VfArray, shift) : undefined;
89776
- const TOf = bAlternateMetrics ? calcTurnoutBias(Vf, VfArray) : undefined;
89777
- const Bs50 = bAlternateMetrics ? estPartisanBias(dSVpoints, N) : undefined;
89715
+ // const dSVpoints = bAdvanced ? inferSVpoints(Vf, VfArray, shift) : undefined;
89716
+ const TOf = bAdvanced ? calcTurnoutBias(Vf, VfArray) : undefined;
89717
+ const Bs50 = bAdvanced ? estPartisanBias(dSVpoints, N) : undefined;
89778
89718
  const Bs50f = (!(Bs50 === undefined)) ? U.trim(Bs50 / N) : undefined;
89779
- const Bv50f = bAlternateMetrics ? estVotesBias(dSVpoints, N) : undefined;
89780
- const rvPoints = bAlternateMetrics ? keyRVpoints(VfArray) : undefined;
89781
- const decl = bAlternateMetrics ? calcDeclination(VfArray) : undefined;
89782
- const gSym = bAlternateMetrics ? calcGlobalSymmetry(dSVpoints, rSVpoints, Bs50f) : undefined;
89783
- const EG = bAlternateMetrics ? calcEfficiencyGap(Vf, estSf) : undefined;
89784
- const BsGf = bAlternateMetrics ? estGeometricSeatsBias(Vf, dSVpoints, rSVpoints) : undefined;
89785
- const prop = bAlternateMetrics ? calcDisproportionality(Vf, estSf) : undefined;
89786
- const mMs = bAlternateMetrics ? estMeanMedianDifference(VfArray, Vf) : undefined;
89787
- const mMd = bAlternateMetrics ? estMeanMedianDifference(VfArray) : undefined;
89788
- const LO = bAlternateMetrics ? calcLopsidedOutcomes(VfArray) : undefined;
89719
+ const Bv50f = bAdvanced ? estVotesBias(dSVpoints, N) : undefined;
89720
+ const rvPoints = bAdvanced ? keyRVpoints(VfArray) : undefined;
89721
+ const decl = bAdvanced ? calcDeclination(VfArray) : undefined;
89722
+ const gSym = bAdvanced ? calcGlobalSymmetry(dSVpoints, rSVpoints, Bs50f) : undefined;
89723
+ const EG = bAdvanced ? calcEfficiencyGap(Vf, estSf) : undefined;
89724
+ const BsGf = bAdvanced ? estGeometricSeatsBias(Vf, dSVpoints, rSVpoints) : undefined;
89725
+ const prop = bAdvanced ? calcDisproportionality(Vf, estSf) : undefined;
89726
+ const mMs = bAdvanced ? estMeanMedianDifference(VfArray, Vf) : undefined;
89727
+ const mMd = bAdvanced ? estMeanMedianDifference(VfArray) : undefined;
89728
+ const LO = bAdvanced ? calcLopsidedOutcomes(VfArray) : undefined;
89789
89729
  // Calculate alternate responsiveness metrics for reference
89790
- const bigR = bAlternateMetrics ? calcBigR(Vf, estSf) : undefined;
89791
- const littleR = bAlternateMetrics ? estResponsiveness(Vf, dSVpoints) : undefined;
89792
- const MIR = (bAlternateMetrics && littleR) ? calcMinimalInverseResponsiveness(Vf, littleR) : undefined;
89793
- const rD = (!bConstrained || bAlternateMetrics) ? estResponsiveDistricts(VfArray) : undefined;
89794
- const rDf = bAlternateMetrics ? estResponsiveDistrictsShare(rD, N) : undefined;
89795
- const gamma = (bAlternateMetrics && littleR) ? calcGamma(Vf, estSf, littleR) : undefined;
89730
+ const bigR = bAdvanced ? calcBigR(Vf, estSf) : undefined;
89731
+ const littleR = bAdvanced ? estResponsiveness(Vf, dSVpoints) : undefined;
89732
+ const MIR = (bAdvanced && littleR) ? calcMinimalInverseResponsiveness(Vf, littleR) : undefined;
89733
+ const rD = (!bConstrained || bAdvanced) ? estResponsiveDistricts(VfArray) : undefined;
89734
+ const rDf = bAdvanced ? estResponsiveDistrictsShare(rD, N) : undefined;
89735
+ const gamma = (bAdvanced && littleR) ? calcGamma(Vf, estSf, littleR) : undefined;
89796
89736
  const Cn = countCompetitiveDistricts(VfArray);
89797
89737
  // NOTE - Cd by definition uses a *possibly* different (more narrow) probability
89798
89738
  // distribution than Rd.
89799
89739
  const cD = estCompetitiveDistricts(VfArray);
89800
- // const cD = bConstrained ? estCompetitiveDistricts(VfArray) : rD as number;
89801
89740
  const cDf = estCompetitiveDistrictsShare(cD, N);
89802
89741
  const competitivenessScore = scoreCompetitiveness(cDf);
89803
- // NOTE: Original version:
89804
- // const Mrange = findMarginalDistricts(Vf, VfArray, N);
89805
- // const Md = estMarginalCompetitiveDistricts(Mrange, VfArray);
89806
- // const Mdf = estMarginalCompetitiveShare(Md, Mrange);
89807
- // const competitivenessScore = scoreCompetitiveness(Mdf, cDf);
89808
89742
  let biasScoring = {
89809
89743
  bestS: bestS,
89810
89744
  bestSf: bestSf,
89811
89745
  estS: estS,
89812
89746
  estSf: estSf,
89813
- bias: bias,
89814
- score: biasScore
89747
+ deviation: deviation,
89748
+ score: proportionalityScore
89815
89749
  };
89816
89750
  const impactScoring = {
89817
89751
  unearnedS: unearnedS,
@@ -89821,12 +89755,9 @@ function scorePartisan(Vf, VfArray, options) {
89821
89755
  cSimple: Cn,
89822
89756
  cD: cD,
89823
89757
  cDf: cDf,
89824
- // mRange: Mrange,
89825
- // mD: Md,
89826
- // mDf: Mdf,
89827
89758
  score: competitivenessScore
89828
89759
  };
89829
- if (bAlternateMetrics) {
89760
+ if (bAdvanced) {
89830
89761
  biasScoring.tOf = TOf;
89831
89762
  biasScoring.fptpS = fptpS;
89832
89763
  biasScoring.bS50 = Bs50f;
@@ -89847,47 +89778,37 @@ function scorePartisan(Vf, VfArray, options) {
89847
89778
  competitiveScoring.rD = rD;
89848
89779
  competitiveScoring.rDf = rDf;
89849
89780
  }
89850
- // Weight bias, impact, and competitiveness into partisan scores to compare
89851
- // plans across states and within a state.
89852
- const bS = biasScoring.score;
89853
- const iS = impactScoring.score;
89854
- const cS = competitiveScoring.score;
89855
- const acrossStatesPartisanScore = weightPartisan(bS, iS, cS, 0 /* AcrossStates */);
89856
- const withinStatesPartisanScore = weightPartisan(bS, iS, cS, 1 /* WithinAState */);
89781
+ const DWins = VfArray.filter(x => x > 0.5);
89782
+ const RWins = VfArray.filter(x => x <= 0.5); // Ties credited to R's
89783
+ const averageDVf = (DWins.length > 0) ? U.avgArray(DWins) : undefined;
89784
+ const averageRVf = (RWins.length > 0) ? U.avgArray(RWins) : undefined;
89857
89785
  const s = {
89858
89786
  bias: biasScoring,
89859
89787
  impact: impactScoring,
89860
- competitiveness: competitiveScoring,
89788
+ responsiveness: competitiveScoring,
89861
89789
  dSVpoints: dSVpoints,
89862
89790
  rSVpoints: rSVpoints,
89863
- score: acrossStatesPartisanScore,
89864
- score2: withinStatesPartisanScore,
89791
+ averageDVf: averageDVf,
89792
+ averageRVf: averageRVf,
89865
89793
  details: {}
89866
89794
  };
89867
89795
  return s;
89868
89796
  }
89869
89797
  exports.scorePartisan = scorePartisan;
89870
- function weightPartisan(bS, iS, cS, context) {
89871
- const bW = C.biasWeight(context);
89872
- const iW = C.impactWeight(context);
89873
- const cW = C.competitivenessWeight(context);
89874
- const score = Math.round(((bS * bW) + (iS * iW) + (cS * cW)) / (bW + iW + cW));
89875
- return score;
89876
- }
89877
- exports.weightPartisan = weightPartisan;
89878
89798
  function extraBonus(Vf) {
89879
- const okExtra = (0.5 - Vf) * (C.winnerBonus() - 1.0);
89799
+ const over50Pct = (Vf > 0.5) ? (Vf - 0.5) : (0.5 - Vf);
89800
+ const okExtra = over50Pct * (C.winnerBonus() - 1.0);
89880
89801
  return U.trim(okExtra);
89881
89802
  }
89882
89803
  exports.extraBonus = extraBonus;
89883
- function scorebias(rawBias, Vf, Sf) {
89804
+ function scoreDeviation(deviation, Vf, Sf) {
89884
89805
  if (isAntimajoritarian(Vf, Sf)) {
89885
89806
  return 0;
89886
89807
  }
89887
89808
  else {
89888
89809
  // Adjust bias to incorporate an acceptable winner's bonus based on Vf
89889
89810
  const extra = extraBonus(Vf);
89890
- const adjusted = adjustBias(Vf, rawBias, extra);
89811
+ const adjusted = adjustDeviation(Vf, deviation, extra);
89891
89812
  // Then normalize
89892
89813
  const _normalizer = new normalize_1.Normalizer(adjusted);
89893
89814
  const worst = C.biasRange()[C.BEG];
@@ -89901,15 +89822,24 @@ function scorebias(rawBias, Vf, Sf) {
89901
89822
  return score;
89902
89823
  }
89903
89824
  }
89904
- exports.scorebias = scorebias;
89905
- // Adjust bias to account for a winner's bonus
89906
- function adjustBias(Vf, bias, extra) {
89907
- if (Vf > 0.5)
89908
- return Math.min(bias - extra, 0);
89909
- else
89910
- return Math.max(bias - extra, 0);
89825
+ exports.scoreDeviation = scoreDeviation;
89826
+ // Adjust deviation from proportionality to account for a winner's bonus
89827
+ // * If the bias is in the *same* direction as the statewide vote %, then
89828
+ // discount the bias by the winner's bonus (extra).
89829
+ // * But if the bias and statewide vote % go in opposite directions, leave the
89830
+ // bias unadjusted.
89831
+ function adjustDeviation(Vf, deviation, extra) {
89832
+ let adjusted = deviation;
89833
+ if ((Vf > 0.5) && (deviation < 0)) {
89834
+ adjusted = Math.min(deviation + extra, 0);
89835
+ }
89836
+ else if ((Vf < 0.5) && (deviation > 0)) {
89837
+ adjusted = Math.max(deviation - extra, 0);
89838
+ }
89839
+ return adjusted;
89911
89840
  }
89912
- exports.adjustBias = adjustBias;
89841
+ exports.adjustDeviation = adjustDeviation;
89842
+ // NOTE - Not used.
89913
89843
  // Normalize unearned seats
89914
89844
  function scoreImpact(rawUE, Vf, Sf, N) {
89915
89845
  if (isAntimajoritarian(Vf, Sf)) {
@@ -89918,7 +89848,7 @@ function scoreImpact(rawUE, Vf, Sf, N) {
89918
89848
  else {
89919
89849
  // Adjust impact to incorporate an acceptable winner's bonus based on Vf
89920
89850
  const extra = extraBonus(Vf);
89921
- const adjustedBias = adjustBias(Vf, rawUE / N, extra);
89851
+ const adjustedBias = adjustDeviation(Vf, rawUE / N, extra);
89922
89852
  const adjustedImpact = adjustedBias * N;
89923
89853
  // Then normalize
89924
89854
  const _normalizer = new normalize_1.Normalizer(adjustedImpact);
@@ -89941,9 +89871,8 @@ function isAntimajoritarian(Vf, Sf) {
89941
89871
  return bDem || bRep;
89942
89872
  }
89943
89873
  exports.isAntimajoritarian = isAntimajoritarian;
89944
- // COMPETITIVENESS - Revised 06/23/2020
89945
89874
  // Normalize overall competitiveness - Raw values are in the range [0.0–1.0].
89946
- // But the practical max is more like 2/3's, so unitize that range to [0.0–1.0].
89875
+ // But the practical max is more like 3/4's, so unitize that range to [0.0–1.0].
89947
89876
  // Then scale the values to [0–100].
89948
89877
  function scoreCompetitiveness(Cdf) {
89949
89878
  const _normalizer = new normalize_1.Normalizer(Cdf);
@@ -90036,8 +89965,6 @@ function inferSVpoints(Vf, VfArray, shift, range) {
90036
89965
  const shiftedVPI = shiftDistricts(Vf, VfArray, shiftedVf, shift);
90037
89966
  const shiftedSf = estSeats(shiftedVPI, range) / nDistricts;
90038
89967
  SVpoints.push({ v: shiftedVf, s: shiftedSf });
90039
- // TODO - Why can't I trim these? Why does that only break the Hypotheticals?!?
90040
- // SVpoints.push({v: U.trim(Number(shiftedVf)), s: shiftedSf});
90041
89968
  }
90042
89969
  return SVpoints;
90043
89970
  }
@@ -90122,11 +90049,12 @@ function estFPTPSeats(VfArray) {
90122
90049
  }));
90123
90050
  }
90124
90051
  exports.estFPTPSeats = estFPTPSeats;
90125
- // B% - The bias calculated as ^S% — S%
90126
- function estBias(estSf, bestSf) {
90052
+ // B% - The deviation from proportionality calculated as ^S% — S%
90053
+ function estDeviation(estSf, bestSf) {
90127
90054
  return U.trim(bestSf - estSf);
90128
90055
  }
90129
- exports.estBias = estBias;
90056
+ exports.estDeviation = estDeviation;
90057
+ // NOTE - Not used.
90130
90058
  // UE# - The estimated # of unearned seats
90131
90059
  // UE_# from http://bit.ly/2Fcuf4q
90132
90060
  function estUnearnedSeats(proportional, probable) {
@@ -90231,11 +90159,9 @@ function estCompetitiveDistricts(VfArray, bCompress = false) {
90231
90159
  return U.trim(U.sumArray(VfArray.map(v => estDistrictCompetitiveness(v, bCompress))));
90232
90160
  }
90233
90161
  exports.estCompetitiveDistricts = estCompetitiveDistricts;
90234
- // COMPETITIVENESS - Modified 06/22/2020
90235
- // Re-scale a Democratic vote share to the competitive range (e.g., 45–55%).
90236
90162
  function estDistrictCompetitiveness(Vf, bCompress = false) {
90237
90163
  const _normalizer = new normalize_1.Normalizer(Vf);
90238
- // The end points of a compressed probability distribution
90164
+ // The end points of the probability distribution
90239
90165
  // NOTE - These aren't the points where races start or stop being contested,
90240
90166
  // just the end points of a distribution that yields the desired behavior
90241
90167
  // in the typical competitive range [45-55%].
@@ -90460,9 +90386,6 @@ function keyRVpoints(VfArray) {
90460
90386
  const nDistricts = VfArray.length;
90461
90387
  const estS = estSeats(VfArray);
90462
90388
  const Sb = estSeatShare(estS, nDistricts);
90463
- // TODO - Understand why the corresponding V to Sb is always @ 0.5.
90464
- // John Nagle: "This is the dividing vote for party A vs party B wins defined
90465
- // by Warrington. My modification just puts fractions of districts to the each side."
90466
90389
  const Rb = Sb / 2;
90467
90390
  const Ra = (1 + Sb) / 2;
90468
90391
  const Vb = 1.0 - (U.sumArray(VfArray.map(v => estSeatProbability(v) * v))) / estS;
@@ -90602,23 +90525,19 @@ function calcGamma(Vf, Sf, r) {
90602
90525
  exports.calcGamma = calcGamma;
90603
90526
  // HELPERS
90604
90527
  function printPartisanScorecardHeader() {
90605
- console.log('XX, Name, N, V%, ^S#, S#, B%, B$, UE#, I$, C#, Cd, Cdf, C$, <P$');
90528
+ console.log('XX, Name, N, V%, ^S#, S#, B%, B$, C#, Cd, Cdf, C$');
90606
90529
  }
90607
90530
  exports.printPartisanScorecardHeader = printPartisanScorecardHeader;
90608
90531
  function printPartisanScorecardRow(xx, name, N, Vf, s) {
90609
- console.log('%s, %s, %i, %f, %i, %f, %f, %i, %f, %i, %i, %f, %f, %i, %i', xx, // 1
90532
+ console.log('%s, %s, %i, %f, %i, %f, %f, %i, %i, %f, %f, %i', xx, // 1
90610
90533
  name, // 2
90611
90534
  N, // 3
90612
90535
  Vf, // 4
90613
90536
  s.bias.bestS, // 5
90614
90537
  s.bias.estS, // 6
90615
- s.bias.bias, // 7
90616
- s.bias.score, s.impact.unearnedS, // 9
90617
- s.impact.score, s.competitiveness.cSimple, // 11
90618
- s.competitiveness.cD, s.competitiveness.cDf,
90619
- // s.competitiveness.mD,
90620
- s.competitiveness.score, s.score // 15
90621
- );
90538
+ s.bias.deviation, // 7
90539
+ s.bias.score, s.responsiveness.cSimple, // 9
90540
+ s.responsiveness.cD, s.responsiveness.cDf, s.responsiveness.score);
90622
90541
  }
90623
90542
  exports.printPartisanScorecardRow = printPartisanScorecardRow;
90624
90543
  // Generate partisan details (Table 1)
@@ -90627,12 +90546,12 @@ function printPartisanDetailsHeader() {
90627
90546
  }
90628
90547
  exports.printPartisanDetailsHeader = printPartisanDetailsHeader;
90629
90548
  function printPartisanDetailsRow(xx, name, N, Vf, s) {
90630
- console.log('%s, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f', xx, Vf, s.bias.estSf, s.bias.bias, // Simple bias
90549
+ console.log('%s, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f', xx, Vf, s.bias.estSf, s.bias.deviation, // Simple deviation from proportionality
90631
90550
  s.bias.bS50, s.bias.bV50, s.bias.decl, s.bias.gSym, s.bias.eG, s.bias.bSV, // Beta
90632
90551
  s.bias.prop, // PR
90633
- s.bias.mMs, s.bias.tOf, s.bias.mMd, s.bias.lO, s.competitiveness.rD, s.competitiveness.bigR, s.competitiveness.littleR, s.competitiveness.mIR, // Zeta
90634
- s.competitiveness.cD, // COMPETITIVENESS - Temporary to confirm new calc
90635
- s.competitiveness.cDf);
90552
+ s.bias.mMs, s.bias.tOf, s.bias.mMd, s.bias.lO, s.responsiveness.rD, s.responsiveness.bigR, s.responsiveness.littleR, s.responsiveness.mIR, // Zeta
90553
+ s.responsiveness.cD, // COMPETITIVENESS - Temporary to confirm new calc
90554
+ s.responsiveness.cDf);
90636
90555
  }
90637
90556
  exports.printPartisanDetailsRow = printPartisanDetailsRow;
90638
90557
 
@@ -90659,7 +90578,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
90659
90578
  return result;
90660
90579
  };
90661
90580
  Object.defineProperty(exports, "__esModule", { value: true });
90662
- const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
90663
90581
  const C = __importStar(__webpack_require__(/*! ./config */ "./src/config.ts"));
90664
90582
  const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
90665
90583
  const cohesive_1 = __webpack_require__(/*! ./cohesive */ "./src/cohesive.ts");
@@ -90675,7 +90593,8 @@ function scorePlan(p, overridesJSON) {
90675
90593
  const cS = {
90676
90594
  score: compactnessScore,
90677
90595
  reock: reockM,
90678
- polsby: polsbyM
90596
+ polsby: polsbyM,
90597
+ details: {}
90679
90598
  };
90680
90599
  // Splitting
90681
90600
  const CxD = p.splittingProfile.countyPopByDistrict;
@@ -90687,40 +90606,26 @@ function scorePlan(p, overridesJSON) {
90687
90606
  const sS = {
90688
90607
  score: splittingScore,
90689
90608
  county: countyM,
90690
- district: districtM
90609
+ district: districtM,
90610
+ details: {}
90691
90611
  };
90692
90612
  // Population deviation
90693
90613
  const pdS = equal_1.doPopulationDeviation(p.populationProfile.totalPopByDistrict, p.populationProfile.targetSize, p.legislativeDistricts);
90694
- // Combine traditional principles into a score to compare plans w/in a state
90695
- const tpScore = weightTradtionalPrinciples(cS.score, sS.score, pdS.normalized, 1 /* WithinAState */);
90696
- // Populate the "best" traditional principles scorecard
90697
- const tpS = {
90698
- score: tpScore,
90699
- compactness: cS,
90700
- splitting: sS,
90701
- populationDeviation: pdS,
90702
- details: {}
90703
- };
90704
- // PARTISAN ("fair") subcategories - bias, impact, & competitiveness (plus lots of supporting measures)
90614
+ // Partisan - bias & responsiveness
90705
90615
  const options = {
90706
- alternates: true,
90616
+ advanced: true,
90707
90617
  constrained: false,
90708
90618
  shift: 0 /* Proportional */
90709
90619
  };
90710
90620
  const pS = partisan_1.scorePartisan(p.partisanProfile.statewideVf, p.partisanProfile.vfArray, options);
90711
- // Combine the partisan/partisan & traditional principles/best scores into an overall
90712
- // score for comparing plans w/in a state
90713
- let score = weightOverall(pS.score2, tpS.score, 1 /* WithinAState */);
90714
90621
  const mS = minority_1.evalMinorityOpportunity(p);
90715
- // Add minority bonus, keeping score to the range [0–100]
90716
- const bonus = C.minorityBonus() * (mS.score / 100);
90717
- score = mixinMinorityBonus(score, bonus);
90718
- // Roll up an overall scorecard
90622
+ // Combine the pieces into a scorecard
90719
90623
  const scorecard = {
90720
90624
  partisan: pS,
90721
90625
  minority: mS,
90722
- traditionalPrinciples: tpS,
90723
- score: score,
90626
+ compactness: cS,
90627
+ splitting: sS,
90628
+ populationDeviation: pdS,
90724
90629
  details: {}
90725
90630
  };
90726
90631
  return scorecard;
@@ -90741,44 +90646,20 @@ function weightSplitting(csS, dsS) {
90741
90646
  return score;
90742
90647
  }
90743
90648
  exports.weightSplitting = weightSplitting;
90744
- function weightTradtionalPrinciples(cS, sS, pdS, context) {
90745
- const cW = C.compactnessWeight(context);
90746
- const sW = C.splittingWeight(context);
90747
- const pdW = C.popdevWeight(context);
90748
- const score = Math.round(((cS * cW) + (sS * sW) + (pdS * pdW)) / (cW + sW + pdW));
90749
- return score;
90750
- }
90751
- exports.weightTradtionalPrinciples = weightTradtionalPrinciples;
90752
- function weightOverall(pS, tpS, context) {
90753
- const pW = C.partisanWeight(context);
90754
- const tpW = C.traditionalPrinciplesWeight(context);
90755
- const score = Math.round(((pS * pW) + (tpS * tpW)) / (pW + tpW));
90756
- return score;
90757
- }
90758
- exports.weightOverall = weightOverall;
90759
- function mixinMinorityBonus(score, minorityBonus) {
90760
- const modifiedScore = Math.min(score + minorityBonus, S.NORMALIZED_RANGE);
90761
- return modifiedScore;
90762
- }
90763
- exports.mixinMinorityBonus = mixinMinorityBonus;
90764
90649
  function printScorecardHeader() {
90765
- console.log('XX, Name, N, V%, ^S#, S#, B%, B$, UE#, I$, C#, Cd, Cdf, C$, >P$, Rc, Rc$, Pc, Pc$, G$, Cs, Cs$, Ds, Ds$, S$, Eq, Eq$, T$, Od, Md, M$, $$$');
90650
+ console.log('XX, Name, N, V%, ^S#, S#, B%, B$, C#, Cd, Cdf, C$, Rc, Rc$, Pc, Pc$, G$, Cs, Cs$, Ds, Ds$, S$, Eq, Eq$, Od, Md, M$');
90766
90651
  }
90767
90652
  exports.printScorecardHeader = printScorecardHeader;
90768
90653
  function printScorecardRow(xx, name, N, Vf, s) {
90769
- console.log('%s, %s, %i, %f, %i, %f, %f, %i, %f, %i, %i, %f, %f, %i, %i, %f, %i, %f, %i, %i, %f, %i, %f, %i, %i, %f, %i, %i, %f, %f, %i, %i', xx, // 1
90654
+ console.log('%s, %s, %i, %f, %i, %f, %f, %i, %i, %f, %f, %i, %f, %i, %f, %i, %i, %f, %i, %f, %i, %i, %f, %i, %f, %f, %i', xx, // 1
90770
90655
  name, // 2
90771
90656
  N, // 3
90772
90657
  Vf, // 4
90773
90658
  s.partisan.bias.bestS, // 5
90774
90659
  s.partisan.bias.estS, // 6
90775
- s.partisan.bias.bias, // 7
90776
- s.partisan.bias.score, s.partisan.impact.unearnedS, // 9
90777
- s.partisan.impact.score, s.partisan.competitiveness.cSimple, // 11
90778
- s.partisan.competitiveness.cD, s.partisan.competitiveness.cDf,
90779
- // s.partisan.competitiveness.mD,
90780
- s.partisan.competitiveness.score, s.partisan.score2, // 15
90781
- s.traditionalPrinciples.compactness.reock.raw, s.traditionalPrinciples.compactness.reock.normalized, s.traditionalPrinciples.compactness.polsby.raw, s.traditionalPrinciples.compactness.polsby.normalized, s.traditionalPrinciples.compactness.score, s.traditionalPrinciples.splitting.county.raw, s.traditionalPrinciples.splitting.county.normalized, s.traditionalPrinciples.splitting.district.raw, s.traditionalPrinciples.splitting.district.normalized, s.traditionalPrinciples.splitting.score, s.traditionalPrinciples.populationDeviation.raw, s.traditionalPrinciples.populationDeviation.normalized, s.traditionalPrinciples.score, s.minority.opportunityDistricts, s.minority.coalitionDistricts, s.minority.score, s.score);
90660
+ s.partisan.bias.deviation, // 7
90661
+ s.partisan.bias.score, s.partisan.responsiveness.cSimple, // 9
90662
+ s.partisan.responsiveness.cD, s.partisan.responsiveness.cDf, s.partisan.responsiveness.score, s.compactness.reock.raw, s.compactness.reock.normalized, s.compactness.polsby.raw, s.compactness.polsby.normalized, s.compactness.score, s.splitting.county.raw, s.splitting.county.normalized, s.splitting.district.raw, s.splitting.district.normalized, s.splitting.score, s.populationDeviation.raw, s.populationDeviation.normalized, s.minority.opportunityDistricts, s.minority.coalitionDistricts, s.minority.score);
90782
90663
  }
90783
90664
  exports.printScorecardRow = printScorecardRow;
90784
90665
 
@@ -102927,10 +102808,10 @@ class AnalyticsSession {
102927
102808
  const scorecard = this._scorecard;
102928
102809
  const r = {
102929
102810
  proportionality: scorecard.partisan.bias.score,
102930
- competitiveness: scorecard.partisan.competitiveness.score,
102811
+ competitiveness: scorecard.partisan.responsiveness.score,
102931
102812
  minorityRights: scorecard.minority.score,
102932
- compactness: scorecard.traditionalPrinciples.compactness.score,
102933
- splitting: scorecard.traditionalPrinciples.splitting.score
102813
+ compactness: scorecard.compactness.score,
102814
+ splitting: scorecard.splitting.score
102934
102815
  };
102935
102816
  return r;
102936
102817
  }
@@ -104428,7 +104309,7 @@ function doAnalyzePostProcessing(s, bLog = false) {
104428
104309
  // Just populate the normalized population deviation score in the test
104429
104310
  const scorecard = s._scorecard;
104430
104311
  let popDev = s.getTest(4 /* PopulationDeviation */);
104431
- popDev['normalizedScore'] = scorecard.traditionalPrinciples.populationDeviation.normalized;
104312
+ popDev['normalizedScore'] = scorecard.populationDeviation.normalized;
104432
104313
  const datasets = {
104433
104314
  shapes: S.SHAPES,
104434
104315
  census: U.deepCopy(s.config['descriptions']['CENSUS']),
@@ -104437,12 +104318,12 @@ function doAnalyzePostProcessing(s, bLog = false) {
104437
104318
  };
104438
104319
  scorecard.partisan.details['election'] = datasets.election;
104439
104320
  scorecard.minority.details['vap'] = datasets.vap;
104440
- scorecard.traditionalPrinciples.details['shapes'] = datasets.shapes;
104441
- scorecard.traditionalPrinciples.details['census'] = datasets.census;
104321
+ scorecard.details['shapes'] = datasets.shapes;
104322
+ scorecard.details['census'] = datasets.census;
104442
104323
  const simpleSplits = s.getTest(5 /* UnexpectedCountySplits */);
104443
- scorecard.traditionalPrinciples.details['unexpectedAffected'] = simpleSplits['score'];
104444
- scorecard.traditionalPrinciples.details['nSplits'] = simpleSplits['details']['nSplits'];
104445
- scorecard.traditionalPrinciples.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
104324
+ scorecard.compactness.details['unexpectedAffected'] = simpleSplits['score'];
104325
+ scorecard.compactness.details['nSplits'] = simpleSplits['details']['nSplits'];
104326
+ scorecard.compactness.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
104446
104327
  // NOTE - Add split precincts in dra-client directly
104447
104328
  // Derive secondary tests
104448
104329
  analyze_1.doDeriveSecondaryTests(s, bLog);
@@ -104587,10 +104468,10 @@ function scorePlan(s, p, bLog = false, overridesJSON) {
104587
104468
  // doHasEqualPopulations() to use later.This is preserving the old calling sequence.
104588
104469
  let test = s.getTest(4 /* PopulationDeviation */);
104589
104470
  // Get the raw population deviation
104590
- const popDev = scorecard.traditionalPrinciples.populationDeviation.raw;
104471
+ const popDev = scorecard.populationDeviation.raw;
104591
104472
  // Populate the test entry
104592
104473
  test['score'] = popDev;
104593
- test['details'] = { 'maxDeviation': scorecard.traditionalPrinciples.populationDeviation.notes['maxDeviation'] };
104474
+ test['details'] = { 'maxDeviation': scorecard.populationDeviation.notes['maxDeviation'] };
104594
104475
  // Populate the N+1 summary "district" in district.statistics
104595
104476
  let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
104596
104477
  let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];