@dra2020/district-analytics 1.0.11 → 2.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.
package/dist/cli.js CHANGED
@@ -8992,7 +8992,7 @@ class AnalyticsSession {
8992
8992
  // NOTE - Session settings are required:
8993
8993
  // - Analytics suites can be defaulted to all with [], but
8994
8994
  // - Dataset keys must be explicitly specified with 'dataset'
8995
- // TODO - Remove this mechanism. Always run everything.
8995
+ // TODO - DASHBOARD: Remove this mechanism. Always run everything.
8996
8996
  let defaultSuites = [0 /* Legal */, 1 /* Fair */, 2 /* Best */];
8997
8997
  // If the config passed in has no suites = [], use the default suites
8998
8998
  if (U.isArrayEmpty(config['suites'])) {
@@ -9172,10 +9172,10 @@ class Districts {
9172
9172
  }
9173
9173
  // This is the workhorse computational routine!
9174
9174
  //
9175
- // TODO - Optimize for getting multiple properties from the same feature?
9176
- // TODO - Optimize by only re-calc'ing districts that have changed?
9175
+ // TODO - OPTIMIZE for getting multiple properties from the same feature?
9176
+ // TODO - OPTIMIZE by only re-calc'ing districts that have changed?
9177
9177
  // In this case, special attention to getting county-splits right.
9178
- // TODO - Optimize by async'ing this?
9178
+ // TODO - OPTIMIZE by async'ing this?
9179
9179
  // TODO - Is there a way to do this programmatically off data? Does it matter?
9180
9180
  recalcStatistics(bLog = false) {
9181
9181
  // Compute these once per recalc cycle
@@ -9184,7 +9184,7 @@ class Districts {
9184
9184
  let planByDistrict = this._session.plan.byDistrictID();
9185
9185
  let plan = this._session.plan;
9186
9186
  let graph = this._session.graph;
9187
- // TODO - SPLITTING
9187
+ // NOTE - SPLITTING
9188
9188
  // Add an extra 0th virtual county bucket for county-district splitting analysis
9189
9189
  let nCountyBuckets = this._session.counties.nCounties + 1;
9190
9190
  // INITIALIZE STATE VALUES THAT WILL BE ACCUMULATED
@@ -9210,7 +9210,7 @@ class Districts {
9210
9210
  // INITIALIZE DISTRICT VALUES THAT WILL BE ACCUMULATED (VS. DERIVED)
9211
9211
  let featurePop;
9212
9212
  let totalPop = 0;
9213
- // TODO - SPLITTING
9213
+ // NOTE - SPLITTING
9214
9214
  let countySplits = U.initArray(nCountyBuckets, 0);
9215
9215
  let demVotes = 0;
9216
9216
  let repVotes = 0;
@@ -9241,31 +9241,37 @@ class Districts {
9241
9241
  // Map from geoID to feature index
9242
9242
  let featureID = outerThis._session.features.featureID(geoID);
9243
9243
  let f = outerThis._session.features.featureByIndex(featureID);
9244
- // ACCUMULATE VALUES
9245
- // Total population of each feature
9246
- // NOTE - This result is used more than once
9247
- featurePop = outerThis._session.features.fieldForFeature(f, "CENSUS" /* CENSUS */, "Tot" /* TotalPop */);
9248
- // Total district population
9249
- totalPop += featurePop;
9250
- // TODO - SPLITTING
9251
- // Total population by counties w/in a district,
9252
- // except the dummy unassigned district 0
9253
- if (i > 0)
9254
- countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
9255
- // Democratic and Republican vote totals
9256
- demVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
9257
- repVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "R" /* RepVotes */);
9258
- // Voting-age demographic breakdowns (or citizen voting-age)
9259
- totalVAP += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
9260
- whitePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
9261
- blackPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */);
9262
- hispanicPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */);
9263
- pacificPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */);
9264
- asianPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */);
9265
- nativePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */);
9266
- // 4 - MORE ...
9244
+ if (f == undefined) {
9245
+ console.log("Skipping undefined feature in district statistics: GEOID =", geoID, "Feature ID =", featureID);
9246
+ }
9247
+ else {
9248
+ // ACCUMULATE VALUES
9249
+ // Total population of each feature
9250
+ // NOTE - This result is used more than once
9251
+ featurePop = outerThis._session.features.fieldForFeature(f, "CENSUS" /* CENSUS */, "Tot" /* TotalPop */);
9252
+ // Total district population
9253
+ totalPop += featurePop;
9254
+ // NOTE - SPLITTING
9255
+ // Total population by counties w/in a district,
9256
+ // except the dummy unassigned district 0
9257
+ if (i > 0)
9258
+ countySplits[outerThis.getCountyIndex(geoID)] += featurePop;
9259
+ // Democratic and Republican vote totals
9260
+ demVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "D" /* DemVotes */);
9261
+ repVotes += outerThis._session.features.fieldForFeature(f, "ELECTION" /* ELECTION */, "R" /* RepVotes */);
9262
+ // Voting-age demographic breakdowns (or citizen voting-age)
9263
+ totalVAP += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Tot" /* TotalPop */);
9264
+ whitePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "Wh" /* WhitePop */);
9265
+ blackPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "BlC" /* BlackPop */);
9266
+ hispanicPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "His" /* HispanicPop */);
9267
+ pacificPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "PacC" /* PacificPop */);
9268
+ asianPop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "AsnC" /* AsianPop */);
9269
+ nativePop += outerThis._session.features.fieldForFeature(f, "VAP" /* VAP */, "NatC" /* NativePop */);
9270
+ // 4 - MORE ...
9271
+ }
9267
9272
  }
