@dra2020/district-analytics 7.1.7 → 8.0.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
@@ -89056,7 +89056,7 @@ exports.scorePolsbyPopper = scorePolsbyPopper;
89056
89056
  /*! exports provided: partisan, minority, compactness, splitting, popdev, default */
89057
89057
  /***/ (function(module) {
89058
89058
 
89059
- 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]]}}");
89059
+ 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,0.5],\"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]]}}");
89060
89060
 
89061
89061
  /***/ }),
89062
89062
 
@@ -89160,11 +89160,20 @@ function minorityOpportunityDistribution(overridesJSON) {
89160
89160
  return dist;
89161
89161
  }
89162
89162
  exports.minorityOpportunityDistribution = minorityOpportunityDistribution;
89163
+ // For Black VAP %
89163
89164
  function minorityShift(overridesJSON) {
89164
- const shift = config_json_1.default.minority.shift;
89165
+ const BLACK = 0;
89166
+ const shift = config_json_1.default.minority.shift[BLACK];
89165
89167
  return shift;
89166
89168
  }
89167
89169
  exports.minorityShift = minorityShift;
89170
+ // Dilution for other demos
89171
+ function minorityShiftDilution(overridesJSON) {
89172
+ const DILUTION = 1;
89173
+ const shift = config_json_1.default.minority.shift[DILUTION];
89174
+ return shift;
89175
+ }
89176
+ exports.minorityShiftDilution = minorityShiftDilution;
89168
89177
  function coalitionDistrictWeight(overridesJSON) {
89169
89178
  const weight = config_json_1.default.minority.coalition.weight;
89170
89179
  return weight;
@@ -89357,47 +89366,36 @@ const normalize_1 = __webpack_require__(/*! ./normalize */ "./src/normalize.ts")
89357
89366
  const partisan_1 = __webpack_require__(/*! ./partisan */ "./src/partisan.ts");
89358
89367
  function evalMinorityOpportunity(p, bLog = false) {
89359
89368
  // Initialize arrays for results
89360
- const offset = 1; // Don't process 'White'
89361
- const nDemos = 6 /* Total */; // Ditto
89362
- // const nDemos = T.DemographicField.Native + 1 - offset; // Ditto
89369
+ const nDemos = 5 /* Native */ + 1; // Profile includes 'White'
89370
+ const offset = 1; // But don't process 'White'
89363
89371
  const demosByDistrict = p.demographicProfile.mfArrayByDistrict;
89364
89372
  // Initialize the demographic buckets
89365
89373
  // Get the statewide minority VAP/CVAP % (ignore 'White')
89366
89374
  const vapPctArray = p.demographicProfile.stateMfArray.slice(1);
89367
89375
  // Determine proportional minority districts by demographic (ignoring'White')
89368
89376
  const districtsByDemo = calcDistrictsByDemo(vapPctArray, p.nDistricts);
89369
- let bucketsByDemo = new Array(nDemos + 1); // Add a row for the 'Total' row
89377
+ let bucketsByDemo = new Array(nDemos);
89370
89378
  let totalProportional = 0;
89371
89379
  for (let j = 0; j < nDemos; j++) {
89372
89380
  const vapPct = vapPctArray[j];
89373
89381
  const prop = districtsByDemo[j];
89374
- // Accumulate the proportional values for each demographic, ignoring the first
89375
- // all Minority demographic.
89382
+ bucketsByDemo[j] = [0, 0, 0, 0, 0, 0, vapPct, prop];
89383
+ // Sum the prop for each individual race/ethnicity demographic
89376
89384
  if (j > 0)
89377
89385
  totalProportional += prop;
89378
- bucketsByDemo[j] = [0, 0, 0, vapPct, prop]; // Five conceptual columns for each demographic
89379
89386
  }
89380
- // Add a 'Total' row
89381
- bucketsByDemo[nDemos] = [0, 0, 0, 0, totalProportional];
89382
89387
  let opptyByDemo = U.initArray(nDemos, 0.0); // A state-level value
89383
89388
  // For each district
89384
89389
  for (let i = 0; i < p.nDistricts; i++) {
89385
89390
  // Find the opportunities for minority representation
89386
89391
  for (let j = 0; j < nDemos; j++) {
89387
- const proportion = U.deepCopy(demosByDistrict[i][j + offset]); // Skip the 'White' entries
89388
- if (exceedsMinimumThreshold(proportion)) {
89392
+ const Mf = demosByDistrict[i][j + offset]; // Skip the 'White' entries
89393
+ const bucket = bucketVAPPct(Mf);
89394
+ if (bucket > 0) {
89389
89395
  // Bucket opportunity districts for each demographic
89390
- const bucket = (exceedsMaximumThreshold(proportion)) ? 1 : 0;
89391
- bucketsByDemo[j][bucket] += 1;
89392
- bucketsByDemo[j][2 /* Total */] += 1;
89396
+ bucketsByDemo[j][bucket - 1] += 1; // Zero-based array
89393
89397
  // Accumulate seat probabilities
89394
- opptyByDemo[j] += estMinorityOpportunity(proportion);
89395
- // Also accumulate the 'Total' row summing the opportunities for each demographic,
89396
- // ignoring the first all Minority demographic.
89397
- if (j > 0) {
89398
- bucketsByDemo[nDemos][bucket] += 1;
89399
- bucketsByDemo[nDemos][2 /* Total */] += 1;
89400
- }
89398
+ opptyByDemo[j] += estMinorityOpportunity(Mf, j);
89401
89399
  }
89402
89400
  }
89403
89401
  }
@@ -89405,8 +89403,8 @@ function evalMinorityOpportunity(p, bLog = false) {
89405
89403
  const oD = U.sumArray(opptyByDemo.slice(1)); // Sum individual demos, skipping all minorities
89406
89404
  const cD = opptyByDemo[0 /* Minority */]; // All minorities
89407
89405
  // The # of proportional districts for each separate demographic and all minorities
89408
- const pOd = bucketsByDemo[6 /* Total */][4 /* PropSeats */];
89409
- const pCd = bucketsByDemo[0 /* Minority */][4 /* PropSeats */];
89406
+ const pOd = totalProportional;
89407
+ const pCd = bucketsByDemo[0 /* Minority */][7 /* PropSeats */];
89410
89408
  // Score opportunity
89411
89409
  const score = scoreMinority(oD, pOd, cD, pCd);
89412
89410
  let mS = {
@@ -89447,13 +89445,15 @@ exports.calcDistrictsByDemo = calcDistrictsByDemo;
89447
89445
  // NOTE - Sam Wang suggest 90% probability for a 37% district. That seems a little
89448
89446
  // too abrupt and all or nothing, so I backed off to the ~70%.
89449
89447
  //
89450
- function estMinorityOpportunity(Mf) {
89448
+ function estMinorityOpportunity(Mf, demo) {
89451
89449
  // NOTE - Switch to compress the probability distribution
89452
89450
  const bCompress = false;
89453
89451
  const dist = bCompress ? C.minorityOpportunityDistribution() : [0.0, 1.0];
89454
89452
  const range = C.minorityOpportunityRange();
89455
89453
  const _normalizer = new normalize_1.Normalizer(Mf);
89456
- const shift = C.minorityShift();
89454
+ let shift = C.minorityShift(); // For Black VAP % (and Minority)
89455
+ if (demo && (demo > 1)) // For other non-Black demos,
89456
+ shift *= C.minorityShiftDilution(); // dilute the Black shift (by half)
89457
89457
  _normalizer.wipNum += shift;
89458
89458
  _normalizer.clip(dist[C.BEG], dist[C.END]);
89459
89459
  _normalizer.unitize(dist[C.BEG], dist[C.END]);
@@ -89462,13 +89462,21 @@ function estMinorityOpportunity(Mf) {
89462
89462
  }
89463
89463
  exports.estMinorityOpportunity = estMinorityOpportunity;
89464
89464
  // HELPERS
89465
- function exceedsMinimumThreshold(Mf) {
89466
- const threshold = C.minorityOpportunityRange()[C.BEG];
89467
- return Mf >= threshold;
89468
- }
89469
- function exceedsMaximumThreshold(Mf) {
89470
- const threshold = C.minorityOpportunityRange()[C.END];
89471
- return Mf > threshold;
89465
+ function bucketVAPPct(Mf) {
89466
+ if (Mf < 0.35)
89467
+ return 0;
89468
+ else if ((Mf >= 0.35) && (Mf < 0.40))
89469
+ return 1;
89470
+ else if ((Mf >= 0.40) && (Mf < 0.45))
89471
+ return 2;
89472
+ else if ((Mf >= 0.45) && (Mf < 0.50))
89473
+ return 3;
89474
+ else if ((Mf >= 0.50) && (Mf < 0.55))
89475
+ return 4;
89476
+ else if ((Mf >= 0.55) && (Mf < 0.60))
89477
+ return 5;
89478
+ else // Mf >= 0.60
89479
+ return 6;
89472
89480
  }
89473
89481
  function calcProportionalDistricts(proportion, nDistricts) {
89474
89482
  const roundUp = 0.0;