@dra2020/district-analytics 2.0.2 → 2.0.5

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
@@ -8074,6 +8074,13 @@ class AnalyticsSession {
8074
8074
  this.features = new D.Features(this, SessionRequest['data'], this.config['datasets']);
8075
8075
  this.plan = new D.Plan(this, SessionRequest['plan']);
8076
8076
  this.districts = new D.Districts(this, SessionRequest['districtShapes']);
8077
+ // TODO - Confirming that the graph includes OUT_OF_STATE neighbors
8078
+ // if (U.keyExists(S.OUT_OF_STATE, this.graph._graph)) {
8079
+ // console.log("Contiguity graph includes out-of-state neighbors.");
8080
+ // }
8081
+ // else {
8082
+ // console.log("Contiguity graph does NOT include out-of-state neighbors.");
8083
+ // }
8077
8084
  // NOTE: I've pulled these out of the individual analytics to here. Eventually,
8078
8085
  // we could want them to passed into an analytics session as data, along with
8079
8086
  // everything else. For now, this keeps branching out of the main code.
@@ -8183,6 +8190,9 @@ const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"
8183
8190
  const valid_1 = __webpack_require__(/*! ./valid */ "./src/valid.ts");
8184
8191
  const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
8185
8192
  const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
8193
+ // DEBUG COUNTERS
8194
+ let nMissingDataset = 0;
8195
+ let nMissingProperty = 0;
8186
8196
  // DISTRICT STATISTICS
8187
8197
  // Indexes for statistics fields in Districts
8188
8198
  // NOTE - Not a const, so the number can be determined dynamically
@@ -8267,6 +8277,9 @@ class Districts {
8267
8277
  // TODO - OPTIMIZE by async'ing this?
8268
8278
  // TODO - Is there a way to do this programmatically off data? Does it matter?
8269
8279
  recalcStatistics(bLog = false) {
8280
+ // Initialize debug counters
8281
+ nMissingDataset = 0;
8282
+ nMissingProperty = 0;
8270
8283
  // Compute these once per recalc cycle
8271
8284
  let targetSize = this._session.state.totalPop / this._session.state.nDistricts;
8272
8285
  let deviationThreshold = this._session.populationDeviationThreshold();
@@ -8364,8 +8377,8 @@ class Districts {
8364
8377
  });
8365
8378
  // COMPUTE DERIVED VALUES
8366
8379
  // Population deviation % and equal population (boolean) by district.
8367
- // Don't set the values for the dummy unassigned district.
8368
- let popDevPct = null;
8380
+ // Default the value for the dummy unassigned district to 0%.
8381
+ let popDevPct = 0 / targetSize;
8369
8382
  if (i > 0) {
8370
8383
  popDevPct = (totalPop - targetSize) / targetSize;
8371
8384
  bEqualPop = (popDevPct <= deviationThreshold);
@@ -8504,6 +8517,8 @@ class Districts {
8504
8517
  this.statistics[DistrictField.AsianPct][summaryRow] = stateAsianPop / stateVAPPop;
8505
8518
  this.statistics[DistrictField.NativePct][summaryRow] = stateNativePop / stateVAPPop;
8506
8519
  }
8520
+ console.log(`${nMissingDataset} features with missing datasets.`);
8521
+ console.log(`${nMissingProperty} features with missing properties.`);
8507
8522
  }
8508
8523
  // NOTE - I did not roll these into district statistics, because creating the
8509
8524
  // district shapes themselves is the big district-by-district activity, these
@@ -8558,36 +8573,46 @@ exports.Features = Features;
8558
8573
  // f is a direct GeoJSON feature
8559
8574
  // p is a geoID
8560
8575
  function _getFeatures(f, datasetKey, p) {
8561
- // Echo parameters for debugging
8562
- // console.log("f =", f, "k = ", datasetKey, "p =", p);
8563
8576
  // Shim to load sample data2.json from disk for command-line scaffolding
8564
8577
  if (f.properties && f.properties['datasets']) {
8578
+ if (!f.properties['datasets'][datasetKey]) {
8579
+ // Feature is missing the dataset
8580
+ nMissingDataset += 1;
8581
+ console.log(`${nMissingDataset}: Data ${datasetKey} missing for feature ${f} Returning zero.`);
8582
+ return 0;
8583
+ }
8565
8584
  return f.properties['datasets'][datasetKey][p];
8566
8585
  }
8567
8586
  // NOTE - The fGetW() code from dra-client below here ...
8568
8587
  // Direct property?
8569
- if (f.properties && f.properties[p] !== undefined)
8588
+ if (f.properties && f.properties[p] !== undefined) {
8570
8589
  return f.properties[p];
8590
+ }
8571
8591
  // Joined property?
8572
8592
  let a = _fGetJoined(f);
8573
8593
  if (a) {
8574
8594
  for (let i = 0; i < a.length; i++) {
8575
8595
  let o = a[i];
8576
8596
  if (!datasetKey) {
8577
- if (o[p] !== undefined)
8597
+ if (o[p] !== undefined) {
8578
8598
  return o[p];
8599
+ }
8579
8600
  }
8580
8601
  else {
8581
8602
  if (o['datasets'] && o['datasets'][datasetKey]) {
8582
8603
  let v = (o['datasets'][datasetKey][p]);
8583
- if ((!(v == null)) && (!(v == undefined)))
8604
+ if ((!(v == null)) && (!(v == undefined))) {
8584
8605
  return o['datasets'][datasetKey][p];
8606
+ }
8585
8607
  }
8586
8608
  }
8587
8609
  }
8588
8610
  }
8589
- console.log(`${p} value undefined for ${f.properties['GEOID10']}!`);
8590
- return undefined;
8611
+ // Feature is missing the property
8612
+ nMissingProperty += 1;
8613
+ console.log(`${nMissingProperty}: ${p} value undefined for ${f.properties['GEOID10']}. Returning zero.`);
8614
+ return 0;
8615
+ // return undefined;
8591
8616
  }
8592
8617
  function _fGetJoined(f) {
8593
8618
  return (f.properties && f.properties.joined) ? f.properties.joined : undefined;
@@ -8632,6 +8657,7 @@ class Plan {
8632
8657
  }
8633
8658
  // NOTE - DON'T remove water-only features from the plan, as they may be required
8634
8659
  // for contiguity. Just skip them in aggregating district statistics.
8660
+ //
8635
8661
  // removeWaterOnlyFeatures(plan: T.PlanByGeoID): T.PlanByGeoID {
8636
8662
  // let newPlan = {} as T.PlanByGeoID;
8637
8663
  // for (let geoID in plan) {
@@ -9135,7 +9161,7 @@ exports.doFindCountiesSplitUnexpectedly = doFindCountiesSplitUnexpectedly;
9135
9161
  function doFindSplitVTDs(s, bLog = false) {
9136
9162
  let test = s.getTest(10 /* VTDSplits */);
9137
9163
  let splitVTDs = [];
9138
- // TODO - SPLITTING: Flesh this out, using Terry's virtual VTD's ...
9164
+ // TODO - SPLITTING: Flesh this out, using virtual VTD's ...
9139
9165
  test['score'] = splitVTDs.length;
9140
9166
  test['details']['splitVTDs'] = splitVTDs;
9141
9167
  return test;
@@ -9382,17 +9408,22 @@ const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
9382
9408
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
9383
9409
  function doPopulationDeviation(s, bLog = false) {
9384
9410
  let test = s.getTest(4 /* PopulationDeviation */);
9385
- // Compute the min, max, and average district populations,
9386
- // excluding the dummy 'unassigned' 0 and N+1 summary "districts."
9411
+ let targetSize = s.state.totalPop / s.state.nDistricts;
9412
+ // Compute the min & max district populations
9413
+ // ... excluding the dummy the 'unassigned' 0 and N+1 summary "districts"
9387
9414
  let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
9388
9415
  totPopByDistrict = totPopByDistrict.slice(1, -1);
9389
- let min = U.minArray(totPopByDistrict);
9390
- let max = U.maxArray(totPopByDistrict);
9391
- let total = U.sumArray(totPopByDistrict);
9392
- // Calculate the raw population deviation.
9393
- // The target size is the average population.
9394
- let avg = total / s.state.nDistricts;
9395
- let popDev = (max - min) / avg;
9416
+ // Remove empty districts
9417
+ totPopByDistrict = totPopByDistrict.filter(x => x > 0);
9418
+ let min = 0;
9419
+ let max = 0;
9420
+ // If there's more than 1 non-empty district, calculate a non-zero deviation
9421
+ if (totPopByDistrict.length > 1) {
9422
+ min = U.minArray(totPopByDistrict);
9423
+ max = U.maxArray(totPopByDistrict);
9424
+ }
9425
+ // Calculate the raw population deviation
9426
+ let popDev = (max - min) / targetSize;
9396
9427
  // Round the raw value to the desired level of precision
9397
9428
  popDev = U.trim(popDev);
9398
9429
  // Populate the test entry
@@ -9402,7 +9433,7 @@ function doPopulationDeviation(s, bLog = false) {
9402
9433
  let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
9403
9434
  let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
9404
9435
  let summaryRow = s.districts.numberOfRows() - 1;
9405
- totalPop[summaryRow] = avg; // aka "target size"
9436
+ totalPop[summaryRow] = targetSize;
9406
9437
  popDevPct[summaryRow] = popDev;
9407
9438
  return test;
9408
9439
  }
@@ -9766,9 +9797,9 @@ function doPreprocessCensus(s, bLog = false) {
9766
9797
  // Sum total population by county
9767
9798
  totalByCounty[countyFIPS] += value;
9768
9799
  }
9769
- // else {
9770
- // console.log("Skipping water-only feature in Census preprocessing:", geoID);
9771
- // }
9800
+ else {
9801
+ console.log("Skipping water-only feature in Census preprocessing:", geoID);
9802
+ }
9772
9803
  }
9773
9804
  // NOTE - The above could be replaced, if I got totals on county.geojson.
9774
9805
  // CREATE A FIPS CODE-ORDINAL MAP
@@ -10366,8 +10397,10 @@ const testDefns = {
10366
10397
  // Raw numeric analytics, such as population deviation, compactness, etc. are
10367
10398
  // normalized as part of creating a scorecard, so the code to normalize results
10368
10399
  // is encapsulated here.
10369
- // Configure scale parameters for normalizing each raw test result
10370
- // This needs to be separate from the scorecard configuration info above,
10400
+ // Configure scale parameters for normalizing each raw test result.
10401
+ // Scales consist of a minimum & a maximum *raw* value. If the values get
10402
+ // inverted (to make bigger better), these will switch.
10403
+ // This process needs to be separate from the test configuration info above,
10371
10404
  // because some scales need access to the analytics session object.
10372
10405
  function doConfigureScales(s) {
10373
10406
  // Scale defn for PopulationDeviation