@dra2020/district-analytics 9.0.0 → 9.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.
@@ -330,9 +330,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
330
330
  return result;
331
331
  };
332
332
  Object.defineProperty(exports, "__esModule", { value: true });
333
+ const G = __importStar(__webpack_require__(/*! @dra2020/dra-graph */ "@dra2020/dra-graph"));
333
334
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
334
335
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
335
- const valid_1 = __webpack_require__(/*! ./valid */ "./src/valid.ts");
336
+ // import { isConnected, isEmbedded } from './valid';
336
337
  const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
337
338
  const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
338
339
  // DEBUG COUNTERS
@@ -512,7 +513,8 @@ class Districts {
512
513
  countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
513
514
  }
514
515
  else {
515
- console.log("County not recognized:", geoID);
516
+ if (bLog)
517
+ console.log("County not recognized:", geoID);
516
518
  }
517
519
  // Democratic and Republican vote totals
518
520
  demVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
@@ -578,8 +580,15 @@ class Districts {
578
580
  // Leave the default values for the dummy unassigned district,
579
581
  // and districts that are empty.
580
582
  if ((i > 0) && bNotEmpty) {
581
- bContiguous = valid_1.isConnected(geoIDs, graph);
582
- bNotEmbedded = (!valid_1.isEmbedded(i, planByDistrict[i], plan, graph));
583
+ // GRAPH - 10/05/2020 - Using dra-graph instead.
584
+ // bContiguous = isConnected(geoIDs, graph);
585
+ // bNotEmbedded = (!isEmbedded(i, planByDistrict[i], plan, graph));
586
+ // GRAPH - 10/05/2020 - Using dra-graph.
587
+ const features = geoIDs;
588
+ const nakedGraph = graph._graph;
589
+ const nakedPlan = plan._planByGeoID;
590
+ bContiguous = G.isConnected(features, nakedGraph);
591
+ bNotEmbedded = (!G.isEmbedded(i, features, nakedPlan, nakedGraph));
583
592
  }
584
593
  // 6 - MORE ...
585
594
  { // UPDATE THE DISTRICT STATISTICS
@@ -783,7 +792,7 @@ function _getFeatures(f, datasetKey, p) {
783
792
  if (!f.properties['datasets'][datasetKey]) {
784
793
  // Feature is missing the dataset
785
794
  nMissingDataset += 1;
786
- console.log(`${nMissingDataset}: Data ${datasetKey} missing for feature ${f} Returning zero.`);
795
+ // console.log(`${nMissingDataset}: Data ${datasetKey} missing for feature ${f} Returning zero.`);
787
796
  return 0;
788
797
  }
789
798
  return f.properties['datasets'][datasetKey][p];
@@ -815,7 +824,7 @@ function _getFeatures(f, datasetKey, p) {
815
824
  }
816
825
  // Feature is missing the property
817
826
  nMissingProperty += 1;
818
- console.log(`${nMissingProperty}: ${p} value undefined for ${f.properties['GEOID10']}. Returning zero.`);
827
+ // console.log(`${nMissingProperty}: ${p} value undefined for ${f.properties['GEOID10']}. Returning zero.`);
819
828
  return 0;
820
829
  // return undefined;
821
830
  }
@@ -1152,8 +1161,10 @@ function doFindCountiesSplitUnexpectedly(s, bLog = false) {
1152
1161
  // 07-06-20 - Guard in case the FIPS code isn't in the county name lookup
1153
1162
  if (name)
1154
1163
  countiesSplitUnexpectedly.push(name);
1155
- else
1156
- console.log("County is not in the FIPS-to-name lookup table: ", fips);
1164
+ else {
1165
+ if (bLog)
1166
+ console.log("County is not in the FIPS-to-name lookup table: ", fips);
1167
+ }
1157
1168
  }
1158
1169
  countiesSplitUnexpectedly = countiesSplitUnexpectedly.sort();
1159
1170
  test['score'] = U.trim(unexpectedAffected);
@@ -1517,7 +1528,8 @@ function doPreprocessCensus(s, bLog = false) {
1517
1528
  totalByCounty[countyFIPS] += value;
1518
1529
  }
1519
1530
  else {
1520
- console.log("County not recognized:", geoID);
1531
+ if (bLog)
1532
+ console.log("County not recognized:", geoID);
1521
1533
  }
1522
1534
  }
1523
1535
  else {
@@ -2410,11 +2422,13 @@ function doIsComplete(s, bLog = false) {
2410
2422
  // Check the official congressional maps for CT, KY, IL, and MI.
2411
2423
  bAllNonWaterOnlyAssigned = !unassignedFeatures.some(function (geoID) {
2412
2424
  if (U.isWaterOnly(geoID, s)) {
2413
- console.log("Unassigned water-only feature ignored in completeness check: ", geoID);
2425
+ if (bLog)
2426
+ console.log("Unassigned water-only feature ignored in completeness check: ", geoID);
2414
2427
  return false;
2415
2428
  }
2416
2429
  if (U.isUninhabited(geoID, s)) {
2417
- console.log("Uninhabited feature ignored in completeness check: ", geoID);
2430
+ if (bLog)
2431
+ console.log("Uninhabited feature ignored in completeness check: ", geoID);
2418
2432
  return false;
2419
2433
  }
2420
2434
  // Not water-only and inhabited
@@ -2500,30 +2514,38 @@ function doIsContiguous(s, bLog = false) {
2500
2514
  return test;
2501
2515
  }
2502
2516
  exports.doIsContiguous = doIsContiguous;
2517
+ /* GRAPH - Removed 10/05/2020. Using dra-graph instead.
2503
2518
  // Are the features in a district fully connected?
2504
- function isConnected(districtGeos, graph) {
2505
- // TODO - TERRY, why does this constructor need a <T> type specification?
2506
- let visited = new Set();
2507
- let toProcess = [];
2508
- // Start processing with the first geoID in the district
2509
- let iter = districtGeos.values();
2510
- toProcess.push(iter.next().value);
2511
- // While there are geoIDs in the district that haven't been processed
2512
- while (toProcess.length > 0) {
2513
- // Grab a geoID and process it
2514
- let node = toProcess.pop();
2515
- visited.add(node);
2516
- // Get its actual, in-state neighbors
2517
- let actualNeighbors = graph.peerNeighbors(node).filter(x => U.isInState(x));
2518
- // Add neighbors to visit, if they're in the same district Y haven't already been visited
2519
- let neighborsToVisit = actualNeighbors.filter(x => districtGeos.has(x) && (!visited.has(x)));
2520
- // TODO - TERRY, is this the quickest/best way to do this?
2521
- toProcess.push(...neighborsToVisit);
2522
- }
2523
- // Stop when you've visited all the geoIDs in the district
2524
- return visited.size == districtGeos.size;
2525
- }
2526
- exports.isConnected = isConnected;
2519
+ export function isConnected(districtGeos: Set<string>, graph: D.Graph): boolean
2520
+ {
2521
+ // TODO - TERRY, why does this constructor need a <T> type specification?
2522
+ let visited = new Set<string>();
2523
+ let toProcess: string[] = [];
2524
+
2525
+ // Start processing with the first geoID in the district
2526
+ let iter = districtGeos.values();
2527
+ toProcess.push(iter.next().value);
2528
+
2529
+ // While there are geoIDs in the district that haven't been processed
2530
+ while (toProcess.length > 0)
2531
+ {
2532
+ // Grab a geoID and process it
2533
+ let node = toProcess.pop() as string;
2534
+ visited.add(node);
2535
+
2536
+ // Get its actual, in-state neighbors
2537
+ let actualNeighbors = graph.peerNeighbors(node).filter(x => U.isInState(x));
2538
+
2539
+ // Add neighbors to visit, if they're in the same district Y haven't already been visited
2540
+ let neighborsToVisit = actualNeighbors.filter(x => districtGeos.has(x) && (!visited.has(x)));
2541
+ // TODO - TERRY, is this the quickest/best way to do this?
2542
+ toProcess.push(...neighborsToVisit);
2543
+ }
2544
+
2545
+ // Stop when you've visited all the geoIDs in the district
2546
+ return visited.size == districtGeos.size;
2547
+ }
2548
+ */
2527
2549
  //
2528
2550
  // FREE OF HOLES - Are any districts fully embedded w/in another district?
2529
2551
  //
@@ -2566,68 +2588,89 @@ function doIsFreeOfHoles(s, bLog = false) {
2566
2588
  return test;
2567
2589
  }
2568
2590
  exports.doIsFreeOfHoles = doIsFreeOfHoles;
2591
+ /* GRAPH - Removed 10/05/2020. Using dra-graph instead.
2569
2592
  // Test whether one district is embedded w/in any other.
2570
- function isEmbedded(districtID, geoIDs, plan, graph) {
2571
- // NOTE - "features" here = "geoIDs." These aren't "features" proper, just
2572
- // identifier strings.
2573
- let features = geoIDs;
2574
- let planByGeo = plan.byGeoID();
2575
- // Assume the district is embedded
2576
- let bEmbedded = true;
2577
- // Keep track of the neighoring districts
2578
- let neighboringDistricts = new Set();
2579
- // TODO - OPTIMIZE: Use just the boundary features, when available
2580
- // Get the features for the real district
2581
- let featuresToCheck = Array.from(features);
2582
- // If the district has features, check whether it is embedded
2583
- if (!(U.isArrayEmpty(featuresToCheck))) {
2584
- // For each feature that needs to be checked (see above)
2585
- for (let feature of featuresToCheck) {
2586
- // Get its neighbors (including the virtual "out of state" ones)
2587
- let neighbors = graph.peerNeighbors(feature);
2588
- for (let neighbor of neighbors) {
2589
- if (U.isOutOfState(neighbor)) {
2590
- bEmbedded = false;
2591
- // No need to check any more neighbors
2592
- break;
2593
- }
2594
- else {
2595
- let neighboringDistrict = U.getDistrict(planByGeo, neighbor);
2596
- // Assume that a missing district assignment (= None) means that the
2597
- // feature is "water-only" AND part of the state border (vs. internal)
2598
- // and, therefore, not in the plan/map.
2599
- if (neighboringDistrict == undefined) {
2600
- bEmbedded = false;
2601
- // No need to check any more neighbors
2602
- break;
2603
- }
2604
- else {
2605
- // TODO - OPTIMIZE: Since we're checking *all* features in a district right
2606
- // now, not just boundary features and neighbors in other districts,
2607
- // prune out the current district. If/when we optimize compactness
2608
- // to cache district boundaries (as before in my Python implementation),
2609
- // we won't have to guard adding "neighboring" districts in this way.
2610
- if (neighboringDistrict != districtID) {
2611
- neighboringDistricts.add(neighboringDistrict);
2612
- }
2613
- if (neighboringDistricts.size > 1) {
2614
- bEmbedded = false;
2615
- // No need to check any more neighbors
2616
- break;
2617
- }
2618
- }
2619
- }
2593
+ export function isEmbedded(districtID: number, geoIDs: Set<string>, plan: D.Plan, graph: D.Graph): boolean
2594
+ {
2595
+ // NOTE - "features" here = "geoIDs." These aren't "features" proper, just
2596
+ // identifier strings.
2597
+ let features = geoIDs;
2598
+ let planByGeo = plan.byGeoID();
2599
+
2600
+ // Assume the district is embedded
2601
+ let bEmbedded = true;
2602
+ // Keep track of the neighoring districts
2603
+ let neighboringDistricts = new Set();
2604
+
2605
+ // TODO - OPTIMIZE: Use just the boundary features, when available
2606
+ // Get the features for the real district
2607
+ let featuresToCheck = Array.from(features);
2608
+
2609
+ // If the district has features, check whether it is embedded
2610
+ if (!(U.isArrayEmpty(featuresToCheck)))
2611
+ {
2612
+ // For each feature that needs to be checked (see above)
2613
+ for (let feature of featuresToCheck)
2614
+ {
2615
+ // Get its neighbors (including the virtual "out of state" ones)
2616
+ let neighbors = graph.peerNeighbors(feature);
2617
+
2618
+ for (let neighbor of neighbors)
2619
+ {
2620
+ if (U.isOutOfState(neighbor))
2621
+ {
2622
+ bEmbedded = false;
2623
+ // No need to check any more neighbors
2624
+ break;
2625
+ }
2626
+ else
2627
+ {
2628
+ let neighboringDistrict = U.getDistrict(planByGeo, neighbor);
2629
+
2630
+ // Assume that a missing district assignment (= None) means that the
2631
+ // feature is "water-only" AND part of the state border (vs. internal)
2632
+ // and, therefore, not in the plan/map.
2633
+
2634
+ if (neighboringDistrict == undefined)
2635
+ {
2636
+ bEmbedded = false;
2637
+ // No need to check any more neighbors
2638
+ break;
2639
+ }
2640
+ else
2641
+ {
2642
+ // TODO - OPTIMIZE: Since we're checking *all* features in a district right
2643
+ // now, not just boundary features and neighbors in other districts,
2644
+ // prune out the current district. If/when we optimize compactness
2645
+ // to cache district boundaries (as before in my Python implementation),
2646
+ // we won't have to guard adding "neighboring" districts in this way.
2647
+ if (neighboringDistrict != districtID)
2648
+ {
2649
+ neighboringDistricts.add(neighboringDistrict);
2620
2650
  }
2621
- // If a district is not embedded, there's no need to check anymore
2622
- // border geos.
2623
- if (!bEmbedded) {
2624
- break;
2651
+
2652
+ if (neighboringDistricts.size > 1)
2653
+ {
2654
+ bEmbedded = false;
2655
+ // No need to check any more neighbors
2656
+ break;
2625
2657
  }
2658
+ }
2626
2659
  }
2660
+ }
2661
+ // If a district is not embedded, there's no need to check anymore
2662
+ // border geos.
2663
+ if (!bEmbedded)
2664
+ {
2665
+ break;
2666
+ }
2627
2667
  }
2628
- return bEmbedded;
2668
+
2669
+ }
2670
+
2671
+ return bEmbedded;
2629
2672
  }
2630
- exports.isEmbedded = isEmbedded;
2673
+ */
2631
2674
 
2632
2675
 
2633
2676
  /***/ }),
@@ -2665,6 +2708,17 @@ module.exports = require("@dra2020/compactness");
2665
2708
 
2666
2709
  /***/ }),
2667
2710
 
2711
+ /***/ "@dra2020/dra-graph":
2712
+ /*!*************************************!*\
2713
+ !*** external "@dra2020/dra-graph" ***!
2714
+ \*************************************/
2715
+ /*! no static exports found */
2716
+ /***/ (function(module, exports) {
2717
+
2718
+ module.exports = require("@dra2020/dra-graph");
2719
+
2720
+ /***/ }),
2721
+
2668
2722
  /***/ "@dra2020/dra-score":
2669
2723
  /*!*************************************!*\
2670
2724
  !*** external "@dra2020/dra-score" ***!