@dra2020/district-analytics 15.4.6 → 15.6.1
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 +133 -102
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/package.json +2 -2
|
@@ -440,74 +440,76 @@ class Districts {
|
|
|
440
440
|
bNotEmpty = true;
|
|
441
441
|
// ... loop over the geoIDs creating district-by-district statistics
|
|
442
442
|
geoIDs.forEach(function (geoID) {
|
|
443
|
-
//
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
443
|
+
// 01-04-22 -- Removed water-only guard
|
|
444
|
+
// // Skip water-only features
|
|
445
|
+
// if (!(U.isWaterOnly(geoID)))
|
|
446
|
+
// {
|
|
447
|
+
// Map from geoID to feature index
|
|
448
|
+
let featureID = outerThis._session.features.featureID(geoID);
|
|
449
|
+
let f = outerThis._session.features.featureByIndex(featureID);
|
|
450
|
+
if (f == undefined) {
|
|
451
|
+
if (bLog)
|
|
452
|
+
console.log("Statistics: Skipping undefined feature in district statistics: GEOID =", geoID, "Feature ID =", featureID);
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
// ACCUMULATE VALUES
|
|
456
|
+
// Total population of each feature
|
|
457
|
+
// NOTE - This result is used more than once
|
|
458
|
+
// 03-27-21
|
|
459
|
+
const dkCENSUS = outerThis._session.features._keys["CENSUS" /* CENSUS */];
|
|
460
|
+
featurePop = fieldForFeature(f, dkCENSUS, 0 /* TotalPop */);
|
|
461
|
+
// featurePop = outerThis._session.features.fieldForFeature(f, T.Dataset.CENSUS, T.FeatureField.TotalPop);
|
|
462
|
+
// Total district population
|
|
463
|
+
totalPop += featurePop;
|
|
464
|
+
// Ignore features when the county is unrecognized
|
|
465
|
+
const countyFIPS = U.parseGeoID(geoID)['county'];
|
|
466
|
+
if (U.keyExists(countyFIPS, outerThis._session.counties.index)) {
|
|
467
|
+
// Total population by counties w/in a district,
|
|
468
|
+
// except the dummy unassigned district 0
|
|
469
|
+
if (i > 0)
|
|
470
|
+
countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
|
|
451
471
|
}
|
|
452
472
|
else {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
// NOTE - This result is used more than once
|
|
456
|
-
// 03-27-21
|
|
457
|
-
const dkCENSUS = outerThis._session.features._keys["CENSUS" /* CENSUS */];
|
|
458
|
-
featurePop = fieldForFeature(f, dkCENSUS, 0 /* TotalPop */);
|
|
459
|
-
// featurePop = outerThis._session.features.fieldForFeature(f, T.Dataset.CENSUS, T.FeatureField.TotalPop);
|
|
460
|
-
// Total district population
|
|
461
|
-
totalPop += featurePop;
|
|
462
|
-
// Ignore features when the county is unrecognized
|
|
463
|
-
const countyFIPS = U.parseGeoID(geoID)['county'];
|
|
464
|
-
if (U.keyExists(countyFIPS, outerThis._session.counties.index)) {
|
|
465
|
-
// Total population by counties w/in a district,
|
|
466
|
-
// except the dummy unassigned district 0
|
|
467
|
-
if (i > 0)
|
|
468
|
-
countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
if (bLog)
|
|
472
|
-
console.log("Statistics: County not recognized:", geoID);
|
|
473
|
-
}
|
|
474
|
-
// Democratic and Republican vote totals
|
|
475
|
-
// 10-22-2020 - Added Other votes
|
|
476
|
-
// 10-24-2020 - Added guard against inconsistent election data
|
|
477
|
-
// 03-27-2021
|
|
478
|
-
const dkELECTION = outerThis._session.features._keys["ELECTION" /* ELECTION */];
|
|
479
|
-
const featureDem = fieldForFeature(f, dkELECTION, 7 /* DemVotes */);
|
|
480
|
-
// const featureDem = outerThis._session.features.fieldForFeature(f, T.Dataset.ELECTION, T.FeatureField.DemVotes);
|
|
481
|
-
const featureRep = fieldForFeature(f, dkELECTION, 8 /* RepVotes */);
|
|
482
|
-
const featureTot = fieldForFeature(f, dkELECTION, 9 /* TotalVotes */);
|
|
483
|
-
demVotes += featureDem;
|
|
484
|
-
repVotes += featureRep;
|
|
485
|
-
totVotes += featureTot;
|
|
486
|
-
// NOTE: Unless you grab the values above before accumulating them,
|
|
487
|
-
// you can't accumulate othVotes for districts. You must calculate
|
|
488
|
-
// them by implication later.
|
|
489
|
-
if (bLog) {
|
|
490
|
-
const bBadElection = (featureDem + featureRep > featureTot) ? true : false;
|
|
491
|
-
if (bBadElection)
|
|
492
|
-
console.log("Statistics: Inconsistent election data for precinct:", geoID, featureDem, featureRep, featureTot);
|
|
493
|
-
}
|
|
494
|
-
// Voting-age demographic breakdowns (or citizen voting-age)
|
|
495
|
-
// 03-27-21
|
|
496
|
-
const dkVAP = outerThis._session.features._keys["VAP" /* VAP */];
|
|
497
|
-
totalVAP += fieldForFeature(f, dkVAP, 0 /* TotalPop */);
|
|
498
|
-
// totalVAP += outerThis._session.features.fieldForFeature(f, T.Dataset.VAP, T.FeatureField.TotalPop);
|
|
499
|
-
whitePop += fieldForFeature(f, dkVAP, 1 /* WhitePop */);
|
|
500
|
-
blackPop += fieldForFeature(f, dkVAP, 2 /* BlackPop */);
|
|
501
|
-
hispanicPop += fieldForFeature(f, dkVAP, 3 /* HispanicPop */);
|
|
502
|
-
pacificPop += fieldForFeature(f, dkVAP, 5 /* PacificPop */);
|
|
503
|
-
asianPop += fieldForFeature(f, dkVAP, 4 /* AsianPop */);
|
|
504
|
-
nativePop += fieldForFeature(f, dkVAP, 6 /* NativePop */);
|
|
473
|
+
if (bLog)
|
|
474
|
+
console.log("Statistics: County not recognized:", geoID);
|
|
505
475
|
}
|
|
476
|
+
// Democratic and Republican vote totals
|
|
477
|
+
// 10-22-2020 - Added Other votes
|
|
478
|
+
// 10-24-2020 - Added guard against inconsistent election data
|
|
479
|
+
// 03-27-2021
|
|
480
|
+
const dkELECTION = outerThis._session.features._keys["ELECTION" /* ELECTION */];
|
|
481
|
+
const featureDem = fieldForFeature(f, dkELECTION, 7 /* DemVotes */);
|
|
482
|
+
// const featureDem = outerThis._session.features.fieldForFeature(f, T.Dataset.ELECTION, T.FeatureField.DemVotes);
|
|
483
|
+
const featureRep = fieldForFeature(f, dkELECTION, 8 /* RepVotes */);
|
|
484
|
+
const featureTot = fieldForFeature(f, dkELECTION, 9 /* TotalVotes */);
|
|
485
|
+
demVotes += featureDem;
|
|
486
|
+
repVotes += featureRep;
|
|
487
|
+
totVotes += featureTot;
|
|
488
|
+
// NOTE: Unless you grab the values above before accumulating them,
|
|
489
|
+
// you can't accumulate othVotes for districts. You must calculate
|
|
490
|
+
// them by implication later.
|
|
491
|
+
if (bLog) {
|
|
492
|
+
const bBadElection = (featureDem + featureRep > featureTot) ? true : false;
|
|
493
|
+
if (bBadElection)
|
|
494
|
+
console.log("Statistics: Inconsistent election data for precinct:", geoID, featureDem, featureRep, featureTot);
|
|
495
|
+
}
|
|
496
|
+
// Voting-age demographic breakdowns (or citizen voting-age)
|
|
497
|
+
// 03-27-21
|
|
498
|
+
const dkVAP = outerThis._session.features._keys["VAP" /* VAP */];
|
|
499
|
+
totalVAP += fieldForFeature(f, dkVAP, 0 /* TotalPop */);
|
|
500
|
+
// totalVAP += outerThis._session.features.fieldForFeature(f, T.Dataset.VAP, T.FeatureField.TotalPop);
|
|
501
|
+
whitePop += fieldForFeature(f, dkVAP, 1 /* WhitePop */);
|
|
502
|
+
blackPop += fieldForFeature(f, dkVAP, 2 /* BlackPop */);
|
|
503
|
+
hispanicPop += fieldForFeature(f, dkVAP, 3 /* HispanicPop */);
|
|
504
|
+
pacificPop += fieldForFeature(f, dkVAP, 5 /* PacificPop */);
|
|
505
|
+
asianPop += fieldForFeature(f, dkVAP, 4 /* AsianPop */);
|
|
506
|
+
nativePop += fieldForFeature(f, dkVAP, 6 /* NativePop */);
|
|
506
507
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
508
|
+
// }
|
|
509
|
+
// else
|
|
510
|
+
// {
|
|
511
|
+
// if (bLog) console.log("Statistics: Skipping water-only feature in district statistics:", geoID);
|
|
512
|
+
// }
|
|
511
513
|
});
|
|
512
514
|
// COMPUTE DERIVED VALUES
|
|
513
515
|
// Population deviation % and equal population (boolean) by district.
|
|
@@ -998,47 +1000,75 @@ exports.fieldForFeature = fieldForFeature;
|
|
|
998
1000
|
// f is a direct GeoJSON feature
|
|
999
1001
|
// p is a geoID
|
|
1000
1002
|
function _getFeatures(f, datasetKey, p) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1003
|
+
if (!f.properties || !f.properties.datasets)
|
|
1004
|
+
return 0;
|
|
1005
|
+
if (datasetKey && !f.properties.datasets[datasetKey])
|
|
1006
|
+
return 0;
|
|
1007
|
+
let n = datasetKey ? f.properties.datasets[datasetKey][p] : f.properties[p];
|
|
1008
|
+
return !n || isNaN(n) ? 0 : n;
|
|
1009
|
+
}
|
|
1010
|
+
/* 01-04-22 -- Replaced with the above
|
|
1011
|
+
function _getFeatures(f: any, datasetKey: string, p: string): any
|
|
1012
|
+
{
|
|
1013
|
+
// Shim to load sample data2.json from disk for command-line scaffolding
|
|
1014
|
+
if (f.properties && f.properties['datasets'])
|
|
1015
|
+
{
|
|
1016
|
+
if (!f.properties['datasets'][datasetKey])
|
|
1017
|
+
{
|
|
1018
|
+
// Feature is missing the dataset
|
|
1019
|
+
nMissingDataset += 1;
|
|
1020
|
+
// console.log(`${nMissingDataset}: Data ${datasetKey} missing for feature ${f} Returning zero.`);
|
|
1021
|
+
|
|
1022
|
+
return 0;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
return f.properties['datasets'][datasetKey][p];
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
// NOTE - The fGetW() code from dra-client below here ...
|
|
1029
|
+
|
|
1030
|
+
// Direct property?
|
|
1031
|
+
if (f.properties && f.properties[p] !== undefined)
|
|
1032
|
+
{
|
|
1033
|
+
return f.properties[p];
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// Joined property?
|
|
1037
|
+
let a: any[] = _fGetJoined(f);
|
|
1038
|
+
if (a)
|
|
1039
|
+
{
|
|
1040
|
+
for (let i: number = 0; i < a.length; i++)
|
|
1041
|
+
{
|
|
1042
|
+
let o: any = a[i];
|
|
1043
|
+
if (!datasetKey)
|
|
1044
|
+
{
|
|
1045
|
+
if (o[p] !== undefined)
|
|
1046
|
+
{
|
|
1047
|
+
return o[p];
|
|
1008
1048
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
for (let i = 0; i < a.length; i++) {
|
|
1020
|
-
let o = a[i];
|
|
1021
|
-
if (!datasetKey) {
|
|
1022
|
-
if (o[p] !== undefined) {
|
|
1023
|
-
return o[p];
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
else {
|
|
1027
|
-
if (o['datasets'] && o['datasets'][datasetKey]) {
|
|
1028
|
-
let v = (o['datasets'][datasetKey][p]);
|
|
1029
|
-
if ((!(v == null)) && (!(v == undefined))) {
|
|
1030
|
-
return o['datasets'][datasetKey][p];
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1049
|
+
}
|
|
1050
|
+
else
|
|
1051
|
+
{
|
|
1052
|
+
if (o['datasets'] && o['datasets'][datasetKey])
|
|
1053
|
+
{
|
|
1054
|
+
let v = (o['datasets'][datasetKey][p]);
|
|
1055
|
+
if ((!(v == null)) && (!(v == undefined)))
|
|
1056
|
+
{
|
|
1057
|
+
return o['datasets'][datasetKey][p];
|
|
1058
|
+
}
|
|
1034
1059
|
}
|
|
1060
|
+
}
|
|
1035
1061
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// Feature is missing the property
|
|
1065
|
+
nMissingProperty += 1;
|
|
1066
|
+
// console.log(`${nMissingProperty}: ${p} value undefined for ${f.properties['GEOID10']}. Returning zero.`);
|
|
1067
|
+
|
|
1068
|
+
return 0;
|
|
1069
|
+
// return undefined;
|
|
1041
1070
|
}
|
|
1071
|
+
*/
|
|
1042
1072
|
function _fGetJoined(f) {
|
|
1043
1073
|
return (f.properties && f.properties.joined) ? f.properties.joined : undefined;
|
|
1044
1074
|
}
|
|
@@ -1598,7 +1628,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
1598
1628
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
1599
1629
|
};
|
|
1600
1630
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
1601
|
-
exports.uncertaintyOfMembership = exports.effectiveSplits = exports.avgSVError = exports.isAntimajoritarian = exports.ratePartisanBias = exports.estSeatProbability = exports.inferSelectedMinority = exports.fieldForFeature = exports.geoIDForFeature = void 0;
|
|
1631
|
+
exports.uncertaintyOfMembership = exports.effectiveSplits = exports.avgSVError = exports.isAntimajoritarian = exports.normalizePartisanBias = exports.ratePartisanBias = exports.estSeatProbability = exports.inferSelectedMinority = exports.fieldForFeature = exports.geoIDForFeature = void 0;
|
|
1602
1632
|
__exportStar(__webpack_require__(/*! ./_api */ "./src/_api.ts"), exports);
|
|
1603
1633
|
var _data_1 = __webpack_require__(/*! ./_data */ "./src/_data.ts");
|
|
1604
1634
|
Object.defineProperty(exports, "geoIDForFeature", ({ enumerable: true, get: function () { return _data_1.geoIDForFeature; } }));
|
|
@@ -1611,6 +1641,7 @@ __exportStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"), exports);
|
|
|
1611
1641
|
const dra_analytics_1 = __webpack_require__(/*! @dra2020/dra-analytics */ "@dra2020/dra-analytics");
|
|
1612
1642
|
exports.estSeatProbability = dra_analytics_1.Partisan.estSeatProbability;
|
|
1613
1643
|
exports.ratePartisanBias = dra_analytics_1.Rate.ratePartisanBias;
|
|
1644
|
+
exports.normalizePartisanBias = dra_analytics_1.Rate.normalizePartisanBias;
|
|
1614
1645
|
exports.isAntimajoritarian = dra_analytics_1.Rate.isAntimajoritarian;
|
|
1615
1646
|
exports.avgSVError = dra_analytics_1.Partisan.avgSVError;
|
|
1616
1647
|
exports.effectiveSplits = dra_analytics_1.Splitting.effectiveSplits;
|