@dra2020/district-analytics 2.0.7 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,6 +118,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
118
118
  Object.defineProperty(exports, "__esModule", { value: true });
119
119
  const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.ts");
120
120
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
121
+ const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
121
122
  const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
122
123
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
123
124
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
@@ -173,6 +174,11 @@ class AnalyticsSession {
173
174
  preprocess_1.doPreprocessData(this, bLog);
174
175
  analyze_1.doAnalyzeDistricts(this, bLog);
175
176
  analyze_1.doAnalyzePlan(this, bLog);
177
+ // TODO - SCORE
178
+ this._profile = score_1.profilePlan(this, bLog);
179
+ // this._profile = Score.sampleProfile;
180
+ this._scorecard = score_1.scorePlan(this._profile, bLog);
181
+ // TODO - SCORE
176
182
  results_1.doAnalyzePostProcessing(this, bLog);
177
183
  }
178
184
  catch (_a) {
@@ -182,13 +188,29 @@ class AnalyticsSession {
182
188
  return true;
183
189
  }
184
190
  // NOTE - This assumes that analyzePlan() has been run!
185
- getPlanAnalytics(bLog = false) {
186
- return results_2.preparePlanAnalytics(this, bLog);
187
- }
188
- // NOTE - This assumes that analyzePlan() has been run!
189
191
  getDistrictStatistics(bLog = false) {
190
192
  return results_2.prepareDistrictStatistics(this, bLog);
191
193
  }
194
+ // TODO - SCORE
195
+ getPlanProfile(bLog = false) {
196
+ return this._profile;
197
+ }
198
+ // TODO - SCORE
199
+ getPlanScorecard(bLog = false) {
200
+ return this._scorecard;
201
+ }
202
+ /* TODO - SCORE
203
+ // NOTE - This assumes that analyzePlan() has been run!
204
+ getPlanAnalytics(bLog: boolean = false): PlanAnalytics
205
+ {
206
+ return preparePlanAnalytics(this, bLog);
207
+ }
208
+ */
209
+ // TODO - SCORE
210
+ // NOTE - This assumes that analyzePlan() has been run!
211
+ getRequirementsChecklist(bLog = false) {
212
+ return results_2.prepareRequirementsChecklist(this, bLog);
213
+ }
192
214
  // NOTE - This assumes that analyzePlan() has been run!
193
215
  getDiscontiguousDistrictFeatures(bLog = false) {
194
216
  // Get the (possibly empty) list of discontiguous district IDs
@@ -346,7 +368,7 @@ class Districts {
346
368
  nMissingDataset = 0;
347
369
  nMissingProperty = 0;
348
370
  // Compute these once per recalc cycle
349
- let targetSize = this._session.state.totalPop / this._session.state.nDistricts;
371
+ let targetSize = Math.round(this._session.state.totalPop / this._session.state.nDistricts);
350
372
  let deviationThreshold = this._session.populationDeviationThreshold();
351
373
  let planByDistrict = this._session.plan.byDistrictID();
352
374
  let plan = this._session.plan;
@@ -398,6 +420,7 @@ class Districts {
398
420
  let outerThis = this;
399
421
  // Default the pop dev % for the dummy Unassigned district to 0%.
400
422
  // Default the pop dev % for real (1–N) but empty districts to 100%.
423
+ // TODO - SCORE
401
424
  let popDevPct = (i > 0) ? (targetSize / targetSize) : 0 / targetSize;
402
425
  // Get the geoIDs assigned to the district
403
426
  // Guard against empty districts
@@ -424,6 +447,7 @@ class Districts {
424
447
  // NOTE - SPLITTING
425
448
  // Total population by counties w/in a district,
426
449
  // except the dummy unassigned district 0
450
+ // TODO - VFEATURE
427
451
  if (i > 0)
428
452
  countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
429
453
  // Democratic and Republican vote totals
@@ -448,7 +472,7 @@ class Districts {
448
472
  if (i > 0) {
449
473
  if (totalPop > 0) {
450
474
  popDevPct = (totalPop - targetSize) / targetSize;
451
- bEqualPop = (popDevPct <= deviationThreshold);
475
+ bEqualPop = (Math.abs(popDevPct) <= deviationThreshold);
452
476
  }
453
477
  }
454
478
  // Total two-party (not total total!) votes, Democratic and Republican vote
@@ -597,8 +621,10 @@ class Districts {
597
621
  compact_1.extractDistrictProperties(this._session, bLog);
598
622
  }
599
623
  getCountyIndex(geoID) {
600
- let countyGeoID = U.parseGeoID(geoID)['county'];
601
- let countyFIPS = U.getFIPSFromCountyGeoID(countyGeoID);
624
+ // TODO - VFEATURE
625
+ let countyFIPS = U.parseGeoID(geoID)['county'];
626
+ // let countyGeoID = U.parseGeoID(geoID)['county'] as string;
627
+ // let countyFIPS = U.getFIPSFromCountyGeoID(countyGeoID);
602
628
  let countyIndex = this._session.counties.indexFromFIPS(countyFIPS);
603
629
  return countyIndex;
604
630
  }
@@ -615,8 +641,9 @@ class Features {
615
641
  nFeatures() { return this._data.features.length; }
616
642
  featureByIndex(i) { return this._data.features[i]; }
617
643
  geoIDForFeature(f) {
644
+ // TODO - 2020
618
645
  // GEOIDs will be one of these properties
619
- let value = f.properties['GEOID10'] || f.properties['GEOID20'] || f.properties['GEOID'];
646
+ const value = f.properties['GEOID10'] || f.properties['GEOID20'] || f.properties['GEOID'];
620
647
  return value;
621
648
  }
622
649
  fieldForFeature(f, dt, fk) {
@@ -1397,6 +1424,7 @@ function doPolsbyPopper(s, bLog = false) {
1397
1424
  }
1398
1425
  exports.doPolsbyPopper = doPolsbyPopper;
1399
1426
  // HELPER TO EXTRACT PROPERTIES OF DISTRICT SHAPES
1427
+ // TODO - SCORE: Create an array, as opposed to a dict
1400
1428
  function extractDistrictProperties(s, bLog = false) {
1401
1429
  // NOTE - I am assuming that district IDs are integers 1–N
1402
1430
  for (let i = 1; i <= s.state.nDistricts; i++) {
@@ -1880,8 +1908,10 @@ function doPreprocessCensus(s, bLog = false) {
1880
1908
  // Sum total population across the state
1881
1909
  s.state.totalPop += value;
1882
1910
  // Get the county FIPS code for the feature
1883
- let county = U.parseGeoID(geoID)['county'];
1884
- let countyFIPS = U.getFIPSFromCountyGeoID(county);
1911
+ // TODO - VFEATURE
1912
+ let countyFIPS = U.parseGeoID(geoID)['county'];
1913
+ // let county = U.parseGeoID(geoID)['county'] as string;
1914
+ // let countyFIPS = U.getFIPSFromCountyGeoID(county);
1885
1915
  // If a subtotal for the county doesn't exist, initialize one
1886
1916
  if (!(U.keyExists(countyFIPS, totalByCounty))) {
1887
1917
  totalByCounty[countyFIPS] = 0;
@@ -1899,7 +1929,7 @@ function doPreprocessCensus(s, bLog = false) {
1899
1929
  let fipsCodes = U.getObjectKeys(totalByCounty);
1900
1930
  // Sort the results
1901
1931
  fipsCodes = fipsCodes.sort();
1902
- // NOTE - SPLITTING
1932
+ // TODO - SCORE: This was added for SPLITTING
1903
1933
  // Add a dummy county, for county-district splitting analysis
1904
1934
  fipsCodes.unshift('000');
1905
1935
  // Create the ID-ordinal map
@@ -1986,7 +2016,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
1986
2016
  };
1987
2017
  Object.defineProperty(exports, "__esModule", { value: true });
1988
2018
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1989
- const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
1990
2019
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
1991
2020
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
1992
2021
  const state_reqs_json_1 = __importDefault(__webpack_require__(/*! ../static/state-reqs.json */ "./static/state-reqs.json"));
@@ -2058,7 +2087,7 @@ let samplePartisan = {
2058
2087
  planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
2059
2088
  }
2060
2089
  };
2061
- // TODO - MINORITY: This category is still being fleshed out.
2090
+ // TODO - SCORE: Add a minority report
2062
2091
  let sampleMinority = {
2063
2092
  score: null,
2064
2093
  metrics: {
@@ -2093,7 +2122,233 @@ exports.samplePlanAnalytics = {
2093
2122
  partisan: samplePartisan,
2094
2123
  minority: sampleMinority
2095
2124
  };
2096
- function preparePlanAnalytics(s, bLog = false) {
2125
+ /* TODO - SCORE
2126
+ export function preparePlanAnalytics(s: AnalyticsSession, bLog: boolean = false): PlanAnalytics
2127
+ {
2128
+ if (!(s.bPostProcessingDone))
2129
+ {
2130
+ doAnalyzePostProcessing(s);
2131
+ }
2132
+
2133
+ // REQUIREMENTS CATEGORY
2134
+ let paRequirements: RequirementsCategory;
2135
+
2136
+ {
2137
+ let completeTest = s.getTest(T.Test.Complete) as T.TestEntry;
2138
+ let contiguousTest = s.getTest(T.Test.Contiguous) as T.TestEntry;
2139
+ let freeOfHolesTest = s.getTest(T.Test.FreeOfHoles) as T.TestEntry;
2140
+ let equalPopulationTest = s.getTest(T.Test.EqualPopulation) as T.TestEntry;
2141
+
2142
+ // Combine individual checks into an overall score
2143
+
2144
+ // TODO - DASHBOARD: Until we add three-state support top to bottom in
2145
+ // requirements/validations, map booleans to tri-states here.
2146
+ let completeMetric = U.mapBooleanToTriState(completeTest['score'] as boolean);
2147
+ let contiguousMetric = U.mapBooleanToTriState(contiguousTest['score'] as boolean);
2148
+ let freeOfHolesMetric = U.mapBooleanToTriState(freeOfHolesTest['score'] as boolean);
2149
+ let equalPopulationMetric = U.mapBooleanToTriState(equalPopulationTest['score'] as boolean);
2150
+
2151
+ let reqScore: T.TriState = T.TriState.Green;
2152
+ let checks = [completeMetric, contiguousMetric, freeOfHolesMetric, equalPopulationMetric];
2153
+ if (checks.includes(T.TriState.Yellow)) reqScore = T.TriState.Yellow;
2154
+ if (checks.includes(T.TriState.Red)) reqScore = T.TriState.Red;
2155
+
2156
+ // Get values to support details entries
2157
+ let unassignedFeaturesDetail = U.deepCopy(completeTest['details']['unassignedFeatures']) || [];
2158
+ let emptyDistrictsDetail = U.deepCopy(completeTest['details']['emptyDistricts']) || [];
2159
+ let discontiguousDistrictsDetail = U.deepCopy(contiguousTest['details']['discontiguousDistricts']) || [];
2160
+ let embeddedDistrictsDetail = U.deepCopy(freeOfHolesTest['details']['embeddedDistricts']) || [];
2161
+
2162
+ let populationDeviationDetail = U.deepCopy(equalPopulationTest['details']['deviation']);
2163
+ let deviationThresholdDetail = U.trim(s.populationDeviationThreshold());
2164
+
2165
+ let xx: string = s.state.xx;
2166
+ // TODO - JSON: Is there a better / easier way to work with the variable?
2167
+ let stateReqsDict: T.Dict = allStateReqs;
2168
+ let reqLinkToStateReqs: string = stateReqsDict[xx];
2169
+
2170
+ // Populate the category
2171
+ paRequirements = {
2172
+ score: reqScore,
2173
+ metrics: {
2174
+ complete: completeMetric,
2175
+ contiguous: contiguousMetric,
2176
+ freeOfHoles: freeOfHolesMetric,
2177
+ equalPopulation: equalPopulationMetric
2178
+ },
2179
+ details: {
2180
+ unassignedFeatures: unassignedFeaturesDetail,
2181
+ emptyDistricts: emptyDistrictsDetail,
2182
+ discontiguousDistricts: discontiguousDistrictsDetail,
2183
+ embeddedDistricts: embeddedDistrictsDetail,
2184
+ populationDeviation: populationDeviationDetail,
2185
+ deviationThreshold: deviationThresholdDetail
2186
+ },
2187
+ datasets: {
2188
+ census: U.deepCopy(s.config['descriptions']['CENSUS']),
2189
+ },
2190
+ resources: {
2191
+ stateReqs: reqLinkToStateReqs
2192
+ }
2193
+ }
2194
+ }
2195
+
2196
+ // COMPACTNESS CATEGORY
2197
+ let paCompactness: CompactnessCategory;
2198
+ {
2199
+ let reockWeight = 0.5;
2200
+ let polsbyWeight = 1.0 - reockWeight;
2201
+
2202
+ let reockTest = s.getTest(T.Test.Reock) as T.TestEntry;
2203
+ let polsbyTest = s.getTest(T.Test.PolsbyPopper) as T.TestEntry;
2204
+
2205
+ let normalizedReock = reockTest['normalizedScore'] as number;
2206
+ let normalizedPolsby = reockTest['normalizedScore'] as number;
2207
+ let compactnessScore = U.trim((reockWeight * normalizedReock) + (polsbyWeight * normalizedPolsby), 0);
2208
+
2209
+ let reockMetric = U.deepCopy(reockTest['score'] as number);
2210
+ let polsbyMetric = U.deepCopy(polsbyTest['score'] as number);
2211
+
2212
+ // Populate the category
2213
+ paCompactness = {
2214
+ score: compactnessScore,
2215
+ metrics: {
2216
+ reock: reockMetric,
2217
+ polsby: polsbyMetric
2218
+ },
2219
+ details: {
2220
+ // None at this time
2221
+ },
2222
+ datasets: {
2223
+ // NOTE - DATASETS
2224
+ shapes: U.deepCopy(s.config['descriptions']['SHAPES'])
2225
+ // shapes: "2010 VTD shapes"
2226
+ },
2227
+ resources: {
2228
+ // None at this time
2229
+ }
2230
+ }
2231
+ }
2232
+
2233
+ // SPLITTING CATEGORY
2234
+
2235
+ let paSplitting: SplittingCategory
2236
+
2237
+ {
2238
+ let unexpectedCountySplittingTest = s.getTest(T.Test.UnexpectedCountySplits) as T.TestEntry;
2239
+ let VTDSplitsTest = s.getTest(T.Test.VTDSplits) as T.TestEntry;
2240
+ let countySplittingTest = s.getTest(T.Test.CountySplitting) as T.TestEntry;
2241
+ let districtSplittingTest = s.getTest(T.Test.DistrictSplitting) as T.TestEntry;
2242
+
2243
+ let unexpectedAffectedMetric = U.deepCopy(unexpectedCountySplittingTest['score']);
2244
+ let countiesSplitUnexpectedlyDetail = U.deepCopy(unexpectedCountySplittingTest['details']['countiesSplitUnexpectedly']);
2245
+
2246
+ let nVTDSplitsMetric = U.deepCopy(VTDSplitsTest['score']);
2247
+ let splitVTDsDetail = U.deepCopy(VTDSplitsTest['details']['splitVTDs']);
2248
+
2249
+ let SqEnt_DCreducedMetric = U.deepCopy(countySplittingTest['score']);
2250
+ let SqEnt_CDreducedMetric = U.deepCopy(districtSplittingTest['score']);
2251
+
2252
+ let countySplittingNormalized = countySplittingTest['normalizedScore'] as number;
2253
+ let districtSplittingNormalized = districtSplittingTest['normalizedScore'] as number;
2254
+ let splittingScore = U.trim((S.COUNTY_SPLITTING_WEIGHT * countySplittingNormalized) +
2255
+ + (S.DISTRICT_SPLITTING_WEIGHT * districtSplittingNormalized), 0);
2256
+
2257
+ paSplitting = {
2258
+ score: splittingScore,
2259
+ metrics: {
2260
+ sqEnt_DCreduced: SqEnt_DCreducedMetric,
2261
+ sqEnt_CDreduced: SqEnt_CDreducedMetric
2262
+ // NOTE - The un-reduced raw values
2263
+ // sqEnt_DC : SqEnt_DCMetric,
2264
+ // sqEnt_CD : SqEnt_CDMetric
2265
+ },
2266
+ details: {
2267
+ countiesSplitUnexpectedly: countiesSplitUnexpectedlyDetail,
2268
+ unexpectedAffected: unexpectedAffectedMetric,
2269
+ nSplitVTDs: nVTDSplitsMetric,
2270
+ splitVTDs: splitVTDsDetail
2271
+ },
2272
+ datasets: {
2273
+ // None at this time
2274
+ },
2275
+ resources: {
2276
+ // None at this time
2277
+ }
2278
+ }
2279
+ }
2280
+
2281
+ // PARTISAN CATEGORY
2282
+ //
2283
+ // TODO - PARTISAN: This category is still being fleshed out. Just an example below.
2284
+ let paPartisan: PartisanCategory;
2285
+
2286
+ {
2287
+ paPartisan = {
2288
+ score: 100,
2289
+ metrics: {
2290
+ partisanBias: 0.15,
2291
+ responsiveness: 2.0
2292
+ },
2293
+ details: {},
2294
+ datasets: {
2295
+ election: "2016 Presidential, US Senate, Governor, and AG election results"
2296
+ },
2297
+ resources: {
2298
+ planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
2299
+ }
2300
+ }
2301
+ }
2302
+
2303
+ // MINORITY CATEGORY
2304
+ //
2305
+ // TODO - MINORITY: This category is still being fleshed out. Just an example below.
2306
+ let paMinority: MinorityCategory;
2307
+
2308
+ {
2309
+ paMinority = {
2310
+ score: null,
2311
+ metrics: {
2312
+ nBlack37to50: 1,
2313
+ nBlackMajority: 12,
2314
+ nHispanic37to50: 0,
2315
+ nHispanicMajority: 0,
2316
+ nPacific37to50: 0,
2317
+ nPacificMajority: 0,
2318
+ nAsian37to50: 0,
2319
+ nAsianMajority: 0,
2320
+ nNative37to50: 0,
2321
+ nNativeMajority: 0,
2322
+ nMinority37to50: 0,
2323
+ nMinorityMajority: 0,
2324
+
2325
+ averageDVoteShare: 0.90
2326
+ },
2327
+ details: {
2328
+ vap: true,
2329
+ comboCategories: true
2330
+ },
2331
+ datasets: {
2332
+ vap: "2010 Voting Age Population"
2333
+ },
2334
+ resources: {}
2335
+ }
2336
+ }
2337
+
2338
+ // PLAN ANALYTICS
2339
+ let pa: PlanAnalytics = {
2340
+ requirements: paRequirements,
2341
+ compactness: paCompactness,
2342
+ // TODO - Not implemented yet
2343
+ splitting: paSplitting,
2344
+ partisan: paPartisan,
2345
+ minority: paMinority
2346
+ }
2347
+
2348
+ return pa;
2349
+ }
2350
+ */
2351
+ function prepareRequirementsChecklist(s, bLog = false) {
2097
2352
  if (!(s.bPostProcessingDone)) {
2098
2353
  doAnalyzePostProcessing(s);
2099
2354
  }
@@ -2153,142 +2408,9 @@ function preparePlanAnalytics(s, bLog = false) {
2153
2408
  }
2154
2409
  };
2155
2410
  }
2156
- // COMPACTNESS CATEGORY
2157
- let paCompactness;
2158
- {
2159
- let reockWeight = 0.5;
2160
- let polsbyWeight = 1.0 - reockWeight;
2161
- let reockTest = s.getTest(5 /* Reock */);
2162
- let polsbyTest = s.getTest(6 /* PolsbyPopper */);
2163
- let normalizedReock = reockTest['normalizedScore'];
2164
- let normalizedPolsby = reockTest['normalizedScore'];
2165
- let compactnessScore = U.trim((reockWeight * normalizedReock) + (polsbyWeight * normalizedPolsby), 0);
2166
- let reockMetric = U.deepCopy(reockTest['score']);
2167
- let polsbyMetric = U.deepCopy(polsbyTest['score']);
2168
- // Populate the category
2169
- paCompactness = {
2170
- score: compactnessScore,
2171
- metrics: {
2172
- reock: reockMetric,
2173
- polsby: polsbyMetric
2174
- },
2175
- details: {
2176
- // None at this time
2177
- },
2178
- datasets: {
2179
- // NOTE - DATASETS
2180
- shapes: U.deepCopy(s.config['descriptions']['SHAPES'])
2181
- // shapes: "2010 VTD shapes"
2182
- },
2183
- resources: {
2184
- // None at this time
2185
- }
2186
- };
2187
- }
2188
- // SPLITTING CATEGORY
2189
- let paSplitting;
2190
- {
2191
- let unexpectedCountySplittingTest = s.getTest(7 /* UnexpectedCountySplits */);
2192
- let VTDSplitsTest = s.getTest(10 /* VTDSplits */);
2193
- let countySplittingTest = s.getTest(8 /* CountySplitting */);
2194
- let districtSplittingTest = s.getTest(9 /* DistrictSplitting */);
2195
- let unexpectedAffectedMetric = U.deepCopy(unexpectedCountySplittingTest['score']);
2196
- let countiesSplitUnexpectedlyDetail = U.deepCopy(unexpectedCountySplittingTest['details']['countiesSplitUnexpectedly']);
2197
- let nVTDSplitsMetric = U.deepCopy(VTDSplitsTest['score']);
2198
- let splitVTDsDetail = U.deepCopy(VTDSplitsTest['details']['splitVTDs']);
2199
- let SqEnt_DCreducedMetric = U.deepCopy(countySplittingTest['score']);
2200
- let SqEnt_CDreducedMetric = U.deepCopy(districtSplittingTest['score']);
2201
- let countySplittingNormalized = countySplittingTest['normalizedScore'];
2202
- let districtSplittingNormalized = districtSplittingTest['normalizedScore'];
2203
- let splittingScore = U.trim((S.COUNTY_SPLITTING_WEIGHT * countySplittingNormalized) +
2204
- +(S.DISTRICT_SPLITTING_WEIGHT * districtSplittingNormalized), 0);
2205
- paSplitting = {
2206
- score: splittingScore,
2207
- metrics: {
2208
- sqEnt_DCreduced: SqEnt_DCreducedMetric,
2209
- sqEnt_CDreduced: SqEnt_CDreducedMetric
2210
- // NOTE - The un-reduced raw values
2211
- // sqEnt_DC : SqEnt_DCMetric,
2212
- // sqEnt_CD : SqEnt_CDMetric
2213
- },
2214
- details: {
2215
- countiesSplitUnexpectedly: countiesSplitUnexpectedlyDetail,
2216
- unexpectedAffected: unexpectedAffectedMetric,
2217
- nSplitVTDs: nVTDSplitsMetric,
2218
- splitVTDs: splitVTDsDetail
2219
- },
2220
- datasets: {
2221
- // None at this time
2222
- },
2223
- resources: {
2224
- // None at this time
2225
- }
2226
- };
2227
- }
2228
- // PARTISAN CATEGORY
2229
- //
2230
- // TODO - PARTISAN: This category is still being fleshed out. Just an example below.
2231
- let paPartisan;
2232
- {
2233
- paPartisan = {
2234
- score: 100,
2235
- metrics: {
2236
- partisanBias: 0.15,
2237
- responsiveness: 2.0
2238
- },
2239
- details: {},
2240
- datasets: {
2241
- election: "2016 Presidential, US Senate, Governor, and AG election results"
2242
- },
2243
- resources: {
2244
- planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
2245
- }
2246
- };
2247
- }
2248
- // MINORITY CATEGORY
2249
- //
2250
- // TODO - MINORITY: This category is still being fleshed out. Just an example below.
2251
- let paMinority;
2252
- {
2253
- paMinority = {
2254
- score: null,
2255
- metrics: {
2256
- nBlack37to50: 1,
2257
- nBlackMajority: 12,
2258
- nHispanic37to50: 0,
2259
- nHispanicMajority: 0,
2260
- nPacific37to50: 0,
2261
- nPacificMajority: 0,
2262
- nAsian37to50: 0,
2263
- nAsianMajority: 0,
2264
- nNative37to50: 0,
2265
- nNativeMajority: 0,
2266
- nMinority37to50: 0,
2267
- nMinorityMajority: 0,
2268
- averageDVoteShare: 0.90
2269
- },
2270
- details: {
2271
- vap: true,
2272
- comboCategories: true
2273
- },
2274
- datasets: {
2275
- vap: "2010 Voting Age Population"
2276
- },
2277
- resources: {}
2278
- };
2279
- }
2280
- // PLAN ANALYTICS
2281
- let pa = {
2282
- requirements: paRequirements,
2283
- compactness: paCompactness,
2284
- // TODO - Not implemented yet
2285
- splitting: paSplitting,
2286
- partisan: paPartisan,
2287
- minority: paMinority
2288
- };
2289
- return pa;
2411
+ return paRequirements;
2290
2412
  }
2291
- exports.preparePlanAnalytics = preparePlanAnalytics;
2413
+ exports.prepareRequirementsChecklist = prepareRequirementsChecklist;
2292
2414
  // Example
2293
2415
  exports.sampleDistrictStatistics = {
2294
2416
  table: [
@@ -2544,6 +2666,127 @@ function doAnalyzePostProcessing(s, bLog = false) {
2544
2666
  exports.doAnalyzePostProcessing = doAnalyzePostProcessing;
2545
2667
 
2546
2668
 
2669
+ /***/ }),
2670
+
2671
+ /***/ "./src/score.ts":
2672
+ /*!**********************!*\
2673
+ !*** ./src/score.ts ***!
2674
+ \**********************/
2675
+ /*! no static exports found */
2676
+ /***/ (function(module, exports, __webpack_require__) {
2677
+
2678
+ "use strict";
2679
+
2680
+ //
2681
+ // SCORING
2682
+ //
2683
+ var __importStar = (this && this.__importStar) || function (mod) {
2684
+ if (mod && mod.__esModule) return mod;
2685
+ var result = {};
2686
+ if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
2687
+ result["default"] = mod;
2688
+ return result;
2689
+ };
2690
+ Object.defineProperty(exports, "__esModule", { value: true });
2691
+ const Score = __importStar(__webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score"));
2692
+ const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
2693
+ const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
2694
+ // PROFILE A PLAN
2695
+ function profilePlan(s, bLog = false) {
2696
+ const state = s.state.xx;
2697
+ const planName = s.title;
2698
+ const nDistricts = s.state.nDistricts;
2699
+ const nCounties = s.counties.nCounties;
2700
+ const targetSize = Math.round(s.state.totalPop / nDistricts);
2701
+ const popByDistrict = U.deepCopy(s.districts.statistics[D.DistrictField.TotalPop].slice(1, -1));
2702
+ const geoPropsByDistrict = makeArrayOfGeoProps(s, bLog);
2703
+ const splits = makeNakedCxD(s);
2704
+ const summaryRow = s.districts.numberOfRows() - 1;
2705
+ const statewideVf = s.districts.statistics[D.DistrictField.DemPct][summaryRow];
2706
+ const vpiArray = U.deepCopy(s.districts.statistics[D.DistrictField.DemPct].slice(1, -1));
2707
+ const demographicsByDistrict = makeArrayOfDemographics(s);
2708
+ const profile = {
2709
+ state: state,
2710
+ planName: planName,
2711
+ nDistricts: nDistricts,
2712
+ nCounties: nCounties,
2713
+ legislativeDistricts: s.legislativeDistricts,
2714
+ populationProfile: {
2715
+ TotalPopByDistrict: popByDistrict,
2716
+ targetSize: targetSize
2717
+ },
2718
+ compactnessProfile: {
2719
+ GeometryByDistrict: geoPropsByDistrict
2720
+ },
2721
+ splittingProfile: {
2722
+ CountyPopByDistrict: splits
2723
+ },
2724
+ partisanProfile: {
2725
+ statewideVf: statewideVf,
2726
+ VfArray: vpiArray
2727
+ },
2728
+ demographicProfile: {
2729
+ DemographicsByDistrict: demographicsByDistrict
2730
+ }
2731
+ };
2732
+ return profile;
2733
+ }
2734
+ exports.profilePlan = profilePlan;
2735
+ // NOTE - The CxD splits structure from _data.ts includes dummy districts for
2736
+ // unassigned precincts & state summary and an extra 0 county. But dra-score takes
2737
+ // a simple 1–D x 1–C splits array (zero-based, of course).
2738
+ function makeNakedCxD(s, bLog = false) {
2739
+ const adornedCxD = s.districts.statistics[D.DistrictField.CountySplits];
2740
+ let CxD = [];
2741
+ // Remove the unassigned & total dummy "districts"
2742
+ for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
2743
+ // TODO - SCORE: OH has an extra county!?!
2744
+ const splits = U.deepCopy(adornedCxD[districtID].slice(1));
2745
+ CxD.push(splits);
2746
+ }
2747
+ return CxD;
2748
+ }
2749
+ // TODO - SCORE: Convert dict of geo props to array by district index
2750
+ function makeArrayOfGeoProps(s, bLog = false) {
2751
+ let geometryByDistrict = [];
2752
+ for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
2753
+ let districtProps = s.districts.getGeoProperties(districtID);
2754
+ // Guard against no shape and no properties
2755
+ if (districtProps) {
2756
+ let a = districtProps[0 /* Area */];
2757
+ let p = districtProps[2 /* Perimeter */];
2758
+ let d = districtProps[1 /* Diameter */];
2759
+ // Save each triple
2760
+ geometryByDistrict.push([a, p, d]);
2761
+ }
2762
+ }
2763
+ return geometryByDistrict;
2764
+ }
2765
+ function makeArrayOfDemographics(s, bLog = false) {
2766
+ let demographicsArray = [];
2767
+ // Remove the unassigned & total dummy "districts"
2768
+ for (let districtID = 1; districtID <= s.state.nDistricts; districtID++) {
2769
+ const districtDemographics = [
2770
+ U.deepCopy(s.districts.statistics[D.DistrictField.WhitePct][districtID]),
2771
+ U.deepCopy(s.districts.statistics[D.DistrictField.MinorityPct][districtID]),
2772
+ U.deepCopy(s.districts.statistics[D.DistrictField.BlackPct][districtID]),
2773
+ U.deepCopy(s.districts.statistics[D.DistrictField.HispanicPct][districtID]),
2774
+ U.deepCopy(s.districts.statistics[D.DistrictField.PacificPct][districtID]),
2775
+ U.deepCopy(s.districts.statistics[D.DistrictField.AsianPct][districtID]),
2776
+ U.deepCopy(s.districts.statistics[D.DistrictField.NativePct][districtID])
2777
+ ];
2778
+ demographicsArray.push(districtDemographics);
2779
+ }
2780
+ return demographicsArray;
2781
+ }
2782
+ // SCORE A PLAN
2783
+ function scorePlan(p, bLog = false) {
2784
+ let scorer = new Score.Scorer();
2785
+ return scorer.score(p);
2786
+ }
2787
+ exports.scorePlan = scorePlan;
2788
+
2789
+
2547
2790
  /***/ }),
2548
2791
 
2549
2792
  /***/ "./src/settings.ts":
@@ -2594,6 +2837,10 @@ exports.DISTRICT_SPLITTING_WEIGHT = 1.0 - exports.COUNTY_SPLITTING_WEIGHT;
2594
2837
  // TYPE DEFINITIONS
2595
2838
  //
2596
2839
  Object.defineProperty(exports, "__esModule", { value: true });
2840
+ // TODO - SCORE
2841
+ var dra_score_1 = __webpack_require__(/*! @dra2020/dra-score */ "@dra2020/dra-score");
2842
+ exports.sampleProfile = dra_score_1.sampleProfile;
2843
+ exports.sampleScorecard = dra_score_1.sampleScorecard;
2597
2844
  // END
2598
2845
 
2599
2846
 
@@ -2646,27 +2893,50 @@ function getDistrict(plan, geoID) {
2646
2893
  }
2647
2894
  exports.getDistrict = getDistrict;
2648
2895
  // WORKING WITH GEOIDS
2896
+ // TODO - VFEATURE
2649
2897
  function parseGeoID(geoID) {
2650
- let parts = {};
2651
- parts['state'] = geoID.substring(0, 2);
2652
- parts['county'] = geoID.substring(0, 5);
2653
- let l = geoID.length;
2654
- if (l >= 11) {
2655
- parts['tract'] = geoID.substring(0, 11);
2656
- }
2657
- if (l >= 12) {
2658
- parts['bg'] = geoID.substring(0, 12);
2659
- }
2660
- if (l == 15) {
2661
- parts['block'] = geoID;
2662
- }
2898
+ let bVfeature = false;
2899
+ // Rewrite vfeature GEOIDs to enable lexical parsing of higher-level parts
2900
+ // Template: vfeature_{geoid}_{chunk}_hash
2901
+ // Example: vfeature_39153153ASV_0_28e0bc2c8163e5982e1da2d61e2388a8325c575e
2902
+ if (geoID.indexOf('vfeature') >= 0) {
2903
+ bVfeature = true;
2904
+ // Strip off leading 'vfeature_'
2905
+ let parentGeoID = geoID.slice(9);
2906
+ // Strip off trailing goo
2907
+ const uPos = parentGeoID.indexOf('_');
2908
+ parentGeoID = parentGeoID.slice(0, uPos);
2909
+ geoID = parentGeoID;
2910
+ }
2911
+ const parts = {
2912
+ vfeature: bVfeature,
2913
+ state: geoID.substring(0, 2),
2914
+ county: geoID.substring(2, 5),
2915
+ rest: geoID.slice(5)
2916
+ };
2917
+ // let l: number = geoID.length;
2918
+ // if (l >= 11)
2919
+ // {
2920
+ // parts['tract'] = geoID.substring(0, 11);
2921
+ // }
2922
+ // if (l >= 12)
2923
+ // {
2924
+ // parts['bg'] = geoID.substring(0, 12);
2925
+ // }
2926
+ // if (l == 15)
2927
+ // {
2928
+ // parts['block'] = geoID;
2929
+ // }
2663
2930
  return parts;
2664
2931
  }
2665
2932
  exports.parseGeoID = parseGeoID;
2666
- function getFIPSFromCountyGeoID(geoID) {
2667
- return geoID.substring(2, 5);
2668
- }
2669
- exports.getFIPSFromCountyGeoID = getFIPSFromCountyGeoID;
2933
+ // TODO - VFEATURE
2934
+ // export function getFIPSFromCountyGeoID(geoID: string): string
2935
+ // {
2936
+ // const fips = geoID.substring(2, 5);
2937
+ // if (isNaN(Number(fips))) console.log("Non-numeric GEOID =", geoID);
2938
+ // return fips;
2939
+ // }
2670
2940
  function isWaterOnly(geoID) {
2671
2941
  let waterOnlySignature = 'ZZZZZZ';
2672
2942
  if (geoID.indexOf(waterOnlySignature) >= 0)
@@ -3105,6 +3375,17 @@ module.exports = JSON.parse("{\"AL\":\"https://www.brennancenter.org/sites/defau
3105
3375
 
3106
3376
  /***/ }),
3107
3377
 
3378
+ /***/ "@dra2020/dra-score":
3379
+ /*!*************************************!*\
3380
+ !*** external "@dra2020/dra-score" ***!
3381
+ \*************************************/
3382
+ /*! no static exports found */
3383
+ /***/ (function(module, exports) {
3384
+
3385
+ module.exports = require("@dra2020/dra-score");
3386
+
3387
+ /***/ }),
3388
+
3108
3389
  /***/ "@dra2020/poly":
3109
3390
  /*!********************************!*\
3110
3391
  !*** external "@dra2020/poly" ***!