@dra2020/district-analytics 4.2.0 → 4.3.2

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.
@@ -121,6 +121,7 @@ const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.t
121
121
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
122
122
  const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
123
123
  const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
124
+ // import { doConfigureScales, doAnalyzePostProcessing, RequirementsChecklist} from './results' // TODO - DELETE
124
125
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
125
126
  const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
126
127
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
@@ -131,7 +132,7 @@ class AnalyticsSession {
131
132
  this.bOneTimeProcessingDone = false;
132
133
  this.bPlanAnalyzed = false;
133
134
  this.bPostProcessingDone = false;
134
- this.testScales = {};
135
+ // testScales = {} as T.TestScales; TODO - DELETE
135
136
  this.tests = {};
136
137
  this.title = SessionRequest['title'];
137
138
  this.legislativeDistricts = SessionRequest['legislativeDistricts'];
@@ -142,19 +143,21 @@ class AnalyticsSession {
142
143
  this.features = new D.Features(this, SessionRequest['data'], this.config['datasets']);
143
144
  this.plan = new D.Plan(this, SessionRequest['plan']);
144
145
  this.districts = new D.Districts(this, SessionRequest['districtShapes']);
145
- // TODO - SCORE: Toggle
146
- if (this.useLegacy()) {
147
- console.log("Using legacy district-analytics.");
148
- // NOTE: I've pulled these out of the individual analytics to here. Eventually,
149
- // we could want them to passed into an analytics session as data, along with
150
- // everything else. For now, this keeps branching out of the main code.
151
- results_1.doConfigureScales(this);
152
- }
153
- else {
154
- console.log("Using dra-score analytics.");
155
- // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
156
- results_1.doConfigureScales(this);
157
- }
146
+ // TODO - DELETE
147
+ // if (this.useLegacy())
148
+ // {
149
+ // console.log("Using legacy district-analytics.")
150
+ // // NOTE: I've pulled these out of the individual analytics to here. Eventually,
151
+ // // we could want them to passed into an analytics session as data, along with
152
+ // // everything else. For now, this keeps branching out of the main code.
153
+ // doConfigureScales(this);
154
+ // }
155
+ // else
156
+ // {
157
+ // console.log("Using dra-score analytics.")
158
+ // // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
159
+ // doConfigureScales(this);
160
+ // }
158
161
  }
159
162
  processConfig(config) {
160
163
  // NOTE - Session settings are required:
@@ -167,13 +170,15 @@ class AnalyticsSession {
167
170
  config['cycle'] = 2010;
168
171
  return config;
169
172
  }
170
- // TODO - SCORE: Toggle = Invert this logic
171
- useLegacy() {
172
- // TODO - SCORE: Opt-out
173
- return (U.keyExists('useScore', this.config) && (this.config['useScore'] != null) && (!(this.config['useScore']))) ? true : false;
174
- // TODO - SCORE: Opt-in
175
- // return (U.keyExists('useScore', this.config) && (this.config['useScore'])) ? false : true;
173
+ /* TODO - DELETE
174
+ useLegacy(): boolean
175
+ {
176
+ // TODO - SCORE: Opt-out
177
+ return (U.keyExists('useScore', this.config) && (this.config['useScore'] != null) && (!(this.config['useScore']))) ? true : false;
178
+ // TODO - SCORE: Opt-in
179
+ // return (U.keyExists('useScore', this.config) && (this.config['useScore'])) ? false : true;
176
180
  }
181
+ */
177
182
  // Using the the data in the analytics session, calculate all the
178
183
  // analytics & validations, saving/updating the individual test results.
179
184
  analyzePlan(bLog = false, overridesJSON) {
@@ -305,19 +310,21 @@ class AnalyticsSession {
305
310
  }
306
311
  // NOTE - Not sure why this has to be up here ...
307
312
  populationDeviationThreshold() {
308
- // TODO - SCORE: Toggle
309
- if (this.useLegacy()) {
310
- return 1 - this.testScales[4 /* PopulationDeviation */]['scale'][0];
311
- }
312
- else {
313
- // NOTE - This assumes the plan has been profiled
314
- const scorer = new Score.Scorer();
315
- const popdev = scorer.populationDeviationThreshold(this.legislativeDistricts);
316
- return popdev;
317
- // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
318
- // NOTE - The plan may not have been scored yet, i.e., no scorecard yet.
319
- // return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
320
- }
313
+ // TODO - DELETE
314
+ // if (this.useLegacy())
315
+ // {
316
+ // return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
317
+ // }
318
+ // else
319
+ // {
320
+ // NOTE - This assumes the plan has been profiled
321
+ const scorer = new Score.Scorer();
322
+ const popdev = scorer.populationDeviationThreshold(this.legislativeDistricts);
323
+ return popdev;
324
+ // TODO - SCORE: Temporary HACK. Query dra-score for threshold.
325
+ // NOTE - The plan may not have been scored yet, i.e., no scorecard yet.
326
+ // return 1 - this.testScales[T.Test.PopulationDeviation]['scale'][0];
327
+ // }
321
328
  }
322
329
  }
323
330
  exports.AnalyticsSession = AnalyticsSession;
@@ -926,10 +933,22 @@ exports.Graph = Graph;
926
933
  Object.defineProperty(exports, "__esModule", { value: true });
927
934
  const valid_1 = __webpack_require__(/*! ./valid */ "./src/valid.ts");
928
935
  const equal_1 = __webpack_require__(/*! ./equal */ "./src/equal.ts");
929
- const compact_1 = __webpack_require__(/*! ./compact */ "./src/compact.ts");
936
+ // import { doPopulationDeviation, doHasEqualPopulations } from './equal'; TODO - DELETE
937
+ // import { doReock, doPolsbyPopper } from './compact'; TODO - DELETE
930
938
  const cohesive_1 = __webpack_require__(/*! ./cohesive */ "./src/cohesive.ts");
931
- const political_1 = __webpack_require__(/*! ./political */ "./src/political.ts");
932
- const minority_1 = __webpack_require__(/*! ./minority */ "./src/minority.ts");
939
+ /* TODO - DELETE
940
+ import
941
+ {
942
+ doFindCountiesSplitUnexpectedly, doFindSplitVTDs,
943
+ doCountySplitting, doDistrictSplitting
944
+ } from './cohesive';
945
+ import
946
+ {
947
+ doSeatsBias, doVotesBias,
948
+ doResponsiveness, doResponsiveDistricts, doEfficiencyGap
949
+ } from './political';
950
+ import { doMajorityMinorityDistricts } from './minority'
951
+ */
933
952
  // Compile district-level info for plan/map-level analytics
934
953
  function doAnalyzeDistricts(s, bLog = false) {
935
954
  s.districts.recalcStatistics(bLog);
@@ -941,58 +960,65 @@ exports.doAnalyzeDistricts = doAnalyzeDistricts;
941
960
  // NOTE - I could make this table-driven, but I'm thinking that the explicit
942
961
  // calls might make chunking for aync easier.
943
962
  function doAnalyzePlan(s, bLog = false) {
944
- // TODO - SCORE: Toggle
945
- if (s.useLegacy()) {
946
- // Disable most legacy analytics
947
- // Get the requested suites, and only execute those tests
948
- let requestedSuites = s.config['suites'];
949
- // Tests in the "Legal" suite, i.e., pass/ fail constraints
950
- if (requestedSuites.includes(0 /* Legal */)) {
951
- s.tests[0 /* Complete */] = valid_1.doIsComplete(s, bLog);
952
- s.tests[1 /* Contiguous */] = valid_1.doIsContiguous(s, bLog);
953
- s.tests[2 /* FreeOfHoles */] = valid_1.doIsFreeOfHoles(s, bLog);
954
- s.tests[4 /* PopulationDeviation */] = equal_1.doPopulationDeviation(s, bLog);
955
- // NOTE - I can't check whether a population deviation is legal or not, until
956
- // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
957
- // the given type of district (CD vs. LD). The EqualPopulation test is derived
958
- // from PopulationDeviation, as part of scorecard or test log preparation.
959
- // Create an empty test entry here though ...
960
- s.tests[3 /* EqualPopulation */] = s.getTest(3 /* EqualPopulation */);
961
- }
962
- // Tests in the "Fair" suite
963
- if (requestedSuites.includes(1 /* Fair */)) {
964
- s.tests[11 /* SeatsBias */] = political_1.doSeatsBias(s, bLog);
965
- s.tests[12 /* VotesBias */] = political_1.doVotesBias(s, bLog);
966
- s.tests[13 /* Responsiveness */] = political_1.doResponsiveness(s, bLog);
967
- s.tests[14 /* ResponsiveDistricts */] = political_1.doResponsiveDistricts(s, bLog);
968
- s.tests[15 /* EfficiencyGap */] = political_1.doEfficiencyGap(s, bLog);
969
- s.tests[16 /* MajorityMinorityDistricts */] = minority_1.doMajorityMinorityDistricts(s, bLog);
970
- }
971
- // Tests in the "Best" suite, i.e., criteria for better/worse
972
- if (requestedSuites.includes(2 /* Best */)) {
973
- s.tests[5 /* Reock */] = compact_1.doReock(s, bLog);
974
- s.tests[6 /* PolsbyPopper */] = compact_1.doPolsbyPopper(s, bLog);
975
- s.tests[7 /* UnexpectedCountySplits */] = cohesive_1.doFindCountiesSplitUnexpectedly(s, bLog);
976
- s.tests[10 /* VTDSplits */] = cohesive_1.doFindSplitVTDs(s, bLog);
977
- s.tests[8 /* CountySplitting */] = cohesive_1.doCountySplitting(s, bLog);
978
- s.tests[9 /* DistrictSplitting */] = cohesive_1.doDistrictSplitting(s, bLog);
979
- }
980
- }
981
- else {
982
- // TODO - SCORE: Except these. Continue to do these here vs. dra-score.
983
- s.tests[0 /* Complete */] = valid_1.doIsComplete(s, bLog);
984
- s.tests[1 /* Contiguous */] = valid_1.doIsContiguous(s, bLog);
985
- s.tests[2 /* FreeOfHoles */] = valid_1.doIsFreeOfHoles(s, bLog);
986
- s.tests[4 /* PopulationDeviation */] = equal_1.doPopulationDeviation(s, bLog);
987
- // NOTE - I can't check whether a population deviation is legal or not, until
988
- // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
989
- // the given type of district (CD vs. LD). The EqualPopulation test is derived
990
- // from PopulationDeviation, as part of scorecard or test log preparation.
991
- // Create an empty test entry here though ...
992
- s.tests[3 /* EqualPopulation */] = s.getTest(3 /* EqualPopulation */);
993
- s.tests[7 /* UnexpectedCountySplits */] = cohesive_1.doFindCountiesSplitUnexpectedly(s, bLog);
994
- s.tests[10 /* VTDSplits */] = cohesive_1.doFindSplitVTDs(s, bLog);
995
- }
963
+ // TODO - DELETE
964
+ // if (s.useLegacy())
965
+ // {
966
+ // // Disable most legacy analytics
967
+ // // Get the requested suites, and only execute those tests
968
+ // let requestedSuites = s.config['suites'];
969
+ // // Tests in the "Legal" suite, i.e., pass/ fail constraints
970
+ // if (requestedSuites.includes(T.Suite.Legal))
971
+ // {
972
+ // s.tests[T.Test.Complete] = doIsComplete(s, bLog);
973
+ // s.tests[T.Test.Contiguous] = doIsContiguous(s, bLog);
974
+ // s.tests[T.Test.FreeOfHoles] = doIsFreeOfHoles(s, bLog);
975
+ // // s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
976
+ // // NOTE - I can't check whether a population deviation is legal or not, until
977
+ // // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
978
+ // // the given type of district (CD vs. LD). The EqualPopulation test is derived
979
+ // // from PopulationDeviation, as part of scorecard or test log preparation.
980
+ // // Create an empty test entry here though ...
981
+ // s.tests[T.Test.EqualPopulation] = s.getTest(T.Test.EqualPopulation) as T.TestEntry;
982
+ // }
983
+ // // Tests in the "Fair" suite
984
+ // if (requestedSuites.includes(T.Suite.Fair))
985
+ // {
986
+ // /* TODO - DELETE
987
+ // s.tests[T.Test.SeatsBias] = doSeatsBias(s, bLog);
988
+ // s.tests[T.Test.VotesBias] = doVotesBias(s, bLog);
989
+ // s.tests[T.Test.Responsiveness] = doResponsiveness(s, bLog);
990
+ // s.tests[T.Test.ResponsiveDistricts] = doResponsiveDistricts(s, bLog);
991
+ // s.tests[T.Test.EfficiencyGap] = doEfficiencyGap(s, bLog);
992
+ // s.tests[T.Test.MajorityMinorityDistricts] = doMajorityMinorityDistricts(s, bLog);
993
+ // */
994
+ // }
995
+ // // Tests in the "Best" suite, i.e., criteria for better/worse
996
+ // if (requestedSuites.includes(T.Suite.Best))
997
+ // {
998
+ // // s.tests[T.Test.Reock] = doReock(s, bLog); TODO - DELETE
999
+ // // s.tests[T.Test.PolsbyPopper] = doPolsbyPopper(s, bLog); TODO - DELETE
1000
+ // s.tests[T.Test.UnexpectedCountySplits] = doFindCountiesSplitUnexpectedly(s, bLog);
1001
+ // s.tests[T.Test.VTDSplits] = doFindSplitVTDs(s, bLog);
1002
+ // // s.tests[T.Test.CountySplitting] = doCountySplitting(s, bLog); TODO - DELETE
1003
+ // // s.tests[T.Test.DistrictSplitting] = doDistrictSplitting(s, bLog); TODO - DELETE
1004
+ // }
1005
+ // }
1006
+ // else
1007
+ // {
1008
+ // TODO - SCORE: Except these. Continue to do these here vs. dra-score.
1009
+ s.tests[0 /* Complete */] = valid_1.doIsComplete(s, bLog);
1010
+ s.tests[1 /* Contiguous */] = valid_1.doIsContiguous(s, bLog);
1011
+ s.tests[2 /* FreeOfHoles */] = valid_1.doIsFreeOfHoles(s, bLog);
1012
+ // s.tests[T.Test.PopulationDeviation] = doPopulationDeviation(s, bLog); TODO - DELETE
1013
+ // NOTE - I can't check whether a population deviation is legal or not, until
1014
+ // the raw % is normalized. A zero (0) would mean "too much" / "not legal," for
1015
+ // the given type of district (CD vs. LD). The EqualPopulation test is derived
1016
+ // from PopulationDeviation, as part of scorecard or test log preparation.
1017
+ // Create an empty test entry here though ...
1018
+ s.tests[3 /* EqualPopulation */] = s.getTest(3 /* EqualPopulation */);
1019
+ s.tests[5 /* UnexpectedCountySplits */] = cohesive_1.doFindCountiesSplitUnexpectedly(s, bLog);
1020
+ s.tests[6 /* VTDSplits */] = cohesive_1.doFindSplitVTDs(s, bLog);
1021
+ // }
996
1022
  // Enable a Test Log and Scorecard to be generated
997
1023
  s.bPlanAnalyzed = true;
998
1024
  s.bPostProcessingDone = false;
@@ -1033,185 +1059,279 @@ var __importStar = (this && this.__importStar) || function (mod) {
1033
1059
  };
1034
1060
  Object.defineProperty(exports, "__esModule", { value: true });
1035
1061
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1036
- const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
1037
1062
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1063
+ // NOTE - The active code is below the long multi-line section to be deleted.
1064
+ /* TODO - DELETE
1038
1065
  // CALCULATE ENHANCED SQRT ENTROPY METRIC
1039
- function doCountySplitting(s, bLog = false) {
1040
- let test = s.getTest(8 /* CountySplitting */);
1041
- let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
1042
- let countyTotals = s.counties.totalPopulation;
1043
- let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
1044
- let f = calcCountyFractions(CxD, countyTotals);
1045
- let w = calcCountyWeights(countyTotals);
1046
- let SqEnt_DC = countySplitting(f, w, bLog);
1047
- let CxDreducedC = U.deepCopy(CxD);
1048
- reduceCSplits(CxDreducedC, districtTotals);
1049
- let fReduced = calcCountyFractions(CxDreducedC, countyTotals);
1050
- let wReduced = calcCountyWeights(countyTotals);
1051
- let SqEnt_DCreduced = countySplitting(fReduced, wReduced, bLog);
1052
- test['score'] = SqEnt_DCreduced;
1053
- test['details']['SqEnt_DC'] = SqEnt_DC;
1054
- return test;
1066
+
1067
+ export function doCountySplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
1068
+ {
1069
+ let test = s.getTest(T.Test.CountySplitting) as T.TestEntry;
1070
+
1071
+ let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
1072
+ let countyTotals = s.counties.totalPopulation;
1073
+ let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
1074
+
1075
+ let f = calcCountyFractions(CxD, countyTotals);
1076
+ let w = calcCountyWeights(countyTotals);
1077
+
1078
+ let SqEnt_DC = countySplitting(f, w, bLog);
1079
+
1080
+ let CxDreducedC = U.deepCopy(CxD);
1081
+ reduceCSplits(CxDreducedC, districtTotals);
1082
+
1083
+ let fReduced = calcCountyFractions(CxDreducedC, countyTotals);
1084
+ let wReduced = calcCountyWeights(countyTotals);
1085
+
1086
+ let SqEnt_DCreduced = countySplitting(fReduced, wReduced, bLog);
1087
+
1088
+ test['score'] = SqEnt_DCreduced;
1089
+ test['details']['SqEnt_DC'] = SqEnt_DC;
1090
+
1091
+ return test;
1055
1092
  }
1056
- exports.doCountySplitting = doCountySplitting;
1057
- function doDistrictSplitting(s, bLog = false) {
1058
- let test = s.getTest(9 /* DistrictSplitting */);
1059
- let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
1060
- let countyTotals = s.counties.totalPopulation;
1061
- let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
1062
- let g = calcDistrictFractions(CxD, districtTotals);
1063
- let x = calcDistrictWeights(districtTotals);
1064
- let SqEnt_CD = districtSplitting(g, x, bLog);
1065
- let CxDreducedD = U.deepCopy(CxD);
1066
- reduceDSplits(CxDreducedD, countyTotals);
1067
- let gReduced = calcDistrictFractions(CxDreducedD, districtTotals);
1068
- let xReduced = calcDistrictWeights(districtTotals);
1069
- let SqEnt_CDreduced = districtSplitting(gReduced, xReduced, bLog);
1070
- test['score'] = SqEnt_CDreduced;
1071
- test['details']['SqEnt_CD'] = SqEnt_CD;
1072
- return test;
1093
+
1094
+ export function doDistrictSplitting(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
1095
+ {
1096
+ let test = s.getTest(T.Test.DistrictSplitting) as T.TestEntry;
1097
+
1098
+ let CxD = s.districts.statistics[D.DistrictField.CountySplits].slice(0, -1);
1099
+ let countyTotals = s.counties.totalPopulation;
1100
+ let districtTotals = s.districts.statistics[D.DistrictField.TotalPop].slice(0, -1);
1101
+
1102
+ let g = calcDistrictFractions(CxD, districtTotals);
1103
+ let x = calcDistrictWeights(districtTotals);
1104
+
1105
+ let SqEnt_CD = districtSplitting(g, x, bLog);
1106
+
1107
+ let CxDreducedD = U.deepCopy(CxD);
1108
+ reduceDSplits(CxDreducedD, countyTotals);
1109
+
1110
+ let gReduced = calcDistrictFractions(CxDreducedD, districtTotals);
1111
+ let xReduced = calcDistrictWeights(districtTotals);
1112
+
1113
+ let SqEnt_CDreduced = districtSplitting(gReduced, xReduced, bLog);
1114
+
1115
+ test['score'] = SqEnt_CDreduced;
1116
+ test['details']['SqEnt_CD'] = SqEnt_CD;
1117
+
1118
+ return test;
1073
1119
  }
1074
- exports.doDistrictSplitting = doDistrictSplitting;
1120
+
1121
+
1075
1122
  // HELPERS
1076
- // Loop over all the county-district combos, skipping the virtual district 0
1123
+
1124
+ // Loop over all the county-district combos, skipping the virtual district 0
1077
1125
  // and virtual county 0.
1078
1126
  //
1079
1127
  // NOTE - The county-district splits and the county & district totals may all,
1080
1128
  // in general, be fractional/decimal numbers as opposed to integers, due to
1081
1129
  // dissaggregation & re-aggregation. Hence, comparisons need to approximate
1082
1130
  // equality.
1131
+
1083
1132
  // Consolidate districts (rows) consisting of just one county (column)
1084
1133
  // UP into the dummy district (0).
1085
- function reduceCSplits(CxDreducedC, districtTotals) {
1086
- let nD = CxDreducedC.length;
1087
- let nC = CxDreducedC[0].length;
1088
- for (let j = 1; j < nC; j++) {
1089
- for (let i = 1; i < nD; i++) {
1090
- let split_total = CxDreducedC[i][j];
1091
- if (split_total > 0) {
1092
- if (areRoughlyEqual(split_total, districtTotals[i])) {
1093
- CxDreducedC[0][j] += split_total;
1094
- CxDreducedC[i][j] = 0;
1095
- }
1096
- }
1134
+ function reduceCSplits(CxDreducedC: number[][], districtTotals: number[]): void
1135
+ {
1136
+ let nD = CxDreducedC.length;
1137
+ let nC = CxDreducedC[0].length;
1138
+
1139
+ for (let j = 1; j < nC; j++)
1140
+ {
1141
+ for (let i = 1; i < nD; i++)
1142
+ {
1143
+ let split_total = CxDreducedC[i][j];
1144
+
1145
+ if (split_total > 0)
1146
+ {
1147
+ if (areRoughlyEqual(split_total, districtTotals[i]))
1148
+ {
1149
+ CxDreducedC[0][j] += split_total;
1150
+ CxDreducedC[i][j] = 0;
1097
1151
  }
1152
+ }
1098
1153
  }
1154
+ }
1099
1155
  }
1156
+
1100
1157
  // Consolidate whole counties (columns) in a district (row) LEFT into the
1101
1158
  // dummy county (0).
1102
- function reduceDSplits(CxDreducedD, countyTotals) {
1103
- let nD = CxDreducedD.length;
1104
- let nC = CxDreducedD[0].length;
1105
- for (let i = 1; i < nD; i++) {
1106
- for (let j = 1; j < nC; j++) {
1107
- let split_total = CxDreducedD[i][j];
1108
- if (split_total > 0) {
1109
- if (areRoughlyEqual(split_total, countyTotals[j])) {
1110
- CxDreducedD[i][0] += split_total;
1111
- CxDreducedD[i][j] = 0;
1112
- }
1113
- }
1159
+ function reduceDSplits(CxDreducedD: number[][], countyTotals: number[]): void
1160
+ {
1161
+ let nD = CxDreducedD.length;
1162
+ let nC = CxDreducedD[0].length;
1163
+
1164
+ for (let i = 1; i < nD; i++)
1165
+ {
1166
+ for (let j = 1; j < nC; j++)
1167
+ {
1168
+ let split_total = CxDreducedD[i][j];
1169
+
1170
+ if (split_total > 0)
1171
+ {
1172
+ if (areRoughlyEqual(split_total, countyTotals[j]))
1173
+ {
1174
+ CxDreducedD[i][0] += split_total;
1175
+ CxDreducedD[i][j] = 0;
1114
1176
  }
1177
+ }
1115
1178
  }
1179
+ }
1116
1180
  }
1117
- function calcCountyWeights(countyTotals) {
1118
- let nC = countyTotals.length;
1119
- let cTotal = U.sumArray(countyTotals);
1120
- let w = U.initArray(nC, 0.0);
1121
- for (let j = 0; j < nC; j++) {
1122
- w[j] = countyTotals[j] / cTotal;
1123
- }
1124
- return w;
1125
- }
1126
- function calcDistrictWeights(districtTotals) {
1127
- let nD = districtTotals.length;
1128
- let dTotal = U.sumArray(districtTotals);
1129
- let x = U.initArray(nD, 0.0);
1130
- for (let i = 0; i < nD; i++) {
1131
- x[i] = districtTotals[i] / dTotal;
1132
- }
1133
- return x;
1134
- }
1135
- function calcCountyFractions(CxDreducedD, countyTotals) {
1136
- let nD = CxDreducedD.length;
1137
- let nC = CxDreducedD[0].length;
1138
- let f = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
1139
- for (let j = 0; j < nC; j++) {
1140
- for (let i = 0; i < nD; i++) {
1141
- if (countyTotals[j] > 0) {
1142
- f[i][j] = CxDreducedD[i][j] / countyTotals[j];
1143
- }
1144
- else {
1145
- f[i][j] = 0.0;
1146
- }
1147
- }
1181
+
1182
+ function calcCountyWeights(countyTotals: number[]): number[]
1183
+ {
1184
+ let nC: number = countyTotals.length;
1185
+ let cTotal: number = U.sumArray(countyTotals);
1186
+
1187
+ let w: number[] = U.initArray(nC, 0.0);
1188
+
1189
+ for (let j = 0; j < nC; j++)
1190
+ {
1191
+ w[j] = countyTotals[j] / cTotal;
1192
+ }
1193
+
1194
+ return w;
1195
+ }
1196
+
1197
+ function calcDistrictWeights(districtTotals: number[]): number[]
1198
+ {
1199
+ let nD = districtTotals.length;
1200
+ let dTotal: number = U.sumArray(districtTotals);
1201
+
1202
+ let x: number[] = U.initArray(nD, 0.0);
1203
+
1204
+ for (let i = 0; i < nD; i++)
1205
+ {
1206
+ x[i] = districtTotals[i] / dTotal;
1207
+ }
1208
+
1209
+ return x;
1210
+ }
1211
+
1212
+ function calcCountyFractions(CxDreducedD: number[][], countyTotals: number[]): number[][]
1213
+ {
1214
+ let nD = CxDreducedD.length;
1215
+ let nC = CxDreducedD[0].length;
1216
+
1217
+ let f: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
1218
+
1219
+ for (let j = 0; j < nC; j++)
1220
+ {
1221
+ for (let i = 0; i < nD; i++)
1222
+ {
1223
+ if (countyTotals[j] > 0)
1224
+ {
1225
+ f[i][j] = CxDreducedD[i][j] / countyTotals[j];
1226
+ }
1227
+ else
1228
+ {
1229
+ f[i][j] = 0.0;
1230
+ }
1148
1231
  }
1149
- return f;
1232
+ }
1233
+
1234
+ return f;
1150
1235
  }
1151
- function calcDistrictFractions(CxDreducedC, districtTotals) {
1152
- let nD = CxDreducedC.length;
1153
- let nC = CxDreducedC[0].length;
1154
- let g = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
1155
- for (let j = 0; j < nC; j++) {
1156
- for (let i = 0; i < nD; i++) {
1157
- if (districtTotals[i] > 0) {
1158
- g[i][j] = CxDreducedC[i][j] / districtTotals[i];
1159
- }
1160
- else {
1161
- g[i][j] = 0.0;
1162
- }
1163
- }
1236
+
1237
+ function calcDistrictFractions(CxDreducedC: number[][], districtTotals: number[]): number[][]
1238
+ {
1239
+ let nD = CxDreducedC.length;
1240
+ let nC = CxDreducedC[0].length;
1241
+
1242
+ let g: number[][] = new Array(nD).fill(0.0).map(() => new Array(nC).fill(0.0));
1243
+
1244
+ for (let j = 0; j < nC; j++)
1245
+ {
1246
+ for (let i = 0; i < nD; i++)
1247
+ {
1248
+ if (districtTotals[i] > 0)
1249
+ {
1250
+ g[i][j] = CxDreducedC[i][j] / districtTotals[i];
1251
+ }
1252
+ else
1253
+ {
1254
+ g[i][j] = 0.0;
1255
+ }
1164
1256
  }
1165
- return g;
1257
+ }
1258
+
1259
+ return g;
1166
1260
  }
1261
+
1167
1262
  // Deal with decimal census "counts" due to disagg/re-agg
1168
- function areRoughlyEqual(x, y) {
1169
- let delta = Math.abs(x - y);
1170
- let result = (delta < S.EQUAL_TOLERANCE) ? true : false;
1171
- return result;
1263
+ function areRoughlyEqual(x: number, y: number): boolean
1264
+ {
1265
+ let delta = Math.abs(x - y);
1266
+ let result = (delta < S.EQUAL_TOLERANCE) ? true : false;
1267
+
1268
+ return result;
1172
1269
  }
1270
+
1173
1271
  // For all districts in a county, sum the split score.
1174
- function countySplitScore(j, f, numD, bLog = false) {
1175
- let e = 0.0;
1176
- for (let i = 0; i < numD; i++) {
1177
- e += Math.sqrt(f[i][j]);
1178
- }
1179
- return e;
1272
+ function countySplitScore(j: number, f: number[][], numD: number, bLog: boolean = false): number
1273
+ {
1274
+ let e = 0.0;
1275
+
1276
+ for (let i = 0; i < numD; i++)
1277
+ {
1278
+ e += Math.sqrt(f[i][j]);
1279
+ }
1280
+
1281
+ return e;
1180
1282
  }
1283
+
1181
1284
  // For all counties, sum the weighted county splits.
1182
- function countySplitting(f, w, bLog = false) {
1183
- let numC = f[0].length;
1184
- let numD = f.length;
1185
- let e = 0.0;
1186
- for (let j = 0; j < numC; j++) {
1187
- let splitScore = countySplitScore(j, f, numD, bLog);
1188
- e += w[j] * splitScore;
1189
- if (bLog)
1190
- console.log("County splitting =", j, w[j], splitScore, e);
1191
- }
1192
- return U.trim(e, 3);
1285
+ function countySplitting(f: number[][], w: number[], bLog: boolean = false): number
1286
+ {
1287
+ let numC = f[0].length;
1288
+ let numD = f.length;
1289
+
1290
+ let e = 0.0;
1291
+
1292
+ for (let j = 0; j < numC; j++)
1293
+ {
1294
+ let splitScore = countySplitScore(j, f, numD, bLog);
1295
+ e += w[j] * splitScore;
1296
+
1297
+ if (bLog) console.log("County splitting =", j, w[j], splitScore, e);
1298
+ }
1299
+
1300
+ return U.trim(e, 3);
1193
1301
  }
1302
+
1194
1303
  // For all counties in a district, sum the split score.
1195
- function districtSplitScore(i, g, numC, bLog = false) {
1196
- let e = 0.0;
1197
- for (let j = 0; j < numC; j++) {
1198
- e += Math.sqrt(g[i][j]);
1199
- }
1200
- return e;
1304
+ function districtSplitScore(i: number, g: number[][], numC: number, bLog: boolean = false): number
1305
+ {
1306
+ let e = 0.0;
1307
+
1308
+ for (let j = 0; j < numC; j++)
1309
+ {
1310
+ e += Math.sqrt(g[i][j]);
1311
+ }
1312
+
1313
+ return e;
1201
1314
  }
1315
+
1202
1316
  // For all districts, sum the weighted district splits.
1203
- function districtSplitting(g, x, bLog = false) {
1204
- let numC = g[0].length;
1205
- let numD = g.length;
1206
- let e = 0.0;
1207
- for (let i = 0; i < numD; i++) {
1208
- let splitScore = districtSplitScore(i, g, numC, bLog);
1209
- e += x[i] * splitScore;
1210
- if (bLog)
1211
- console.log("District split score =", i, x[i], splitScore, e);
1212
- }
1213
- return U.trim(e, 3);
1317
+ function districtSplitting(g: number[][], x: number[], bLog: boolean = false): number
1318
+ {
1319
+ let numC = g[0].length;
1320
+ let numD = g.length;
1321
+
1322
+ let e = 0.0;
1323
+
1324
+ for (let i = 0; i < numD; i++)
1325
+ {
1326
+ let splitScore = districtSplitScore(i, g, numC, bLog);
1327
+ e += x[i] * splitScore;
1328
+
1329
+ if (bLog) console.log("District split score =", i, x[i], splitScore, e);
1330
+ }
1331
+
1332
+ return U.trim(e, 3);
1214
1333
  }
1334
+ */
1215
1335
  // ANALYZE SIMPLE COUNTY & VTD SPLITTING
1216
1336
  /*
1217
1337
 
@@ -1246,7 +1366,7 @@ These counties are split unexpectedly:
1246
1366
 
1247
1367
  */
1248
1368
  function doFindCountiesSplitUnexpectedly(s, bLog = false) {
1249
- let test = s.getTest(7 /* UnexpectedCountySplits */);
1369
+ let test = s.getTest(5 /* UnexpectedCountySplits */);
1250
1370
  // THE THREE VALUES TO DETERMINE FOR A PLAN
1251
1371
  let unexpectedSplits = 0;
1252
1372
  let unexpectedAffected = 0;
@@ -1339,10 +1459,10 @@ function doFindCountiesSplitUnexpectedly(s, bLog = false) {
1339
1459
  return test;
1340
1460
  }
1341
1461
  exports.doFindCountiesSplitUnexpectedly = doFindCountiesSplitUnexpectedly;
1462
+ // NOTE - This function just creates an empty container that dra-client fills in when generating the UI
1342
1463
  function doFindSplitVTDs(s, bLog = false) {
1343
- let test = s.getTest(10 /* VTDSplits */);
1464
+ let test = s.getTest(6 /* VTDSplits */);
1344
1465
  let splitVTDs = [];
1345
- // TODO - SPLITTING: Flesh this out, using virtual VTD's ...
1346
1466
  test['score'] = splitVTDs.length;
1347
1467
  test['details']['splitVTDs'] = splitVTDs;
1348
1468
  return test;
@@ -1372,10 +1492,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
1372
1492
  return result;
1373
1493
  };
1374
1494
  Object.defineProperty(exports, "__esModule", { value: true });
1495
+ // NOTE - This file will NOT be empty, when legacy code is deleted.
1375
1496
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "@dra2020/poly"));
1376
1497
  const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
1377
- const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1378
- // TODO - SCORE: Remove legacy code
1498
+ // TODO - DELETE
1379
1499
  // Measures of compactness compare district shapes to various ideally compact
1380
1500
  // benchmarks, such as circles. All else equal, more compact districts are better.
1381
1501
  //
@@ -1454,62 +1574,83 @@ const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1454
1574
  // For each measure, the compactness of a set of Congressional districts is the
1455
1575
  // average of that measure for all the districts.
1456
1576
  //
1577
+ /* TODO - DELETE
1457
1578
  // Calculate Reock compactness:
1458
1579
  // reock = (4 * a) / (math.pi * d**2)
1459
1580
  // NOTE - Depends on extractDistrictProperties running first
1460
- function doReock(s, bLog = false) {
1461
- let test = s.getTest(5 /* Reock */);
1462
- // Calculate Reock scores by district
1463
- let scores = [];
1464
- for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
1465
- let districtProps = s.districts.getGeoProperties(districtID);
1466
- // Guard against no shape and no properties
1467
- if (districtProps) {
1468
- let a = districtProps[0 /* Area */];
1469
- let d = districtProps[1 /* Diameter */];
1470
- let reock = (4 * a) / (Math.PI * Math.pow(d, 2));
1471
- // Save each district score
1472
- scores.push(reock);
1473
- // Echo the results by district
1474
- if (bLog)
1475
- console.log("Reock for district", districtID, "=", reock);
1476
- }
1581
+ export function doReock(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
1582
+ {
1583
+ let test = s.getTest(T.Test.Reock) as T.TestEntry;
1584
+
1585
+ // Calculate Reock scores by district
1586
+ let scores: number[] = [];
1587
+
1588
+ for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
1589
+ {
1590
+ let districtProps = s.districts.getGeoProperties(districtID);
1591
+ // Guard against no shape and no properties
1592
+ if (districtProps)
1593
+ {
1594
+ let a = districtProps[T.DistrictShapeProperty.Area];
1595
+ let d = districtProps[T.DistrictShapeProperty.Diameter];
1596
+
1597
+ let reock = (4 * a) / (Math.PI * d ** 2);
1598
+
1599
+ // Save each district score
1600
+ scores.push(reock);
1601
+
1602
+ // Echo the results by district
1603
+ if (bLog) console.log("Reock for district", districtID, "=", reock);
1477
1604
  }
1478
- // Populate the test entry ... for the shapes that exist!
1479
- let averageReock = U.avgArray(scores);
1480
- test['score'] = U.trim(averageReock);
1481
- test['details'] = {}; // TODO - Any details?
1482
- return test;
1605
+ }
1606
+
1607
+ // Populate the test entry ... for the shapes that exist!
1608
+ let averageReock = U.avgArray(scores);
1609
+
1610
+ test['score'] = U.trim(averageReock);
1611
+ test['details'] = {}; // TODO - Any details?
1612
+
1613
+ return test;
1483
1614
  }
1484
- exports.doReock = doReock;
1615
+
1485
1616
  // Calculate Polsby-Popper compactness measures:
1486
1617
  // polsby_popper = (4 * math.pi) * (a / p**2)
1487
1618
  // NOTE - Depends on extractDistrictProperties running first
1488
- function doPolsbyPopper(s, bLog = false) {
1489
- let test = s.getTest(6 /* PolsbyPopper */);
1490
- // Calculate Polsby-Popper scores by district
1491
- let scores = [];
1492
- for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
1493
- let districtProps = s.districts.getGeoProperties(districtID);
1494
- // Guard against no shape and no properties
1495
- if (districtProps) {
1496
- let a = districtProps[0 /* Area */];
1497
- let p = districtProps[2 /* Perimeter */];
1498
- let polsbyPopper = (4 * Math.PI) * (a / Math.pow(p, 2));
1499
- // Save each district score
1500
- scores.push(polsbyPopper);
1501
- // Echo the results by district
1502
- if (bLog)
1503
- console.log("Polsby-Popper for district", districtID, "=", polsbyPopper);
1504
- }
1619
+ export function doPolsbyPopper(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
1620
+ {
1621
+ let test = s.getTest(T.Test.PolsbyPopper) as T.TestEntry;
1622
+
1623
+ // Calculate Polsby-Popper scores by district
1624
+ let scores: number[] = [];
1625
+
1626
+ for (let districtID = 1; districtID <= s.state.nDistricts; districtID++)
1627
+ {
1628
+ let districtProps = s.districts.getGeoProperties(districtID);
1629
+ // Guard against no shape and no properties
1630
+ if (districtProps)
1631
+ {
1632
+ let a = districtProps[T.DistrictShapeProperty.Area];
1633
+ let p = districtProps[T.DistrictShapeProperty.Perimeter];
1634
+
1635
+ let polsbyPopper = (4 * Math.PI) * (a / p ** 2);
1636
+
1637
+ // Save each district score
1638
+ scores.push(polsbyPopper);
1639
+
1640
+ // Echo the results by district
1641
+ if (bLog) console.log("Polsby-Popper for district", districtID, "=", polsbyPopper);
1505
1642
  }
1506
- // Populate the test entry ... for the shapes that exist!
1507
- let averagePolsbyPopper = U.avgArray(scores);
1508
- test['score'] = U.trim(averagePolsbyPopper);
1509
- test['details'] = {}; // TODO - Any details?
1510
- return test;
1643
+ }
1644
+
1645
+ // Populate the test entry ... for the shapes that exist!
1646
+ let averagePolsbyPopper = U.avgArray(scores);
1647
+
1648
+ test['score'] = U.trim(averagePolsbyPopper);
1649
+ test['details'] = {}; // TODO - Any details?
1650
+
1651
+ return test;
1511
1652
  }
1512
- exports.doPolsbyPopper = doPolsbyPopper;
1653
+ */
1513
1654
  // HELPER TO EXTRACT PROPERTIES OF DISTRICT SHAPES
1514
1655
  // TODO - SCORE: Create an array, as opposed to a dict
1515
1656
  function extractDistrictProperties(s, bLog = false) {
@@ -1587,41 +1728,53 @@ var __importStar = (this && this.__importStar) || function (mod) {
1587
1728
  return result;
1588
1729
  };
1589
1730
  Object.defineProperty(exports, "__esModule", { value: true });
1590
- const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1591
1731
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1592
- // TODO - SCORE: Delete
1593
- function doPopulationDeviation(s, bLog = false) {
1594
- let test = s.getTest(4 /* PopulationDeviation */);
1595
- let targetSize = s.state.totalPop / s.state.nDistricts;
1596
- // Compute the min & max district populations
1597
- // ... excluding the dummy the 'unassigned' 0 and N+1 summary "districts"
1598
- let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
1599
- totPopByDistrict = totPopByDistrict.slice(1, -1);
1600
- // Remove empty districts
1601
- totPopByDistrict = totPopByDistrict.filter(x => x > 0);
1602
- let min = 0;
1603
- let max = 0;
1604
- // If there's more than 1 non-empty district, calculate a non-zero deviation
1605
- if (totPopByDistrict.length > 1) {
1606
- min = U.minArray(totPopByDistrict);
1607
- max = U.maxArray(totPopByDistrict);
1608
- }
1609
- // Calculate the raw population deviation
1610
- let popDev = (max - min) / targetSize;
1611
- // Round the raw value to the desired level of precision
1612
- popDev = U.trim(popDev);
1613
- // Populate the test entry
1614
- test['score'] = popDev;
1615
- test['details'] = { 'maxDeviation': max - min };
1616
- // Populate the N+1 summary "district" in district.statistics
1617
- let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
1618
- let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
1619
- let summaryRow = s.districts.numberOfRows() - 1;
1620
- totalPop[summaryRow] = targetSize;
1621
- popDevPct[summaryRow] = popDev;
1622
- return test;
1732
+ /* TODO - DELETE
1733
+ export function doPopulationDeviation(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
1734
+ {
1735
+ let test = s.getTest(T.Test.PopulationDeviation) as T.TestEntry;
1736
+
1737
+ let targetSize = s.state.totalPop / s.state.nDistricts;
1738
+
1739
+ // Compute the min & max district populations
1740
+ // ... excluding the dummy the 'unassigned' 0 and N+1 summary "districts"
1741
+ let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
1742
+ totPopByDistrict = totPopByDistrict.slice(1, -1);
1743
+
1744
+ // Remove empty districts
1745
+ totPopByDistrict = totPopByDistrict.filter(x => x > 0);
1746
+
1747
+ let min = 0;
1748
+ let max = 0;
1749
+
1750
+ // If there's more than 1 non-empty district, calculate a non-zero deviation
1751
+ if (totPopByDistrict.length > 1)
1752
+ {
1753
+ min = U.minArray(totPopByDistrict);
1754
+ max = U.maxArray(totPopByDistrict);
1755
+ }
1756
+
1757
+ // Calculate the raw population deviation
1758
+ let popDev = (max - min) / targetSize;
1759
+
1760
+ // Round the raw value to the desired level of precision
1761
+ popDev = U.trim(popDev);
1762
+
1763
+ // Populate the test entry
1764
+ test['score'] = popDev;
1765
+ test['details'] = { 'maxDeviation': max - min };
1766
+
1767
+ // Populate the N+1 summary "district" in district.statistics
1768
+ let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
1769
+ let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
1770
+ let summaryRow = s.districts.numberOfRows() - 1;
1771
+
1772
+ totalPop[summaryRow] = targetSize;
1773
+ popDevPct[summaryRow] = popDev;
1774
+
1775
+ return test;
1623
1776
  }
1624
- exports.doPopulationDeviation = doPopulationDeviation;
1777
+ */
1625
1778
  // NOTE - This validity check is *derived* and depends on population deviation %
1626
1779
  // being computed (above) and normalized in test log & scorecard generation.
1627
1780
  function doHasEqualPopulations(s, bLog = false) {
@@ -1671,7 +1824,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
1671
1824
  };
1672
1825
  Object.defineProperty(exports, "__esModule", { value: true });
1673
1826
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "@dra2020/poly"));
1674
- // TODO - SCORE: Remove legacy code
1675
1827
  // HELPER
1676
1828
  function polyParts(poly) {
1677
1829
  let parts = { type: 'FeatureCollection', features: [] };
@@ -1810,35 +1962,6 @@ __export(__webpack_require__(/*! ./results */ "./src/results.ts"));
1810
1962
  __export(__webpack_require__(/*! ./types */ "./src/types.ts"));
1811
1963
 
1812
1964
 
1813
- /***/ }),
1814
-
1815
- /***/ "./src/minority.ts":
1816
- /*!*************************!*\
1817
- !*** ./src/minority.ts ***!
1818
- \*************************/
1819
- /*! no static exports found */
1820
- /***/ (function(module, exports, __webpack_require__) {
1821
-
1822
- "use strict";
1823
-
1824
- //
1825
- // PROTECTS MINORITIES
1826
- //
1827
- Object.defineProperty(exports, "__esModule", { value: true });
1828
- // TODO - SCORE: Remove legacy code
1829
- function doMajorityMinorityDistricts(s, bLog = false) {
1830
- let test = s.getTest(16 /* MajorityMinorityDistricts */);
1831
- if (bLog)
1832
- console.log("TODO - Calculating # of majority-minority districts ...");
1833
- return test;
1834
- }
1835
- exports.doMajorityMinorityDistricts = doMajorityMinorityDistricts;
1836
- // Sources for majority-minority info:
1837
- // - https://en.wikipedia.org/wiki/List_of_majority-minority_United_States_congressional_districts
1838
- // TODO - 2020: Update/revise this, when the update comes out in September:
1839
- // - http://www.ncsl.org/Portals/1/Documents/Redistricting/Redistricting_2010.pdf
1840
-
1841
-
1842
1965
  /***/ }),
1843
1966
 
1844
1967
  /***/ "./src/political.ts":
@@ -1853,18 +1976,14 @@ exports.doMajorityMinorityDistricts = doMajorityMinorityDistricts;
1853
1976
  //
1854
1977
  // FAIR/PROPORTIONAL
1855
1978
  //
1856
- var __importStar = (this && this.__importStar) || function (mod) {
1857
- if (mod && mod.__esModule) return mod;
1858
- var result = {};
1859
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
1860
- result["default"] = mod;
1861
- return result;
1862
- };
1863
1979
  Object.defineProperty(exports, "__esModule", { value: true });
1980
+ // NOTE - This file will NOT be empty, when legacy code is deleted.
1864
1981
  const assert_1 = __webpack_require__(/*! assert */ "assert");
1865
- const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1866
- const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1867
- // TODO - SCORE: Remove legacy code
1982
+ /* TODO - DELETE
1983
+ import * as D from './_data'
1984
+ import { AnalyticsSession } from './_api';
1985
+
1986
+
1868
1987
  // Partisan analytics need the following data:
1869
1988
  //
1870
1989
  // An "election model" by geo_id, where each item has 4 pieces of data:
@@ -1883,66 +2002,89 @@ const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1883
2002
  //
1884
2003
  // I'm labelling this general concept a "Voter Preference Index (VPI)," a
1885
2004
  // conscious +1 letter play on Cook's "PVI" acronymn.
2005
+
2006
+
1886
2007
  // MEASURING BIAS & RESPONSIVENESS (NAGLE'S METHOD)
1887
- function doSeatsBias(s, bLog = false) {
1888
- let test = s.getTest(11 /* SeatsBias */);
1889
- if (bLog)
1890
- console.log("TODO - Calculating seats bias ...");
1891
- return test;
2008
+
2009
+ export function doSeatsBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
2010
+ {
2011
+ let test = s.getTest(T.Test.SeatsBias) as T.TestEntry;
2012
+
2013
+ if (bLog) console.log("TODO - Calculating seats bias ...");
2014
+
2015
+ return test;
1892
2016
  }
1893
- exports.doSeatsBias = doSeatsBias;
1894
- function doVotesBias(s, bLog = false) {
1895
- let test = s.getTest(12 /* VotesBias */);
1896
- if (bLog)
1897
- console.log("TODO - Calculating votes bias ...");
1898
- return test;
2017
+
2018
+ export function doVotesBias(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
2019
+ {
2020
+ let test = s.getTest(T.Test.VotesBias) as T.TestEntry;
2021
+
2022
+ if (bLog) console.log("TODO - Calculating votes bias ...");
2023
+
2024
+ return test;
1899
2025
  }
1900
- exports.doVotesBias = doVotesBias;
1901
- function doResponsiveness(s, bLog = false) {
1902
- let test = s.getTest(13 /* Responsiveness */);
1903
- if (bLog)
1904
- console.log("TODO - Calculating responsiveness ...");
1905
- return test;
2026
+
2027
+ export function doResponsiveness(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
2028
+ {
2029
+ let test = s.getTest(T.Test.Responsiveness) as T.TestEntry;
2030
+
2031
+ if (bLog) console.log("TODO - Calculating responsiveness ...");
2032
+
2033
+ return test;
1906
2034
  }
1907
- exports.doResponsiveness = doResponsiveness;
1908
- function doResponsiveDistricts(s, bLog = false) {
1909
- let test = s.getTest(14 /* ResponsiveDistricts */);
1910
- if (bLog)
1911
- console.log("TODO - Calculating # of responsive districts ...");
1912
- return test;
2035
+
2036
+ export function doResponsiveDistricts(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
2037
+ {
2038
+ let test = s.getTest(T.Test.ResponsiveDistricts) as T.TestEntry;
2039
+
2040
+ if (bLog) console.log("TODO - Calculating # of responsive districts ...");
2041
+
2042
+ return test;
1913
2043
  }
1914
- exports.doResponsiveDistricts = doResponsiveDistricts;
2044
+
2045
+
1915
2046
  // OTHER MEASURES OF PARTISAN BIAS
2047
+
1916
2048
  // TODO - PARTISAN: This formula might need to be inverted for D vs. R +/-
1917
2049
  // TODO - Normalize the results.
1918
- function doEfficiencyGap(s, bLog = false) {
1919
- if (bLog)
1920
- console.log("TODO - Calculating the efficiency gap ...");
1921
- let test = s.getTest(15 /* EfficiencyGap */);
1922
- // Get partisan statistics by districts.
1923
- // Use Democratic votes, seats, and shares by convention.
1924
- let DVotes = s.districts.statistics[D.DistrictField.DemVotes];
1925
- let DSeats = s.districts.statistics[D.DistrictField.DemSeat];
1926
- let TPVotes = s.districts.statistics[D.DistrictField.TwoPartyVote];
1927
- // Exclude the dummy unassigned '0' and N+1 summary "districts"
1928
- DVotes = DVotes.slice(1, -1);
1929
- DSeats = DSeats.slice(1, -1);
1930
- TPVotes = TPVotes.slice(1, -1);
1931
- // Calculate D vote share & D seat share
1932
- let DVoteShare = U.sumArray(DVotes) / U.sumArray(TPVotes);
1933
- let DSeatShare = U.sumArray(DSeats) / s.state.nDistricts;
1934
- // Finally, calculate the Efficiency Gap
1935
- let efficiencyGap = (DSeatShare - 0.5) - (2.0 * (DVoteShare - 0.5));
1936
- // Round the raw value to the desired level of precision
1937
- efficiencyGap = U.trim(efficiencyGap);
1938
- // Populate the test entry
1939
- test['score'] = efficiencyGap;
1940
- // test['normalizedScore'] = 0; /* TODO - Normalize the raw score */
1941
- test['details'] = {}; /* TODO - Add details, if any */
1942
- return test;
2050
+ export function doEfficiencyGap(s: AnalyticsSession, bLog: boolean = false): T.TestEntry
2051
+ {
2052
+ if (bLog) console.log("TODO - Calculating the efficiency gap ...");
2053
+
2054
+ let test = s.getTest(T.Test.EfficiencyGap) as T.TestEntry;
2055
+
2056
+ // Get partisan statistics by districts.
2057
+ // Use Democratic votes, seats, and shares by convention.
2058
+ let DVotes = s.districts.statistics[D.DistrictField.DemVotes];
2059
+ let DSeats = s.districts.statistics[D.DistrictField.DemSeat];
2060
+ let TPVotes = s.districts.statistics[D.DistrictField.TwoPartyVote];
2061
+
2062
+ // Exclude the dummy unassigned '0' and N+1 summary "districts"
2063
+ DVotes = DVotes.slice(1, -1);
2064
+ DSeats = DSeats.slice(1, -1);
2065
+ TPVotes = TPVotes.slice(1, -1);
2066
+
2067
+ // Calculate D vote share & D seat share
2068
+ let DVoteShare = U.sumArray(DVotes) / U.sumArray(TPVotes);
2069
+ let DSeatShare = U.sumArray(DSeats) / s.state.nDistricts;
2070
+
2071
+ // Finally, calculate the Efficiency Gap
2072
+ let efficiencyGap = (DSeatShare - 0.5) - (2.0 * (DVoteShare - 0.5));
2073
+
2074
+ // Round the raw value to the desired level of precision
2075
+ efficiencyGap = U.trim(efficiencyGap);
2076
+
2077
+ // Populate the test entry
2078
+ test['score'] = efficiencyGap;
2079
+ // test['normalizedScore'] = 0; // TODO - Normalize the raw score
2080
+ test['details'] = {}; // TODO - Add details, if any
2081
+
2082
+ return test;
1943
2083
  }
1944
- exports.doEfficiencyGap = doEfficiencyGap;
2084
+
2085
+
1945
2086
  // HELPERS
2087
+ */
1946
2088
  function fptpWin(demPct) {
1947
2089
  // Vote shares should be fractions in the range [0.0 – 1.0]
1948
2090
  assert_1.strict((demPct <= 1.0) && (demPct >= 0.));
@@ -2548,24 +2690,26 @@ const populationDeviationDefn = {
2548
2690
  externalType: TestType.Percentage,
2549
2691
  suites: [0 /* Legal */, 2 /* Best */] // Both so EqualPopulation can be assessed
2550
2692
  };
2551
- // TODO - SCORE: Comment these out ...
2552
- const reockDefn = {
2553
- ID: 5 /* Reock */,
2554
- name: "Reock",
2555
- normalize: true,
2556
- externalType: TestType.Number,
2557
- suites: [2 /* Best */]
2693
+ /* TODO - DELETE
2694
+ const reockDefn: T.Dict = {
2695
+ ID: T.Test.Reock,
2696
+ name: "Reock",
2697
+ normalize: true,
2698
+ externalType: TestType.Number,
2699
+ suites: [T.Suite.Best]
2558
2700
  };
2559
- const polsbyPopperDefn = {
2560
- ID: 6 /* PolsbyPopper */,
2561
- name: "Polsby-Popper",
2562
- normalize: true,
2563
- externalType: TestType.Number,
2564
- suites: [2 /* Best */]
2701
+
2702
+ const polsbyPopperDefn: T.Dict = {
2703
+ ID: T.Test.PolsbyPopper,
2704
+ name: "Polsby-Popper",
2705
+ normalize: true,
2706
+ externalType: TestType.Number,
2707
+ suites: [T.Suite.Best]
2565
2708
  };
2709
+ */
2566
2710
  // NOTE - SPLITTING
2567
2711
  const unexpectedCountySplitsDefn = {
2568
- ID: 7 /* UnexpectedCountySplits */,
2712
+ ID: 5 /* UnexpectedCountySplits */,
2569
2713
  name: "Unexpected County Splits",
2570
2714
  normalize: false,
2571
2715
  externalType: TestType.Percentage,
@@ -2573,35 +2717,12 @@ const unexpectedCountySplitsDefn = {
2573
2717
  };
2574
2718
  // NOTE - SPLITTING
2575
2719
  const VTDSplitsDefn = {
2576
- ID: 10 /* VTDSplits */,
2720
+ ID: 6 /* VTDSplits */,
2577
2721
  name: "VTD Splits",
2578
2722
  normalize: false,
2579
2723
  externalType: TestType.Number,
2580
2724
  suites: [2 /* Best */]
2581
2725
  };
2582
- // NOTE - SPLITTING
2583
- const countySplittingDefn = {
2584
- ID: 8 /* CountySplitting */,
2585
- name: "County Splitting",
2586
- normalize: true,
2587
- externalType: TestType.Number,
2588
- suites: [2 /* Best */]
2589
- };
2590
- // NOTE - SPLITTING
2591
- const districtSplittingDefn = {
2592
- ID: 9 /* DistrictSplitting */,
2593
- name: "District Splitting",
2594
- normalize: true,
2595
- externalType: TestType.Number,
2596
- suites: [2 /* Best */]
2597
- };
2598
- const efficiencyGapDefn = {
2599
- ID: 15 /* EfficiencyGap */,
2600
- name: "Efficiency Gap",
2601
- normalize: false,
2602
- externalType: TestType.Percentage,
2603
- suites: [1 /* Fair */]
2604
- };
2605
2726
  // All the tests that have been defined (can be reported on)
2606
2727
  const testDefns = {
2607
2728
  [0 /* Complete */]: completeDefn,
@@ -2609,94 +2730,103 @@ const testDefns = {
2609
2730
  [2 /* FreeOfHoles */]: freeOfHolesDefn,
2610
2731
  [3 /* EqualPopulation */]: equalPopulationDefn,
2611
2732
  [4 /* PopulationDeviation */]: populationDeviationDefn,
2612
- [5 /* Reock */]: reockDefn,
2613
- [6 /* PolsbyPopper */]: polsbyPopperDefn,
2614
- // NOTE - SPLITTING
2615
- [7 /* UnexpectedCountySplits */]: unexpectedCountySplitsDefn,
2616
- [10 /* VTDSplits */]: VTDSplitsDefn,
2617
- [8 /* CountySplitting */]: countySplittingDefn,
2618
- [9 /* DistrictSplitting */]: districtSplittingDefn,
2619
- // TODO - More tests ...
2620
- [15 /* EfficiencyGap */]: efficiencyGapDefn
2733
+ // [T.Test.Reock]: reockDefn, TODO - DELETE
2734
+ // [T.Test.PolsbyPopper]: polsbyPopperDefn, TODO - DELETE
2735
+ [5 /* UnexpectedCountySplits */]: unexpectedCountySplitsDefn,
2736
+ [6 /* VTDSplits */]: VTDSplitsDefn,
2621
2737
  };
2738
+ /* TODO - DELETE
2622
2739
  // NORMALIZE RAW ANALYTICS
2623
2740
  // Raw numeric analytics, such as population deviation, compactness, etc. are
2624
2741
  // normalized as part of creating a scorecard, so the code to normalize results
2625
2742
  // is encapsulated here.
2743
+
2626
2744
  // Configure scale parameters for normalizing each raw test result.
2627
2745
  // Scales consist of a minimum & a maximum *raw* value. If the values get
2628
2746
  // inverted (to make bigger better), these will switch.
2629
2747
  // This process needs to be separate from the test configuration info above,
2630
2748
  // because some scales need access to the analytics session object.
2631
- function doConfigureScales(s) {
2632
- // Scale defn for PopulationDeviation
2633
- const CDLimit = 0.75 / 100; // Deviation threshold for CD's
2634
- const LDLimit = 10.00 / 100; // Deviation threshold for LD's
2635
- const CDGoodEnough = 0.20 / 100;
2636
- const LDGoodEnough = (CDGoodEnough / CDLimit) * LDLimit;
2637
- const popDevScale = (s.legislativeDistricts) ? [1.0 - LDLimit, 1.0 - LDGoodEnough] : [1.0 - CDLimit, 1.0 - CDGoodEnough];
2638
- // const scale = [1.0 - CDLimit, 1.0 - CDGoodEnough];
2639
- s.testScales[4 /* PopulationDeviation */] = { scale: popDevScale, bInvertRaw: true };
2640
- s.testScales[5 /* Reock */] = { scale: [0.25, 0.50] };
2641
- s.testScales[6 /* PolsbyPopper */] = { scale: [0.10, 0.50] };
2642
- const nDistricts = s.state.nDistricts;
2643
- const nCounties = s.counties.nCounties;
2644
- // NOTE - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
2645
- // number of county splits seems too stringent, empirically.
2646
- const allowableCountySplitsMultiplier = 1.5;
2647
- const nAllowableSplits = Math.min(allowableCountySplitsMultiplier * (nDistricts - 1));
2648
- const countySplittingThreshold = ((nAllowableSplits * 1.71) + ((nCounties - nAllowableSplits) * 1.0)) / nCounties;
2649
- const countySplittingScale = [1.0, countySplittingThreshold];
2650
- s.testScales[8 /* CountySplitting */] = { scale: countySplittingScale, bInvertScaled: true };
2651
- const districtSplittingThreshold = 1.5;
2652
- const districtSplittingScale = [1.0, districtSplittingThreshold];
2653
- s.testScales[9 /* DistrictSplitting */] = { scale: districtSplittingScale, bInvertScaled: true };
2654
- // TODO - More analytics ...
2655
- }
2656
- exports.doConfigureScales = doConfigureScales;
2749
+ export function doConfigureScales(s: AnalyticsSession): void
2750
+ {
2751
+ // Scale defn for PopulationDeviation
2752
+ const CDLimit = 0.75 / 100; // Deviation threshold for CD's
2753
+ const LDLimit = 10.00 / 100; // Deviation threshold for LD's
2754
+
2755
+ const CDGoodEnough = 0.20 / 100;
2756
+ const LDGoodEnough = (CDGoodEnough / CDLimit) * LDLimit;
2757
+ const popDevScale = (s.legislativeDistricts) ? [1.0 - LDLimit, 1.0 - LDGoodEnough] : [1.0 - CDLimit, 1.0 - CDGoodEnough];
2758
+ // const scale = [1.0 - CDLimit, 1.0 - CDGoodEnough];
2759
+
2760
+ s.testScales[T.Test.PopulationDeviation] = { scale: popDevScale, bInvertRaw: true };
2761
+
2762
+ s.testScales[T.Test.Reock] = { scale: [0.25, 0.50] };
2763
+ s.testScales[T.Test.PolsbyPopper] = { scale: [0.10, 0.50] };
2764
+
2765
+ const nDistricts = s.state.nDistricts;
2766
+ const nCounties = s.counties.nCounties;
2767
+
2768
+ // NOTE - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
2769
+ // number of county splits seems too stringent, empirically.
2770
+ const allowableCountySplitsMultiplier = 1.5;
2771
+ const nAllowableSplits = Math.min(allowableCountySplitsMultiplier * (nDistricts - 1));
2772
+ const countySplittingThreshold = ((nAllowableSplits * 1.71) + ((nCounties - nAllowableSplits) * 1.0)) / nCounties;
2773
+ const countySplittingScale = [1.0, countySplittingThreshold];
2774
+ s.testScales[T.Test.CountySplitting] = { scale: countySplittingScale, bInvertScaled: true };
2775
+
2776
+ const districtSplittingThreshold = 1.5;
2777
+ const districtSplittingScale = [1.0, districtSplittingThreshold];
2778
+ s.testScales[T.Test.DistrictSplitting] = { scale: districtSplittingScale, bInvertScaled: true };
2779
+
2780
+ // TODO - More analytics ...
2781
+ }
2782
+ */
2657
2783
  // Postprocess analytics - Normalize numeric results and derive secondary tests.
2658
2784
  // Do this after analytics have been run and before preparing a test log or scorecard.
2659
2785
  function doAnalyzePostProcessing(s, bLog = false) {
2660
- // TODO - SCORE: Toggle
2661
- if (s.useLegacy()) {
2662
- // Normalize the raw scores for all the numerics tests
2663
- let testResults = U.getNumericObjectKeys(testDefns);
2664
- for (let testID of testResults) {
2665
- if (testDefns[testID]['normalize']) {
2666
- let testResult = s.getTest(testID);
2667
- let rawScore = testResult['score'];
2668
- let normalizedScore;
2669
- normalizedScore = U.normalize(rawScore, s.testScales[testID]);
2670
- testResult['normalizedScore'] = normalizedScore;
2671
- // Add the scale used to normalize the raw score to the details
2672
- testResult['details']['scale'] = s.testScales[testID].scale;
2673
- }
2674
- }
2675
- }
2676
- else {
2677
- // Just populate the normalized population deviation score in the test
2678
- const scorecard = s._scorecard;
2679
- let popDev = s.getTest(4 /* PopulationDeviation */);
2680
- popDev['normalizedScore'] = scorecard.traditionalPrinciples.populationDeviation.normalized;
2681
- // TODO - DELETE
2682
- // test['normalizedScore'] = scorecard.best.populationDeviation.normalized;
2683
- // TODO - SCORE: Add datasets used to details by tab
2684
- const datasets = {
2685
- shapes: S.SHAPES,
2686
- census: U.deepCopy(s.config['descriptions']['CENSUS']),
2687
- vap: U.deepCopy(s.config['descriptions']['VAP']),
2688
- election: U.deepCopy(s.config['descriptions']['ELECTION'])
2689
- };
2690
- scorecard.partisan.details['election'] = datasets.election;
2691
- scorecard.minority.details['vap'] = datasets.vap;
2692
- scorecard.traditionalPrinciples.details['shapes'] = datasets.shapes;
2693
- scorecard.traditionalPrinciples.details['census'] = datasets.census;
2694
- // TODO - SCORE: Add legacy splits details
2695
- const simpleSplits = s.getTest(7 /* UnexpectedCountySplits */);
2696
- scorecard.traditionalPrinciples.details['unexpectedAffected'] = simpleSplits['score'];
2697
- scorecard.traditionalPrinciples.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
2698
- // NOTE - Add split precincts in dra-client directly
2699
- }
2786
+ // TODO - DELETE
2787
+ // if (s.useLegacy())
2788
+ // {
2789
+ // // Normalize the raw scores for all the numerics tests
2790
+ // let testResults = U.getNumericObjectKeys(testDefns);
2791
+ // for (let testID of testResults)
2792
+ // {
2793
+ // if (testDefns[testID]['normalize'])
2794
+ // {
2795
+ // let testResult = s.getTest(testID) as T.TestEntry;
2796
+ // let rawScore = testResult['score'] as number;
2797
+ // let normalizedScore: number;
2798
+ // normalizedScore = U.normalize(rawScore, s.testScales[testID]);
2799
+ // testResult['normalizedScore'] = normalizedScore;
2800
+ // // Add the scale used to normalize the raw score to the details
2801
+ // testResult['details']['scale'] = s.testScales[testID].scale;
2802
+ // }
2803
+ // }
2804
+ // }
2805
+ // else
2806
+ // {
2807
+ // Just populate the normalized population deviation score in the test
2808
+ const scorecard = s._scorecard;
2809
+ let popDev = s.getTest(4 /* PopulationDeviation */);
2810
+ popDev['normalizedScore'] = scorecard.traditionalPrinciples.populationDeviation.normalized;
2811
+ // TODO - DELETE
2812
+ // test['normalizedScore'] = scorecard.best.populationDeviation.normalized;
2813
+ // TODO - SCORE: Add datasets used to details by tab
2814
+ const datasets = {
2815
+ shapes: S.SHAPES,
2816
+ census: U.deepCopy(s.config['descriptions']['CENSUS']),
2817
+ vap: U.deepCopy(s.config['descriptions']['VAP']),
2818
+ election: U.deepCopy(s.config['descriptions']['ELECTION'])
2819
+ };
2820
+ scorecard.partisan.details['election'] = datasets.election;
2821
+ scorecard.minority.details['vap'] = datasets.vap;
2822
+ scorecard.traditionalPrinciples.details['shapes'] = datasets.shapes;
2823
+ scorecard.traditionalPrinciples.details['census'] = datasets.census;
2824
+ // TODO - SCORE: Add legacy splits details
2825
+ const simpleSplits = s.getTest(5 /* UnexpectedCountySplits */);
2826
+ scorecard.traditionalPrinciples.details['unexpectedAffected'] = simpleSplits['score'];
2827
+ scorecard.traditionalPrinciples.details['countiesSplitUnexpectedly'] = U.deepCopy(simpleSplits['details']['countiesSplitUnexpectedly']);
2828
+ // NOTE - Add split precincts in dra-client directly
2829
+ // }
2700
2830
  // Derive secondary tests
2701
2831
  analyze_1.doDeriveSecondaryTests(s, bLog);
2702
2832
  // Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard