@dra2020/district-analytics 1.0.4 → 1.0.7
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/.prettierrc +5 -0
- package/dist/_api.d.ts +27 -0
- package/dist/_data.d.ts +130 -0
- package/dist/analyze.d.ts +4 -0
- package/dist/cli.js +12091 -0
- package/dist/cli.js.map +1 -0
- package/dist/cohesive.d.ts +4 -0
- package/dist/compact.d.ts +5 -0
- package/dist/constants.d.ts +6 -0
- package/dist/district-analytics.js +102 -52
- package/dist/district-analytics.js.map +1 -0
- package/dist/equal.d.ts +4 -0
- package/dist/geofeature.d.ts +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/minority.d.ts +3 -0
- package/dist/political.d.ts +8 -0
- package/dist/preprocess.d.ts +2 -0
- package/dist/report.d.ts +15 -0
- package/dist/settings.d.ts +5 -0
- package/dist/test/_cli.d.ts +5 -0
- package/dist/types.d.ts +110 -0
- package/dist/utils.d.ts +28 -0
- package/dist/valid.d.ts +8 -0
- package/jestconfig.json +14 -0
- package/lib/HelloWorld.d.ts +3 -0
- package/lib/HelloWorld.js +11 -0
- package/lib/_api.js +91 -0
- package/lib/_api.js.map +1 -0
- package/lib/_cli.js +434 -0
- package/lib/_cli.js.map +1 -0
- package/lib/_data.js +425 -0
- package/lib/_data.js.map +1 -0
- package/lib/analyze.d.ts +3 -0
- package/lib/analyze.js +69 -0
- package/lib/analyze.js.map +1 -0
- package/lib/api.d.ts +34 -0
- package/lib/api.js +117 -0
- package/lib/api.js.map +1 -0
- package/lib/cli.d.ts +1 -0
- package/lib/cli.js +386 -0
- package/lib/cli.js.map +1 -0
- package/lib/cohesive.d.ts +4 -0
- package/lib/cohesive.js +132 -0
- package/lib/cohesive.js.map +1 -0
- package/lib/compact.d.ts +4 -0
- package/lib/compact.js +183 -0
- package/lib/compact.js.map +1 -0
- package/lib/constants.js +367 -0
- package/lib/constants.js.map +1 -0
- package/lib/data.js +188 -0
- package/lib/data.js.map +1 -0
- package/lib/equal.d.ts +4 -0
- package/lib/equal.js +59 -0
- package/lib/equal.js.map +1 -0
- package/lib/features.js +19 -0
- package/lib/features.js.map +1 -0
- package/lib/geofeature.js +112 -0
- package/lib/geofeature.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -0
- package/lib/minority.d.ts +3 -0
- package/lib/minority.js +61 -0
- package/lib/minority.js.map +1 -0
- package/lib/political.d.ts +7 -0
- package/lib/political.js +88 -0
- package/lib/political.js.map +1 -0
- package/lib/preprocess.d.ts +4 -0
- package/lib/preprocess.js +101 -0
- package/lib/preprocess.js.map +1 -0
- package/lib/report.d.ts +14 -0
- package/lib/report.js +817 -0
- package/lib/report.js.map +1 -0
- package/lib/sample.d.ts +1 -0
- package/lib/sample.js +32 -0
- package/lib/sample.js.map +1 -0
- package/lib/scorecard.d.ts +4 -0
- package/lib/scorecard.js +237 -0
- package/lib/scorecard.js.map +1 -0
- package/lib/settings.d.ts +5 -0
- package/lib/settings.js +18 -0
- package/lib/settings.js.map +1 -0
- package/lib/types.d.ts +125 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/lib/utils.d.ts +20 -0
- package/lib/utils.js +223 -0
- package/lib/utils.js.map +1 -0
- package/lib/valid.d.ts +5 -0
- package/lib/valid.js +230 -0
- package/lib/valid.js.map +1 -0
- package/main.js +4 -0
- package/package.json +2 -7
- package/src/_api.ts +121 -0
- package/src/_data.ts +595 -0
- package/src/analyze.ts +92 -0
- package/src/cohesive.ts +156 -0
- package/src/compact.ts +208 -0
- package/src/constants.ts +371 -0
- package/src/equal.ts +75 -0
- package/src/geofeature.ts +138 -0
- package/src/index.ts +6 -0
- package/src/minority.ts +70 -0
- package/src/political.ts +114 -0
- package/src/preprocess.ts +132 -0
- package/src/report.ts +1022 -0
- package/src/settings.ts +20 -0
- package/src/types.ts +185 -0
- package/src/utils.ts +245 -0
- package/src/valid.ts +275 -0
- package/tsconfig.json +25 -0
- package/tslint.json +3 -0
- package/types/polygon-clipping/index.d.ts +1 -0
- package/webpack.config.js +73 -0
package/lib/report.js
ADDED
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
//
|
|
3
|
+
// GENERATE REPORTS
|
|
4
|
+
// - A test log: a simple enumeration of all analytics & validations w/ raw results
|
|
5
|
+
// - A scorecard: a structured subset of analytics & validations w/ normalized
|
|
6
|
+
// results, cateories, and an overall score
|
|
7
|
+
//
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const U = require("./utils");
|
|
10
|
+
const S = require("./settings");
|
|
11
|
+
const D = require("./_data");
|
|
12
|
+
const analyze_1 = require("./analyze");
|
|
13
|
+
// TEST META-DATA
|
|
14
|
+
var TestType;
|
|
15
|
+
(function (TestType) {
|
|
16
|
+
TestType[TestType["PassFail"] = 0] = "PassFail";
|
|
17
|
+
TestType[TestType["Percentage"] = 1] = "Percentage";
|
|
18
|
+
TestType[TestType["Number"] = 2] = "Number";
|
|
19
|
+
})(TestType || (TestType = {}));
|
|
20
|
+
const completeDefn = {
|
|
21
|
+
ID: 0 /* Complete */,
|
|
22
|
+
name: "Complete",
|
|
23
|
+
normalize: false,
|
|
24
|
+
externalType: TestType.PassFail,
|
|
25
|
+
detailsFn: doPrepareCompleteDetails,
|
|
26
|
+
suites: [0 /* Legal */]
|
|
27
|
+
};
|
|
28
|
+
const contiguousDefn = {
|
|
29
|
+
ID: 1 /* Contiguous */,
|
|
30
|
+
name: "Contiguous",
|
|
31
|
+
normalize: false,
|
|
32
|
+
externalType: TestType.PassFail,
|
|
33
|
+
detailsFn: doPrepareContiguousDetails,
|
|
34
|
+
suites: [0 /* Legal */]
|
|
35
|
+
};
|
|
36
|
+
const freeOfHolesDefn = {
|
|
37
|
+
ID: 2 /* FreeOfHoles */,
|
|
38
|
+
name: "Free of Holes",
|
|
39
|
+
normalize: false,
|
|
40
|
+
externalType: TestType.PassFail,
|
|
41
|
+
detailsFn: doPrepareFreeOfHolesDetails,
|
|
42
|
+
suites: [0 /* Legal */]
|
|
43
|
+
};
|
|
44
|
+
const equalPopulationDefn = {
|
|
45
|
+
ID: 3 /* EqualPopulation */,
|
|
46
|
+
name: "Equal Population",
|
|
47
|
+
normalize: false,
|
|
48
|
+
externalType: TestType.PassFail,
|
|
49
|
+
detailsFn: doPrepareEqualPopulationDetails,
|
|
50
|
+
suites: [0 /* Legal */]
|
|
51
|
+
};
|
|
52
|
+
const populationDeviationDefn = {
|
|
53
|
+
ID: 4 /* PopulationDeviation */,
|
|
54
|
+
name: "Population Deviation",
|
|
55
|
+
normalize: true,
|
|
56
|
+
externalType: TestType.Percentage,
|
|
57
|
+
detailsFn: doPreparePopulationDeviationDetails,
|
|
58
|
+
suites: [0 /* Legal */, 2 /* Best */] // Both so EqualPopulation can be assessed
|
|
59
|
+
};
|
|
60
|
+
const reockDefn = {
|
|
61
|
+
ID: 5 /* Reock */,
|
|
62
|
+
name: "Reock",
|
|
63
|
+
normalize: true,
|
|
64
|
+
externalType: TestType.Number,
|
|
65
|
+
detailsFn: doPrepareReockDetails,
|
|
66
|
+
suites: [2 /* Best */]
|
|
67
|
+
};
|
|
68
|
+
const polsbyPopperDefn = {
|
|
69
|
+
ID: 6 /* PolsbyPopper */,
|
|
70
|
+
name: "Polsby-Popper",
|
|
71
|
+
normalize: true,
|
|
72
|
+
externalType: TestType.Number,
|
|
73
|
+
detailsFn: doPreparePolsbyPopperDetails,
|
|
74
|
+
suites: [2 /* Best */]
|
|
75
|
+
};
|
|
76
|
+
const countySplitsDefn = {
|
|
77
|
+
ID: 7 /* CountySplits */,
|
|
78
|
+
name: "County splits",
|
|
79
|
+
trailer: "of the population had their county split unexpectedly.",
|
|
80
|
+
normalize: true,
|
|
81
|
+
externalType: TestType.Percentage,
|
|
82
|
+
detailsFn: doPrepareCountySplitDetails,
|
|
83
|
+
suites: [2 /* Best */]
|
|
84
|
+
};
|
|
85
|
+
const efficiencyGapDefn = {
|
|
86
|
+
ID: 13 /* EfficiencyGap */,
|
|
87
|
+
name: "Efficiency Gap",
|
|
88
|
+
normalize: false,
|
|
89
|
+
externalType: TestType.Percentage,
|
|
90
|
+
detailsFn: doPrepareEfficiencyGapDetails,
|
|
91
|
+
suites: [1 /* Fair */]
|
|
92
|
+
};
|
|
93
|
+
// All the tests that have been defined (can be reported on)
|
|
94
|
+
const testDefns = {
|
|
95
|
+
[0 /* Complete */]: completeDefn,
|
|
96
|
+
[1 /* Contiguous */]: contiguousDefn,
|
|
97
|
+
[2 /* FreeOfHoles */]: freeOfHolesDefn,
|
|
98
|
+
[3 /* EqualPopulation */]: equalPopulationDefn,
|
|
99
|
+
[4 /* PopulationDeviation */]: populationDeviationDefn,
|
|
100
|
+
[5 /* Reock */]: reockDefn,
|
|
101
|
+
[6 /* PolsbyPopper */]: polsbyPopperDefn,
|
|
102
|
+
[7 /* CountySplits */]: countySplitsDefn,
|
|
103
|
+
[13 /* EfficiencyGap */]: efficiencyGapDefn
|
|
104
|
+
/* TODO - More tests ... */
|
|
105
|
+
};
|
|
106
|
+
// Scorecard category definitions
|
|
107
|
+
const validCategory = {
|
|
108
|
+
catName: "Valid",
|
|
109
|
+
catTests: [
|
|
110
|
+
{ testID: 0 /* Complete */ },
|
|
111
|
+
{ testID: 1 /* Contiguous */ },
|
|
112
|
+
{ testID: 2 /* FreeOfHoles */ },
|
|
113
|
+
{ testID: 3 /* EqualPopulation */ }
|
|
114
|
+
],
|
|
115
|
+
catNumeric: false,
|
|
116
|
+
catWeight: undefined,
|
|
117
|
+
catPrepareFn: doPrepareValidSection
|
|
118
|
+
};
|
|
119
|
+
const fairCategory = {
|
|
120
|
+
catName: "Fair",
|
|
121
|
+
catTests: [
|
|
122
|
+
{
|
|
123
|
+
testID: 13 /* EfficiencyGap */,
|
|
124
|
+
testWeight: 100
|
|
125
|
+
}
|
|
126
|
+
],
|
|
127
|
+
catNumeric: true,
|
|
128
|
+
catWeight: undefined,
|
|
129
|
+
catPrepareFn: doPrepareFairSection
|
|
130
|
+
};
|
|
131
|
+
// TODO - Decide on the relative weights of these tests!
|
|
132
|
+
// NOTE: 'testWeights' are simply relative, i.e., each normalized score is
|
|
133
|
+
// multiplied by the associated 'testWeight', and the sum of those is divided
|
|
134
|
+
// by the total weight. Weights don't have to add to 100.
|
|
135
|
+
const bestCategory = {
|
|
136
|
+
catName: "Best",
|
|
137
|
+
catTests: [
|
|
138
|
+
{
|
|
139
|
+
testID: 4 /* PopulationDeviation */,
|
|
140
|
+
testWeight: 10
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
testID: 5 /* Reock */,
|
|
144
|
+
testWeight: 25
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
testID: 6 /* PolsbyPopper */,
|
|
148
|
+
testWeight: 25
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
testID: 7 /* CountySplits */,
|
|
152
|
+
testWeight: 50
|
|
153
|
+
}
|
|
154
|
+
],
|
|
155
|
+
catNumeric: true,
|
|
156
|
+
catWeight: undefined,
|
|
157
|
+
catPrepareFn: doPrepareBestSection
|
|
158
|
+
};
|
|
159
|
+
// The overall scorecard definition
|
|
160
|
+
const scorecardDefn = {
|
|
161
|
+
[0 /* Legal */]: validCategory,
|
|
162
|
+
// TODO - NIY
|
|
163
|
+
// [T.Suite.Fair]: fairCategory,
|
|
164
|
+
[2 /* Best */]: bestCategory
|
|
165
|
+
};
|
|
166
|
+
// NORMALIZE RAW ANALYTICS
|
|
167
|
+
// Raw numeric analytics, such as population deviation, compactness, etc. are
|
|
168
|
+
// normalized as part of creating a scorecard, so the code to normalize results
|
|
169
|
+
// is encapsulated here.
|
|
170
|
+
// Configure scale parameters for normalizing each raw test result
|
|
171
|
+
// This needs to be separate from the scorecard configuration info above,
|
|
172
|
+
// because some scales need access to the analytics session object.
|
|
173
|
+
function doConfigureScales(s) {
|
|
174
|
+
// Scale defn for PopulationDeviation
|
|
175
|
+
const CDLimit = 0.75 / 100; // Deviation threshold for CD's
|
|
176
|
+
const LDLimit = 10.00 / 100; // Deviation threshold for LD's
|
|
177
|
+
const CDGoodEnough = 0.20 / 100;
|
|
178
|
+
const LDGoodEnough = (CDGoodEnough / CDLimit) * LDLimit;
|
|
179
|
+
const scale = (s.legislativeDistricts) ? [1.0 - LDLimit, 1.0 - LDGoodEnough] : [1.0 - CDLimit, 1.0 - CDGoodEnough];
|
|
180
|
+
// const scale = [1.0 - CDLimit, 1.0 - CDGoodEnough];
|
|
181
|
+
s.testScales[4 /* PopulationDeviation */] = { testScale: scale, testInvertp: true };
|
|
182
|
+
s.testScales[5 /* Reock */] = { testScale: [0.25, 0.50], testInvertp: false };
|
|
183
|
+
s.testScales[6 /* PolsbyPopper */] = { testScale: [0.10, 0.50], testInvertp: false };
|
|
184
|
+
const SPLITLimit = 0.1; // TODO - Just a placeholder default maximum (10%)
|
|
185
|
+
s.testScales[7 /* CountySplits */] = { testScale: [1.0 - SPLITLimit, 1.0], testInvertp: true };
|
|
186
|
+
// TODO - More analytics ...
|
|
187
|
+
}
|
|
188
|
+
exports.doConfigureScales = doConfigureScales;
|
|
189
|
+
// Postprocess analytics - Normalize numeric results and derive secondary tests.
|
|
190
|
+
// Do this after analytics have been run and before preparing a test log or scorecard.
|
|
191
|
+
function doAnalyzePostProcessing(s) {
|
|
192
|
+
// Normalize the raw scores for all the numerics tests
|
|
193
|
+
let testResults = U.getNumericObjectKeys(testDefns);
|
|
194
|
+
for (let testID of testResults) {
|
|
195
|
+
if (testDefns[testID]['normalize']) {
|
|
196
|
+
let testResult = s.getTest(testID);
|
|
197
|
+
let rawScore = testResult['score'];
|
|
198
|
+
let normalizedScore;
|
|
199
|
+
let { testScale, testInvertp } = s.testScales[testID];
|
|
200
|
+
normalizedScore = U.normalize(rawScore, testScale, testInvertp);
|
|
201
|
+
testResult['normalizedScore'] = normalizedScore;
|
|
202
|
+
// Add the scale used to normalize the raw score to the details
|
|
203
|
+
testResult['details']['scale'] = testScale;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Derive secondary tests
|
|
207
|
+
analyze_1.doDeriveSecondaryTests(s);
|
|
208
|
+
// Toggle the semaphore, so postprocessing isn't for both the testlog & scorecard
|
|
209
|
+
s.bPostProcessingDone = true;
|
|
210
|
+
}
|
|
211
|
+
exports.doAnalyzePostProcessing = doAnalyzePostProcessing;
|
|
212
|
+
// Prepare a structured but unformatted scorecard, from the test results
|
|
213
|
+
function doGenerateScorecard(s) {
|
|
214
|
+
if (!(s.bPostProcessingDone)) {
|
|
215
|
+
doAnalyzePostProcessing(s);
|
|
216
|
+
}
|
|
217
|
+
// Create a new scorecard
|
|
218
|
+
let scorecard = {};
|
|
219
|
+
// Filter the defined scorecard categories by the requested test suites
|
|
220
|
+
let categories = U.getNumericObjectKeys(scorecardDefn);
|
|
221
|
+
let suitesRequested = s.config['suites'];
|
|
222
|
+
categories = categories.filter(x => suitesRequested.includes(x));
|
|
223
|
+
// ... and initialize each one in the new scorecard
|
|
224
|
+
for (let c of categories) {
|
|
225
|
+
scorecard[c] = {};
|
|
226
|
+
scorecard[c]['catName'] = scorecardDefn[c]['catName'];
|
|
227
|
+
scorecard[c]['catTests'] = {};
|
|
228
|
+
// scorecard[c]['catScore'] = undefined;
|
|
229
|
+
}
|
|
230
|
+
// For each scorecard category
|
|
231
|
+
for (let c of categories) {
|
|
232
|
+
// Grab the scorecard category definition
|
|
233
|
+
let { catName, catTests, catNumeric } = scorecardDefn[c];
|
|
234
|
+
let numericCategoryScore = 0;
|
|
235
|
+
let totalWeight = 0;
|
|
236
|
+
let booleanCategoryScore = true;
|
|
237
|
+
// Process the results for each test result in the category
|
|
238
|
+
for (let testDefn of catTests) {
|
|
239
|
+
// Get the config info for the test
|
|
240
|
+
let testID = testDefn['testID'];
|
|
241
|
+
// ... and the actual test result
|
|
242
|
+
let testResult = s.getTest(testID);
|
|
243
|
+
// Create a new test entry for the scorecard
|
|
244
|
+
let testReport = U.deepCopy(testResult);
|
|
245
|
+
// Add the name
|
|
246
|
+
testReport['name'] = testDefns[testID]['name'];
|
|
247
|
+
if (catNumeric) {
|
|
248
|
+
// Normalize raw numeric scores ... moved to FIRST PASS above
|
|
249
|
+
// Accumulate a category score
|
|
250
|
+
let normalizedScore = testReport['normalizedScore'];
|
|
251
|
+
numericCategoryScore += normalizedScore * testDefn['testWeight'];
|
|
252
|
+
totalWeight += testDefn['testWeight'];
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// AND together pass/fail tests into a category score
|
|
256
|
+
if (!testReport['score']) {
|
|
257
|
+
booleanCategoryScore = false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
scorecard[c]['catTests'][testID] = testReport;
|
|
261
|
+
}
|
|
262
|
+
// Set the category score
|
|
263
|
+
if (catNumeric) {
|
|
264
|
+
scorecard[c]['catScore'] = Math.round(numericCategoryScore / totalWeight);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
scorecard[c]['catScore'] = booleanCategoryScore;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// TODO - Compute an overall score from the category weights
|
|
271
|
+
return scorecard;
|
|
272
|
+
}
|
|
273
|
+
// Prepare a formatted scorecard suitable for rendering
|
|
274
|
+
function doPrepareScorecard(s) {
|
|
275
|
+
// Initialize the output format
|
|
276
|
+
let text = { data: [] };
|
|
277
|
+
let blocks = text.data;
|
|
278
|
+
// If the plan as already been analyzed, prepare a scorecard
|
|
279
|
+
if (s.bPlanAnalyzed) {
|
|
280
|
+
// Create and cache a new, unformatted scorecard
|
|
281
|
+
s.scorecard = doGenerateScorecard(s);
|
|
282
|
+
// Create a scorecard header
|
|
283
|
+
blocks.push({ variant: 'h4', text: `Analysis` });
|
|
284
|
+
// Report district statistics
|
|
285
|
+
blocks.push({ variant: 'h5', text: `Individual Districts` });
|
|
286
|
+
let districtStatisticsText = doPrepareDistrictStatistics(s);
|
|
287
|
+
blocks.push(...districtStatisticsText);
|
|
288
|
+
// Prepare each scorecard category
|
|
289
|
+
blocks.push({ variant: 'h5', text: `Overall Plan` });
|
|
290
|
+
let categories = U.getNumericObjectKeys(s.scorecard);
|
|
291
|
+
for (let c of categories) {
|
|
292
|
+
let sectionPrepareFn = scorecardDefn[c]['catPrepareFn'];
|
|
293
|
+
let sectionText = sectionPrepareFn(s, c);
|
|
294
|
+
blocks.push(...sectionText);
|
|
295
|
+
}
|
|
296
|
+
// Report what datasets were used
|
|
297
|
+
let c = s.config['datasets']["CENSUS" /* CENSUS */];
|
|
298
|
+
let v = s.config['datasets']["VAP" /* VAP */];
|
|
299
|
+
let e = s.config['datasets']["ELECTION" /* ELECTION */];
|
|
300
|
+
blocks.push({ variant: 'body1', text: `Using datasets:` });
|
|
301
|
+
blocks.push({ variant: 'body1', text: `* ${c}: ${D.DatasetDescriptions[c]}` });
|
|
302
|
+
blocks.push({ variant: 'body1', text: `* ${v}: ${D.DatasetDescriptions[v]}` });
|
|
303
|
+
blocks.push({ variant: 'body1', text: `* ${e}: ${D.DatasetDescriptions[e]}` });
|
|
304
|
+
}
|
|
305
|
+
// Otherwise, return a blank scorecard
|
|
306
|
+
// TODO - What dra-client returns from renderAnalyzeCore()
|
|
307
|
+
// return <STV.StaticTextView text={ text } />;
|
|
308
|
+
return text;
|
|
309
|
+
}
|
|
310
|
+
exports.doPrepareScorecard = doPrepareScorecard;
|
|
311
|
+
function doPrepareDistrictStatistics(s) {
|
|
312
|
+
let text = { data: [] };
|
|
313
|
+
let blocks = text.data;
|
|
314
|
+
blocks.push({ variant: 'beginTable' });
|
|
315
|
+
blocks.push({ variant: 'row', cells: ['ID', 'Total', 'Δ%', 'OK?', '*', 'Dem', 'Rep', 'White', 'Minority', 'Black', 'Hispanic', 'Pacific', 'Asian', 'Native'] });
|
|
316
|
+
for (let d = 0; d < s.districts.numberOfRows(); d++) {
|
|
317
|
+
let tot = s.districts.statistics[D.DistrictField.TotalPop][d];
|
|
318
|
+
if (tot == 0)
|
|
319
|
+
blocks.push({ variant: 'row', cells: [String(d), '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-', '-'] });
|
|
320
|
+
else {
|
|
321
|
+
tot = Math.round(tot);
|
|
322
|
+
let dev = fractionToPercentage(s.districts.statistics[D.DistrictField.PopDevPct][d]);
|
|
323
|
+
let bEq = true; // TODO - Set based on population threshold
|
|
324
|
+
let bC = s.districts.statistics[D.DistrictField.bContiguous][d]
|
|
325
|
+
&& s.districts.statistics[D.DistrictField.bNotEmbedded][d];
|
|
326
|
+
let dPct = fractionToPercentage(s.districts.statistics[D.DistrictField.DemPct][d]);
|
|
327
|
+
let rPct = fractionToPercentage(s.districts.statistics[D.DistrictField.RepPct][d]);
|
|
328
|
+
let wPct = fractionToPercentage(s.districts.statistics[D.DistrictField.WhitePct][d]);
|
|
329
|
+
let mPct = fractionToPercentage(s.districts.statistics[D.DistrictField.MinorityPct][d]);
|
|
330
|
+
let bPct = fractionToPercentage(s.districts.statistics[D.DistrictField.BlackPct][d]);
|
|
331
|
+
let hPct = fractionToPercentage(s.districts.statistics[D.DistrictField.HispanicPct][d]);
|
|
332
|
+
let pPct = fractionToPercentage(s.districts.statistics[D.DistrictField.PacificPct][d]);
|
|
333
|
+
let aPct = fractionToPercentage(s.districts.statistics[D.DistrictField.AsianPct][d]);
|
|
334
|
+
let nPct = fractionToPercentage(s.districts.statistics[D.DistrictField.NativePct][d]);
|
|
335
|
+
let id;
|
|
336
|
+
if (d == 0)
|
|
337
|
+
id = "??";
|
|
338
|
+
else if (d == (s.districts.numberOfRows() - 1))
|
|
339
|
+
id = " ";
|
|
340
|
+
else
|
|
341
|
+
id = String(d);
|
|
342
|
+
blocks.push({
|
|
343
|
+
variant: 'row',
|
|
344
|
+
cells: [
|
|
345
|
+
`${id}`,
|
|
346
|
+
`${formatInteger(tot)}`,
|
|
347
|
+
`${formatPercentage(dev)}%`,
|
|
348
|
+
`${pfBoolToString(bEq)}`,
|
|
349
|
+
`${pfBoolToString(bC)}`,
|
|
350
|
+
`${formatPercentage(dPct)}%`,
|
|
351
|
+
`${formatPercentage(rPct)}%`,
|
|
352
|
+
`${formatPercentage(wPct)}%`,
|
|
353
|
+
`${formatPercentage(mPct)}%`,
|
|
354
|
+
`${formatPercentage(bPct)}%`,
|
|
355
|
+
`${formatPercentage(hPct)}%`,
|
|
356
|
+
`${formatPercentage(pPct)}%`,
|
|
357
|
+
`${formatPercentage(aPct)}%`,
|
|
358
|
+
`${formatPercentage(nPct)}%`
|
|
359
|
+
]
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
blocks.push({ variant: 'endTable' });
|
|
364
|
+
return blocks;
|
|
365
|
+
}
|
|
366
|
+
// TEST LOG
|
|
367
|
+
// Prepare formatted test results for rendering
|
|
368
|
+
function doPrepareTestLog(s) {
|
|
369
|
+
// Initialize the output format
|
|
370
|
+
let text = { data: [] };
|
|
371
|
+
let blocks = text.data;
|
|
372
|
+
// If the plan as already been analyzed, prepare a test log
|
|
373
|
+
if (s.bPlanAnalyzed) {
|
|
374
|
+
if (!(s.bPostProcessingDone)) {
|
|
375
|
+
doAnalyzePostProcessing(s);
|
|
376
|
+
}
|
|
377
|
+
// Create a test log header
|
|
378
|
+
blocks.push({ variant: 'h4', text: `Test Log` });
|
|
379
|
+
let testResults = U.getNumericObjectKeys(testDefns);
|
|
380
|
+
let suitesRequested = new Set(s.config['suites']);
|
|
381
|
+
for (let testID of testResults) {
|
|
382
|
+
// Filter the defined tests by the requested test suites
|
|
383
|
+
let inSuites = testDefns[testID]['suites'];
|
|
384
|
+
if (!(U.isArrayEmpty(inSuites.filter(x => suitesRequested.has(x))))) {
|
|
385
|
+
// Get the test result
|
|
386
|
+
let testResult = s.getTest(testID);
|
|
387
|
+
// Prepare the text for it, and append it to the output
|
|
388
|
+
let testText = prepareTestEntry(testID, testResult);
|
|
389
|
+
blocks.push(...testText);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
// Otherwise, return a blank test log
|
|
394
|
+
// TODO - What dra-client returns from renderAnalyzeCore()
|
|
395
|
+
// return <STV.StaticTextView text={ text } />;
|
|
396
|
+
return text;
|
|
397
|
+
}
|
|
398
|
+
exports.doPrepareTestLog = doPrepareTestLog;
|
|
399
|
+
function prepareTestEntry(testID, testResult) {
|
|
400
|
+
let text = { data: [] };
|
|
401
|
+
let blocks = text.data;
|
|
402
|
+
let testName = testDefns[testID]['name'];
|
|
403
|
+
let testNameTrailer = "";
|
|
404
|
+
if (U.keyExists('trailer', testDefns[testID])) {
|
|
405
|
+
testNameTrailer = testDefns[testID]['trailer'];
|
|
406
|
+
}
|
|
407
|
+
let testType = testDefns[testID]['externalType'];
|
|
408
|
+
let bNormalize = testDefns[testID]['normalize'];
|
|
409
|
+
let detailsFn = testDefns[testID]['detailsFn'];
|
|
410
|
+
let detailsText = detailsFn(testResult);
|
|
411
|
+
let score; // NOTE - Won't be undefined here
|
|
412
|
+
let normalizedScore;
|
|
413
|
+
let scoreText;
|
|
414
|
+
// Get the score ...
|
|
415
|
+
score = testResult['score'];
|
|
416
|
+
// ... and format it for rendering
|
|
417
|
+
switch (testType) {
|
|
418
|
+
case TestType.PassFail: {
|
|
419
|
+
scoreText = pfBoolToString(score);
|
|
420
|
+
blocks.push({ variant: 'body1', text: `${testName}: ${scoreText} ${testNameTrailer}` });
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case TestType.Percentage: {
|
|
424
|
+
score = fractionToPercentage(score);
|
|
425
|
+
if (bNormalize) {
|
|
426
|
+
normalizedScore = testResult['normalizedScore'];
|
|
427
|
+
blocks.push({ variant: 'body1', text: `${testName}: ${normalizedScore} / 100 : ${formatPercentage(score)}% ${testNameTrailer}` });
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
blocks.push({ variant: 'body1', text: `${testName}: ${formatPercentage(score)}% ${testNameTrailer}` });
|
|
431
|
+
}
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
case TestType.Number: {
|
|
435
|
+
if (bNormalize) {
|
|
436
|
+
normalizedScore = testResult['normalizedScore'];
|
|
437
|
+
blocks.push({ variant: 'body1', text: `${testName}: ${normalizedScore} / 100 : ${formatNumber(score)} ${testNameTrailer}` });
|
|
438
|
+
}
|
|
439
|
+
else {
|
|
440
|
+
blocks.push({ variant: 'body1', text: `${testName}: ${formatNumber(score)} ${testNameTrailer}` });
|
|
441
|
+
}
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
default: {
|
|
445
|
+
// Unknown test type
|
|
446
|
+
throw new RangeError();
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
// Add the details text
|
|
450
|
+
blocks.push(...detailsText);
|
|
451
|
+
return blocks;
|
|
452
|
+
}
|
|
453
|
+
// FORMATTERS FOR TEST DETAILS
|
|
454
|
+
function doPrepareCompleteDetails(testResult) {
|
|
455
|
+
let text = { data: [] };
|
|
456
|
+
let blocks = text.data;
|
|
457
|
+
if (!U.isObjectEmpty(testResult['details'])) {
|
|
458
|
+
let unassignedText = "";
|
|
459
|
+
let emptyText = "";
|
|
460
|
+
let missingText = "";
|
|
461
|
+
if (U.keyExists('unassignedFeatures', testResult['details'])) {
|
|
462
|
+
let unassignedFeatures = testResult['details']['unassignedFeatures'];
|
|
463
|
+
let unassignedList = prepareListItems(unassignedFeatures);
|
|
464
|
+
let unassignedTextTemplates = [
|
|
465
|
+
`GEOID ${unassignedList} is not assigned to a district.`,
|
|
466
|
+
`GEOIDs ${unassignedList} are not assigned to districts.`,
|
|
467
|
+
`Several GEOIDs are not assigned to districts, including ${unassignedList}.`
|
|
468
|
+
];
|
|
469
|
+
unassignedText = prepareListText(unassignedFeatures, unassignedTextTemplates);
|
|
470
|
+
}
|
|
471
|
+
if (U.keyExists('emptyDistricts', testResult['details'])) {
|
|
472
|
+
let emptyDistricts = testResult['details']['emptyDistricts'];
|
|
473
|
+
let emptyList = prepareListItems(emptyDistricts);
|
|
474
|
+
let emptyTextTemplates = [
|
|
475
|
+
`District ${emptyList} is empty.`,
|
|
476
|
+
`Districts ${emptyList} are empty.`,
|
|
477
|
+
`Several districts are empty, including ${emptyList}.`
|
|
478
|
+
];
|
|
479
|
+
emptyText = prepareListText(emptyDistricts, emptyTextTemplates);
|
|
480
|
+
}
|
|
481
|
+
if (U.keyExists('missingDistricts', testResult['details'])) {
|
|
482
|
+
missingText = `Not enough districts have been defined. `;
|
|
483
|
+
}
|
|
484
|
+
let detailsText = " " + unassignedText + emptyText + missingText;
|
|
485
|
+
blocks.push({ variant: 'body1', text: detailsText });
|
|
486
|
+
}
|
|
487
|
+
return blocks;
|
|
488
|
+
}
|
|
489
|
+
function doPrepareContiguousDetails(testResult) {
|
|
490
|
+
let text = { data: [] };
|
|
491
|
+
let blocks = text.data;
|
|
492
|
+
if (!U.isObjectEmpty(testResult['details'])) {
|
|
493
|
+
let discontiguousDistricts = testResult['details']['discontiguousDistricts'];
|
|
494
|
+
let discontiguousList = prepareListItems(discontiguousDistricts);
|
|
495
|
+
let discontiguousTextTemplates = [
|
|
496
|
+
`District ${discontiguousList} is not contiguous.`,
|
|
497
|
+
`Districts ${discontiguousList} are not contiguous.`,
|
|
498
|
+
`Several districts are not contiguous, including ${discontiguousList}.`
|
|
499
|
+
];
|
|
500
|
+
let detailsText = prepareListText(discontiguousDistricts, discontiguousTextTemplates);
|
|
501
|
+
blocks.push({ variant: 'body1', text: detailsText });
|
|
502
|
+
}
|
|
503
|
+
return blocks;
|
|
504
|
+
}
|
|
505
|
+
function doPrepareFreeOfHolesDetails(testResult) {
|
|
506
|
+
let text = { data: [] };
|
|
507
|
+
let blocks = text.data;
|
|
508
|
+
if (!U.isObjectEmpty(testResult['details'])) {
|
|
509
|
+
let embeddedDistricts = testResult['details']['embeddedDistricts'];
|
|
510
|
+
let embeddedList = prepareListItems(embeddedDistricts);
|
|
511
|
+
let embeddedTextTemplates = [
|
|
512
|
+
`District ${embeddedList} is fully embedded within another district.`,
|
|
513
|
+
`Both districts ${embeddedList} are fully embedded within other districts.`,
|
|
514
|
+
`Several districts are fully embedded within other districts, including ${embeddedList}.`
|
|
515
|
+
];
|
|
516
|
+
let detailsText = prepareListText(embeddedDistricts, embeddedTextTemplates);
|
|
517
|
+
blocks.push({ variant: 'body1', text: detailsText });
|
|
518
|
+
}
|
|
519
|
+
return blocks;
|
|
520
|
+
}
|
|
521
|
+
function doPrepareEqualPopulationDetails(testResult) {
|
|
522
|
+
let text = { data: [] };
|
|
523
|
+
let blocks = text.data;
|
|
524
|
+
if (!U.isObjectEmpty(testResult['details'])) {
|
|
525
|
+
let popDevPct = fractionToPercentage(testResult['details']['deviation']);
|
|
526
|
+
let thresholdPct = fractionToPercentage(1.0 - testResult['details']['thresholds'][0]);
|
|
527
|
+
let detailsText = '';
|
|
528
|
+
if (!(testResult['score'])) {
|
|
529
|
+
detailsText = `The ${formatPercentage(popDevPct)}% population deviation is greater than the ${formatPercentage(thresholdPct)}% threshold tolerated by courts.`;
|
|
530
|
+
}
|
|
531
|
+
blocks.push({ variant: 'body1', text: detailsText });
|
|
532
|
+
}
|
|
533
|
+
return blocks;
|
|
534
|
+
}
|
|
535
|
+
function doPreparePopulationDeviationDetails(testResult) {
|
|
536
|
+
let text = { data: [] };
|
|
537
|
+
let blocks = text.data;
|
|
538
|
+
let n = Math.round(testResult['details']['maxDeviation']);
|
|
539
|
+
let term = "people";
|
|
540
|
+
if (n == 1) {
|
|
541
|
+
term = "person";
|
|
542
|
+
}
|
|
543
|
+
blocks.push({ variant: 'body1', text: `The maximum population deviation between districts is ${formatInteger(n)} ${term}.` });
|
|
544
|
+
return blocks;
|
|
545
|
+
}
|
|
546
|
+
function doPrepareReockDetails(testResult) {
|
|
547
|
+
let text = { data: [] };
|
|
548
|
+
let blocks = text.data;
|
|
549
|
+
// TODO - No details implemented yet
|
|
550
|
+
return blocks;
|
|
551
|
+
}
|
|
552
|
+
function doPreparePolsbyPopperDetails(testResult) {
|
|
553
|
+
let text = { data: [] };
|
|
554
|
+
let blocks = text.data;
|
|
555
|
+
// TODO - No details implemented yet
|
|
556
|
+
return blocks;
|
|
557
|
+
}
|
|
558
|
+
function doPrepareEfficiencyGapDetails(testResult) {
|
|
559
|
+
let text = { data: [] };
|
|
560
|
+
let blocks = text.data;
|
|
561
|
+
// TODO - Not yet implemented
|
|
562
|
+
return blocks;
|
|
563
|
+
}
|
|
564
|
+
function doPrepareCountySplitDetails(testResult) {
|
|
565
|
+
let text = { data: [] };
|
|
566
|
+
let blocks = text.data;
|
|
567
|
+
let unexpectedAffected = fractionToPercentage(testResult['details']['unexpectedAffected']);
|
|
568
|
+
let affectedText = `affecting ${formatPercentage(unexpectedAffected)}% of the total population.`;
|
|
569
|
+
let countiesSplitUnexpectedly = testResult['details']['countiesSplitUnexpectedly'];
|
|
570
|
+
let nCountiesSplitUnexpectedly = countiesSplitUnexpectedly.length;
|
|
571
|
+
let nUnexpectedSplits = testResult['details']['unexpectedSplits'];
|
|
572
|
+
let splitList = prepareListItems(countiesSplitUnexpectedly);
|
|
573
|
+
let splitTextTemplates = [
|
|
574
|
+
`${splitList} county is split unexpectedly, `,
|
|
575
|
+
`${splitList} counties are split unexpectedly, `,
|
|
576
|
+
// `These ${formatInteger(nCountiesSplitUnexpectedly)} counties are split unexpectedly--${splitList}--`
|
|
577
|
+
`${splitList} counties are split unexpectedly ${formatInteger(nUnexpectedSplits)} times, `
|
|
578
|
+
];
|
|
579
|
+
let detailsText = prepareListText(countiesSplitUnexpectedly, splitTextTemplates) + affectedText;
|
|
580
|
+
blocks.push({ variant: 'body1', text: detailsText });
|
|
581
|
+
return blocks;
|
|
582
|
+
}
|
|
583
|
+
// FORMATTERS FOR CATEGORIES
|
|
584
|
+
// This function parses & formats the 'Valid' section of a scorecard.
|
|
585
|
+
function doPrepareValidSection(s, c) {
|
|
586
|
+
// Get the category meta data
|
|
587
|
+
let { catName, catScore, catTests } = s.scorecard[c];
|
|
588
|
+
let testReport;
|
|
589
|
+
// Initialize the section text
|
|
590
|
+
let text = { data: [] };
|
|
591
|
+
let blocks = text.data;
|
|
592
|
+
let testText;
|
|
593
|
+
// Section header
|
|
594
|
+
let stringScore = pfBoolToString(catScore);
|
|
595
|
+
blocks.push({ variant: 'h6', text: `${catName}: ${stringScore}` });
|
|
596
|
+
// Complete
|
|
597
|
+
testReport = catTests[0 /* Complete */];
|
|
598
|
+
testText = prepareTestEntry(0 /* Complete */, testReport);
|
|
599
|
+
blocks.push(...testText);
|
|
600
|
+
// Contiguous
|
|
601
|
+
testReport = catTests[1 /* Contiguous */];
|
|
602
|
+
testText = prepareTestEntry(1 /* Contiguous */, testReport);
|
|
603
|
+
blocks.push(...testText);
|
|
604
|
+
// Free of holes (no embedded districts)
|
|
605
|
+
testReport = catTests[2 /* FreeOfHoles */];
|
|
606
|
+
testText = prepareTestEntry(2 /* FreeOfHoles */, testReport);
|
|
607
|
+
blocks.push(...testText);
|
|
608
|
+
// Equal population (w/in the appropriate legal threshold)
|
|
609
|
+
testReport = catTests[3 /* EqualPopulation */];
|
|
610
|
+
testText = prepareTestEntry(3 /* EqualPopulation */, testReport);
|
|
611
|
+
blocks.push(...testText);
|
|
612
|
+
return blocks;
|
|
613
|
+
}
|
|
614
|
+
// TODO - NIY
|
|
615
|
+
// This function parses & formats the 'Fair' section of a scorecard.
|
|
616
|
+
function doPrepareFairSection(s, c) {
|
|
617
|
+
// Get the category meta data
|
|
618
|
+
let { catName, catScore, catTests } = s.scorecard[c];
|
|
619
|
+
let testReport;
|
|
620
|
+
// Initialize the section text
|
|
621
|
+
let text = { data: [] };
|
|
622
|
+
let blocks = text.data;
|
|
623
|
+
let testText;
|
|
624
|
+
// Section header
|
|
625
|
+
blocks.push({ variant: 'h6', text: `${catName}: ${catScore}` });
|
|
626
|
+
// TODO - Flesh this out
|
|
627
|
+
// There's only one test: Population Deviation.
|
|
628
|
+
// testReport = catTests[T.Test.PopulationDeviation];
|
|
629
|
+
// testText = prepareTestEntry(T.Test.PopulationDeviation, testReport);
|
|
630
|
+
// blocks.push(...testText);
|
|
631
|
+
return blocks;
|
|
632
|
+
}
|
|
633
|
+
// This function parses & formats the 'Best' section of a scorecard.
|
|
634
|
+
function doPrepareBestSection(s, c) {
|
|
635
|
+
// Get the category meta data
|
|
636
|
+
let { catName, catScore, catTests } = s.scorecard[c];
|
|
637
|
+
let testReport;
|
|
638
|
+
// Initialize the section text
|
|
639
|
+
let text = { data: [] };
|
|
640
|
+
let blocks = text.data;
|
|
641
|
+
let testText;
|
|
642
|
+
// Section header
|
|
643
|
+
blocks.push({ variant: 'h6', text: `${catName}: ${catScore}` });
|
|
644
|
+
// Population deviation
|
|
645
|
+
testReport = catTests[4 /* PopulationDeviation */];
|
|
646
|
+
testText = prepareTestEntry(4 /* PopulationDeviation */, testReport);
|
|
647
|
+
blocks.push(...testText);
|
|
648
|
+
// Compactness
|
|
649
|
+
testReport = catTests[5 /* Reock */];
|
|
650
|
+
let normalizedReock = testReport['normalizedScore'];
|
|
651
|
+
let reockTestText = prepareTestEntry(5 /* Reock */, testReport);
|
|
652
|
+
testReport = catTests[6 /* PolsbyPopper */];
|
|
653
|
+
let normalizedPolsbyPopper = testReport['normalizedScore'];
|
|
654
|
+
let polsbyPopperTestText = prepareTestEntry(6 /* PolsbyPopper */, testReport);
|
|
655
|
+
let compactnessScore = (normalizedReock + normalizedPolsbyPopper) / 2;
|
|
656
|
+
blocks.push({ variant: 'body1', text: `Compactness: ${compactnessScore} / 100` });
|
|
657
|
+
blocks.push(...reockTestText);
|
|
658
|
+
blocks.push(...polsbyPopperTestText);
|
|
659
|
+
// County splits
|
|
660
|
+
testReport = catTests[7 /* CountySplits */];
|
|
661
|
+
testText = prepareTestEntry(7 /* CountySplits */, testReport);
|
|
662
|
+
blocks.push(...testText);
|
|
663
|
+
return blocks;
|
|
664
|
+
}
|
|
665
|
+
// FORMATTING HELPERS
|
|
666
|
+
// Convert a boolean representing Pass/Fail to a string
|
|
667
|
+
function pfBoolToString(score) {
|
|
668
|
+
if (score) {
|
|
669
|
+
return "Yes";
|
|
670
|
+
}
|
|
671
|
+
else {
|
|
672
|
+
return "No";
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function fractionToPercentage(f) {
|
|
676
|
+
return f * 100;
|
|
677
|
+
}
|
|
678
|
+
function formatNumber(n) {
|
|
679
|
+
let p = S.PRECISION;
|
|
680
|
+
return n.toLocaleString('en-US', { minimumFractionDigits: p, maximumFractionDigits: p });
|
|
681
|
+
}
|
|
682
|
+
function formatPercentage(n) {
|
|
683
|
+
let p = (S.PRECISION / 2);
|
|
684
|
+
return n.toLocaleString('en-US', { minimumFractionDigits: p, maximumFractionDigits: p });
|
|
685
|
+
}
|
|
686
|
+
function formatInteger(i) {
|
|
687
|
+
return new Intl.NumberFormat().format(i);
|
|
688
|
+
}
|
|
689
|
+
// Prepare the items in a list for rendering
|
|
690
|
+
function prepareListItems(list) {
|
|
691
|
+
let nItems = list.length;
|
|
692
|
+
let listStr;
|
|
693
|
+
switch (nItems) {
|
|
694
|
+
case 1: {
|
|
695
|
+
listStr = list[0];
|
|
696
|
+
break;
|
|
697
|
+
}
|
|
698
|
+
case 2: {
|
|
699
|
+
listStr = list[0] + " and " + list[1];
|
|
700
|
+
break;
|
|
701
|
+
}
|
|
702
|
+
default: {
|
|
703
|
+
let listWithCommas = list.join(', ');
|
|
704
|
+
let lastCommaIndex = listWithCommas.length - ((list[list.length - 1].length) + 1);
|
|
705
|
+
let beforeAnd = listWithCommas.substr(0, lastCommaIndex);
|
|
706
|
+
let afterAnd = listWithCommas.substr(lastCommaIndex + 1);
|
|
707
|
+
listStr = beforeAnd + " and " + afterAnd;
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return listStr;
|
|
712
|
+
}
|
|
713
|
+
// Pick the rendering text for the appropriate list length
|
|
714
|
+
function prepareListText(list, listTemplates) {
|
|
715
|
+
let nItems = list.length;
|
|
716
|
+
switch (nItems) {
|
|
717
|
+
case 1: {
|
|
718
|
+
return listTemplates[0];
|
|
719
|
+
break;
|
|
720
|
+
}
|
|
721
|
+
case 2: {
|
|
722
|
+
return listTemplates[1];
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
default: {
|
|
726
|
+
return listTemplates[2];
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
/* COMMAND-LINE TESTS
|
|
732
|
+
|
|
733
|
+
node main.js scorecard -v -x NC -n 13 -p ~/src/district-analytics/data/SAMPLE-BG-map.csv -d ~/src/district-analytics/data/SAMPLE-BG-data2.json -s ~/src/district-analytics/data/SAMPLE-BG-shapes.geojson -g ~/src/district-analytics/data/SAMPLE-BG-graph.json -c ~/src/district-analytics/data/SAMPLE-COUNTY.geojson
|
|
734
|
+
node --inspect --inspect-brk main.js scorecard -v -x NC -n 13 -p ~/src/district-analytics/data/SAMPLE-BG-map.csv -d ~/src/district-analytics/data/SAMPLE-BG-data2.json -s ~/src/district-analytics/data/SAMPLE-BG-shapes.geojson -g ~/src/district-analytics/data/SAMPLE-BG-graph.json -c ~/src/district-analytics/data/SAMPLE-COUNTY.geojson
|
|
735
|
+
|
|
736
|
+
-or-
|
|
737
|
+
|
|
738
|
+
./main.js scorecard -v -x NC -n 13 -p ../data/SAMPLE-BG-map.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
739
|
+
./main.js --inspect --inspect-brk scorecard -v -x NC -n 13 -p ../data/SAMPLE-BG-map.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
740
|
+
|
|
741
|
+
These calls work at the project directory, using samples in the data/ directory:
|
|
742
|
+
|
|
743
|
+
./main.js testlog -v -x NC -n 13 -p ../data/SAMPLE-BG-map.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
744
|
+
|
|
745
|
+
TODO - Fix this
|
|
746
|
+
./main.js testlog -v -x NC -n 13 -p ../data/SAMPLE-BG-map-missing.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
747
|
+
./main.js scorecard -v -x NC-n 13 -p ../data/SAMPLE-BG-map-missing.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
748
|
+
|
|
749
|
+
./main.js testlog -v -x NC -n 13 -p ../data/SAMPLE-BG-map-unassigned.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
750
|
+
./main.js scorecard -v -x NC -n 13 -p ../data/SAMPLE-BG-map-unassigned.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson
|
|
751
|
+
|
|
752
|
+
TODO - HERE
|
|
753
|
+
|
|
754
|
+
./main.js -v -x NC testlog -p ../data/SAMPLE-BG-map.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson --empty
|
|
755
|
+
./main.js -v -x NC scorecard -p ../data/SAMPLE-BG-map.csv -d ../data/SAMPLE-BG-data2.json -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -c ../data/SAMPLE-COUNTY.geojson --empty
|
|
756
|
+
|
|
757
|
+
TODO
|
|
758
|
+
|
|
759
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-discontiguous.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
760
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-discontiguous.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
761
|
+
|
|
762
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-hole.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
763
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-hole.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
767
|
+
node main.js scorecard -v -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
These calls test NC block-level data stored in my ~/data/redistricting-data/2010/compact/sample directory:
|
|
771
|
+
|
|
772
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-shapes.geojson -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
773
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/tl_2018_37_tabblock10.json -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
774
|
+
|
|
775
|
+
node main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-shapes.geojson -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
776
|
+
node main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/tl_2018_37_tabblock10.json -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
*/
|
|
781
|
+
/* TODO - DELETE
|
|
782
|
+
|
|
783
|
+
These calls work at the project directory, using samples in the data/ directory:
|
|
784
|
+
|
|
785
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
786
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
787
|
+
|
|
788
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-missing.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
789
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-missing.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
790
|
+
|
|
791
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-unassigned.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
792
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-unassigned.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
793
|
+
|
|
794
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv --empty
|
|
795
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv --empty
|
|
796
|
+
|
|
797
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-discontiguous.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
798
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-discontiguous.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
799
|
+
|
|
800
|
+
./main.js testlog -n 13 -p ../data/SAMPLE-BG-map-hole.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
801
|
+
./main.js scorecard -n 13 -p ../data/SAMPLE-BG-map-hole.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
805
|
+
node main.js scorecard -v -n 13 -p ../data/SAMPLE-BG-map.csv -c ../data/SAMPLE-BG-census.csv -s ../data/SAMPLE-BG-shapes.geojson -g ../data/SAMPLE-BG-graph.json -e ../data/SAMPLE-BG-election.csv -f ../data/SAMPLE-FIPS-county-name-map.csv
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
These calls test NC block-level data stored in my ~/data/redistricting-data/2010/compact/sample directory:
|
|
809
|
+
|
|
810
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-shapes.geojson -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
811
|
+
node --inspect --inspect-brk main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/tl_2018_37_tabblock10.json -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
812
|
+
|
|
813
|
+
node main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-shapes.geojson -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
814
|
+
node main.js scorecard -v -n 13 -p ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-map.csv -c ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-census.csv -s ~/data/redistricting-data/2010/compact/sample/tl_2018_37_tabblock10.json -g ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-graph.json -e ~/data/redistricting-data/2010/compact/sample/SAMPLE-BLOCK-election.csv -f ~/data/redistricting-data/2010/compact/sample/SAMPLE-FIPS-county-name-map.csv
|
|
815
|
+
|
|
816
|
+
*/
|
|
817
|
+
//# sourceMappingURL=report.js.map
|