@dra2020/district-analytics 6.1.0 → 6.2.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
@@ -89102,7 +89102,7 @@ exports.scorePolsbyPopper = scorePolsbyPopper;
89102
89102
  /*! exports provided: partisan, minority, traditionalPrinciples, 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\":{\"overall\":{\"range\":[0,0.67],\"weight\":100},\"marginal\":{\"range\":[0,0.85],\"weight\":0},\"range\":[0.45,0.55],\"distribution\":[0.25,0.75],\"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,\"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]}}");
89106
89106
 
89107
89107
  /***/ }),
89108
89108
 
@@ -89160,8 +89160,9 @@ function competitivenessWeight(context, overridesJSON) {
89160
89160
  return cW;
89161
89161
  }
89162
89162
  exports.competitivenessWeight = competitivenessWeight;
89163
+ // COMPETITIVENESS - The simple user-facing range, i.e., 45–55%.
89163
89164
  function competitiveRange(overridesJSON) {
89164
- const range = config_json_1.default.partisan.competitiveness.range;
89165
+ const range = config_json_1.default.partisan.competitiveness.simpleRange;
89165
89166
  return range;
89166
89167
  }
89167
89168
  exports.competitiveRange = competitiveRange;
@@ -89170,26 +89171,29 @@ function competitiveDistribution(overridesJSON) {
89170
89171
  return dist;
89171
89172
  }
89172
89173
  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.
89173
89177
  function overallCompetitivenessRange(overridesJSON) {
89174
- const range = config_json_1.default.partisan.competitiveness.overall.range;
89178
+ const range = config_json_1.default.partisan.competitiveness.range;
89175
89179
  return range;
89176
89180
  }
89177
89181
  exports.overallCompetitivenessRange = overallCompetitivenessRange;
89178
- function marginalCompetitivenessRange(overridesJSON) {
89179
- const range = config_json_1.default.partisan.competitiveness.marginal.range;
89180
- return range;
89181
- }
89182
- exports.marginalCompetitivenessRange = marginalCompetitivenessRange;
89183
- function marginalCompetitivenessWeight(overridesJSON) {
89184
- const mcW = config_json_1.default.partisan.competitiveness.marginal.weight;
89185
- return mcW;
89186
- }
89187
- exports.marginalCompetitivenessWeight = marginalCompetitivenessWeight;
89188
- function overallCompetitivenessWeight(overridesJSON) {
89189
- const ocW = config_json_1.default.partisan.competitiveness.overall.weight;
89190
- return ocW;
89191
- }
89192
- exports.overallCompetitivenessWeight = overallCompetitivenessWeight;
89182
+ // export function marginalCompetitivenessRange(overridesJSON?: any): number[]
89183
+ // {
89184
+ // const range = config.partisan.competitiveness.marginal.range;
89185
+ // return range;
89186
+ // }
89187
+ // export function marginalCompetitivenessWeight(overridesJSON?: any): number
89188
+ // {
89189
+ // const mcW = config.partisan.competitiveness.marginal.weight;
89190
+ // return mcW;
89191
+ // }
89192
+ // export function overallCompetitivenessWeight(overridesJSON?: any): number
89193
+ // {
89194
+ // const ocW = config.partisan.competitiveness.overall.weight;
89195
+ // return ocW;
89196
+ // }
89193
89197
  // MINORITY
89194
89198
  function minorityOpportunityRange(overridesJSON) {
89195
89199
  const range = config_json_1.default.minority.range;
@@ -89396,6 +89400,8 @@ function __export(m) {
89396
89400
  }
89397
89401
  Object.defineProperty(exports, "__esModule", { value: true });
89398
89402
  __export(__webpack_require__(/*! ./_api */ "./src/_api.ts"));
89403
+ var partisan_1 = __webpack_require__(/*! ./partisan */ "./src/partisan.ts");
89404
+ exports.estSeatProbability = partisan_1.estSeatProbability;
89399
89405
 
89400
89406
 
89401
89407
  /***/ }),
