@dra2020/district-analytics 2.0.6 → 2.0.9
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 +93 -9
- package/dist/cli.js.map +1 -1
- package/dist/district-analytics.js +93 -9
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/geofeature.d.ts +2 -0
- package/dist/src/score.d.ts +4 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8055,6 +8055,7 @@ const preprocess_1 = __webpack_require__(/*! ./preprocess */ "./src/preprocess.t
|
|
|
8055
8055
|
const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
|
|
8056
8056
|
const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
8057
8057
|
const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
|
|
8058
|
+
const geofeature_1 = __webpack_require__(/*! ./geofeature */ "./src/geofeature.ts");
|
|
8058
8059
|
const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
|
|
8059
8060
|
const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
|
|
8060
8061
|
class AnalyticsSession {
|
|
@@ -8127,19 +8128,82 @@ class AnalyticsSession {
|
|
|
8127
8128
|
// NOTE - This assumes that analyzePlan() has been run!
|
|
8128
8129
|
getDiscontiguousDistrictFeatures(bLog = false) {
|
|
8129
8130
|
// Get the (possibly empty) list of discontiguous district IDs
|
|
8130
|
-
|
|
8131
|
-
|
|
8131
|
+
const contiguousTest = this.getTest(1 /* Contiguous */);
|
|
8132
|
+
const discontiguousDistrictIDs = contiguousTest['details']['discontiguousDistricts'] || [];
|
|
8132
8133
|
// Convert them into a (possibly empty) list of features
|
|
8133
8134
|
let discontiguousDistrictFeatures = { type: 'FeatureCollection', features: [] };
|
|
8134
8135
|
if (!(U.isArrayEmpty(discontiguousDistrictIDs))) {
|
|
8135
8136
|
for (let id of discontiguousDistrictIDs) {
|
|
8136
8137
|
let poly = this.districts.getDistrictShapeByID(id);
|
|
8137
|
-
if (poly)
|
|
8138
|
-
|
|
8138
|
+
if (poly) {
|
|
8139
|
+
// If a district has a shape & it is not contiguous, by definition,
|
|
8140
|
+
// it will be a Multipolygon, i.e., it will have multiple pieces, some
|
|
8141
|
+
// possibly embedded w/in other districts. Get & add all the pieces.
|
|
8142
|
+
const districtParts = geofeature_1.polyParts(poly);
|
|
8143
|
+
discontiguousDistrictFeatures.features.push(...districtParts.features);
|
|
8144
|
+
// discontiguousDistrictFeatures.features.push(poly);
|
|
8145
|
+
}
|
|
8139
8146
|
}
|
|
8140
8147
|
}
|
|
8141
8148
|
return discontiguousDistrictFeatures;
|
|
8142
8149
|
}
|
|
8150
|
+
// Comments clipped from dra-client geodistrict.ts.
|
|
8151
|
+
// Discontiguous polygons are:
|
|
8152
|
+
// 1. All polygons in a multi-polygon; and
|
|
8153
|
+
// 2. All holes in a otherwise cohesive polygon.
|
|
8154
|
+
// Note that all non-cohesive features are always simple polygons.
|
|
8155
|
+
/*
|
|
8156
|
+
let i: number, j: number;
|
|
8157
|
+
let nPoly: number = 0;
|
|
8158
|
+
for (i = 0;nPoly == 0 && i < this.cacheDistricts.features.length;i++)
|
|
8159
|
+
{
|
|
8160
|
+
let f = this.cacheDistricts.features[i];
|
|
8161
|
+
|
|
8162
|
+
if (f.geometry.type === 'MultiPolygon')
|
|
8163
|
+
nPoly += f.geometry.coordinates.length;
|
|
8164
|
+
else if (f.geometry.type === 'Polygon' && f.geometry.coordinates.length)
|
|
8165
|
+
nPoly += (f.geometry.coordinates.length - 1);
|
|
8166
|
+
}
|
|
8167
|
+
if (nPoly)
|
|
8168
|
+
{
|
|
8169
|
+
this.cacheNoncohesive = {type: 'FeatureCollection', features: []};
|
|
8170
|
+
let af: any = this.cacheNoncohesive.features;
|
|
8171
|
+
let oUnique: any = {};
|
|
8172
|
+
|
|
8173
|
+
// First add discontiguous polygons
|
|
8174
|
+
for (i = 0;i < this.cacheDistricts.features.length;i++)
|
|
8175
|
+
{
|
|
8176
|
+
let f = this.cacheDistricts.features[i];
|
|
8177
|
+
|
|
8178
|
+
if (f.geometry.type === 'MultiPolygon')
|
|
8179
|
+
{
|
|
8180
|
+
// Push all non-contiguous polygons
|
|
8181
|
+
for (j = 0;j < f.geometry.coordinates.length;j++)
|
|
8182
|
+
{
|
|
8183
|
+
let p: any = f.geometry.coordinates[j];
|
|
8184
|
+
oUnique[Hash.qhash(p[0])] = true;
|
|
8185
|
+
af.push({type: 'Feature', properties: {id: `${af.length + 1}`}, geometry: {type: 'Polygon', coordinates: p}});
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
|
|
8190
|
+
// Now add unique holes
|
|
8191
|
+
for (i = 0;i < this.cacheDistricts.features.length;i++)
|
|
8192
|
+
{
|
|
8193
|
+
let f = this.cacheDistricts.features[i];
|
|
8194
|
+
|
|
8195
|
+
if (f.geometry.type === 'Polygon')
|
|
8196
|
+
{
|
|
8197
|
+
// Push all holes from this polygon
|
|
8198
|
+
for (j = 1;j < f.geometry.coordinates.length;j++)
|
|
8199
|
+
{
|
|
8200
|
+
let p: any = f.geometry.coordinates[j];
|
|
8201
|
+
if (oUnique[Hash.qhash(p)] === undefined)
|
|
8202
|
+
af.push({type: 'Feature', properties: {id: `${af.length + 1}`}, geometry: {type: 'Polygon', coordinates: [p]}});
|
|
8203
|
+
}
|
|
8204
|
+
}
|
|
8205
|
+
}
|
|
8206
|
+
} */
|
|
8143
8207
|
// HELPERS USED INTERNALLY
|
|
8144
8208
|
// Get an individual test, so you can drive UI with the results.
|
|
8145
8209
|
getTest(testID) {
|
|
@@ -8331,6 +8395,9 @@ class Districts {
|
|
|
8331
8395
|
// 3 - MORE ...
|
|
8332
8396
|
// HACK - Because "this" gets ghosted inside the forEach loop below
|
|
8333
8397
|
let outerThis = this;
|
|
8398
|
+
// Default the pop dev % for the dummy Unassigned district to 0%.
|
|
8399
|
+
// Default the pop dev % for real (1–N) but empty districts to 100%.
|
|
8400
|
+
let popDevPct = (i > 0) ? (targetSize / targetSize) : 0 / targetSize;
|
|
8334
8401
|
// Get the geoIDs assigned to the district
|
|
8335
8402
|
// Guard against empty districts
|
|
8336
8403
|
let geoIDs = this._session.plan.geoIDsForDistrictID(i);
|
|
@@ -8377,11 +8444,11 @@ class Districts {
|
|
|
8377
8444
|
});
|
|
8378
8445
|
// COMPUTE DERIVED VALUES
|
|
8379
8446
|
// Population deviation % and equal population (boolean) by district.
|
|
8380
|
-
// Default the value for the dummy unassigned district to 0%.
|
|
8381
|
-
let popDevPct = 0 / targetSize;
|
|
8382
8447
|
if (i > 0) {
|
|
8383
|
-
|
|
8384
|
-
|
|
8448
|
+
if (totalPop > 0) {
|
|
8449
|
+
popDevPct = (totalPop - targetSize) / targetSize;
|
|
8450
|
+
bEqualPop = (Math.abs(popDevPct) <= deviationThreshold);
|
|
8451
|
+
}
|
|
8385
8452
|
}
|
|
8386
8453
|
// Total two-party (not total total!) votes, Democratic and Republican vote
|
|
8387
8454
|
// shares, and Democratic first-past-the-post win (= 1) or loss (= 0).
|
|
@@ -8470,7 +8537,7 @@ class Districts {
|
|
|
8470
8537
|
}
|
|
8471
8538
|
}
|
|
8472
8539
|
else { // If a district is empty, zero these results (vs. null)
|
|
8473
|
-
this.statistics[DistrictField.PopDevPct][i] =
|
|
8540
|
+
this.statistics[DistrictField.PopDevPct][i] = popDevPct;
|
|
8474
8541
|
this.statistics[DistrictField.DemVotes][i] = 0;
|
|
8475
8542
|
this.statistics[DistrictField.RepVotes][i] = 0;
|
|
8476
8543
|
this.statistics[DistrictField.TwoPartyVote][i] = 0;
|
|
@@ -9487,6 +9554,23 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
9487
9554
|
};
|
|
9488
9555
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9489
9556
|
const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "./node_modules/@dra2020/poly/dist/poly.js"));
|
|
9557
|
+
// HELPER
|
|
9558
|
+
function polyParts(poly) {
|
|
9559
|
+
let parts = { type: 'FeatureCollection', features: [] };
|
|
9560
|
+
let af = parts.features;
|
|
9561
|
+
if (poly.geometry.type === 'MultiPolygon') {
|
|
9562
|
+
// Push all non-contiguous polygons
|
|
9563
|
+
for (let j = 0; j < poly.geometry.coordinates.length; j++) {
|
|
9564
|
+
let onePoly = poly.geometry.coordinates[j];
|
|
9565
|
+
af.push({ type: 'Feature', properties: { id: `${af.length + 1}` }, geometry: { type: 'Polygon', coordinates: onePoly } });
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9568
|
+
else {
|
|
9569
|
+
parts.features.push(poly);
|
|
9570
|
+
}
|
|
9571
|
+
return parts;
|
|
9572
|
+
}
|
|
9573
|
+
exports.polyParts = polyParts;
|
|
9490
9574
|
// CARTESIAN SHIMS OVER 'POLY' FUNCTIONS
|
|
9491
9575
|
// TODO - POLY: Confirm Cartesian calculations
|
|
9492
9576
|
function gfArea(poly) {
|