9268
- // else console.log("Skipping water-only feature in district statistics:", geoID);
9273
+ else
9274
+ console.log("Skipping water-only feature in district statistics:", geoID);
9269
9275
  });
9270
9276
  // COMPUTE DERIVED VALUES
9271
9277
  // Population deviation % and equal population (boolean) by district.
@@ -9463,6 +9469,8 @@ exports.Features = Features;
9463
9469
  // f is a direct GeoJSON feature
9464
9470
  // p is a geoID
9465
9471
  function _getFeatures(f, datasetKey, p) {
9472
+ // Echo parameters for debugging
9473
+ // console.log("f =", f, "k = ", datasetKey, "p =", p);
9466
9474
  // Shim to load sample data2.json from disk for command-line scaffolding
9467
9475
  if (f.properties && f.properties['datasets']) {
9468
9476
  return f.properties['datasets'][datasetKey][p];
@@ -9549,7 +9557,7 @@ class Plan {
9549
9557
  // return newPlan;
9550
9558
  // }
9551
9559
  invertPlan() {
9552
- // TODO - UNASSIGNED
9560
+ // NOTE - UNASSIGNED
9553
9561
  this._planByDistrictID = invertPlan(this._planByGeoID, this._session);
9554
9562
  this.districtIDs = U.getNumericObjectKeys(this._planByDistrictID);
9555
9563
  }
@@ -9565,8 +9573,8 @@ function invertPlan(plan, s) {
9565
9573
  let invertedPlan = {};
9566
9574
  // Add a dummy 'unassigned' district
9567
9575
  invertedPlan[S.NOT_ASSIGNED] = new Set();
9568
- // TODO - UNASSIGNED
9569
- // NOTE - The feature assignments coming from DRA do not include unassigned ones.
9576
+ // NOTE - UNASSIGNED
9577
+ // The feature assignments coming from DRA do not include unassigned ones.
9570
9578
  // - In the DRA-calling context, there's an analytics session with a reference
9571
9579
  // to the features. Loop over all the features to find the unassigned ones,
9572
9580
  // and add them to the dummy unassigned district explicitly.
@@ -9579,7 +9587,7 @@ function invertPlan(plan, s) {
9579
9587
  // to the dummy unassigned district 0.
9580
9588
  if (!(U.keyExists(geoID, plan)))
9581
9589
  invertedPlan[S.NOT_ASSIGNED].add(geoID);
9582
- // TODO - WATER-ONLY: NOT skipping water-only features here, because we're
9590
+ // NOTE - NOT skipping WATER-ONLY features here, because we're
9583
9591
  // not skipping them below when they are explicitly assigned in plans. Should
9584
9592
  // we skip them in both places?
9585
9593
  }
@@ -9606,7 +9614,13 @@ class Graph {
9606
9614
  peerNeighbors(node) {
9607
9615
  // Get the neighboring geoIDs connected to a geoID
9608
9616
  // Ignore the lengths of the shared borders (the values), for now
9609
- return U.getObjectKeys(this._graph[node]);
9617
+ // Protect against getting a GEOID that's not in the graph
9618
+ if (U.keyExists(node, this._graph)) {
9619
+ return U.getObjectKeys(this._graph[node]);
9620
+ }
9621
+ else
9622
+ return [];
9623
+ // return U.getObjectKeys(this._graph[node]);
9610
9624
  }
9611
9625
  }
9612
9626
  exports.Graph = Graph;
@@ -10349,7 +10363,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
10349
10363
  Object.defineProperty(exports, "__esModule", { value: true });
10350
10364
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
10351
10365
  // CARTESIAN SHIMS OVER 'POLY' FUNCTIONS
10352
- // TODO - TERRY: Confirm Cartesian calculations
10366
+ // TODO - POLY: Confirm Cartesian calculations
10353
10367
  function gfArea(poly) {
10354
10368
  let area = _polygonArea(poly);
10355
10369
  return area;
@@ -10384,7 +10398,7 @@ function _polygonSimpleArea(p) {
10384
10398
  // Generalizes the above for MultiPolygons -- cloned from polyArea() in 'poly'
10385
10399
  function _polygonArea(poly) {
10386
10400
  let polyOptions = { noLatitudeCorrection: true }; // NO-OP?
10387
- poly = Poly.polyNormalize(poly, polyOptions); // TODO - Discuss w/ Terry
10401
+ poly = Poly.polyNormalize(poly, polyOptions); // TODO - POLY: Discuss w/ Terry
10388
10402
  let a = 0;
10389
10403
  // A MultiPolygon is a set of polygons
10390
10404
  for (let i = 0; poly && i < poly.length; i++) {
@@ -10397,7 +10411,7 @@ function _polygonArea(poly) {
10397
10411
  }
10398
10412
  return a;
10399
10413
  }
10400
- // TODO - TERRY: Confirm Cartesian calculations
10414
+ // TODO - POLY: Confirm Cartesian calculations w/ Terry
10401
10415
  // The perimeter calculation already just computes cartesian distance if you
10402
10416
  // pass in the noLatitudeCorrection flag. You would need to divide by
10403
10417
  // Poly.EARTH_RADIUS to go from the returned units of meters to Lat/Lon “units”.
@@ -10406,7 +10420,7 @@ function gfPerimeter(poly) {
10406
10420
  return perimeter;
10407
10421
  }
10408
10422
  exports.gfPerimeter = gfPerimeter;
10409
- // TODO - TERRY: Confirm Cartesian calculations
10423
+ // TODO - POLY: Confirm Cartesian calculations w/ Terry
10410
10424
  // Cloned from polyPerimeter() in 'poly' and revised to use Cartesian distance
10411
10425
  // NOTE: No conversion of degrees to radians!
10412
10426
  function _polygonPerimeter(poly) {
@@ -10430,7 +10444,7 @@ function _distance(x1, y1, x2, y2) {
10430
10444
  d = Math.sqrt((dLat * dLat) + (dLon * dLon));
10431
10445
  return d;
10432
10446
  }
10433
- // TODO - TERRY: Confirm Cartesian calculations
10447
+ // TODO - POLY: Confirm Cartesian calculations w/ Terry
10434
10448
  // As I mentioned, the polyCircle code was already just treating the coordinate
10435
10449
  // system as Cartesian. I then did polyFromCircle to convert it to a polygon that
10436
10450
  // then could be passed to polyArea in order to take into account the projection.
@@ -10616,7 +10630,7 @@ function doPreprocessData(s, bLog = false) {
10616
10630
  doPreprocessElection(s, bLog);
10617
10631
  s.bOneTimeProcessingDone = true;
10618
10632
  }
10619
- // TODO - UNASSIGNED: Made both the planByGeoID & DistrictID are right
10633
+ // NOTE - UNASSIGNED: Made both the planByGeoID & DistrictID are right
10620
10634
  // Invert the plan by district ID
10621
10635
  s.plan.invertPlan();
10622
10636
  // Create a map of geoIDs to feature IDs
@@ -10668,7 +10682,7 @@ function doPreprocessCensus(s, bLog = false) {
10668
10682
  let fipsCodes = U.getObjectKeys(totalByCounty);
10669
10683
  // Sort the results
10670
10684
  fipsCodes = fipsCodes.sort();
10671
- // TODO - SPLITTING
10685
+ // NOTE - SPLITTING
10672
10686
  // Add a dummy county, for county-district splitting analysis
10673
10687
  fipsCodes.unshift('000');
10674
10688
  // Create the ID-ordinal map
@@ -10699,7 +10713,7 @@ function doPreprocessCensus(s, bLog = false) {
10699
10713
  // Loop over the counties
10700
10714
  for (let county in fipsCodes) {
10701
10715
  let fipsCode = fipsCodes[county];
10702
- // TODO - SPLITTING
10716
+ // NOTE - SPLITTING
10703
10717
  // Skip the dummy county
10704
10718
  if (fipsCode == '000')
10705
10719
  continue;
@@ -10757,8 +10771,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
10757
10771
  const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
10758
10772
  const S = __importStar(__webpack_require__(/*! ./settings */ "./src/settings.ts"));
10759
10773
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
10760
- // TODO - DASHBOARD: Delete
10761
- // import { doAnalyzePostProcessing } from './report'
10762
10774
  const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
10763
10775
  const state_reqs_json_1 = __importDefault(__webpack_require__(/*! ../static/state-reqs.json */ "./static/state-reqs.json"));
10764
10776
  // Example
@@ -10809,12 +10821,12 @@ let sampleSplitting = {
10809
10821
  ],
10810
10822
  unexpectedAffected: 0.3096,
10811
10823
  nSplitVTDs: 12,
10812
- splitVTDs: []
10824
+ splitVTDs: ["VTD-01", "VTD-02", "VTD-03", "VTD-04", "VTD-05", "VTD-06", "VTD-07", "VTD-08", "VTD-09", "VTD-10", "VTD-11", "VTD-12"]
10813
10825
  },
10814
10826
  datasets: {},
10815
10827
  resources: {}
10816
10828
  };
10817
- // TODO - This category is still being fleshed out.
10829
+ // TODO - PARTISAN: This category is still being fleshed out.
10818
10830
  let samplePartisan = {
10819
10831
  score: 100,
10820
10832
  metrics: {
@@ -10829,7 +10841,7 @@ let samplePartisan = {
10829
10841
  planScore: "https://planscore.org/plan.html?20180219T202039.596761160Z"
10830
10842
  }
10831
10843
  };
10832
- // TODO - This category is still being fleshed out.
10844
+ // TODO - MINORITY: This category is still being fleshed out.
10833
10845
  let sampleMinority = {
10834
10846
  score: null,
10835
10847
  metrics: {
@@ -10947,9 +10959,9 @@ function preparePlanAnalytics(s, bLog = false) {
10947
10959
  // None at this time
10948
10960
  },
10949
10961
  datasets: {
10950
- shapes: "2010 VTD shapes"
10951
- // TODO - DATASETS
10952
- // shapes: U.deepCopy(s.config['descriptions']['SHAPES'])
10962
+ // NOTE - DATASETS
10963
+ shapes: U.deepCopy(s.config['descriptions']['SHAPES'])
10964
+ // shapes: "2010 VTD shapes"
10953
10965
  },
10954
10966
  resources: {
10955
10967
  // None at this time
@@ -11200,7 +11212,7 @@ const polsbyPopperDefn = {
11200
11212
  externalType: TestType.Number,
11201
11213
  suites: [2 /* Best */]
11202
11214
  };
11203
- // TODO - SPLITTING
11215
+ // NOTE - SPLITTING
11204
11216
  const unexpectedCountySplitsDefn = {
11205
11217
  ID: 7 /* UnexpectedCountySplits */,
11206
11218
  name: "Unexpected County Splits",
@@ -11208,7 +11220,7 @@ const unexpectedCountySplitsDefn = {
11208
11220
  externalType: TestType.Percentage,
11209
11221
  suites: [2 /* Best */]
11210
11222
  };
11211
- // TODO - SPLITTING
11223
+ // NOTE - SPLITTING
11212
11224
  const VTDSplitsDefn = {
11213
11225
  ID: 10 /* VTDSplits */,
11214
11226
  name: "VTD Splits",
@@ -11216,7 +11228,7 @@ const VTDSplitsDefn = {
11216
11228
  externalType: TestType.Number,
11217
11229
  suites: [2 /* Best */]
11218
11230
  };
11219
- // TODO - SPLITTING
11231
+ // NOTE - SPLITTING
11220
11232
  const countySplittingDefn = {
11221
11233
  ID: 8 /* CountySplitting */,
11222
11234
  name: "County Splitting",
@@ -11224,7 +11236,7 @@ const countySplittingDefn = {
11224
11236
  externalType: TestType.Number,
11225
11237
  suites: [2 /* Best */]
11226
11238
  };
11227
- // TODO - SPLITTING
11239
+ // NOTE - SPLITTING
11228
11240
  const districtSplittingDefn = {
11229
11241
  ID: 9 /* DistrictSplitting */,
11230
11242
  name: "District Splitting",
@@ -11248,7 +11260,7 @@ const testDefns = {
11248
11260
  [4 /* PopulationDeviation */]: populationDeviationDefn,
11249
11261
  [5 /* Reock */]: reockDefn,
11250
11262
  [6 /* PolsbyPopper */]: polsbyPopperDefn,
11251
- // TODO - SPLITTING
11263
+ // NOTE - SPLITTING
11252
11264
  [7 /* UnexpectedCountySplits */]: unexpectedCountySplitsDefn,
11253
11265
  [10 /* VTDSplits */]: VTDSplitsDefn,
11254
11266
  [8 /* CountySplitting */]: countySplittingDefn,
@@ -11276,7 +11288,7 @@ function doConfigureScales(s) {
11276
11288
  s.testScales[6 /* PolsbyPopper */] = { scale: [0.10, 0.50] };
11277
11289
  const nDistricts = s.state.nDistricts;
11278
11290
  const nCounties = s.counties.nCounties;
11279
- // TODO - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
11291
+ // NOTE - SPLITTING: Experiment w/ this multiplier. Only allowing the expected
11280
11292
  // number of county splits seems too stringent, empirically.
11281
11293
  const allowableCountySplitsMultiplier = 1.5;
11282
11294
  const nAllowableSplits = Math.min(allowableCountySplitsMultiplier * (nDistricts - 1));
@@ -11335,7 +11347,7 @@ exports.PRECISION = 4;
11335
11347
  exports.NORMALIZED_RANGE = 100;
11336
11348
  // The dummy district ID for features not assigned districts yet
11337
11349
  exports.NOT_ASSIGNED = 0;
11338
- // TODO - TERRY/DAVE: Discuss
11350
+ // TODO - DASHBOARD: Discuss w/ Dave
11339
11351
  // # of items to report as problematic (e.g., features, districts, etc.)
11340
11352
  exports.NUMBER_OF_ITEMS_TO_REPORT = 10;
11341
11353
  // The virtual geoID for "neighbors" in other states
@@ -11382,7 +11394,7 @@ function isOutOfState(geoID) {
11382
11394
  return geoID == S.OUT_OF_STATE;
11383
11395
  }
11384
11396
  exports.isOutOfState = isOutOfState;
11385
- // TODO - UNASSIGNED
11397
+ // NOTE - UNASSIGNED
11386
11398
  // Get the districtID to which a geoID is assigned
11387
11399
  function getDistrict(plan, geoID) {
11388
11400
  // All geoIDs in a state *should be* assigned to a district (including the
@@ -11440,7 +11452,7 @@ function normalize(rawScore, testScale) {
11440
11452
  let coercedValue = Math.min(Math.max(rawScore, rangeMin), rangeMax);
11441
11453
  // Scale the bounded value w/in the range [0 - (rangeMax - rangeMin)]
11442
11454
  let scaledValue = (coercedValue - rangeMin) / (rangeMax - rangeMin);
11443
- // TODO - SPLITTING
11455
+ // NOTE - SPLITTING
11444
11456
  // Invert the scaled value if necessary to make bigger = better
11445
11457
  if (testScale.bInvertScaled) {
11446
11458
  scaledValue = 1.0 - scaledValue;
@@ -11943,8 +11955,6 @@ const _api_1 = __webpack_require__(/*! ../src/_api */ "./src/_api.ts");
11943
11955
  const preprocess_1 = __webpack_require__(/*! ../src/preprocess */ "./src/preprocess.ts");
11944
11956
  const analyze_1 = __webpack_require__(/*! ../src/analyze */ "./src/analyze.ts");
11945
11957
  const results_1 = __webpack_require__(/*! ../src/results */ "./src/results.ts");
11946
- // TODO - DASHBOARD: Delete
11947
- // import { doAnalyzePostProcessing } from '../src/report'
11948
11958
  const valid_1 = __webpack_require__(/*! ../src/valid */ "./src/valid.ts");
11949
11959
  const equal_1 = __webpack_require__(/*! ../src/equal */ "./src/equal.ts");
11950
11960
  const compact_1 = __webpack_require__(/*! ../src/compact */ "./src/compact.ts");
@@ -11956,7 +11966,7 @@ const S = __importStar(__webpack_require__(/*! ../src/settings */ "./src/setting
11956
11966
  const D = __importStar(__webpack_require__(/*! ../src/_data */ "./src/_data.ts"));
11957
11967
  // Simulate DRA unioning district shapes in the background
11958
11968
  function addToPoly(poly, polys) {
11959
- // TODO - Fix 'poly' import, so I don't have to do this workaround.
11969
+ // TODO - POLY: Fix 'poly' import, so I don't have to do this workaround.
11960
11970
  // return PC.union(poly, ...polys);
11961
11971
  let union = PC.union;
11962
11972
  if (union === undefined)
@@ -12053,18 +12063,20 @@ let bEmpty = argv.empty;
12053
12063
  let suites = argv.suites;
12054
12064
  // Some default dataset keys
12055
12065
  let datasetKeys = {
12066
+ SHAPES: "2010_VD",
12056
12067
  CENSUS: "D16F",
12057
12068
  VAP: "D16T",
12058
12069
  ELECTION: "E16GPR"
12059
12070
  };
12060
12071
  let datasetDescriptions = {
12072
+ SHAPES: "2010 Voting Districts",
12061
12073
  CENSUS: "2016 ACS Total Population",
12062
12074
  VAP: "2016 ACS Voting Age Population",
12063
12075
  ELECTION: "2016 Presidential Election",
12064
12076
  };
12065
12077
  // Session settings are required:
12066
12078
  // - Analytics suites can be defaulted to all with [], but
12067
- // - Dataset must be explicitly specified
12079
+ // - Datasets must be explicitly specified
12068
12080
  let sessionSettings = {
12069
12081
  'suites': suites,
12070
12082
  'datasets': datasetKeys,
@@ -12224,7 +12236,7 @@ switch (command) {
12224
12236
  case 'cohesive': {
12225
12237
  preprocess_1.doPreprocessData(s);
12226
12238
  analyze_1.doAnalyzeDistricts(s);
12227
- // TODO - SPLITTING
12239
+ // NOTE - SPLITTING
12228
12240
  let t1 = cohesive_1.doFindCountiesSplitUnexpectedly(s);
12229
12241
  let t2 = cohesive_1.doFindSplitVTDs(s);
12230
12242
  let t3 = cohesive_1.doCountySplitting(s);