@@ -89431,39 +89437,59 @@ function evalMinorityOpportunity(p, bLog = false) {
89431
89437
  const RWins = VfArray.filter(x => x <= 0.5); // Ties credited to R's
89432
89438
  const averageDVf = (DWins.length > 0) ? U.avgArray(DWins) : undefined;
89433
89439
  const averageRVf = (RWins.length > 0) ? U.avgArray(RWins) : undefined;
89434
- // Determine proportional minority districts by demographic (ignore 'White')
89435
- const districtsByDemo = calcDistrictsByDemo(p.demographicProfile.stateMfArray.slice(1), p.nDistricts);
89436
89440
  // Initialize arrays for results
89437
89441
  const offset = 1; // Don't process 'White'
89438
89442
  const nDemos = 6 /* Native */ + 1 - offset; // Ditto
89439
- const nBuckets = 2; // 37–50% and > 50%
89440
89443
  const demosByDistrict = p.demographicProfile.mfArrayByDistrict;
89441
89444
  // Initialize the demographic buckets
89442
- let bucketsByDemo = new Array(nDemos);
89445
+ // COMPETITIVENESS - 06/23/2020 - And populate the statewide values.
89446
+ // Get the statewide minority VAP/CVAP % (ignore 'White')
89447
+ const vapPctArray = p.demographicProfile.stateMfArray.slice(1);
89448
+ // Determine proportional minority districts by demographic (ignoring'White')
89449
+ const districtsByDemo = calcDistrictsByDemo(vapPctArray, p.nDistricts);
89450
+ let bucketsByDemo = new Array(nDemos + 1); // Add a row for the 'Total' row
89451
+ let totalProportional = 0;
89443
89452
  for (let j = 0; j < nDemos; j++) {
89444
- bucketsByDemo[j] = [0, 0];
89445
- }
89446
- let opptyByDemo = U.initArray(nDemos, 0.0);
89453
+ const vapPct = vapPctArray[j];
89454
+ const prop = districtsByDemo[j];
89455
+ // Accumulate the proportional values for each demographic, ignoring the first
89456
+ // all Minority demographic.
89457
+ if (j > 0)
89458
+ totalProportional += prop;
89459
+ bucketsByDemo[j] = [0, 0, 0, vapPct, prop]; // Five conceptual columns for each demographic
89460
+ }
89461
+ // Add a 'Total' row
89462
+ bucketsByDemo[nDemos] = [0, 0, 0, 0, totalProportional];
89463
+ let opptyByDemo = U.initArray(nDemos, 0.0); // A state-level value
89447
89464
  // For each district
89448
89465
  for (let i = 0; i < p.nDistricts; i++) {
89449
89466
  // Find the opportunities for minority representation
89450
89467
  for (let j = 0; j < nDemos; j++) {
89451
89468
  const proportion = U.deepCopy(demosByDistrict[i][j + offset]); // Skip the 'White' entries
89452
89469
  if (exceedsMinimumThreshold(proportion)) {
89453
- // Bucket opportunity districts
89470
+ // Bucket opportunity districts for each demographic
89454
89471
  const bucket = (exceedsMaximumThreshold(proportion)) ? 1 : 0;
89455
89472
  bucketsByDemo[j][bucket] += 1;
89473
+ bucketsByDemo[j][2 /* Total */] += 1;
89456
89474
  // Accumulate seat probabilities
89457
89475
  opptyByDemo[j] += estMinorityOpportunity(proportion);
89476
+ // Also accumulate the 'Total' row summing the opportunities for each demographic,
89477
+ // ignoring the first all Minority demographic.
89478
+ if (j > 0) {
89479
+ bucketsByDemo[nDemos][bucket] += 1;
89480
+ bucketsByDemo[nDemos][2 /* Total */] += 1;
89481
+ }
89458
89482
  }
89459
89483
  }
89460
89484
  }
89461
89485
  // The # of opportunity districts for each separate demographic and all minorities
89462
89486
  const oD = U.sumArray(opptyByDemo.slice(1)); // Sum individual demos, skipping all minorities
89463
- const cD = opptyByDemo[0]; // All minorities
89487
+ const cD = opptyByDemo[1 /* Minority */ - offset]; // All minorities
89464
89488
  // The # of proportional districts for each separate demographic and all minorities
89465
- const pOd = U.sumArray(districtsByDemo.slice(1)); // Sum individual demos, skipping all minorities
89466
- const pCd = districtsByDemo[0]; // All minorities
89489
+ const pOd = bucketsByDemo[7 /* Total */ - 1][4 /* PropSeats */];
89490
+ const pCd = bucketsByDemo[1 /* Minority */ - 1][4 /* PropSeats */];
89491
+ // const pOd: number = U.sumArray(districtsByDemo.slice(1)); // Sum individual demos, skipping all minorities
89492
+ // const pCd: number = districtsByDemo[0]; // All minorities
89467
89493
  // Score opportunity
