@dra2020/district-analytics 6.0.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,\"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;
@@ -89206,11 +89210,11 @@ function minorityShift(overridesJSON) {
89206
89210
  return shift;
89207
89211
  }
89208
89212
  exports.minorityShift = minorityShift;
89209
- function opportunityDistrictBonus(overridesJSON) {
89210
- const bonus = config_json_1.default.minority.bonus;
89211
- return bonus;
89213
+ function coalitionDistrictWeight(overridesJSON) {
89214
+ const weight = config_json_1.default.minority.coalition.weight;
89215
+ return weight;
89212
89216
  }
89213
- exports.opportunityDistrictBonus = opportunityDistrictBonus;
89217
+ exports.coalitionDistrictWeight = coalitionDistrictWeight;
89214
89218
  function minorityBonus(overridesJSON) {
89215
89219
  const bonus = config_json_1.default.minority.bonus;
89216
89220
  return bonus;
@@ -89396,9 +89400,8 @@ function __export(m) {
89396
89400
  }
89397
89401
  Object.defineProperty(exports, "__esModule", { value: true });
89398
89402
  __export(__webpack_require__(/*! ./_api */ "./src/_api.ts"));
89399
- var types_1 = __webpack_require__(/*! ./types */ "./src/types.ts");
89400
- exports.sampleScorecard = types_1.sampleScorecard;
89401
- exports.sampleProfile = types_1.sampleProfile;
89403
+ var partisan_1 = __webpack_require__(/*! ./partisan */ "./src/partisan.ts");
89404
+ exports.estSeatProbability = partisan_1.estSeatProbability;
89402
89405
 
89403
89406
 
89404
89407
  /***/ }),
@@ -89434,57 +89437,91 @@ function evalMinorityOpportunity(p, bLog = false) {
89434
89437
  const RWins = VfArray.filter(x => x <= 0.5); // Ties credited to R's
89435
89438
  const averageDVf = (DWins.length > 0) ? U.avgArray(DWins) : undefined;
89436
89439
  const averageRVf = (RWins.length > 0) ? U.avgArray(RWins) : undefined;
89437
- // Determine proportional minority districts by demographic (ignore 'White')
89438
- const districtsByDemo = calcDistrictsByDemo(p.demographicProfile.stateMfArray.slice(1), p.nDistricts);
89439
89440
  // Initialize arrays for results
89440
89441
  const offset = 1; // Don't process 'White'
89441
89442
  const nDemos = 6 /* Native */ + 1 - offset; // Ditto
89442
- const nBuckets = 2; // 37–50% and > 50%
89443
89443
  const demosByDistrict = p.demographicProfile.mfArrayByDistrict;
89444
89444
  // Initialize the demographic buckets
89445
- 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;
89446
89452
  for (let j = 0; j < nDemos; j++) {
89447
- bucketsByDemo[j] = [0, 0];
89448
- }
89449
- 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
89450
89464
  // For each district
89451
89465
  for (let i = 0; i < p.nDistricts; i++) {
89452
89466
  // Find the opportunities for minority representation
89453
89467
  for (let j = 0; j < nDemos; j++) {
89454
- const proportion = U.deepCopy(demosByDistrict[i][j + offset]);
89468
+ const proportion = U.deepCopy(demosByDistrict[i][j + offset]); // Skip the 'White' entries
89455
89469
  if (exceedsMinimumThreshold(proportion)) {
89456
- // Bucket opportunity districts
89470
+ // Bucket opportunity districts for each demographic
89457
89471
  const bucket = (exceedsMaximumThreshold(proportion)) ? 1 : 0;
89458
89472
  bucketsByDemo[j][bucket] += 1;
89473
+ bucketsByDemo[j][2 /* Total */] += 1;
89459
89474
  // Accumulate seat probabilities
89460
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
+ }
89461
89482
  }
89462
89483
  }
89463
89484
  }
89464
- // Sum the # of opportunity districts - ignore total minority
89465
- const oD = U.sumArray(opptyByDemo.slice(1));
89466
- // Sum the # of proportional districts - ignore total minority
89467
- const pD = U.sumArray(districtsByDemo.slice(1));
89485
+ // The # of opportunity districts for each separate demographic and all minorities
89486
+ const oD = U.sumArray(opptyByDemo.slice(1)); // Sum individual demos, skipping all minorities
89487
+ const cD = opptyByDemo[1 /* Minority */ - offset]; // All minorities
89488
+ // The # of proportional districts for each separate demographic and 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
89468
89493
  // Score opportunity
