@dra2020/district-analytics 9.0.1 → 9.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/district-analytics.js +144 -90
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/valid.d.ts +0 -3
- package/package.json +4 -3
- package/dist/cli.js +0 -611
- package/dist/cli.js.map +0 -1
- package/dist/src/geofeature.d.ts +0 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
582
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
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
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
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
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
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
|
-
|
|
2668
|
+
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
return bEmbedded;
|
|
2629
2672
|
}
|
|
2630
|
-
|
|
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" ***!
|