89468
89494
  const score = scoreMinority(oD, pOd, cD, pCd);
89469
89495
  let mS = {
@@ -89472,9 +89498,9 @@ function evalMinorityOpportunity(p, bLog = false) {
89472
89498
  averageRVf: averageRVf,
89473
89499
  bucketsByDemographic: bucketsByDemo
89474
89500
  },
89475
- proportionalOpportunities: pOd,
89501
+ // proportionalOpportunities: pOd,
89476
89502
  opportunityDistricts: oD,
89477
- proportionalCoalitions: pCd,
89503
+ // proportionalCoalitions: pCd,
89478
89504
  coalitionDistricts: cD,
89479
89505
  score: score,
89480
89506
  details: {}
@@ -89730,6 +89756,7 @@ function scorePartisan(Vf, VfArray, options) {
89730
89756
  const bestS = bestSeats(N, Vf);
89731
89757
  const bestSf = bestSeatShare(bestS, N);
89732
89758
  const fptpS = bAlternateMetrics ? estFPTPSeats(VfArray) : undefined;
89759
+ // NOTE - When not constrained, use the full probability distribution to calc metrics.
89733
89760
  const range = bConstrained ? C.competitiveDistribution() : undefined;
89734
89761
  const estS = estSeats(VfArray, range);
89735
89762
  const estSf = estSeatShare(estS, N);
@@ -89763,13 +89790,17 @@ function scorePartisan(Vf, VfArray, options) {
89763
89790
  const rDf = bAlternateMetrics ? estResponsiveDistrictsShare(rD, N) : undefined;
89764
89791
  const gamma = (bAlternateMetrics && littleR) ? calcGamma(Vf, estSf, littleR) : undefined;
89765
89792
  const Cn = countCompetitiveDistricts(VfArray);
89766
- const cD = estCompetitiveDistricts(VfArray); // NOTE - Cd by definition uses a more narrow probability distribution vs. Rd
89793
+ // NOTE - Cd by definition uses a *possibly* different (more narrow) probability
89794
+ // distribution than Rd.
89795
+ const cD = estCompetitiveDistricts(VfArray);
89767
89796
  // const cD = bConstrained ? estCompetitiveDistricts(VfArray) : rD as number;
89768
89797
  const cDf = estCompetitiveDistrictsShare(cD, N);
89769
- const Mrange = findMarginalDistricts(Vf, VfArray, N);
89770
- const Md = estMarginalCompetitiveDistricts(Mrange, VfArray);
89771
- const Mdf = estMarginalCompetitiveShare(Md, Mrange);
89772
- const competitivenessScore = scoreCompetitiveness(Mdf, cDf);
89798
+ const competitivenessScore = scoreCompetitiveness(cDf);
89799
+ // NOTE: Original version:
89800
+ // const Mrange = findMarginalDistricts(Vf, VfArray, N);
89801
+ // const Md = estMarginalCompetitiveDistricts(Mrange, VfArray);
89802
+ // const Mdf = estMarginalCompetitiveShare(Md, Mrange);
89803
+ // const competitivenessScore = scoreCompetitiveness(Mdf, cDf);
89773
89804
  let biasScoring = {
89774
89805
  bestS: bestS,
89775
89806
  bestSf: bestSf,
@@ -89786,9 +89817,9 @@ function scorePartisan(Vf, VfArray, options) {
89786
89817
  cSimple: Cn,
89787
89818
  cD: cD,
89788
89819
  cDf: cDf,
89789
- mRange: Mrange,
89790
- mD: Md,
89791
- mDf: Mdf,
89820
+ // mRange: Mrange,
89821
+ // mD: Md,
89822
+ // mDf: Mdf,
89792
89823
  score: competitivenessScore
89793
89824
  };
89794
89825
  if (bAlternateMetrics) {
@@ -89906,32 +89937,59 @@ function isAntimajoritarian(Vf, Sf) {
89906
89937
  return bDem || bRep;
89907
89938
  }
89908
89939
  exports.isAntimajoritarian = isAntimajoritarian;
89909
- function scoreCompetitiveness(rawMarginal, rawOverall) {
89910
- // Normalize overall competitiveness - Raw values are in the range [0.0–1.0].
89911
- // But the practical max is more like 2/3's, so unitize that range to [0.0–1.0].
89912
- // Then scale the values to [0–100].
89913
- const _overall = new normalize_1.Normalizer(rawOverall);
89940
+ // COMPETITIVENESS - Revised 06/23/2020
89941
+ // Normalize overall competitiveness - Raw values are in the range [0.0–1.0].
89942
+ // But the practical max is more like 2/3's, so unitize that range to [0.0–1.0].
89943
+ // Then scale the values to [0–100].
89944
+ function scoreCompetitiveness(Cdf) {
89945
+ const _normalizer = new normalize_1.Normalizer(Cdf);
89914
89946
  let worst = C.overallCompetitivenessRange()[C.BEG];
89915
89947
  let best = C.overallCompetitivenessRange()[C.END];
89916
- _overall.clip(worst, best);
89917
- _overall.unitize(worst, best);
89918
- _overall.rescale();
89919
- const ocS = _overall.normalizedNum;
89920
- // Normalize marginal competitiveness
89921
- const _marginal = new normalize_1.Normalizer(rawMarginal);
89922
- worst = C.marginalCompetitivenessRange()[C.BEG];
89923
- best = C.marginalCompetitivenessRange()[C.END];
89924
- _marginal.clip(worst, best);
89925
- _marginal.unitize(worst, best);
89926
- _marginal.rescale();
89927
- const mcS = _marginal.normalizedNum;
89928
- const mcW = C.marginalCompetitivenessWeight();
89929
- const ocW = C.overallCompetitivenessWeight();
89930
- // Then combine the results
89931
- const score = ((mcW + ocW) > 0) ? Math.round(((mcW * mcS) + (ocW * ocS)) / (mcW + ocW)) : 0;
89948
+ _normalizer.clip(worst, best);
89949
+ _normalizer.unitize(worst, best);
89950
+ _normalizer.rescale();
89951
+ const score = _normalizer.normalizedNum;
89932
89952
  return score;
89933
89953
  }
89934
89954
  exports.scoreCompetitiveness = scoreCompetitiveness;
89955
+ /* NOTE - Original version:
89956
+ export function scoreCompetitiveness(rawMarginal: number, rawOverall: number): number
89957
+ {
89958
+ // Normalize overall competitiveness - Raw values are in the range [0.0–1.0].
89959
+ // But the practical max is more like 2/3's, so unitize that range to [0.0–1.0].
89960
+ // Then scale the values to [0–100].
89961
+ const _overall = new Normalizer(rawOverall);
89962
+
89963
+ let worst = C.overallCompetitivenessRange()[C.BEG];
89964
+ let best = C.overallCompetitivenessRange()[C.END];
89965
+
89966
+ _overall.clip(worst, best);
89967
+ _overall.unitize(worst, best);
89968
+ _overall.rescale();
89969
+
89970
+ const ocS = _overall.normalizedNum as number;
89971
+
89972
+
89973
+ // Normalize marginal competitiveness
89974
+ const _marginal = new Normalizer(rawMarginal);
89975
+
89976
+ worst = C.marginalCompetitivenessRange()[C.BEG];
89977
+ best = C.marginalCompetitivenessRange()[C.END];
89978
+
89979
+ _marginal.clip(worst, best);
89980
+ _marginal.unitize(worst, best);
89981
+ _marginal.rescale();
89982
+ const mcS = _marginal.normalizedNum as number;
89983
+
89984
+ const mcW = C.marginalCompetitivenessWeight();
89985
+ const ocW = C.overallCompetitivenessWeight();
89986
+
89987
+ // Then combine the results
89988
+ const score = ((mcW + ocW) > 0) ? Math.round(((mcW * mcS) + (ocW * ocS)) / (mcW + ocW)) : 0;
89989
+
89990
+ return score;
89991
+ }
89992
+ */
89935
89993
  // CORE CAPABILITIES FROM JOHN NAGLE'S METHOD
89936
89994
  const { erf } = __webpack_require__(/*! mathjs */ "./node_modules/mathjs/main/esm/index.js");
89937
89995
  // console.log("erf(0.2) =", erf(0.2)); // returns 0.22270258921047847
@@ -90165,19 +90223,20 @@ function isCompetitive(v) {
90165
90223
  return ((v >= C.competitiveRange()[C.BEG]) && (v <= C.competitiveRange()[C.END])) ? 1 : 0;
90166
90224
  }
90167
90225
  // cD - The estimated # of competitive districts
90168
- function estCompetitiveDistricts(VfArray) {
90169
- return U.trim(U.sumArray(VfArray.map(v => estDistrictCompetitiveness(v))));
90226
+ function estCompetitiveDistricts(VfArray, bCompress = false) {
90227
+ return U.trim(U.sumArray(VfArray.map(v => estDistrictCompetitiveness(v, bCompress))));
90170
90228
  }
90171
90229
  exports.estCompetitiveDistricts = estCompetitiveDistricts;
90230
+ // COMPETITIVENESS - Modified 06/22/2020
90172
90231
  // Re-scale a Democratic vote share to the competitive range (e.g., 45–55%).
90173
- function estDistrictCompetitiveness(Vf) {
90232
+ function estDistrictCompetitiveness(Vf, bCompress = false) {
90174
90233
  const _normalizer = new normalize_1.Normalizer(Vf);
90175
90234
  // The end points of a compressed probability distribution
90176
90235
  // NOTE - These aren't the points where races start or stop being contested,
90177
90236
  // just the end points of a distribution that yields the desired behavior
90178
90237
  // in the typical competitive range [45-55%].
90179
- const distBeg = C.competitiveDistribution()[C.BEG];
90180
- const distEnd = C.competitiveDistribution()[C.END];
90238
+ const distBeg = bCompress ? C.competitiveDistribution()[C.BEG] : 0.0;
90239
+ const distEnd = bCompress ? C.competitiveDistribution()[C.END] : 1.0;
90181
90240
  _normalizer.clip(distBeg, distEnd);
90182
90241
  _normalizer.unitize(distBeg, distEnd);
90183
90242
  const dC = estDistrictResponsiveness(_normalizer.wipNum);
@@ -90191,14 +90250,14 @@ function estCompetitiveDistrictsShare(cD, N) {
90191
90250
  exports.estCompetitiveDistrictsShare = estCompetitiveDistrictsShare;
90192
90251
  // Md - The estimated # of "marginal" districts in and around the likely FPTP
90193
90252
  // seats & the best seat split that are competitive.
90194
- function estMarginalCompetitiveDistricts(Mrange, VfArray) {
90253
+ function estMarginalCompetitiveDistricts(Mrange, VfArray, bCompress = false) {
90195
90254
  const minId = Mrange[C.BEG];
90196
90255
  const maxId = Mrange[C.END];
90197
90256
  // Sort the array values, and subset it to those districts
90198
90257
  // NOTE - I'm *not* keeping track of the district indexes right now
90199
90258
  let subsetVfArray = U.deepCopy(VfArray).sort().slice(minId - 1, maxId);
90200
90259
  // Est. competitive districts on that array
90201
- const Md = U.sumArray(subsetVfArray.map((v) => estDistrictCompetitiveness(v)));
90260
+ const Md = U.sumArray(subsetVfArray.map((v) => estDistrictCompetitiveness(v, bCompress)));
90202
90261
  return U.trim(Md);
90203
90262
  }
90204
90263
  exports.estMarginalCompetitiveDistricts = estMarginalCompetitiveDistricts;
@@ -90539,7 +90598,7 @@ function calcGamma(Vf, Sf, r) {
90539
90598
  exports.calcGamma = calcGamma;
90540
90599
  // HELPERS
90541
90600
  function printPartisanScorecardHeader() {
90542
- console.log('XX, Name, N, V%, ^S#, S#, B%, B$, UE#, I$, C#, Cd, Md, C$, <P$');
90601
+ console.log('XX, Name, N, V%, ^S#, S#, B%, B$, UE#, I$, C#, Cd, Cdf, C$, <P$');
90543
90602
  }
90544
90603
  exports.printPartisanScorecardHeader = printPartisanScorecardHeader;
90545
90604
  function printPartisanScorecardRow(xx, name, N, Vf, s) {
@@ -90552,21 +90611,24 @@ function printPartisanScorecardRow(xx, name, N, Vf, s) {
90552
90611
  s.bias.bias, // 7
90553
90612
  s.bias.score, s.impact.unearnedS, // 9
90554
90613
  s.impact.score, s.competitiveness.cSimple, // 11
90555
- s.competitiveness.cD, s.competitiveness.mD, s.competitiveness.score, s.score // 15
90614
+ s.competitiveness.cD, s.competitiveness.cDf,
90615
+ // s.competitiveness.mD,
90616
+ s.competitiveness.score, s.score // 15
90556
90617
  );
90557
90618
  }
90558
90619
  exports.printPartisanScorecardRow = printPartisanScorecardRow;
90559
90620
  // Generate partisan details (Table 1)
90560
90621
  function printPartisanDetailsHeader() {
90561
- console.log('XX, <V>, S(<V>), B%, BS_50, BV_50, Decl, GS, EG, Beta, PR, MM, TO, MM\', LO, Rd, R, r, MIR');
90622
+ console.log('XX, <V>, S(<V>), B%, BS_50, BV_50, Decl, GS, EG, Beta, PR, MM, TO, MM\', LO, Rd, R, r, MIR, Cd, Cdf');
90562
90623
  }
90563
90624
  exports.printPartisanDetailsHeader = printPartisanDetailsHeader;
90564
90625
  function printPartisanDetailsRow(xx, name, N, Vf, s) {
90565
- console.log('%s, %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
90626
+ 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
90566
90627
  s.bias.bS50, s.bias.bV50, s.bias.decl, s.bias.gSym, s.bias.eG, s.bias.bSV, // Beta
90567
90628
  s.bias.prop, // PR
90568
- 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
90569
- );
90629
+ 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
90630
+ s.competitiveness.cD, // COMPETITIVENESS - Temporary to confirm new calc
90631
+ s.competitiveness.cDf);
90570
90632
  }
90571
90633
  exports.printPartisanDetailsRow = printPartisanDetailsRow;
90572
90634
 
@@ -90696,11 +90758,11 @@ function mixinMinorityBonus(score, minorityBonus) {
90696
90758
  }
90697
90759
  exports.mixinMinorityBonus = mixinMinorityBonus;
90698
90760
  function printScorecardHeader() {
90699
- console.log('XX, Name, N, V%, ^S#, S#, B%, B$, UE#, I$, C#, Cd, Md, C$, >P$, Rc, Rc$, Pc, Pc$, G$, Cs, Cs$, Ds, Ds$, S$, Eq, Eq$, T$, Od, M$, $$$');
90761
+ 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$, $$$');
90700
90762
  }
90701
90763
  exports.printScorecardHeader = printScorecardHeader;
90702
90764
  function printScorecardRow(xx, name, N, Vf, s) {
90703
- 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, %i, %i', xx, // 1
90765
+ 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
90704
90766
  name, // 2
90705
90767
  N, // 3
90706
90768
  Vf, // 4
@@ -90709,8 +90771,10 @@ function printScorecardRow(xx, name, N, Vf, s) {
90709
90771
  s.partisan.bias.bias, // 7
90710
90772
  s.partisan.bias.score, s.partisan.impact.unearnedS, // 9
90711
90773
  s.partisan.impact.score, s.partisan.competitiveness.cSimple, // 11
90712
- s.partisan.competitiveness.cD, s.partisan.competitiveness.mD, s.partisan.competitiveness.score, s.partisan.score2, // 15
90713
- 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.score, s.score);
90774
+ s.partisan.competitiveness.cD, s.partisan.competitiveness.cDf,
90775
+ // s.partisan.competitiveness.mD,
90776
+ s.partisan.competitiveness.score, s.partisan.score2, // 15
90777
+ 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);
90714
90778
  }
90715
90779
  exports.printScorecardRow = printScorecardRow;
90716
90780
 
@@ -102855,6 +102919,17 @@ class AnalyticsSession {
102855
102919
  getPlanScorecard(bLog = false) {
102856
102920
  return this._scorecard;
102857
102921
  }
102922
+ getRatings(bLog = false) {
102923
+ const scorecard = this._scorecard;
102924
+ const r = {
102925
+ proportionality: scorecard.partisan.bias.score,
102926
+ competitiveness: scorecard.partisan.competitiveness.score,
102927
+ minorityRights: scorecard.minority.score,
102928
+ compactness: scorecard.traditionalPrinciples.compactness.score,
102929
+ splitting: scorecard.traditionalPrinciples.splitting.score
102930
+ };
102931
+ return r;
102932
+ }
102858
102933
  // NOTE - This assumes that analyzePlan() has been run!
102859
102934
  getRequirementsChecklist(bLog = false) {
102860
102935
  return results_2.prepareRequirementsChecklist(this, bLog);