89469
- const score = scoreMinority(oD, pD);
89494
+ const score = scoreMinority(oD, pOd, cD, pCd);
89470
89495
  let mS = {
89471
89496
  report: {
89472
89497
  averageDVf: averageDVf,
89473
89498
  averageRVf: averageRVf,
89474
89499
  bucketsByDemographic: bucketsByDemo
89475
89500
  },
89476
- nProportional: pD,
89501
+ // proportionalOpportunities: pOd,
89477
89502
  opportunityDistricts: oD,
89503
+ // proportionalCoalitions: pCd,
89504
+ coalitionDistricts: cD,
89478
89505
  score: score,
89479
89506
  details: {}
89480
89507
  };
89481
89508
  return mS;
89482
89509
  }
89483
89510
  exports.evalMinorityOpportunity = evalMinorityOpportunity;
89484
- function scoreMinority(oD, pD) {
89511
+ // NOTE - The probable # of opportunity & coalition districts can be *larger* than
89512
+ // what would be a proportional # based on the statewide percentage, because of
89513
+ // how minority opportunities are estimated (so that 37% minority shares score
89514
+ // like 52% share).
89515
+ function scoreMinority(oD, pOd, cD, pCd) {
89485
89516
  // Score minority opportunity [0–100] here; weight it later
89486
89517
  const bonus = 100; // C.minorityBonus();
89487
- const score = (pD > 0) ? Math.round((Math.min(oD, pD) / pD) * bonus) : 0;
89518
+ const cDWeight = C.coalitionDistrictWeight();
89519
+ // Cap opportunity & coalition districts
89520
+ const oDCapped = Math.min(oD, pOd);
89521
+ const cdCapped = Math.min(cD, pCd);
89522
+ const opportunityScore = (pOd > 0) ? Math.round((oDCapped / pOd) * bonus) : 0;
89523
+ const coalitionScore = (pCd > 0) ? Math.round((cdCapped / pCd) * bonus) : 0;
89524
+ const score = Math.round(Math.min(opportunityScore + cDWeight * Math.max(coalitionScore - opportunityScore, 0), 100));
89488
89525
  return score;
89489
89526
  }
89490
89527
  exports.scoreMinority = scoreMinority;
@@ -89510,7 +89547,7 @@ function estMinorityOpportunity(Mf) {
89510
89547
  _normalizer.wipNum += shift;
89511
89548
  _normalizer.clip(dist[C.BEG], dist[C.END]);
89512
89549
  _normalizer.unitize(dist[C.BEG], dist[C.END]);
89513
- const oppty = (Mf < range[C.BEG]) ? 0.0 : partisan_1.estSeatProbability(_normalizer.wipNum, dist);
89550
+ const oppty = (Mf < range[C.BEG]) ? 0.0 : Math.min(partisan_1.estSeatProbability(_normalizer.wipNum, dist), 1.0);
89514
89551
  return oppty;
89515
89552
  }
89516
89553
  exports.estMinorityOpportunity = estMinorityOpportunity;
@@ -89719,6 +89756,7 @@ function scorePartisan(Vf, VfArray, options) {
89719
89756
  const bestS = bestSeats(N, Vf);
89720
89757
  const bestSf = bestSeatShare(bestS, N);
89721
89758
  const fptpS = bAlternateMetrics ? estFPTPSeats(VfArray) : undefined;
89759
+ // NOTE - When not constrained, use the full probability distribution to calc metrics.
89722
89760
  const range = bConstrained ? C.competitiveDistribution() : undefined;
89723
89761
  const estS = estSeats(VfArray, range);
89724
89762
  const estSf = estSeatShare(estS, N);
@@ -89728,35 +89766,41 @@ function scorePartisan(Vf, VfArray, options) {
89728
89766
  const impactScore = scoreImpact(unearnedS, Vf, estSf, N);
89729
89767
  // Calculate additional alternate metrics for reference
89730
89768
  // NOTE - Use the uncompressed seat probability function
89731
- const inferredSVpoints = bAlternateMetrics ? inferSVpoints(Vf, VfArray, shift) : undefined;
89769
+ const dSVpoints = inferSVpoints(Vf, VfArray, shift);
89770
+ const rSVpoints = invertSVPoints(dSVpoints);
89771
+ // const dSVpoints = bAlternateMetrics ? inferSVpoints(Vf, VfArray, shift) : undefined;
89732
89772
  const TOf = bAlternateMetrics ? calcTurnoutBias(Vf, VfArray) : undefined;
89733
- const Bs50 = bAlternateMetrics ? estPartisanBias(inferredSVpoints, N) : undefined;
89773
+ const Bs50 = bAlternateMetrics ? estPartisanBias(dSVpoints, N) : undefined;
89734
89774
  const Bs50f = (!(Bs50 === undefined)) ? U.trim(Bs50 / N) : undefined;
89735
- const Bv50f = bAlternateMetrics ? estVotesBias(inferredSVpoints, N) : undefined;
89775
+ const Bv50f = bAlternateMetrics ? estVotesBias(dSVpoints, N) : undefined;
89736
89776
  const rvPoints = bAlternateMetrics ? keyRVpoints(VfArray) : undefined;
89737
89777
  const decl = bAlternateMetrics ? calcDeclination(VfArray) : undefined;
89738
- const gSym = bAlternateMetrics ? calcGlobalSymmetry(inferredSVpoints, Bs50f) : undefined;
89778
+ const gSym = bAlternateMetrics ? calcGlobalSymmetry(dSVpoints, rSVpoints, Bs50f) : undefined;
89739
89779
  const EG = bAlternateMetrics ? calcEfficiencyGap(Vf, estSf) : undefined;
89740
- const BsGf = bAlternateMetrics ? estGeometricSeatsBias(Vf, inferredSVpoints) : undefined;
89780
+ const BsGf = bAlternateMetrics ? estGeometricSeatsBias(Vf, dSVpoints, rSVpoints) : undefined;
89741
89781
  const prop = bAlternateMetrics ? calcDisproportionality(Vf, estSf) : undefined;
89742
89782
  const mMs = bAlternateMetrics ? estMeanMedianDifference(VfArray, Vf) : undefined;
89743
89783
  const mMd = bAlternateMetrics ? estMeanMedianDifference(VfArray) : undefined;
89744
89784
  const LO = bAlternateMetrics ? calcLopsidedOutcomes(VfArray) : undefined;
89745
89785
  // Calculate alternate responsiveness metrics for reference
89746
89786
  const bigR = bAlternateMetrics ? calcBigR(Vf, estSf) : undefined;
89747
- const littleR = bAlternateMetrics ? estResponsiveness(Vf, inferredSVpoints) : undefined;
89787
+ const littleR = bAlternateMetrics ? estResponsiveness(Vf, dSVpoints) : undefined;
89748
89788
  const MIR = (bAlternateMetrics && littleR) ? calcMinimalInverseResponsiveness(Vf, littleR) : undefined;
89749
89789
  const rD = (!bConstrained || bAlternateMetrics) ? estResponsiveDistricts(VfArray) : undefined;
89750
89790
  const rDf = bAlternateMetrics ? estResponsiveDistrictsShare(rD, N) : undefined;
89751
89791
  const gamma = (bAlternateMetrics && littleR) ? calcGamma(Vf, estSf, littleR) : undefined;
89752
89792
  const Cn = countCompetitiveDistricts(VfArray);
89753
- 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);
89754
89796
  // const cD = bConstrained ? estCompetitiveDistricts(VfArray) : rD as number;
89755
89797
  const cDf = estCompetitiveDistrictsShare(cD, N);
89756
- const Mrange = findMarginalDistricts(Vf, VfArray, N);
89757
- const Md = estMarginalCompetitiveDistricts(Mrange, VfArray);
89758
- const Mdf = estMarginalCompetitiveShare(Md, Mrange);
89759
- 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);
89760
89804
  let biasScoring = {
89761
89805
  bestS: bestS,
89762
89806
  bestSf: bestSf,
@@ -89773,9 +89817,9 @@ function scorePartisan(Vf, VfArray, options) {
89773
89817
  cSimple: Cn,
89774
89818
  cD: cD,
89775
89819
  cDf: cDf,
89776
- mRange: Mrange,
89777
- mD: Md,
89778
- mDf: Mdf,
89820
+ // mRange: Mrange,
89821
+ // mD: Md,
89822
+ // mDf: Mdf,
89779
89823
  score: competitivenessScore
89780
89824
  };
89781
89825
  if (bAlternateMetrics) {
@@ -89810,6 +89854,8 @@ function scorePartisan(Vf, VfArray, options) {
89810
89854
  bias: biasScoring,
89811
89855
  impact: impactScoring,
89812
89856
  competitiveness: competitiveScoring,
89857
+ dSVpoints: dSVpoints,
89858
+ rSVpoints: rSVpoints,
89813
89859
  score: acrossStatesPartisanScore,
89814
89860
  score2: withinStatesPartisanScore,
89815
89861
  details: {}
@@ -89891,32 +89937,59 @@ function isAntimajoritarian(Vf, Sf) {
89891
89937
  return bDem || bRep;
89892
89938
  }
89893
89939
  exports.isAntimajoritarian = isAntimajoritarian;
89894
- function scoreCompetitiveness(rawMarginal, rawOverall) {
89895
- // Normalize overall competitiveness - Raw values are in the range [0.0–1.0].
89896
- // But the practical max is more like 2/3's, so unitize that range to [0.0–1.0].
89897
- // Then scale the values to [0–100].
89898
- 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);
89899
89946
  let worst = C.overallCompetitivenessRange()[C.BEG];
89900
89947
  let best = C.overallCompetitivenessRange()[C.END];
89901
- _overall.clip(worst, best);
89902
- _overall.unitize(worst, best);
89903
- _overall.rescale();
89904
- const ocS = _overall.normalizedNum;
89905
- // Normalize marginal competitiveness
89906
- const _marginal = new normalize_1.Normalizer(rawMarginal);
89907
- worst = C.marginalCompetitivenessRange()[C.BEG];
89908
- best = C.marginalCompetitivenessRange()[C.END];
89909
- _marginal.clip(worst, best);
89910
- _marginal.unitize(worst, best);
89911
- _marginal.rescale();
89912
- const mcS = _marginal.normalizedNum;
89913
- const mcW = C.marginalCompetitivenessWeight();
89914
- const ocW = C.overallCompetitivenessWeight();
89915
- // Then combine the results
89916
- 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;
89917
89952
  return score;
89918
89953
  }
89919
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
+ */
89920
89993
  // CORE CAPABILITIES FROM JOHN NAGLE'S METHOD
89921
89994
  const { erf } = __webpack_require__(/*! mathjs */ "./node_modules/mathjs/main/esm/index.js");
89922
89995
  // console.log("erf(0.2) =", erf(0.2)); // returns 0.22270258921047847
@@ -90150,19 +90223,20 @@ function isCompetitive(v) {
90150
90223
  return ((v >= C.competitiveRange()[C.BEG]) && (v <= C.competitiveRange()[C.END])) ? 1 : 0;
90151
90224
  }
90152
90225
  // cD - The estimated # of competitive districts
90153
- function estCompetitiveDistricts(VfArray) {
90154
- 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))));
90155
90228
  }
