@dra2020/district-analytics 4.3.0 → 4.3.3
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 +734 -581
- package/dist/cli.js.map +1 -1
- package/dist/district-analytics.js +649 -519
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/_api.d.ts +0 -2
- package/dist/src/cohesive.d.ts +0 -2
- package/dist/src/compact.d.ts +0 -3
- package/dist/src/equal.d.ts +0 -1
- package/dist/src/minority.d.ts +0 -3
- package/dist/src/political.d.ts +0 -7
- package/dist/src/results.d.ts +0 -1
- package/dist/src/types.d.ts +2 -15
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -90063,6 +90063,7 @@ function scorePopulationDeviation(rawValue, bLegislative) {
|
|
|
90063
90063
|
const _normalizer = new normalize_1.Normalizer(rawValue);
|
|
90064
90064
|
// Raw range in not inverted (i.e., smaller is better)
|
|
90065
90065
|
const range = C.popdevRange(bLegislative);
|
|
90066
|
+
_normalizer.clip(0.0, 1.0); // Handle deviations bigger than a whole district
|
|
90066
90067
|
_normalizer.invert();
|
|
90067
90068
|
_normalizer.clip(1.0 - range[C.BEG], 1.0 - range[C.END]);
|
|
90068
90069
|
_normalizer.unitize(1.0 - range[C.BEG], 1.0 - range[C.END]);
|
|
@@ -90223,6 +90224,11 @@ function calcProportionalDistricts(proportion, nDistricts) {
|
|
|
90223
90224
|
return integral;
|
|
90224
90225
|
}
|
|
90225
90226
|
exports.calcProportionalDistricts = calcProportionalDistricts;
|
|
90227
|
+
// TODO - 2020: Revise the second, when the update comes out (in September?).
|
|
90228
|
+
/* Sources for majority-minority info:
|
|
90229
|
+
- https://en.wikipedia.org/wiki/List_of_majority-minority_United_States_congressional_districts
|
|
90230
|
+
- http://www.ncsl.org/Portals/1/Documents/Redistricting/Redistricting_2010.pdf
|
|
90231
|
+
*/
|
|
90226
90232
|
|
|
90227
90233
|
|
|
90228
90234
|
/***/ }),
|
|
@@ -90434,7 +90440,8 @@ function scorePartisan(Vf, VfArray, options) {
|
|
|
90434
90440
|
const rD = (!bConstrained || bAlternateMetrics) ? estResponsiveDistricts(VfArray) : undefined;
|
|
90435
90441
|
const rDf = bAlternateMetrics ? estResponsiveDistrictsShare(rD, N) : undefined;
|
|
90436
90442
|
const Cn = countCompetitiveDistricts(VfArray);
|
|
90437
|
-
const cD =
|
|
90443
|
+
const cD = estCompetitiveDistricts(VfArray); // NOTE - Cd by definition uses a more narrow probability distribution vs. Rd
|
|
90444
|
+
// const cD = bConstrained ? estCompetitiveDistricts(VfArray) : rD as number;
|
|
90438
90445
|
const cDf = estCompetitiveDistrictsShare(cD, N);
|
|
90439
90446
|
const Mrange = findMarginalDistricts(Vf, VfArray, N);
|
|
90440
90447
|
const Md = estMarginalCompetitiveDistricts(Mrange, VfArray);
|
|
@@ -91204,13 +91211,13 @@ function printPartisanScorecardRow(xx, name, N, Vf, s) {
|
|
|
91204
91211
|
exports.printPartisanScorecardRow = printPartisanScorecardRow;
|
|
91205
91212
|
// Generate partisan details (Table 1)
|
|
91206
91213
|
function printPartisanDetailsHeader() {
|
|
91207
|
-
console.log('XX, <V>, S(<V>), S50V, V50S, Decl, B_G, EG, Beta, l-gamma, mM, TO, mM\', LO, R, r, Zeta');
|
|
91214
|
+
console.log('XX, <V>, S(<V>), S50V, V50S, Decl, B_G, EG, Beta, l-gamma, mM, TO, mM\', LO, Rd, R, r, Zeta');
|
|
91208
91215
|
}
|
|
91209
91216
|
exports.printPartisanDetailsHeader = printPartisanDetailsHeader;
|
|
91210
91217
|
function printPartisanDetailsRow(xx, name, N, Vf, s) {
|
|
91211
|
-
console.log('%s, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f', xx, Vf, s.bias.estSf, s.bias.bS50, s.bias.bV50, s.bias.decl, s.bias.gSym, s.bias.eG, s.bias.bSV, // Beta
|
|
91218
|
+
console.log('%s, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f, %f', xx, Vf, s.bias.estSf, s.bias.bS50, s.bias.bV50, s.bias.decl, s.bias.gSym, s.bias.eG, s.bias.bSV, // Beta
|
|
91212
91219
|
s.bias.prop, // Lower-gamma
|
|
91213
|
-
s.bias.mMs, s.bias.tOf, s.bias.mMd, s.bias.lO, s.competitiveness.bigR, s.competitiveness.littleR, s.competitiveness.mIR // Zeta
|
|
91220
|
+
s.bias.mMs, s.bias.tOf, s.bias.mMd, s.bias.lO, s.competitiveness.rD, s.competitiveness.bigR, s.competitiveness.littleR, s.competitiveness.mIR // Zeta
|
|
91214
91221
|
);
|
|
91215
91222
|
}
|
|
91216
91223
|
exports.printPartisanDetailsRow = printPartisanDetailsRow;
|
|
@@ -91283,7 +91290,7 @@ function scorePlan(p, overridesJSON) {
|
|
|
91283
91290
|
// PARTISAN ("fair") subcategories - bias, impact, & competitiveness (plus lots of supporting measures)
|
|
91284
91291
|
const options = {
|
|
91285
91292
|
alternates: true,
|
|
91286
|
-
constrained:
|
|
91293
|
+
constrained: false,
|
|
91287
91294
|
shift: 0 /* Proportional */
|
|
91288
91295
|
};
|
|
91289
91296
|
const pS = partisan_1.scorePartisan(p.partisanProfile.statewideVf, p.partisanProfile.vfArray, options);
|
|
@@ -101325,6 +101332,7 @@ const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.t
|
|
|
101325
101332
|
const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
|
|
101326
101333
|
const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
|
|
101327
101334
|
const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
101335
|
+
// import { doConfigureScales, doAnalyzePostProcessing, RequirementsChecklist} from './results' // TODO - DELETE
|
|
101328
101336
|
const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
101329
101337
|
const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
|
|
101330
101338
|
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
@@ -101335,7 +101343,7 @@ class AnalyticsSession {
|
|
|
101335
101343
|
this.bOneTimeProcessingDone = false;
|
|
101336
101344
|
this.bPlanAnalyzed = false;
|
|
101337
101345
|
this.bPostProcessingDone = false;
|
|
101338
|
-
|
|
101346
|
+
// testScales = {} as T.TestScales; TODO - DELETE
|
|
101339
101347
|
this.tests = {};
|
|
101340
101348
|
this.title = SessionRequest['title'];
|
|
101341
101349
|
this.legislativeDistricts = SessionRequest['legislativeDistricts'];
|
|
@@ -101346,19 +101354,21 @@ class AnalyticsSession {
|
|
|
101346
101354
|
this.features = new D.Features(this, SessionRequest['data'], this.config['datasets']);
|
|
101347
101355
|
this.plan = new D.Plan(this, SessionRequest['plan']);
|
|
101348
101356
|
this.districts = new D.Districts(this, SessionRequest['districtShapes']);
|
|
101349
|
-
// TODO -
|
|
101350
|
-
if (this.useLegacy())
|
|
101351
|
-
|
|
101352
|
-
|
|
101353
|
-
|
|
101354
|
-
|
|
101355
|
-
|
|
101356
|
-
|
|
101357
|
-
|
|
101358
|
-
|
|
101359
|
-
|
|
101360
|
-
|
|
101361
|
-
|
|
101357
|
+
// TODO - DELETE
|
|
101358
|
+
// if (this.useLegacy())
|
|
101359
|
+
// {
|
|
101360
|
+
// console.log("Using legacy district-analytics.")
|
|
101361
|
+
// // NOTE: I've pulled these out of the individual analytics to here. Eventually,
|
|
101362
|
+
// // we could want them to passed into an analytics session as data, along with
|
|
101363
|
+
// // everything else. For now, this keeps branching out of the main code.
|
|
101364
|
+
// doConfigureScales(this);
|
|
101365
|
+
// }
|
|
101366
|
+
// else
|
|
101367
|
+
// {
|
|
101368
|
+
// console.log("Using dra-score analytics.")
|
|
101369
|
+
// // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
|
|
101370
|
+
// doConfigureScales(this);
|
|
101371
|
+
// }
|
|
101362
101372
|
}
|
|
101363
101373
|
processConfig(config) {
|
|
101364
101374
|
// NOTE - Session settings are required:
|
|
@@ -101371,13 +101381,15 @@ class AnalyticsSession {
|
|
|
101371
101381
|
config['cycle'] = 2010;
|
|
101372
101382
|
return config;
|
|
101373
101383
|
}
|
|
101374
|
-
|
|
101375
|
-
useLegacy()
|
|
101376
|
-
|
|
101377
|
-
|
|
101378
|
-
|
|
101379
|
-
|
|
101384
|
+
/* TODO - DELETE
|
|
101385
|
+
useLegacy(): boolean
|
|
101386
|
+
{
|
|
101387
|
+
// TODO - SCORE: Opt-out
|
|
101388
|
+
return (U.keyExists('useScore', this.config) && (this.config['useScore'] != null) && (!(this.config['useScore']))) ? true : false;
|
|
101389
|
+
// TODO - SCORE: Opt-in
|
|
101390
|
+
// return (U.keyExists('useScore', this.config) && (this.config['useScore'])) ? false : true;
|
|
101380
101391
|
}
|
|
101392
|
+
*/
|
|
101381
101393
|
// Using the the data in the analytics session, calculate all the
|
|
101382
101394
|
// analytics & validations, saving/updating the individual test results.
|
|
101383
101395
|
analyzePlan(bLog = false, overridesJSON) {
|
|
@@ -101509,19 +101521,21 @@ class AnalyticsSession {
|
|
|
101509
101521
|
}
|
|
101510
101522
|
// NOTE - Not sure why this has to be up here ...
|
|
101511
101523
|
populationDeviationThreshold() {
|
|
101512
|
-
// TODO -
|
|
101513
|
-
if (this.useLegacy())
|
|
101514
|
-
|
|
101515
|
-
|
|
101516
|
-
|
|
101517
|
-
|
|
101518
|
-
|
|
101519
|
-
|
|
101520
|
-
|
|
101521
|
-
|
|
101522
|
-
|
|
101523
|
-
|
|
101524
|
-
|
|
101524
|
+
// TODO - DELETE
|
|
101525
|
+
// if (this.useLegacy())
|
|
101526
|
+
// {
|
|
101527
|
+
// return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
|
|
101528
|
+
// }
|
|
101529
|
+
// else
|
|
101530
|
+
// {
|
|
101531
|
+
// NOTE - This assumes the plan has been profiled
|
|
101532
|
+
const scorer = new Score.Scorer();
|
|
101533
|
+
const popdev = scorer.populationDeviationThreshold(this.legislativeDistricts);
|
|
101534
|
+
return popdev;
|
|
101535
|
+
// TODO - SCORE: Temporary HACK. Query dra-score for threshold.
|
|
101536
|
+
// NOTE - The plan may not have been scored yet, i.e., no scorecard yet.
|
|
101537
|
+
// return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
|
|
101538
|
+
// }
|
|
101525
101539
|
}
|
|
101526
101540
|
}
|
|
101527
101541
|
exports.AnalyticsSession = AnalyticsSession;
|
|
@@ -102130,10 +102144,22 @@ exports.Graph = Graph;
|
|
|
102130
102144
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
102131
102145
|
const valid_1 = __webpack_require__(/*! ./valid */ "./src/valid.ts");
|
|
102132
102146
|
const equal_1 = __webpack_require__(/*! ./equal */ "./src/equal.ts");
|
|
102133
|
-
|
|
102147
|
+
// import { doPopulationDeviation, doHasEqualPopulations } from './equal'; TODO - DELETE
|
|
102148
|
+
// import { doReock, doPolsbyPopper } from './compact'; TODO - DELETE
|
|
102134
102149
|
const cohesive_1 = __webpack_require__(/*! ./cohesive */ "./src/cohesive.ts");
|
|
102135
|
-
|
|
102136
|
-
|
|
102150
|
+
/* TODO - DELETE
|
|
102151
|
+
import
|
|
102152
|
+
{
|
|
102153
|
+
doFindCountiesSplitUnexpectedly, doFindSplitVTDs,
|
|
102154
|
+
doCountySplitting, doDistrictSplitting
|
|
102155
|
+
} from './cohesive';
|
|
102156
|
+
import
|
|
102157
|
+
{
|
|
102158
|
+
doSeatsBias, doVotesBias,
|
|
102159
|
+
doResponsiveness, doResponsiveDistricts, doEfficiencyGap
|
|
102160
|
+
} from './political';
|
|
102161
|
+
import { doMajorityMinorityDistricts } from './minority'
|
|
102162
|
+
*/
|
|
102137
102163
|
// Compile district-level info for plan/map-level analytics
|
|
102138
102164
|
function doAnalyzeDistricts(s, bLog = false) {
|
|
102139
102165
|
s.districts.recalcStatistics(bLog);
|
|
@@ -102145,58 +102171,65 @@ exports.doAnalyzeDistricts = doAnalyzeDistricts;
|
|
|
102145
102171
|
// NOTE - I could make this table-driven, but I'm thinking that the explicit
|
|
102146
102172
|
// calls might make chunking for aync easier.
|
|
102147
102173
|
function doAnalyzePlan(s, bLog = false) {
|
|
102148
|
-
// TODO -
|
|
102149
|
-
if (s.useLegacy())
|
|
102150
|
-
|
|
102151
|
-
|
|
102152
|
-
|
|
102153
|
-
|
|
102154
|
-
|
|
102155
|
-
|
|
102156
|
-
|
|
102157
|
-
|
|
102158
|
-
|
|
102159
|
-
|
|
102160
|
-
|
|
102161
|
-
|
|
102162
|
-
|
|
102163
|
-
|
|
102164
|
-
|
|
102165
|
-
|
|
102166
|
-
|
|
102167
|
-
|
|
102168
|
-
|
|
102169
|
-
|
|
102170
|
-
|
|
102171
|
-
|
|
102172
|
-
|
|
102173
|
-
|
|
102174
|
-
|
|
102175
|
-
|
|
102176
|
-
|
|
102177
|
-
|
|
102178
|
-
|
|
102179
|
-
|
|
102180
|
-
|
|
102181
|
-
|
|
102182
|
-
|
|
102183
|
-
|
|
102184
|
-
|
|
102185
|
-
|
|
102186
|
-
|
|
102187
|
-
|
|
102188
|
-
|
|
102189
|
-
|
|
102190
|
-
|
|
102191
|
-
|
|
102192
|
-
|
|
102193
|
-
|
|
102194
|
-
|
|
102195
|
-
|
|
102196
|
-
|
|
102197
|
-
|
|
102198
|
-
|
|
102199
|
-
|
|
102174
|
+
// TODO - DELETE
|
|
102175
|
+
// if (s.useLegacy())
|
|
102176
|
+
// {
|
|
102177
|
+
// // Disable most legacy analytics
|
|
102178
|
+
// // Get the requested suites, and only execute those tests
|
|
102179
|
+
// let requestedSuites = s.config['suites'];
|
|
102180
|
+
// // Tests in the "Legal" suite, i.e., pass/ fail constraints
|
|
102181
|
+
// if (requestedSuites.includes(T.Suite.Legal))
|
|
102182
|
+
// {
|
|
102183
|
+
// s.tests[T.Test.Complete] = doIsComplete(s, bLog);
|
|
102184
|
+
// s.tests[T.Test.Contiguous] = doIsContiguous(s, bLog);
|
|
102185
|
+
// s.tests[T.Test.FreeOfHoles] = doIsFreeOfHoles(s, bLog);
|
|
102186
|
+
// // s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
|
|
102187
|
+
// // NOTE - I can't check whether a population deviation is legal or not, until
|
|
102188
|
+
// // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
|
|
102189
|
+
// // the given type of district (CD vs. LD). The EqualPopulation test is derived
|
|
102190
|
+
// // from PopulationDeviation, as part of scorecard or test log preparation.
|
|
102191
|
+
// // Create an empty test entry here though ...
|
|
102192
|
+
// s.tests[T.Test.EqualPopulation] = s.getTest(T.Test.EqualPopulation) as T.TestEntry;
|
|
102193
|
+
// }
|
|
102194
|
+
// // Tests in the "Fair" suite
|
|
102195
|
+
// if (requestedSuites.includes(T.Suite.Fair))
|
|
102196
|
+
// {
|
|
102197
|
+
// /* TODO - DELETE
|
|
102198
|
+
// s.tests[T.Test.SeatsBias] = doSeatsBias(s, bLog);
|
|
102199
|
+
// s.tests[T.Test.VotesBias] = doVotesBias(s, bLog);
|
|
102200
|
+
// s.tests[T.Test.Responsiveness] = doResponsiveness(s, bLog);
|
|
102201
|
+
// s.tests[T.Test.ResponsiveDistricts] = doResponsiveDistricts(s, bLog);
|
|
102202
|
+
// s.tests[T.Test.EfficiencyGap] = doEfficiencyGap(s, bLog);
|
|
102203
|
+
// s.tests[T.Test.MajorityMinorityDistricts] = doMajorityMinorityDistricts(s, bLog);
|
|
102204
|
+
// */
|
|
102205
|
+
// }
|
|
102206
|
+
// // Tests in the "Best" suite, i.e., criteria for better/worse
|
|
102207
|
+
// if (requestedSuites.includes(T.Suite.Best))
|
|
102208
|
+
// {
|
|
102209
|
+
// // s.tests[T.Test.Reock] = doReock(s, bLog); TODO - DELETE
|
|
102210
|
+
// // s.tests[T.Test.PolsbyPopper] = doPolsbyPopper(s, bLog); TODO - DELETE
|
|
102211
|
+
// s.tests[T.Test.UnexpectedCountySplits] = doFindCountiesSplitUnexpectedly(s, bLog);
|
|
102212
|
+
// s.tests[T.Test.VTDSplits] = doFindSplitVTDs(s, bLog);
|
|
102213
|
+
// // s.tests[T.Test.CountySplitting] = doCountySplitting(s, bLog); TODO - DELETE
|
|
102214
|
+
// // s.tests[T.Test.DistrictSplitting] = doDistrictSplitting(s, bLog); TODO - DELETE
|
|
102215
|
+
// }
|
|
102216
|
+
// }
|
|
102217
|
+
// else
|
|
102218
|
+
// {
|
|
102219
|
+
// TODO - SCORE: Except these. Continue to do these here vs. dra-score.
|
|
102220
|
+
s.tests[0 /* Complete */] = valid_1.doIsComplete(s, bLog);
|
|
102221
|
+
s.tests[1 /* Contiguous */] = valid_1.doIsContiguous(s, bLog);
|
|
102222
|
+
s.tests[2 /* FreeOfHoles */] = valid_1.doIsFreeOfHoles(s, bLog);
|
|
102223
|
+
// s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
|
|
102224
|
+
// NOTE - I can't check whether a population deviation is legal or not, until
|
|
102225
|
+
// the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
|
|
102226
|
+
// the given type of district (CD vs. LD). The EqualPopulation test is derived
|
|
102227
|
+
// from PopulationDeviation, as part of scorecard or test log preparation.
|
|
102228
|
+
// Create an empty test entry here though ...
|
|
102229
|
+
s.tests[3 /* EqualPopulation */] = s.getTest(3 /* EqualPopulation */);
|
|
102230
|
+
s.tests[5 /* UnexpectedCountySplits */] = cohesive_1.doFindCountiesSplitUnexpectedly(s, bLog);
|
|
102231
|
+
s.tests[6 /* VTDSplits */] = cohesive_1.doFindSplitVTDs(s, bLog);
|
|
102232
|
+
// }
|
|
102200
102233
|
// Enable a Test Log and Scorecard to be generated
|
|
102201
102234
|
s.bPlanAnalyzed = true;
|
|
102202
102235
|
s.bPostProcessingDone = false;
|
|
@@ -102237,185 +102270,279 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
102237
102270
|
};
|
|
102238
102271
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
102239
102272
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
102240
|
-
const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
|
|
102241
102273
|
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
102274
|
+
// NOTE - The active code is below the long multi-line section to be deleted.
|
|
102275
|
+
/* TODO - DELETE
|
|
102242
102276
|
// CALCULATE ENHANCED SQRT ENTROPY METRIC
|
|
102243
|
-
|
|
102244
|
-
|
|
102245
|
-
|
|
102246
|
-
|
|
102247
|
-
|
|
102248
|
-
|
|
102249
|
-
|
|
102250
|
-
|
|
102251
|
-
|
|
102252
|
-
|
|
102253
|
-
|
|
102254
|
-
|
|
102255
|
-
|
|
102256
|
-
|
|
102257
|
-
|
|
102258
|
-
|
|
102277
|
+
|
|
102278
|
+
export function doCountySplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
102279
|
+
{
|
|
102280
|
+
let test = s.getTest(T.Test.CountySplitting) as T.TestEntry;
|
|
102281
|
+
|
|
102282
|
+
let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
|
|
102283
|
+
let countyTotals = s.counties.totalPopulation;
|
|
102284
|
+
let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
|
|
102285
|
+
|
|
102286
|
+
let f = calcCountyFractions(CxD, countyTotals);
|
|
102287
|
+
let w = calcCountyWeights(countyTotals);
|
|
102288
|
+
|
|
102289
|
+
let SqEnt_DC = countySplitting(f, w, bLog);
|
|
102290
|
+
|
|
102291
|
+
let CxDreducedC = U.deepCopy(CxD);
|
|
102292
|
+
reduceCSplits(CxDreducedC, districtTotals);
|
|
102293
|
+
|
|
102294
|
+
let fReduced = calcCountyFractions(CxDreducedC, countyTotals);
|
|
102295
|
+
let wReduced = calcCountyWeights(countyTotals);
|
|
102296
|
+
|
|
102297
|
+
let SqEnt_DCreduced = countySplitting(fReduced, wReduced, bLog);
|
|
102298
|
+
|
|
102299
|
+
test['score'] = SqEnt_DCreduced;
|
|
102300
|
+
test['details']['SqEnt_DC'] = SqEnt_DC;
|
|
102301
|
+
|
|
102302
|
+
return test;
|
|
102259
102303
|
}
|
|
102260
|
-
|
|
102261
|
-
function doDistrictSplitting(s, bLog = false)
|
|
102262
|
-
|
|
102263
|
-
|
|
102264
|
-
|
|
102265
|
-
|
|
102266
|
-
|
|
102267
|
-
|
|
102268
|
-
|
|
102269
|
-
|
|
102270
|
-
|
|
102271
|
-
|
|
102272
|
-
|
|
102273
|
-
|
|
102274
|
-
|
|
102275
|
-
|
|
102276
|
-
|
|
102304
|
+
|
|
102305
|
+
export function doDistrictSplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
102306
|
+
{
|
|
102307
|
+
let test = s.getTest(T.Test.DistrictSplitting) as T.TestEntry;
|
|
102308
|
+
|
|
102309
|
+
let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
|
|
102310
|
+
let countyTotals = s.counties.totalPopulation;
|
|
102311
|
+
let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
|
|
102312
|
+
|
|
102313
|
+
let g = calcDistrictFractions(CxD, districtTotals);
|
|
102314
|
+
let x = calcDistrictWeights(districtTotals);
|
|
102315
|
+
|
|
102316
|
+
let SqEnt_CD = districtSplitting(g, x, bLog);
|
|
102317
|
+
|
|
102318
|
+
let CxDreducedD = U.deepCopy(CxD);
|
|
102319
|
+
reduceDSplits(CxDreducedD, countyTotals);
|
|
102320
|
+
|
|
102321
|
+
let gReduced = calcDistrictFractions(CxDreducedD, districtTotals);
|
|
102322
|
+
let xReduced = calcDistrictWeights(districtTotals);
|
|
102323
|
+
|
|
102324
|
+
let SqEnt_CDreduced = districtSplitting(gReduced, xReduced, bLog);
|
|
102325
|
+
|
|
102326
|
+
test['score'] = SqEnt_CDreduced;
|
|
102327
|
+
test['details']['SqEnt_CD'] = SqEnt_CD;
|
|
102328
|
+
|
|
102329
|
+
return test;
|
|
102277
102330
|
}
|
|
102278
|
-
|
|
102331
|
+
|
|
102332
|
+
|
|
102279
102333
|
// HELPERS
|
|
102280
|
-
|
|
102334
|
+
|
|
102335
|
+
// Loop over all the county-district combos, skipping the virtual district 0
|
|
102281
102336
|
// and virtual county 0.
|
|
102282
102337
|
//
|
|
102283
102338
|
// NOTE - The county-district splits and the county & district totals may all,
|
|
102284
102339
|
// in general, be fractional/decimal numbers as opposed to integers, due to
|
|
102285
102340
|
// dissaggregation & re-aggregation. Hence, comparisons need to approximate
|
|
102286
102341
|
// equality.
|
|
102342
|
+
|
|
102287
102343
|
// Consolidate districts (rows) consisting of just one county (column)
|
|
102288
102344
|
// UP into the dummy district (0).
|
|
102289
|
-
function reduceCSplits(CxDreducedC, districtTotals)
|
|
102290
|
-
|
|
102291
|
-
|
|
102292
|
-
|
|
102293
|
-
|
|
102294
|
-
|
|
102295
|
-
|
|
102296
|
-
|
|
102297
|
-
|
|
102298
|
-
|
|
102299
|
-
|
|
102300
|
-
|
|
102345
|
+
function reduceCSplits(CxDreducedC: number[][], districtTotals: number[]): void
|
|
102346
|
+
{
|
|
102347
|
+
let nD = CxDreducedC.length;
|
|
102348
|
+
let nC = CxDreducedC[0].length;
|
|
102349
|
+
|
|
102350
|
+
for (let j = 1; j < nC; j++)
|
|
102351
|
+
{
|
|
102352
|
+
for (let i = 1; i < nD; i++)
|
|
102353
|
+
{
|
|
102354
|
+
let split_total = CxDreducedC[i][j];
|
|
102355
|
+
|
|
102356
|
+
if (split_total > 0)
|
|
102357
|
+
{
|
|
102358
|
+
if (areRoughlyEqual(split_total, districtTotals[i]))
|
|
102359
|
+
{
|
|
102360
|
+
CxDreducedC[0][j] += split_total;
|
|
102361
|
+
CxDreducedC[i][j] = 0;
|
|
102301
102362
|
}
|
|
102363
|
+
}
|
|
102302
102364
|
}
|
|
102365
|
+
}
|
|
102303
102366
|
}
|
|
102367
|
+
|
|
102304
102368
|
// Consolidate whole counties (columns) in a district (row) LEFT into the
|
|
102305
102369
|
// dummy county (0).
|
|
102306
|
-
function reduceDSplits(CxDreducedD, countyTotals)
|
|
102307
|
-
|
|
102308
|
-
|
|
102309
|
-
|
|
102310
|
-
|
|
102311
|
-
|
|
102312
|
-
|
|
102313
|
-
|
|
102314
|
-
|
|
102315
|
-
|
|
102316
|
-
|
|
102317
|
-
|
|
102370
|
+
function reduceDSplits(CxDreducedD: number[][], countyTotals: number[]): void
|
|
102371
|
+
{
|
|
102372
|
+
let nD = CxDreducedD.length;
|
|
102373
|
+
let nC = CxDreducedD[0].length;
|
|
102374
|
+
|
|
102375
|
+
for (let i = 1; i < nD; i++)
|
|
102376
|
+
{
|
|
102377
|
+
for (let j = 1; j < nC; j++)
|
|
102378
|
+
{
|
|
102379
|
+
let split_total = CxDreducedD[i][j];
|
|
102380
|
+
|
|
102381
|
+
if (split_total > 0)
|
|
102382
|
+
{
|
|
102383
|
+
if (areRoughlyEqual(split_total, countyTotals[j]))
|
|
102384
|
+
{
|
|
102385
|
+
CxDreducedD[i][0] += split_total;
|
|
102386
|
+
CxDreducedD[i][j] = 0;
|
|
102318
102387
|
}
|
|
102388
|
+
}
|
|
102319
102389
|
}
|
|
102390
|
+
}
|
|
102320
102391
|
}
|
|
102321
|
-
|
|
102322
|
-
|
|
102323
|
-
|
|
102324
|
-
|
|
102325
|
-
|
|
102326
|
-
|
|
102327
|
-
|
|
102328
|
-
|
|
102392
|
+
|
|
102393
|
+
function calcCountyWeights(countyTotals: number[]): number[]
|
|
102394
|
+
{
|
|
102395
|
+
let nC: number = countyTotals.length;
|
|
102396
|
+
let cTotal: number = U.sumArray(countyTotals);
|
|
102397
|
+
|
|
102398
|
+
let w: number[] = U.initArray(nC, 0.0);
|
|
102399
|
+
|
|
102400
|
+
for (let j = 0; j < nC; j++)
|
|
102401
|
+
{
|
|
102402
|
+
w[j] = countyTotals[j] / cTotal;
|
|
102403
|
+
}
|
|
102404
|
+
|
|
102405
|
+
return w;
|
|
102329
102406
|
}
|
|
102330
|
-
|
|
102331
|
-
|
|
102332
|
-
|
|
102333
|
-
|
|
102334
|
-
|
|
102335
|
-
|
|
102336
|
-
|
|
102337
|
-
|
|
102407
|
+
|
|
102408
|
+
function calcDistrictWeights(districtTotals: number[]): number[]
|
|
102409
|
+
{
|
|
102410
|
+
let nD = districtTotals.length;
|
|
102411
|
+
let dTotal: number = U.sumArray(districtTotals);
|
|
102412
|
+
|
|
102413
|
+
let x: number[] = U.initArray(nD, 0.0);
|
|
102414
|
+
|
|
102415
|
+
for (let i = 0; i < nD; i++)
|
|
102416
|
+
{
|
|
102417
|
+
x[i] = districtTotals[i] / dTotal;
|
|
102418
|
+
}
|
|
102419
|
+
|
|
102420
|
+
return x;
|
|
102338
102421
|
}
|
|
102339
|
-
|
|
102340
|
-
|
|
102341
|
-
|
|
102342
|
-
|
|
102343
|
-
|
|
102344
|
-
|
|
102345
|
-
|
|
102346
|
-
|
|
102347
|
-
|
|
102348
|
-
|
|
102349
|
-
|
|
102350
|
-
|
|
102351
|
-
|
|
102422
|
+
|
|
102423
|
+
function calcCountyFractions(CxDreducedD: number[][], countyTotals: number[]): number[][]
|
|
102424
|
+
{
|
|
102425
|
+
let nD = CxDreducedD.length;
|
|
102426
|
+
let nC = CxDreducedD[0].length;
|
|
102427
|
+
|
|
102428
|
+
let f: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
|
|
102429
|
+
|
|
102430
|
+
for (let j = 0; j < nC; j++)
|
|
102431
|
+
{
|
|
102432
|
+
for (let i = 0; i < nD; i++)
|
|
102433
|
+
{
|
|
102434
|
+
if (countyTotals[j] > 0)
|
|
102435
|
+
{
|
|
102436
|
+
f[i][j] = CxDreducedD[i][j] / countyTotals[j];
|
|
102437
|
+
}
|
|
102438
|
+
else
|
|
102439
|
+
{
|
|
102440
|
+
f[i][j] = 0.0;
|
|
102441
|
+
}
|
|
102352
102442
|
}
|
|
102353
|
-
|
|
102443
|
+
}
|
|
102444
|
+
|
|
102445
|
+
return f;
|
|
102354
102446
|
}
|
|
102355
|
-
|
|
102356
|
-
|
|
102357
|
-
|
|
102358
|
-
|
|
102359
|
-
|
|
102360
|
-
|
|
102361
|
-
|
|
102362
|
-
|
|
102363
|
-
|
|
102364
|
-
|
|
102365
|
-
|
|
102366
|
-
|
|
102367
|
-
|
|
102447
|
+
|
|
102448
|
+
function calcDistrictFractions(CxDreducedC: number[][], districtTotals: number[]): number[][]
|
|
102449
|
+
{
|
|
102450
|
+
let nD = CxDreducedC.length;
|
|
102451
|
+
let nC = CxDreducedC[0].length;
|
|
102452
|
+
|
|
102453
|
+
let g: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
|
|
102454
|
+
|
|
102455
|
+
for (let j = 0; j < nC; j++)
|
|
102456
|
+
{
|
|
102457
|
+
for (let i = 0; i < nD; i++)
|
|
102458
|
+
{
|
|
102459
|
+
if (districtTotals[i] > 0)
|
|
102460
|
+
{
|
|
102461
|
+
g[i][j] = CxDreducedC[i][j] / districtTotals[i];
|
|
102462
|
+
}
|
|
102463
|
+
else
|
|
102464
|
+
{
|
|
102465
|
+
g[i][j] = 0.0;
|
|
102466
|
+
}
|
|
102368
102467
|
}
|
|
102369
|
-
|
|
102468
|
+
}
|
|
102469
|
+
|
|
102470
|
+
return g;
|
|
102370
102471
|
}
|
|
102472
|
+
|
|
102371
102473
|
// Deal with decimal census "counts" due to disagg/re-agg
|
|
102372
|
-
function areRoughlyEqual(x, y)
|
|
102373
|
-
|
|
102374
|
-
|
|
102375
|
-
|
|
102474
|
+
function areRoughlyEqual(x: number, y: number): boolean
|
|
102475
|
+
{
|
|
102476
|
+
let delta = Math.abs(x - y);
|
|
102477
|
+
let result = (delta < S.EQUAL_TOLERANCE) ? true : false;
|
|
102478
|
+
|
|
102479
|
+
return result;
|
|
102376
102480
|
}
|
|
102481
|
+
|
|
102377
102482
|
// For all districts in a county, sum the split score.
|
|
102378
|
-
function countySplitScore(j, f, numD, bLog = false)
|
|
102379
|
-
|
|
102380
|
-
|
|
102381
|
-
|
|
102382
|
-
|
|
102383
|
-
|
|
102483
|
+
function countySplitScore(j: number, f: number[][], numD: number, bLog: boolean = false): number
|
|
102484
|
+
{
|
|
102485
|
+
let e = 0.0;
|
|
102486
|
+
|
|
102487
|
+
for (let i = 0; i < numD; i++)
|
|
102488
|
+
{
|
|
102489
|
+
e += Math.sqrt(f[i][j]);
|
|
102490
|
+
}
|
|
102491
|
+
|
|
102492
|
+
return e;
|
|
102384
102493
|
}
|
|
102494
|
+
|
|
102385
102495
|
// For all counties, sum the weighted county splits.
|
|
102386
|
-
function countySplitting(f, w, bLog = false)
|
|
102387
|
-
|
|
102388
|
-
|
|
102389
|
-
|
|
102390
|
-
|
|
102391
|
-
|
|
102392
|
-
|
|
102393
|
-
|
|
102394
|
-
|
|
102395
|
-
|
|
102396
|
-
|
|
102496
|
+
function countySplitting(f: number[][], w: number[], bLog: boolean = false): number
|
|
102497
|
+
{
|
|
102498
|
+
let numC = f[0].length;
|
|
102499
|
+
let numD = f.length;
|
|
102500
|
+
|
|
102501
|
+
let e = 0.0;
|
|
102502
|
+
|
|
102503
|
+
for (let j = 0; j < numC; j++)
|
|
102504
|
+
{
|
|
102505
|
+
let splitScore = countySplitScore(j, f, numD, bLog);
|
|
102506
|
+
e += w[j] * splitScore;
|
|
102507
|
+
|
|
102508
|
+
if (bLog) console.log("County splitting =", j, w[j], splitScore, e);
|
|
102509
|
+
}
|
|
102510
|
+
|
|
102511
|
+
return U.trim(e, 3);
|
|
102397
102512
|
}
|
|
102513
|
+
|
|
102398
102514
|
// For all counties in a district, sum the split score.
|
|
102399
|
-
function districtSplitScore(i, g, numC, bLog = false)
|
|
102400
|
-
|
|
102401
|
-
|
|
102402
|
-
|
|
102403
|
-
|
|
102404
|
-
|
|
102515
|
+
function districtSplitScore(i: number, g: number[][], numC: number, bLog: boolean = false): number
|
|
102516
|
+
{
|
|
102517
|
+
let e = 0.0;
|
|
102518
|
+
|
|
102519
|
+
for (let j = 0; j < numC; j++)
|
|
102520
|
+
{
|
|
102521
|
+
e += Math.sqrt(g[i][j]);
|
|
102522
|
+
}
|
|
102523
|
+
|
|
102524
|
+
return e;
|
|
102405
102525
|
}
|
|
102526
|
+
|
|
102406
102527
|
// For all districts, sum the weighted district splits.
|
|
102407
|
-
function districtSplitting(g, x, bLog = false)
|
|
102408
|
-
|
|
102409
|
-
|
|
102410
|
-
|
|
102411
|
-
|
|
102412
|
-
|
|
102413
|
-
|
|
102414
|
-
|
|
102415
|
-
|
|
102416
|
-
|
|
102417
|
-
|
|
102528
|
+
function districtSplitting(g: number[][], x: number[], bLog: boolean = false): number
|
|
102529
|
+
{
|
|
102530
|
+
let numC = g[0].length;
|
|
102531
|
+
let numD = g.length;
|
|
102532
|
+
|
|
102533
|
+
let e = 0.0;
|
|
102534
|
+
|
|
102535
|
+
for (let i = 0; i < numD; i++)
|
|
102536
|
+
{
|
|
102537
|
+
let splitScore = districtSplitScore(i, g, numC, bLog);
|
|
102538
|
+
e += x[i] * splitScore;
|
|
102539
|
+
|
|
102540
|
+
if (bLog) console.log("District split score =", i, x[i], splitScore, e);
|
|
102541
|
+
}
|
|
102542
|
+
|
|
102543
|
+
return U.trim(e, 3);
|
|
102418
102544
|
}
|
|
102545
|
+
*/
|
|
102419
102546
|
// ANALYZE SIMPLE COUNTY & VTD SPLITTING
|
|
102420
102547
|
/*
|
|
102421
102548
|
|
|
@@ -102450,7 +102577,7 @@ These counties are split unexpectedly:
|
|
|
102450
102577
|
|
|
102451
102578
|
*/
|
|
102452
102579
|
function doFindCountiesSplitUnexpectedly(s, bLog = false) {
|
|
102453
|
-
let test = s.getTest(
|
|
102580
|
+
let test = s.getTest(5 /* UnexpectedCountySplits */);
|
|
102454
102581
|
// THE THREE VALUES TO DETERMINE FOR A PLAN
|
|
102455
102582
|
let unexpectedSplits = 0;
|
|
102456
102583
|
let unexpectedAffected = 0;
|
|
@@ -102543,10 +102670,10 @@ function doFindCountiesSplitUnexpectedly(s, bLog = false) {
|
|
|
102543
102670
|
return test;
|
|
102544
102671
|
}
|
|
102545
102672
|
exports.doFindCountiesSplitUnexpectedly = doFindCountiesSplitUnexpectedly;
|
|
102673
|
+
// NOTE - This function just creates an empty container that dra-client fills in when generating the UI
|
|
102546
102674
|
function doFindSplitVTDs(s, bLog = false) {
|
|
102547
|
-
let test = s.getTest(
|
|
102675
|
+
let test = s.getTest(6 /* VTDSplits */);
|
|
102548
102676
|
let splitVTDs = [];
|
|
102549
|
-
// TODO - SPLITTING: Flesh this out, using virtual VTD's ...
|
|
102550
102677
|
test['score'] = splitVTDs.length;
|
|
102551
102678
|
test['details']['splitVTDs'] = splitVTDs;
|
|
102552
102679
|
return test;
|
|
@@ -102576,10 +102703,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
102576
102703
|
return result;
|
|
102577
102704
|
};
|
|
102578
102705
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
102706
|
+
// NOTE - This file will NOT be empty, when legacy code is deleted.
|
|
102579
102707
|
const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
|
|
102580
102708
|
const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
|
|
102581
|
-
|
|
102582
|
-
// TODO - SCORE: Remove legacy code
|
|
102709
|
+
// TODO - DELETE
|
|
102583
102710
|
// Measures of compactness compare district shapes to various ideally compact
|
|
102584
102711
|
// benchmarks, such as circles. All else equal, more compact districts are better.
|
|
102585
102712
|
//
|
|
@@ -102658,62 +102785,83 @@ const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
|
102658
102785
|
// For each measure, the compactness of a set of Congressional districts is the
|
|
102659
102786
|
// average of that measure for all the districts.
|
|
102660
102787
|
//
|
|
102788
|
+
/* TODO - DELETE
|
|
102661
102789
|
// Calculate Reock compactness:
|
|
102662
102790
|
// reock = (4 * a) / (math.pi * d**2)
|
|
102663
102791
|
// NOTE - Depends on extractDistrictProperties running first
|
|
102664
|
-
function doReock(s, bLog = false)
|
|
102665
|
-
|
|
102666
|
-
|
|
102667
|
-
|
|
102668
|
-
|
|
102669
|
-
|
|
102670
|
-
|
|
102671
|
-
|
|
102672
|
-
|
|
102673
|
-
|
|
102674
|
-
|
|
102675
|
-
|
|
102676
|
-
|
|
102677
|
-
|
|
102678
|
-
|
|
102679
|
-
|
|
102680
|
-
|
|
102792
|
+
export function doReock(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
102793
|
+
{
|
|
102794
|
+
let test = s.getTest(T.Test.Reock) as T.TestEntry;
|
|
102795
|
+
|
|
102796
|
+
// Calculate Reock scores by district
|
|
102797
|
+
let scores: number[] = [];
|
|
102798
|
+
|
|
102799
|
+
for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
|
|
102800
|
+
{
|
|
102801
|
+
let districtProps = s.districts.getGeoProperties(districtID);
|
|
102802
|
+
// Guard against no shape and no properties
|
|
102803
|
+
if (districtProps)
|
|
102804
|
+
{
|
|
102805
|
+
let a = districtProps[T.DistrictShapeProperty.Area];
|
|
102806
|
+
let d = districtProps[T.DistrictShapeProperty.Diameter];
|
|
102807
|
+
|
|
102808
|
+
let reock = (4 * a) / (Math.PI * d ** 2);
|
|
102809
|
+
|
|
102810
|
+
// Save each district score
|
|
102811
|
+
scores.push(reock);
|
|
102812
|
+
|
|
102813
|
+
// Echo the results by district
|
|
102814
|
+
if (bLog) console.log("Reock for district", districtID, "=", reock);
|
|
102681
102815
|
}
|
|
102682
|
-
|
|
102683
|
-
|
|
102684
|
-
|
|
102685
|
-
|
|
102686
|
-
|
|
102816
|
+
}
|
|
102817
|
+
|
|
102818
|
+
// Populate the test entry ... for the shapes that exist!
|
|
102819
|
+
let averageReock = U.avgArray(scores);
|
|
102820
|
+
|
|
102821
|
+
test['score'] = U.trim(averageReock);
|
|
102822
|
+
test['details'] = {}; // TODO - Any details?
|
|
102823
|
+
|
|
102824
|
+
return test;
|
|
102687
102825
|
}
|
|
102688
|
-
|
|
102826
|
+
|
|
102689
102827
|
// Calculate Polsby-Popper compactness measures:
|
|
102690
102828
|
// polsby_popper = (4 * math.pi) * (a / p**2)
|
|
102691
102829
|
// NOTE - Depends on extractDistrictProperties running first
|
|
102692
|
-
function doPolsbyPopper(s, bLog = false)
|
|
102693
|
-
|
|
102694
|
-
|
|
102695
|
-
|
|
102696
|
-
|
|
102697
|
-
|
|
102698
|
-
|
|
102699
|
-
|
|
102700
|
-
|
|
102701
|
-
|
|
102702
|
-
|
|
102703
|
-
|
|
102704
|
-
|
|
102705
|
-
|
|
102706
|
-
|
|
102707
|
-
|
|
102708
|
-
|
|
102830
|
+
export function doPolsbyPopper(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
102831
|
+
{
|
|
102832
|
+
let test = s.getTest(T.Test.PolsbyPopper) as T.TestEntry;
|
|
102833
|
+
|
|
102834
|
+
// Calculate Polsby-Popper scores by district
|
|
102835
|
+
let scores: number[] = [];
|
|
102836
|
+
|
|
102837
|
+
for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
|
|
102838
|
+
{
|
|
102839
|
+
let districtProps = s.districts.getGeoProperties(districtID);
|
|
102840
|
+
// Guard against no shape and no properties
|
|
102841
|
+
if (districtProps)
|
|
102842
|
+
{
|
|
102843
|
+
let a = districtProps[T.DistrictShapeProperty.Area];
|
|
102844
|
+
let p = districtProps[T.DistrictShapeProperty.Perimeter];
|
|
102845
|
+
|
|
102846
|
+
let polsbyPopper = (4 * Math.PI) * (a / p ** 2);
|
|
102847
|
+
|
|
102848
|
+
// Save each district score
|
|
102849
|
+
scores.push(polsbyPopper);
|
|
102850
|
+
|
|
102851
|
+
// Echo the results by district
|
|
102852
|
+
if (bLog) console.log("Polsby-Popper for district", districtID, "=", polsbyPopper);
|
|
102709
102853
|
}
|
|
102710
|
-
|
|
102711
|
-
|
|
102712
|
-
|
|
102713
|
-
|
|
102714
|
-
|
|
102854
|
+
}
|
|
102855
|
+
|
|
102856
|
+
// Populate the test entry ... for the shapes that exist!
|
|
102857
|
+
let averagePolsbyPopper = U.avgArray(scores);
|
|
102858
|
+
|
|
102859
|
+
test['score'] = U.trim(averagePolsbyPopper);
|
|
102860
|
+
test['details'] = {}; // TODO - Any details?
|
|
102861
|
+
|
|
102862
|
+
return test;
|
|
102715
102863
|
}
|
|
102716
|
-
|
|
102864
|
+
*/
|
|
102717
102865
|
// HELPER TO EXTRACT PROPERTIES OF DISTRICT SHAPES
|
|
102718
102866
|
// TODO - SCORE: Create an array, as opposed to a dict
|
|
102719
102867
|
function extractDistrictProperties(s, bLog = false) {
|
|
@@ -102791,41 +102939,53 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
102791
102939
|
return result;
|
|
102792
102940
|
};
|
|
102793
102941
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
102794
|
-
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
102795
102942
|
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
102796
|
-
|
|
102797
|
-
function doPopulationDeviation(s, bLog = false)
|
|
102798
|
-
|
|
102799
|
-
|
|
102800
|
-
|
|
102801
|
-
|
|
102802
|
-
|
|
102803
|
-
|
|
102804
|
-
|
|
102805
|
-
|
|
102806
|
-
|
|
102807
|
-
|
|
102808
|
-
|
|
102809
|
-
|
|
102810
|
-
|
|
102811
|
-
|
|
102812
|
-
|
|
102813
|
-
|
|
102814
|
-
|
|
102815
|
-
|
|
102816
|
-
|
|
102817
|
-
|
|
102818
|
-
|
|
102819
|
-
|
|
102820
|
-
|
|
102821
|
-
|
|
102822
|
-
|
|
102823
|
-
|
|
102824
|
-
|
|
102825
|
-
|
|
102826
|
-
|
|
102943
|
+
/* TODO - DELETE
|
|
102944
|
+
export function doPopulationDeviation(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
102945
|
+
{
|
|
102946
|
+
let test = s.getTest(T.Test.PopulationDeviation) as T.TestEntry;
|
|
102947
|
+
|
|
102948
|
+
let targetSize = s.state.totalPop / s.state.nDistricts;
|
|
102949
|
+
|
|
102950
|
+
// Compute the min & max district populations
|
|
102951
|
+
// ... excluding the dummy the 'unassigned' 0 and N+1 summary "districts"
|
|
102952
|
+
let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
|
|
102953
|
+
totPopByDistrict = totPopByDistrict.slice(1, -1);
|
|
102954
|
+
|
|
102955
|
+
// Remove empty districts
|
|
102956
|
+
totPopByDistrict = totPopByDistrict.filter(x => x > 0);
|
|
102957
|
+
|
|
102958
|
+
let min = 0;
|
|
102959
|
+
let max = 0;
|
|
102960
|
+
|
|
102961
|
+
// If there's more than 1 non-empty district, calculate a non-zero deviation
|
|
102962
|
+
if (totPopByDistrict.length > 1)
|
|
102963
|
+
{
|
|
102964
|
+
min = U.minArray(totPopByDistrict);
|
|
102965
|
+
max = U.maxArray(totPopByDistrict);
|
|
102966
|
+
}
|
|
102967
|
+
|
|
102968
|
+
// Calculate the raw population deviation
|
|
102969
|
+
let popDev = (max - min) / targetSize;
|
|
102970
|
+
|
|
102971
|
+
// Round the raw value to the desired level of precision
|
|
102972
|
+
popDev = U.trim(popDev);
|
|
102973
|
+
|
|
102974
|
+
// Populate the test entry
|
|
102975
|
+
test['score'] = popDev;
|
|
102976
|
+
test['details'] = { 'maxDeviation': max - min };
|
|
102977
|
+
|
|
102978
|
+
// Populate the N+1 summary "district" in district.statistics
|
|
102979
|
+
let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
|
|
102980
|
+
let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
|
|
102981
|
+
let summaryRow = s.districts.numberOfRows() - 1;
|
|
102982
|
+
|
|
102983
|
+
totalPop[summaryRow] = targetSize;
|
|
102984
|
+
popDevPct[summaryRow] = popDev;
|
|
102985
|
+
|
|
102986
|
+
return test;
|
|
102827
102987
|
}
|
|
102828
|
-
|
|
102988
|
+
*/
|
|
102829
102989
|
// NOTE - This validity check is *derived* and depends on population deviation %
|
|
102830
102990
|
// being computed (above) and normalized in test log & scorecard generation.
|
|
102831
102991
|
function doHasEqualPopulations(s, bLog = false) {
|
|
@@ -102875,7 +103035,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
102875
103035
|
};
|
|
102876
103036
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
102877
103037
|
const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
|
|
102878
|
-
// TODO - SCORE: Remove legacy code
|
|
102879
103038
|
// HELPER
|
|
102880
103039
|
function polyParts(poly) {
|
|
102881
103040
|
let parts = { type: 'FeatureCollection', features: [] };
|
|
@@ -102990,35 +103149,6 @@ function gfDiameter(poly) {
|
|
|
102990
103149
|
exports.gfDiameter = gfDiameter;
|
|
102991
103150
|
|
|
102992
103151
|
|
|
102993
|
-
/***/ }),
|
|
102994
|
-
|
|
102995
|
-
/***/ "./src/minority.ts":
|
|
102996
|
-
/*!*************************!*\
|
|
102997
|
-
!*** ./src/minority.ts ***!
|
|
102998
|
-
\*************************/
|
|
102999
|
-
/*! no static exports found */
|
|
103000
|
-
/***/ (function(module, exports, __webpack_require__) {
|
|
103001
|
-
|
|
103002
|
-
"use strict";
|
|
103003
|
-
|
|
103004
|
-
//
|
|
103005
|
-
// PROTECTS MINORITIES
|
|
103006
|
-
//
|
|
103007
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
103008
|
-
// TODO - SCORE: Remove legacy code
|
|
103009
|
-
function doMajorityMinorityDistricts(s, bLog = false) {
|
|
103010
|
-
let test = s.getTest(16 /* MajorityMinorityDistricts */);
|
|
103011
|
-
if (bLog)
|
|
103012
|
-
console.log("TODO - Calculating # of majority-minority districts ...");
|
|
103013
|
-
return test;
|
|
103014
|
-
}
|
|
103015
|
-
exports.doMajorityMinorityDistricts = doMajorityMinorityDistricts;
|
|
103016
|
-
// Sources for majority-minority info:
|
|
103017
|
-
// - https://en.wikipedia.org/wiki/List_of_majority-minority_United_States_congressional_districts
|
|
103018
|
-
// TODO - 2020: Update/revise this, when the update comes out in September:
|
|
103019
|
-
// - http://www.ncsl.org/Portals/1/Documents/Redistricting/Redistricting_2010.pdf
|
|
103020
|
-
|
|
103021
|
-
|
|
103022
103152
|
/***/ }),
|
|
103023
103153
|
|
|
103024
103154
|
/***/ "./src/political.ts":
|
|
@@ -103033,18 +103163,14 @@ exports.doMajorityMinorityDistricts = doMajorityMinorityDistricts;
|
|
|
103033
103163
|
//
|
|
103034
103164
|
// FAIR/PROPORTIONAL
|
|
103035
103165
|
//
|
|
103036
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
103037
|
-
if (mod && mod.__esModule) return mod;
|
|
103038
|
-
var result = {};
|
|
103039
|
-
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
|
103040
|
-
result["default"] = mod;
|
|
103041
|
-
return result;
|
|
103042
|
-
};
|
|
103043
103166
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
103167
|
+
// NOTE - This file will NOT be empty, when legacy code is deleted.
|
|
103044
103168
|
const assert_1 = __webpack_require__(/*! assert */ "assert");
|
|
103045
|
-
|
|
103046
|
-
|
|
103047
|
-
|
|
103169
|
+
/* TODO - DELETE
|
|
103170
|
+
import * as D from './_data'
|
|
103171
|
+
import { AnalyticsSession } from './_api';
|
|
103172
|
+
|
|
103173
|
+
|
|
103048
103174
|
// Partisan analytics need the following data:
|
|
103049
103175
|
//
|
|
103050
103176
|
// An "election model" by geo_id, where each item has 4 pieces of data:
|
|
@@ -103063,66 +103189,89 @@ const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
|
103063
103189
|
//
|
|
103064
103190
|
// I'm labelling this general concept a "Voter Preference Index (VPI)," a
|
|
103065
103191
|
// conscious +1 letter play on Cook's "PVI" acronymn.
|
|
103192
|
+
|
|
103193
|
+
|
|
103066
103194
|
// MEASURING BIAS & RESPONSIVENESS (NAGLE'S METHOD)
|
|
103067
|
-
|
|
103068
|
-
|
|
103069
|
-
|
|
103070
|
-
|
|
103071
|
-
|
|
103195
|
+
|
|
103196
|
+
export function doSeatsBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
103197
|
+
{
|
|
103198
|
+
let test = s.getTest(T.Test.SeatsBias) as T.TestEntry;
|
|
103199
|
+
|
|
103200
|
+
if (bLog) console.log("TODO - Calculating seats bias ...");
|
|
103201
|
+
|
|
103202
|
+
return test;
|
|
103072
103203
|
}
|
|
103073
|
-
|
|
103074
|
-
function doVotesBias(s, bLog = false)
|
|
103075
|
-
|
|
103076
|
-
|
|
103077
|
-
|
|
103078
|
-
|
|
103204
|
+
|
|
103205
|
+
export function doVotesBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
103206
|
+
{
|
|
103207
|
+
let test = s.getTest(T.Test.VotesBias) as T.TestEntry;
|
|
103208
|
+
|
|
103209
|
+
if (bLog) console.log("TODO - Calculating votes bias ...");
|
|
103210
|
+
|
|
103211
|
+
return test;
|
|
103079
103212
|
}
|
|
103080
|
-
|
|
103081
|
-
function doResponsiveness(s, bLog = false)
|
|
103082
|
-
|
|
103083
|
-
|
|
103084
|
-
|
|
103085
|
-
|
|
103213
|
+
|
|
103214
|
+
export function doResponsiveness(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
103215
|
+
{
|
|
103216
|
+
let test = s.getTest(T.Test.Responsiveness) as T.TestEntry;
|
|
103217
|
+
|
|
103218
|
+
if (bLog) console.log("TODO - Calculating responsiveness ...");
|
|
103219
|
+
|
|
103220
|
+
return test;
|
|
103086
103221
|
}
|
|
103087
|
-
|
|
103088
|
-
function doResponsiveDistricts(s, bLog = false)
|
|
103089
|
-
|
|
103090
|
-
|
|
103091
|
-
|
|
103092
|
-
|
|
103222
|
+
|
|
103223
|
+
export function doResponsiveDistricts(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
103224
|
+
{
|
|
103225
|
+
let test = s.getTest(T.Test.ResponsiveDistricts) as T.TestEntry;
|
|
103226
|
+
|
|
103227
|
+
if (bLog) console.log("TODO - Calculating # of responsive districts ...");
|
|
103228
|
+
|
|
103229
|
+
return test;
|
|
103093
103230
|
}
|
|
103094
|
-
|
|
103231
|
+
|
|
103232
|
+
|
|
103095
103233
|
// OTHER MEASURES OF PARTISAN BIAS
|
|
103234
|
+
|
|
103096
103235
|
// TODO - PARTISAN: This formula might need to be inverted for D vs. R +/-
|
|
103097
103236
|
// TODO - Normalize the results.
|
|
103098
|
-
function doEfficiencyGap(s, bLog = false)
|
|
103099
|
-
|
|
103100
|
-
|
|
103101
|
-
|
|
103102
|
-
|
|
103103
|
-
|
|
103104
|
-
|
|
103105
|
-
|
|
103106
|
-
|
|
103107
|
-
|
|
103108
|
-
|
|
103109
|
-
|
|
103110
|
-
|
|
103111
|
-
|
|
103112
|
-
|
|
103113
|
-
|
|
103114
|
-
|
|
103115
|
-
|
|
103116
|
-
|
|
103117
|
-
|
|
103118
|
-
|
|
103119
|
-
|
|
103120
|
-
|
|
103121
|
-
|
|
103122
|
-
|
|
103237
|
+
export function doEfficiencyGap(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
|
|
103238
|
+
{
|
|
103239
|
+
if (bLog) console.log("TODO - Calculating the efficiency gap ...");
|
|
103240
|
+
|
|
103241
|
+
let test = s.getTest(T.Test.EfficiencyGap) as T.TestEntry;
|
|
103242
|
+
|
|
103243
|
+
// Get partisan statistics by districts.
|
|
103244
|
+
// Use Democratic votes, seats, and shares by convention.
|
|
103245
|
+
let DVotes = s.districts.statistics[D.DistrictField.DemVotes];
|
|
103246
|
+
let DSeats = s.districts.statistics[D.DistrictField.DemSeat];
|
|
103247
|
+
let TPVotes = s.districts.statistics[D.DistrictField.TwoPartyVote];
|
|
103248
|
+
|
|
103249
|
+
// Exclude the dummy unassigned '0' and N+1 summary "districts"
|
|
103250
|
+
DVotes = DVotes.slice(1, -1);
|
|
103251
|
+
DSeats = DSeats.slice(1, -1);
|
|
103252
|
+
TPVotes = TPVotes.slice(1, -1);
|
|
103253
|
+
|
|
103254
|
+
// Calculate D vote share & D seat share
|
|
103255
|
+
let DVoteShare = U.sumArray(DVotes) / U.sumArray(TPVotes);
|
|
103256
|
+
let DSeatShare = U.sumArray(DSeats) / s.state.nDistricts;
|
|
103257
|
+
|
|
103258
|
+
// Finally, calculate the Efficiency Gap
|
|
103259
|
+
let efficiencyGap = (DSeatShare - 0.5) - (2.0 * (DVoteShare - 0.5));
|
|
103260
|
+
|
|
103261
|
+
// Round the raw value to the desired level of precision
|
|
103262
|
+
efficiencyGap = U.trim(efficiencyGap);
|
|
103263
|
+
|
|
103264
|
+
// Populate the test entry
|
|
103265
|
+
test['score'] = efficiencyGap;
|
|
103266
|
+
// test['normalizedScore'] = 0; // TODO - Normalize the raw score
|
|
103267
|
+
test['details'] = {}; // TODO - Add details, if any
|
|
103268
|
+
|
|
103269
|
+
return test;
|
|
103123
103270
|
}
|
|
103124
|
-
|
|
103271
|
+
|
|
103272
|
+
|
|
103125
103273
|
// HELPERS
|
|
103274
|
+
*/
|
|
103126
103275
|
function fptpWin(demPct) {
|
|
103127
103276
|
// Vote shares should be fractions in the range [0.0 – 1.0]
|
|
103128
103277
|
assert_1.strict((demPct <= 1.0) && (demPct >= 0.));
|
|
@@ -103728,24 +103877,26 @@ const populationDeviationDefn = {
|
|
|
103728
103877
|
externalType: TestType.Percentage,
|
|
103729
103878
|
suites: [0 /* Legal */, 2 /* Best */] // Both so EqualPopulation can be assessed
|
|
103730
103879
|
};
|
|
103731
|
-
|
|
103732
|
-
const reockDefn = {
|
|
103733
|
-
|
|
103734
|
-
|
|
103735
|
-
|
|
103736
|
-
|
|
103737
|
-
|
|
103880
|
+
/* TODO - DELETE
|
|
103881
|
+
const reockDefn: T.Dict = {
|
|
103882
|
+
ID: T.Test.Reock,
|
|
103883
|
+
name: "Reock",
|
|
103884
|
+
normalize: true,
|
|
103885
|
+
externalType: TestType.Number,
|
|
103886
|
+
suites: [T.Suite.Best]
|
|
103738
103887
|
};
|
|
103739
|
-
|
|
103740
|
-
|
|
103741
|
-
|
|
103742
|
-
|
|
103743
|
-
|
|
103744
|
-
|
|
103888
|
+
|
|
103889
|
+
const polsbyPopperDefn: T.Dict = {
|
|
103890
|
+
ID: T.Test.PolsbyPopper,
|
|
103891
|
+
name: "Polsby-Popper",
|
|
103892
|
+
normalize: true,
|
|
103893
|
+
externalType: TestType.Number,
|
|
103894
|
+
suites: [T.Suite.Best]
|
|
103745
103895
|
};
|
|
103896
|
+
*/
|
|
103746
103897
|
// NOTE - SPLITTING
|
|
103747
103898
|
const unexpectedCountySplitsDefn = {
|
|
103748
|
-
ID:
|
|
103899
|
+
ID: 5 /* UnexpectedCountySplits */,
|
|
103749
103900
|
name: "Unexpected County Splits",
|
|
103750
103901
|
normalize: false,
|
|
103751
103902
|
externalType: TestType.Percentage,
|
|
@@ -103753,35 +103904,12 @@ const unexpectedCountySplitsDefn = {
|
|
|
103753
103904
|
};
|
|
103754
103905
|
// NOTE - SPLITTING
|
|
103755
103906
|
const VTDSplitsDefn = {
|
|
103756
|
-
ID:
|
|
103907
|
+
ID: 6 /* VTDSplits */,
|
|
103757
103908
|
name: "VTD Splits",
|
|
103758
103909
|
normalize: false,
|
|
103759
103910
|
externalType: TestType.Number,
|
|
103760
103911
|
suites: [2 /* Best */]
|
|
103761
103912
|
};
|
|
103762
|
-
// NOTE - SPLITTING
|
|
103763
|
-
const countySplittingDefn = {
|
|
103764
|
-
ID: 8 /* CountySplitting */,
|
|
103765
|
-
name: "County Splitting",
|
|
103766
|
-
normalize: true,
|
|
103767
|
-
externalType: TestType.Number,
|
|
103768
|
-
suites: [2 /* Best */]
|
|
103769
|
-
};
|
|
103770
|
-
// NOTE - SPLITTING
|
|
103771
|
-
const districtSplittingDefn = {
|
|
103772
|
-
ID: 9 /* DistrictSplitting */,
|
|
103773
|
-
name: "District Splitting",
|
|
103774
|
-
normalize: true,
|
|
103775
|
-
externalType: TestType.Number,
|
|
103776
|
-
suites: [2 /* Best */]
|
|
103777
|
-
};
|
|
103778
|
-
const efficiencyGapDefn = {
|
|
103779
|
-
ID: 15 /* EfficiencyGap */,
|
|
103780
|
-
name: "Efficiency Gap",
|
|
103781
|
-
normalize: false,
|
|
103782
|
-
externalType: TestType.Percentage,
|
|
103783
|
-
suites: [1 /* Fair */]
|
|
103784
|
-
};
|
|
103785
103913
|
// All the tests that have been defined (can be reported on)
|
|
103786
103914
|
const testDefns = {
|
|
103787
103915
|
[0 /* Complete */]: completeDefn,
|
|
@@ -103789,94 +103917,103 @@ const testDefns = {
|
|
|
103789
103917
|
[2 /* FreeOfHoles */]: freeOfHolesDefn,
|
|
103790
103918
|
[3 /* EqualPopulation */]: equalPopulationDefn,
|
|
103791
103919
|
[4 /* PopulationDeviation */]: populationDeviationDefn,
|
|
103792
|
-
[
|
|
103793
|
-
[
|
|
103794
|
-
|
|
103795
|
-
[
|
|
103796
|
-
[10 /* VTDSplits */]: VTDSplitsDefn,
|
|
103797
|
-
[8 /* CountySplitting */]: countySplittingDefn,
|
|
103798
|
-
[9 /* DistrictSplitting */]: districtSplittingDefn,
|
|
103799
|
-
// TODO - More tests ...
|
|
103800
|
-
[15 /* EfficiencyGap */]: efficiencyGapDefn
|
|
103920
|
+
// [T.Test.Reock]: reockDefn, TODO - DELETE
|
|
103921
|
+
// [T.Test.PolsbyPopper]: polsbyPopperDefn, TODO - DELETE
|
|
103922
|
+
[5 /* UnexpectedCountySplits */]: unexpectedCountySplitsDefn,
|
|
103923
|
+
[6 /* VTDSplits */]: VTDSplitsDefn,
|
|
103801
103924
|
};
|
|
103925
|
+
/* TODO - DELETE
|
|
103802
103926
|
// NORMALIZE RAW ANALYTICS
|
|
103803
103927
|
// Raw numeric analytics, such as population deviation, compactness, etc. are
|
|
103804
103928
|
// normalized as part of creating a scorecard, so the code to normalize results
|
|
103805
103929
|
// is encapsulated here.
|
|
103930
|
+
|
|
103806
103931
|
// Configure scale parameters for normalizing each raw test result.
|
|
103807
103932
|
// Scales consist of a minimum & a maximum *raw* value. If the values get
|
|
103808
103933
|
// inverted (to make bigger better), these will switch.
|
|
103809
103934
|
// This process needs to be separate from the test configuration info above,
|
|
103810
103935
|
// because some scales need access to the analytics session object.
|
|
103811
|
-
function doConfigureScales(s)
|
|
103812
|
-
|
|
103813
|
-
|
|
103814
|
-
|
|
103815
|
-
|
|
103816
|
-
|
|
103817
|
-
|
|
103818
|
-
|
|
103819
|
-
|
|
103820
|
-
|
|
103821
|
-
|
|
103822
|
-
|
|
103823
|
-
|
|
103824
|
-
|
|
103825
|
-
|
|
103826
|
-
|
|
103827
|
-
|
|
103828
|
-
|
|
103829
|
-
|
|
103830
|
-
|
|
103831
|
-
|
|
103832
|
-
|
|
103833
|
-
|
|
103834
|
-
|
|
103835
|
-
|
|
103836
|
-
|
|
103936
|
+
export function doConfigureScales(s: AnalyticsSession): void
|
|
103937
|
+
{
|
|
103938
|
+
// Scale defn for PopulationDeviation
|
|
103939
|
+
const CDLimit = 0.75 / 100; // Deviation threshold for CD's
|
|
103940
|
+
const LDLimit = 10.00 / 100; // Deviation threshold for LD's
|
|
103941
|
+
|
|
103942
|
+
const CDGoodEnough = 0.20 / 100;
|
|
103943
|
+
const LDGoodEnough = (CDGoodEnough / CDLimit) * LDLimit;
|
|
103944
|
+
const popDevScale = (s.legislativeDistricts) ? [1.0 - LDLimit, 1.0 - LDGoodEnough] : [1.0 - CDLimit, 1.0 - CDGoodEnough];
|
|
103945
|
+
// const scale = [1.0 - CDLimit, 1.0 - CDGoodEnough];
|
|
103946
|
+
|
|
103947
|
+
s.testScales[T.Test.PopulationDeviation] = { scale: popDevScale, bInvertRaw: true };
|
|
103948
|
+
|
|
103949
|
+
s.testScales[T.Test.Reock] = { scale: [0.25, 0.50] };
|
|
103950
|
+
s.testScales[T.Test.PolsbyPopper] = { scale: [0.10, 0.50] };
|
|
103951
|
+
|
|
103952
|
+
const nDistricts = s.state.nDistricts;
|
|
103953
|
+
const nCounties = s.counties.nCounties;
|
|
103954
|
+
|
|
103955
|
+
// NOTE - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
|
|
103956
|
+
// number of county splits seems too stringent, empirically.
|
|
103957
|
+
const allowableCountySplitsMultiplier = 1.5;
|
|
103958
|
+
const nAllowableSplits = Math.min(allowableCountySplitsMultiplier * (nDistricts - 1));
|
|
103959
|
+
const countySplittingThreshold = ((nAllowableSplits * 1.71) + ((nCounties - nAllowableSplits) * 1.0)) / nCounties;
|
|
103960
|
+
const countySplittingScale = [1.0, countySplittingThreshold];
|
|
103961
|
+
s.testScales[T.Test.CountySplitting] = { scale: countySplittingScale, bInvertScaled: true };
|
|
103962
|
+
|
|
103963
|
+
const districtSplittingThreshold = 1.5;
|
|
103964
|
+
const districtSplittingScale = [1.0, districtSplittingThreshold];
|
|
103965
|
+
s.testScales[T.Test.DistrictSplitting] = { scale: districtSplittingScale, bInvertScaled: true };
|
|
103966
|
+
|
|
103967
|
+
// TODO - More analytics ...
|
|
103968
|
+
}
|
|
103969
|
+
*/
|
|
103837
103970
|
// Postprocess analytics - Normalize numeric results and derive secondary tests.
|
|
103838
103971
|
// Do this after analytics have been run and before preparing a test log or scorecard.
|
|
103839
103972
|
function doAnalyzePostProcessing(s, bLog = false) {
|
|
103840
|
-
// TODO -
|
|
103841
|
-
if (s.useLegacy())
|
|
103842
|
-
|
|
103843
|
-
|
|
103844
|
-
|
|
103845
|
-
|
|
103846
|
-
|
|
103847
|
-
|
|
103848
|
-
|
|
103849
|
-
|
|
103850
|
-
|
|
103851
|
-
|
|
103852
|
-
|
|
103853
|
-
|
|
103854
|
-
|
|
103855
|
-
|
|
103856
|
-
|
|
103857
|
-
|
|
103858
|
-
|
|
103859
|
-
|
|
103860
|
-
|
|
103861
|
-
|
|
103862
|
-
|
|
103863
|
-
|
|
103864
|
-
|
|
103865
|
-
|
|
103866
|
-
|
|
103867
|
-
|
|
103868
|
-
|
|
103869
|
-
|
|
103870
|
-
|
|
103871
|
-
|
|
103872
|
-
|
|
103873
|
-
|
|
103874
|
-
|
|
103875
|
-
|
|
103876
|
-
|
|
103877
|
-
|
|
103878
|
-
|
|
103879
|
-
|
|
103973
|
+
// TODO - DELETE
|
|
103974
|
+
// if (s.useLegacy())
|
|
103975
|
+
// {
|
|
103976
|
+
// // Normalize the raw scores for all the numerics tests
|
|
103977
|
+
// let testResults = U.getNumericObjectKeys(testDefns);
|
|
103978
|
+
// for (let testID of testResults)
|
|
103979
|
+
// {
|
|
103980
|
+
// if (testDefns[testID]['normalize'])
|
|
103981
|
+
// {
|
|
103982
|
+
// let testResult = s.getTest(testID) as T.TestEntry;
|
|
103983
|
+
// let rawScore = testResult['score'] as number;
|
|
103984
|
+
// let normalizedScore: number;
|
|
103985
|
+
// normalizedScore = U.normalize(rawScore, s.testScales[testID]);
|
|
103986
|
+
// testResult['normalizedScore'] = normalizedScore;
|
|
103987
|
+
// // Add the scale used to normalize the raw score to the details
|
|
103988
|
+
// testResult['details']['scale'] = s.testScales[testID].scale;
|
|
103989
|
+
// }
|
|
103990
|
+
// }
|
|
103991
|
+
// }
|
|
103992
|
+
// else
|
|
103993
|
+
// {
|
|
103994
|
+
// Just populate the normalized population deviation score in the test
|
|
103995
|
+
const scorecard = s._scorecard;
|
|
103996
|
+
let popDev = s.getTest(4 /* PopulationDeviation */);
|
|
103997
|
+
popDev['normalizedScore'] = scorecard.traditionalPrinciples.populationDeviation.normalized;
|
|
103998
|
+
// TODO - DELETE
|
|
103999
|
+
// test['normalizedScore'] = scorecard.best.populationDeviation.normalized;
|
|
104000
|
+
// TODO - SCORE: Add datasets used to details by tab
|
|
104001
|
+
const datasets = {
|
|
104002
|
+
shapes: S.SHAPES,
|
|
104003
|
+
census: U.deepCopy(s.config['descriptions']['CENSUS']),
|
|
104004
|
+
vap: U.deepCopy(s.config['descriptions']['VAP']),
|
|
104005
|
+
election: U.deepCopy(s.config['descriptions']['ELECTION'])
|
|
104006
|
+
};
|
|
104007
|
+
scorecard.partisan.details['election'] = datasets.election;
|
|
104008
|
+
scorecard.minority.details['vap'] = datasets.vap;
|
|
104009
|
+
scorecard.traditionalPrinciples.details['shapes'] = datasets.shapes;
|
|
104010
|
+
scorecard.traditionalPrinciples.details['census'] = datasets.census;
|
|
104011
|
+
// TODO - SCORE: Add legacy splits details
|
|
104012
|
+
const simpleSplits = s.getTest(5 /* UnexpectedCountySplits */);
|
|
104013
|
+
scorecard.traditionalPrinciples.details['unexpectedAffected'] = simpleSplits['score'];
|
|
104014
|
+
scorecard.traditionalPrinciples.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
|
|
104015
|
+
// NOTE - Add split precincts in dra-client directly
|
|
104016
|
+
// }
|
|
103880
104017
|
// Derive secondary tests
|
|
103881
104018
|
analyze_1.doDeriveSecondaryTests(s, bLog);
|
|
103882
104019
|
// Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard
|
|
@@ -104616,11 +104753,6 @@ w/in VS Code:
|
|
|
104616
104753
|
* api-analyze (analyze) - Analyzes a plan and logs the results.
|
|
104617
104754
|
|
|
104618
104755
|
* unit-valid (valid) - Exercises the validations.
|
|
104619
|
-
* unit-equal (equal) - Exercises the population deviation analytic.
|
|
104620
|
-
* unit-compact (compact) - Exercises the compactness analytics.
|
|
104621
|
-
* unit-cohesive (cohesive) - Exercises the splitting analytics.
|
|
104622
|
-
* unit-political (political) - Exercises the partisan analytics.
|
|
104623
|
-
* unit-minority (minority) - Exercises the minority analytics.
|
|
104624
104756
|
|
|
104625
104757
|
* invalid-unassigned (valid) - Tests a plan w/ unassigned features.
|
|
104626
104758
|
* invalid-missing (valid) - Tests a plan w/ a missing district.
|
|
@@ -104671,13 +104803,10 @@ const analyze_1 = __webpack_require__(/*! ../src/analyze */ "./src/analyze.ts");
|
|
|
104671
104803
|
const results_1 = __webpack_require__(/*! ../src/results */ "./src/results.ts");
|
|
104672
104804
|
const valid_1 = __webpack_require__(/*! ../src/valid */ "./src/valid.ts");
|
|
104673
104805
|
const equal_1 = __webpack_require__(/*! ../src/equal */ "./src/equal.ts");
|
|
104674
|
-
const compact_1 = __webpack_require__(/*! ../src/compact */ "./src/compact.ts");
|
|
104675
|
-
const cohesive_1 = __webpack_require__(/*! ../src/cohesive */ "./src/cohesive.ts");
|
|
104676
|
-
const political_1 = __webpack_require__(/*! ../src/political */ "./src/political.ts");
|
|
104677
|
-
const minority_1 = __webpack_require__(/*! ../src/minority */ "./src/minority.ts");
|
|
104678
104806
|
const U = __importStar(__webpack_require__(/*! ../src/utils */ "./src/utils.ts"));
|
|
104679
104807
|
const S = __importStar(__webpack_require__(/*! ../src/settings */ "./src/settings.ts"));
|
|
104680
104808
|
const D = __importStar(__webpack_require__(/*! ../src/_data */ "./src/_data.ts"));
|
|
104809
|
+
// import { DistrictRow } from '../src/results'; TODO - DELETE
|
|
104681
104810
|
// Simulate DRA unioning district shapes in the background
|
|
104682
104811
|
function addToPoly(poly, polys) {
|
|
104683
104812
|
// TODO - POLY: Fix 'poly' import, so I don't have to do this workaround.
|
|
@@ -104694,15 +104823,19 @@ let argv = yargs_1.default
|
|
|
104694
104823
|
.example('$0 equal -f foo.geojson', 'Calculate population deviation')
|
|
104695
104824
|
.demandCommand(1, 'You must specify a command to execute.')
|
|
104696
104825
|
.command('valid', 'Perform validations.')
|
|
104826
|
+
/* TODO - DELETE
|
|
104697
104827
|
.command('equal', 'Calculate population deviation.')
|
|
104698
104828
|
.command('compact', 'Calculate compactness.')
|
|
104699
104829
|
.command('cohesive', 'Calculate cohesiveness.')
|
|
104700
104830
|
.command('political', 'Assess fairness.')
|
|
104701
104831
|
.command('minority', 'Count majority-minority districts.')
|
|
104832
|
+
*/
|
|
104702
104833
|
.command('analyze', 'API call to analyze a plan.')
|
|
104834
|
+
/* TODO - DELETE
|
|
104703
104835
|
.command('scorecard', 'Analyze plan & generate a scorecard.')
|
|
104704
104836
|
.command('testlog', 'Analyze plan & generate a testlog.')
|
|
104705
104837
|
.command('report', 'API call to generate a scorecard.')
|
|
104838
|
+
*/
|
|
104706
104839
|
.option('state', {
|
|
104707
104840
|
alias: 'x',
|
|
104708
104841
|
describe: 'Specify the state.',
|
|
@@ -104801,7 +104934,7 @@ let bLog = argv.verbose;
|
|
|
104801
104934
|
// NOTE - The plan here is complete (all features assigned).
|
|
104802
104935
|
let planByDistrictID = D.invertPlan(planByGeoID);
|
|
104803
104936
|
// SIMULATE THE HOST
|
|
104804
|
-
//
|
|
104937
|
+
// Create district shapes & extract properties (area, diameter, perimeter)
|
|
104805
104938
|
const polyOptions = {
|
|
104806
104939
|
noLatitudeCorrection: false
|
|
104807
104940
|
};
|
|
@@ -104919,73 +105052,93 @@ switch (command) {
|
|
|
104919
105052
|
let t1 = valid_1.doIsComplete(s);
|
|
104920
105053
|
let t2 = valid_1.doIsContiguous(s);
|
|
104921
105054
|
let t3 = valid_1.doIsFreeOfHoles(s);
|
|
104922
|
-
let t4 =
|
|
105055
|
+
// let t4 = doPopulationDeviation(s); TODO - DELETE
|
|
104923
105056
|
let t5 = equal_1.doHasEqualPopulations(s);
|
|
104924
105057
|
results_1.doAnalyzePostProcessing(s);
|
|
104925
105058
|
echoTestResult("Complete:", t1);
|
|
104926
105059
|
echoTestResult("Contiguous:", t2);
|
|
104927
105060
|
echoTestResult("Free of holes:", t3);
|
|
104928
|
-
echoTestResult("Population deviation (%):", t4);
|
|
105061
|
+
// echoTestResult("Population deviation (%):", t4); TODO - DELETE
|
|
104929
105062
|
echoTestResult("Equal populations:", t5);
|
|
104930
105063
|
break;
|
|
104931
105064
|
}
|
|
105065
|
+
/* TODO - DELETE: Code moved to dra-score
|
|
104932
105066
|
case 'equal': {
|
|
104933
|
-
|
|
104934
|
-
|
|
104935
|
-
|
|
104936
|
-
|
|
104937
|
-
|
|
104938
|
-
|
|
105067
|
+
doPreprocessData(s);
|
|
105068
|
+
doAnalyzeDistricts(s);
|
|
105069
|
+
|
|
105070
|
+
t = doPopulationDeviation(s);
|
|
105071
|
+
echoTestResult("Population deviation (%):", t);
|
|
105072
|
+
|
|
105073
|
+
doAnalyzePostProcessing(s);
|
|
105074
|
+
break;
|
|
104939
105075
|
}
|
|
104940
105076
|
case 'compact': {
|
|
104941
|
-
|
|
104942
|
-
|
|
104943
|
-
|
|
104944
|
-
|
|
104945
|
-
|
|
104946
|
-
|
|
104947
|
-
|
|
104948
|
-
|
|
105077
|
+
doPreprocessData(s);
|
|
105078
|
+
doAnalyzeDistricts(s);
|
|
105079
|
+
|
|
105080
|
+
let t1 = doReock(s, bLog);
|
|
105081
|
+
let t2 = doPolsbyPopper(s, bLog);
|
|
105082
|
+
|
|
105083
|
+
doAnalyzePostProcessing(s);
|
|
105084
|
+
|
|
105085
|
+
echoTestResult("Reock:", t1);
|
|
105086
|
+
echoTestResult("Polsby-Popper:", t2);
|
|
105087
|
+
|
|
105088
|
+
break;
|
|
104949
105089
|
}
|
|
104950
105090
|
case 'cohesive': {
|
|
104951
|
-
|
|
104952
|
-
|
|
104953
|
-
|
|
104954
|
-
|
|
104955
|
-
|
|
104956
|
-
|
|
104957
|
-
|
|
104958
|
-
|
|
104959
|
-
|
|
104960
|
-
|
|
104961
|
-
|
|
104962
|
-
|
|
104963
|
-
|
|
105091
|
+
doPreprocessData(s);
|
|
105092
|
+
doAnalyzeDistricts(s);
|
|
105093
|
+
|
|
105094
|
+
// NOTE - SPLITTING
|
|
105095
|
+
let t1 = doFindCountiesSplitUnexpectedly(s);
|
|
105096
|
+
let t2 = doFindSplitVTDs(s);
|
|
105097
|
+
let t3 = doCountySplitting(s);
|
|
105098
|
+
let t4 = doDistrictSplitting(s);
|
|
105099
|
+
|
|
105100
|
+
doAnalyzePostProcessing(s);
|
|
105101
|
+
|
|
105102
|
+
echoTestResult("Counties split unexpectedly:", t1);
|
|
105103
|
+
echoTestResult("Split VTDs:", t2);
|
|
105104
|
+
echoTestResult("County splitting:", t3);
|
|
105105
|
+
echoTestResult("District splitting:", t4);
|
|
105106
|
+
|
|
105107
|
+
break;
|
|
104964
105108
|
}
|
|
104965
105109
|
case 'political': {
|
|
104966
|
-
|
|
104967
|
-
|
|
104968
|
-
|
|
104969
|
-
|
|
104970
|
-
|
|
104971
|
-
|
|
104972
|
-
|
|
104973
|
-
|
|
104974
|
-
|
|
104975
|
-
|
|
104976
|
-
|
|
104977
|
-
|
|
104978
|
-
|
|
104979
|
-
|
|
105110
|
+
doPreprocessData(s);
|
|
105111
|
+
doAnalyzeDistricts(s);
|
|
105112
|
+
|
|
105113
|
+
let t1 = doSeatsBias(s);
|
|
105114
|
+
let t2 = doVotesBias(s);
|
|
105115
|
+
let t3 = doResponsiveness(s);
|
|
105116
|
+
let t4 = doResponsiveDistricts(s);
|
|
105117
|
+
let t5 = doEfficiencyGap(s);
|
|
105118
|
+
|
|
105119
|
+
doAnalyzePostProcessing(s);
|
|
105120
|
+
|
|
105121
|
+
// echoTestResult("Seats Bias:", t1); TODO
|
|
105122
|
+
// echoTestResult("Votes Bias:", t2); TODO
|
|
105123
|
+
// echoTestResult("Responsiveness:", t3); TODO
|
|
105124
|
+
// echoTestResult("Responsive Districts:", t4); TODO
|
|
105125
|
+
echoTestResult("Efficiency gap (%):", t5);
|
|
105126
|
+
|
|
105127
|
+
break;
|
|
104980
105128
|
}
|
|
104981
105129
|
case 'minority': {
|
|
104982
|
-
|
|
104983
|
-
|
|
104984
|
-
|
|
104985
|
-
|
|
104986
|
-
|
|
104987
|
-
|
|
105130
|
+
doPreprocessData(s);
|
|
105131
|
+
doAnalyzeDistricts(s);
|
|
105132
|
+
|
|
105133
|
+
let t1 = doMajorityMinorityDistricts(s);
|
|
105134
|
+
|
|
105135
|
+
doAnalyzePostProcessing(s);
|
|
105136
|
+
|
|
105137
|
+
// echoTestResult("Majority-Minority Districts:", t1); TODO
|
|
105138
|
+
|
|
105139
|
+
break;
|
|
104988
105140
|
}
|
|
105141
|
+
*/
|
|
104989
105142
|
// TODO - SCORE: Update this w/ scoring info
|
|
104990
105143
|
case 'analyze': {
|
|
104991
105144
|
s.analyzePlan(bLog);
|