90156
90229
  exports.estCompetitiveDistricts = estCompetitiveDistricts;
90230
+ // COMPETITIVENESS - Modified 06/22/2020
90157
90231
  // Re-scale a Democratic vote share to the competitive range (e.g., 45–55%).
90158
- function estDistrictCompetitiveness(Vf) {
90232
+ function estDistrictCompetitiveness(Vf, bCompress = false) {
90159
90233
  const _normalizer = new normalize_1.Normalizer(Vf);
90160
90234
  // The end points of a compressed probability distribution
90161
90235
  // NOTE - These aren't the points where races start or stop being contested,
90162
90236
  // just the end points of a distribution that yields the desired behavior
90163
90237
  // in the typical competitive range [45-55%].
90164
- const distBeg = C.competitiveDistribution()[C.BEG];
90165
- 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;
90166
90240
  _normalizer.clip(distBeg, distEnd);
90167
90241
  _normalizer.unitize(distBeg, distEnd);
90168
90242
  const dC = estDistrictResponsiveness(_normalizer.wipNum);
@@ -90176,14 +90250,14 @@ function estCompetitiveDistrictsShare(cD, N) {
90176
90250
  exports.estCompetitiveDistrictsShare = estCompetitiveDistrictsShare;
90177
90251
  // Md - The estimated # of "marginal" districts in and around the likely FPTP
90178
90252
  // seats & the best seat split that are competitive.
90179
- function estMarginalCompetitiveDistricts(Mrange, VfArray) {
90253
+ function estMarginalCompetitiveDistricts(Mrange, VfArray, bCompress = false) {
90180
90254
  const minId = Mrange[C.BEG];
90181
90255
  const maxId = Mrange[C.END];
90182
90256
  // Sort the array values, and subset it to those districts
90183
90257
  // NOTE - I'm *not* keeping track of the district indexes right now
90184
90258
  let subsetVfArray = U.deepCopy(VfArray).sort().slice(minId - 1, maxId);
90185
90259
  // Est. competitive districts on that array
90186
- const Md = U.sumArray(subsetVfArray.map((v) => estDistrictCompetitiveness(v)));
90260
+ const Md = U.sumArray(subsetVfArray.map((v) => estDistrictCompetitiveness(v, bCompress)));
90187
90261
  return U.trim(Md);
90188
90262
  }
90189
90263
  exports.estMarginalCompetitiveDistricts = estMarginalCompetitiveDistricts;
@@ -90281,9 +90355,9 @@ function estVotesBias(inferredSVpoints, nDistricts) {
90281
90355
  }
90282
90356
  exports.estVotesBias = estVotesBias;
90283
90357
  // GEOMETRIC SEATS BIAS (@ V = statewide vote share)
90284
- function estGeometricSeatsBias(Vf, inferredSVpoints) {
90358
+ function estGeometricSeatsBias(Vf, dSVpoints, rSVpoints) {
90285
90359
  let BsGf = undefined;
90286
- const bgsSVpoints = inferGeometricSeatsBiasPoints(inferredSVpoints);
90360
+ const bgsSVpoints = inferGeometricSeatsBiasPoints(dSVpoints, rSVpoints);
90287
90361
  // Interpolate the seat fraction @ Vf
90288
90362
  const lowerPt = findBracketingLowerVf(Vf, bgsSVpoints);
90289
90363
  const upperPt = findBracketingUpperVf(Vf, bgsSVpoints);
@@ -90296,14 +90370,13 @@ function estGeometricSeatsBias(Vf, inferredSVpoints) {
90296
90370
  return BsGf;
90297
90371
  }
90298
90372
  exports.estGeometricSeatsBias = estGeometricSeatsBias;
90299
- function inferGeometricSeatsBiasPoints(inferredSVpoints) {
90300
- const nPoints = inferredSVpoints.length;
90301
- const inverseSVpoints = invertSVPoints(inferredSVpoints);
90373
+ function inferGeometricSeatsBiasPoints(dSVpoints, rSVpoints) {
90374
+ const nPoints = dSVpoints.length;
90302
90375
  let bgsSVpoints = [];
90303
90376
  for (let i = 0; i < nPoints; i++) {
90304
- const Vf = inferredSVpoints[i].v;
90305
- const sD = inferredSVpoints[i].s;
90306
- const sR = inverseSVpoints[i].s;
90377
+ const Vf = dSVpoints[i].v;
90378
+ const sD = dSVpoints[i].s;
90379
+ const sR = rSVpoints[i].s;
90307
90380
  const BsGf = 0.5 * (sR - sD);
90308
90381
  bgsSVpoints.push({ v: Vf, s: BsGf });
90309
90382
  }
@@ -90462,11 +90535,10 @@ function calcLopsidedOutcomes(VfArray) {
90462
90535
  }
90463
90536
  exports.calcLopsidedOutcomes = calcLopsidedOutcomes;
90464
90537
  // GLOBAL SYMMETRY - Fig. 17 in Section 5.1
90465
- function calcGlobalSymmetry(inferredSVpoints, S50V) {
90466
- const invertedSVpoints = invertSVPoints(inferredSVpoints);
90538
+ function calcGlobalSymmetry(dSVpoints, rSVpoints, S50V) {
90467
90539
  let gSym = 0.0;
90468
- for (let i in inferredSVpoints) {
90469
- gSym += Math.abs(inferredSVpoints[i].s - invertedSVpoints[i].s) / 2;
90540
+ for (let i in dSVpoints) {
90541
+ gSym += Math.abs(dSVpoints[i].s - rSVpoints[i].s) / 2;
90470
90542
  }
90471
90543
  const sign = (S50V < 0) ? -1 : 1;
90472
90544
  gSym *= sign;
@@ -90526,7 +90598,7 @@ function calcGamma(Vf, Sf, r) {
90526
90598
  exports.calcGamma = calcGamma;
90527
90599
  // HELPERS
90528
90600
  function printPartisanScorecardHeader() {
90529
- 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$');
90530
90602
  }
90531
90603
  exports.printPartisanScorecardHeader = printPartisanScorecardHeader;
90532
90604
  function printPartisanScorecardRow(xx, name, N, Vf, s) {
@@ -90539,21 +90611,24 @@ function printPartisanScorecardRow(xx, name, N, Vf, s) {
90539
90611
  s.bias.bias, // 7
90540
90612
  s.bias.score, s.impact.unearnedS, // 9
90541
90613
  s.impact.score, s.competitiveness.cSimple, // 11
90542
- 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
90543
90617
  );
90544
90618
  }
90545
90619
  exports.printPartisanScorecardRow = printPartisanScorecardRow;
90546
90620
  // Generate partisan details (Table 1)
90547
90621
  function printPartisanDetailsHeader() {
90548
- 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');
90549
90623
  }
90550
90624
  exports.printPartisanDetailsHeader = printPartisanDetailsHeader;
90551
90625
  function printPartisanDetailsRow(xx, name, N, Vf, s) {
90552
- 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
90553
90627
  s.bias.bS50, s.bias.bV50, s.bias.decl, s.bias.gSym, s.bias.eG, s.bias.bSV, // Beta
90554
90628
  s.bias.prop, // PR
90555
- 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
90556
- );
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);
90557
90632
  }
90558
90633
  exports.printPartisanDetailsRow = printPartisanDetailsRow;
90559
90634
 
@@ -90683,11 +90758,11 @@ function mixinMinorityBonus(score, minorityBonus) {
90683
90758
  }
90684
90759
  exports.mixinMinorityBonus = mixinMinorityBonus;
90685
90760
  function printScorecardHeader() {
90686
- 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$, $$$');
90687
90762
  }
90688
90763
  exports.printScorecardHeader = printScorecardHeader;
90689
90764
  function printScorecardRow(xx, name, N, Vf, s) {
90690
- 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
90691
90766
  name, // 2
90692
90767
  N, // 3
90693
90768
  Vf, // 4
@@ -90696,8 +90771,10 @@ function printScorecardRow(xx, name, N, Vf, s) {
90696
90771
  s.partisan.bias.bias, // 7
90697
90772
  s.partisan.bias.score, s.partisan.impact.unearnedS, // 9
90698
90773
  s.partisan.impact.score, s.partisan.competitiveness.cSimple, // 11
90699
- s.partisan.competitiveness.cD, s.partisan.competitiveness.mD, s.partisan.competitiveness.score, s.partisan.score2, // 15
90700
- 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);
90701
90778
  }
90702
90779
  exports.printScorecardRow = printScorecardRow;
90703
90780
 
@@ -90732,30 +90809,6 @@ exports.AVERAGE_BLOCK_SIZE = 30;
90732
90809
  exports.EQUAL_TOLERANCE = exports.AVERAGE_BLOCK_SIZE / 2;
90733
90810
 
90734
90811
 
90735
- /***/ }),
90736
-
90737
- /***/ "./src/types.ts":
90738
- /*!**********************!*\
90739
- !*** ./src/types.ts ***!
90740
- \**********************/
90741
- /*! no static exports found */
90742
- /***/ (function(module, exports, __webpack_require__) {
90743
-
90744
- "use strict";
90745
-
90746
- //
90747
- // TYPE DEFINITIONS
90748
- //
90749
- var __importDefault = (this && this.__importDefault) || function (mod) {
90750
- return (mod && mod.__esModule) ? mod : { "default": mod };
90751
- };
90752
- Object.defineProperty(exports, "__esModule", { value: true });
90753
- const sample_profile_json_1 = __importDefault(__webpack_require__(/*! ../testdata/samples/sample-profile.json */ "./testdata/samples/sample-profile.json"));
90754
- exports.sampleProfile = sample_profile_json_1.default;
90755
- const sample_scorecard_json_1 = __importDefault(__webpack_require__(/*! ../testdata/samples/sample-scorecard.json */ "./testdata/samples/sample-scorecard.json"));
90756
- exports.sampleScorecard = sample_scorecard_json_1.default;
90757
-
90758
-
90759
90812
  /***/ }),
90760
90813
 
90761
90814
  /***/ "./src/utils.ts":
@@ -90854,28 +90907,6 @@ function deepCopy(src) {
90854
90907
  exports.deepCopy = deepCopy;
90855
90908
 
90856
90909
 
90857
- /***/ }),
90858
-
90859
- /***/ "./testdata/samples/sample-profile.json":
90860
- /*!**********************************************!*\
90861
- !*** ./testdata/samples/sample-profile.json ***!
90862
- \**********************************************/
90863
- /*! exports provided: state, planName, nDistricts, nCounties, legislativeDistricts, populationProfile, compactnessProfile, splittingProfile, partisanProfile, demographicProfile, default */
90864
- /***/ (function(module) {
90865
-
90866
- module.exports = JSON.parse("{\"state\":\"NC\",\"planName\":\"NC 116th Congressional\",\"nDistricts\":13,\"nCounties\":100,\"legislativeDistricts\":false,\"populationProfile\":{\"totalPopByDistrict\":[733499,733499,733498,733499,733499,733498,733499,733499,733498,733499,733499,733498,733499],\"targetSize\":733499},\"compactnessProfile\":{\"geometryByDistrict\":[[1.577393519870778,10.159603194222512,2.6574239327900613],[0.7058443860242223,7.806818205304456,1.7632772181381422],[2.9200833695730037,9.972779463090355,2.733997011824872],[0.1913918462294299,3.5460738146162076,0.9224411598627837],[1.039017192939366,6.4920493759205495,2.1060599512212406],[1.0334601456545682,6.466840626614781,1.6394147493749138],[1.6241884494008865,7.988593581066711,1.9529170345835551],[0.7706777049448708,6.980189925133433,2.188634395661598],[0.9976766364327585,8.350880983965949,2.5604199958307654],[0.6762837622380331,5.8543721706585545,1.7264608756890525],[1.719230725216499,10.37139670690812,3.1586859214584764],[0.11329839503948308,2.2954988975477066,0.5379072920877442],[0.48371245467321944,5.3384017624136435,1.4517375375301198]]},\"splittingProfile\":{\"countyPopByDistrict\":[[0,0,0,0,0,0,0,21282,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,240299,56552,0,0,0,12197,0,59916,0,0,54691,0,0,0,24669,0,0,0,0,0,0,0,0,0,0,0,0,24505,0,0,0,0,0,0,22099,0,0,0,0,0,0,0,80880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45422,0,20972,13228,0,0,0,56787,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60619,0,0,0,0,0,0,0,114678,0,0,0,0,0,0,0,109332,0,0,0,0,0,0,0,0,0,0,0,0,95840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,328583,0,0,0,0,0,24447,0,0],[0,0,0,0,0,0,47759,0,0,0,0,0,0,0,9980,66469,0,0,0,0,14793,0,0,0,103505,0,23547,33920,0,0,0,0,0,0,0,0,0,0,0,21362,0,0,0,0,0,0,0,5810,0,0,0,10153,0,59495,0,0,0,0,0,0,0,0,0,0,0,0,177772,0,13144,40661,0,13453,0,87268,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4407,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27288,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133801,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,572410,0,0,0,0,0,0,0,0],[0,37198,11155,0,27281,17797,0,0,0,0,0,0,0,0,0,0,0,9499,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,350670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47401,73673,0,0,0,0,0,0,0,0,51079,0,69340,0,38406,0],[151131,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23719,0,63505,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,162418,0,0,0,0,0,0,0,0,0,0,0,57866,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39464,0,0,141752,0,0,93643,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,8981,107431,0,0,0,0,0,0,0,0,0,0,0,0,0,58098,0,0,0,0,0,0,58505,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,59546,0,0,0,0,0,0,0,0,0,0,0,0,0,202667,0,0,0,0,0,52217,0,0,0,0,0,0,0,0,0,0,63431,0,0,0,0,0,0,0,0,0,0,0,0,0,122623,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,178011,0,0,0,0,0,0,0,0,0,0,0,0,243476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46952,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27798,88247,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88430,0,0,0,60585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,26948,0,0,0,0,26209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75955,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,186130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,46639,134168,0,0,0,0,36157,0,0,0,0,0,0,201292,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,111849,0,0,0,0,0,0,144859,0,0,0,0,98078,0,0,0,0,0,0,0,0,0,0,0,0,206086,0,0,0,0,0,0,0,0,0,0,0,0,6042,0,0,0,0,0,78265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20510,0,0,0,0,0,67810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,126469,90912,0,83029,0,0,0,0,0,27444,0,10587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8861,0,0,0,0,0,59036,106740,0,0,0,0,40271,0,0,0,0,0,44996,33922,20764,0,0,15579,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13981,33090,0,0,0,0,0,0,0,0,0,0,0,17818],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,733498,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,162878,41240,0,0,0,0,0,0,0,0,0,0,325988,0,0,0,0,0,0,0,153395,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49998,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]},\"partisanProfile\":{\"statewideVf\":0.488799,\"vfArray\":[0.38133475250631976,0.3849820112175976,0.3932778243643098,0.4232536822067312,0.42479562842958446,0.43309446651496813,0.43760621455968074,0.43980028165892326,0.4545677480810613,0.4642133701735491,0.6853270858231137,0.6938881738049054,0.6953207231271951]},\"demographicProfile\":{\"stateMfArray\":[0.684371246819619,0.31562875318038097,0.21168281993226215,0.06787156278984616,0.0012540930000187486,0.024136155044881008,0.017483272326632705],\"mfArrayByDistrict\":[[0.46201994876162167,0.5379800512383783,0.44446912914151915,0.065885219684988,0.0009221497550043815,0.0218600624522836,0.01298238746863721],[0.7062964810448031,0.2937035189551968,0.19676408791341676,0.07140508797387993,0.0009787472035794184,0.02027027027027027,0.011283934941653062],[0.7125415968218078,0.2874584031781921,0.21181863608495496,0.05374539732717163,0.002106863519897368,0.01628256424250371,0.010404964330393058],[0.6162003899079305,0.3837996100920695,0.22386087117385056,0.08687191382180923,0.0012060108434249284,0.07153885560599377,0.010091002234143982],[0.7766842620090415,0.22331573799095852,0.14015703622760559,0.06690518783542039,0.0007790124871119258,0.013001753659331847,0.007680851626320752],[0.7111584046318987,0.2888415953681012,0.19851813634865356,0.07148666466027488,0.0008061395588804333,0.013621967123837368,0.010186021181764765],[0.7086112059348308,0.2913887940651691,0.20229594619799895,0.06953648210647081,0.001149028868250555,0.009700759801937688,0.014166663733974303],[0.6697822118227867,0.33021778817721326,0.2240088599271958,0.07249565635824667,0.002909229825482943,0.022877125445843145,0.01884938491094157],[0.6406346877484486,0.35936531225155144,0.19622106825202063,0.059419121439330605,0.0010389455633486816,0.02217720538538736,0.08616917683114156],[0.8192767260107778,0.18072327398922214,0.11582505713398979,0.045060025957170666,0.0006806703721468273,0.014117738340433936,0.008000521964844963],[0.8956213645578734,0.1043786354421266,0.032662784268536554,0.04329373425036473,0.0012436075643032956,0.010267513422177209,0.019651410943402076],[0.46574079494234033,0.5342592050576597,0.36183998712169996,0.12151883451384417,0.001650032195750161,0.050651598079962536,0.010997775566352515],[0.6979595109954735,0.3020404890045265,0.21171009017357523,0.0572352710553516,0.0008767865416830024,0.028566846063370996,0.009525252165235058]]}}");
90867
-
90868
- /***/ }),
90869
-
90870
- /***/ "./testdata/samples/sample-scorecard.json":
90871
- /*!************************************************!*\
90872
- !*** ./testdata/samples/sample-scorecard.json ***!
90873
- \************************************************/
90874
- /*! exports provided: score, partisan, minority, traditionalPrinciples, details, default */
90875
- /***/ (function(module) {
90876
-
90877
- module.exports = JSON.parse("{\"score\":5,\"partisan\":{\"bias\":{\"bestS\":7,\"bestSf\":0.5385,\"estS\":4.1925,\"estSf\":0.3225,\"bias\":0.216,\"tOf\":-0.0023,\"fptpS\":3,\"bS50\":0.2172,\"bV50\":0.045,\"decl\":36.5164,\"gSym\":0.066602,\"gamma\":0.0123,\"eG\":0.2846,\"bSV\":0.2098,\"prop\":0.2695,\"mMd\":0.0593,\"mMs\":0.057,\"lO\":0.1106,\"score\":0},\"impact\":{\"unearnedS\":2.8075,\"score\":0},\"competitiveness\":{\"bigR\":-16.926,\"littleR\":4.3523,\"mIR\":0.1298,\"rD\":4.0207,\"rDf\":0.3093,\"cSimple\":6,\"cD\":0.7266,\"cDf\":0.0559,\"mRange\":[5,11],\"mD\":0.7134,\"mDf\":0.1019,\"score\":10},\"score\":3,\"score2\":2,\"details\":{\"election\":\"2016 Presidential, US Senate, Governor, and AG election results\"}},\"minority\":{\"report\":{\"bucketsByDemographic\":[[10,14],[3,0],[1,9],[0,0],[0,0],[0,0]],\"averageDVf\":0.6737588682747838},\"nProportional\":18,\"opportunityDistricts\":12.9424,\"score\":14,\"details\":{\"vap\":\"2010 Voting Age Population\"}},\"traditionalPrinciples\":{\"score\":18,\"compactness\":{\"score\":35,\"reock\":{\"raw\":0.3373,\"normalized\":35,\"notes\":{}},\"polsby\":{\"raw\":0.2418,\"normalized\":35,\"notes\":{}}},\"splitting\":{\"score\":0,\"county\":{\"raw\":1.1474,\"normalized\":0,\"notes\":{}},\"district\":{\"raw\":1.4839,\"normalized\":3,\"notes\":{}}},\"populationDeviation\":{\"raw\":0.016,\"normalized\":0,\"notes\":{\"maxDeviation\":11693}},\"details\":{\"countiesSplitUnexpectedly\":[\"Bladen\",\"Buncombe\",\"Catawba\",\"Cumberland\",\"Durham\",\"Guilford\",\"Iredell\",\"Johnston\",\"Pitt\",\"Rowan\",\"Wilson\"],\"unexpectedAffected\":0.3096,\"nSplitVTDs\":12,\"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\"],\"shapes\":\"2010 VTD shapes\",\"census\":\"2010 Census Total Population\"}},\"details\":{}}");
90878
-
90879
90910
  /***/ })
90880
90911
 
90881
90912
  /******/ });
@@ -102888,6 +102919,17 @@ class AnalyticsSession {
102888
102919
  getPlanScorecard(bLog = false) {
102889
102920
  return this._scorecard;
102890
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
+ }
102891
102933
  // NOTE - This assumes that analyzePlan() has been run!
102892
102934
  getRequirementsChecklist(bLog = false) {
102893
102935
  return results_2.prepareRequirementsChecklist(this, bLog);