@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.
Files changed (114) hide show
  1. package/.prettierrc +5 -0
  2. package/dist/_api.d.ts +27 -0
  3. package/dist/_data.d.ts +130 -0
  4. package/dist/analyze.d.ts +4 -0
  5. package/dist/cli.js +12091 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/cohesive.d.ts +4 -0
  8. package/dist/compact.d.ts +5 -0
  9. package/dist/constants.d.ts +6 -0
  10. package/dist/district-analytics.js +102 -52
  11. package/dist/district-analytics.js.map +1 -0
  12. package/dist/equal.d.ts +4 -0
  13. package/dist/geofeature.d.ts +3 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/minority.d.ts +3 -0
  16. package/dist/political.d.ts +8 -0
  17. package/dist/preprocess.d.ts +2 -0
  18. package/dist/report.d.ts +15 -0
  19. package/dist/settings.d.ts +5 -0
  20. package/dist/test/_cli.d.ts +5 -0
  21. package/dist/types.d.ts +110 -0
  22. package/dist/utils.d.ts +28 -0
  23. package/dist/valid.d.ts +8 -0
  24. package/jestconfig.json +14 -0
  25. package/lib/HelloWorld.d.ts +3 -0
  26. package/lib/HelloWorld.js +11 -0
  27. package/lib/_api.js +91 -0
  28. package/lib/_api.js.map +1 -0
  29. package/lib/_cli.js +434 -0
  30. package/lib/_cli.js.map +1 -0
  31. package/lib/_data.js +425 -0
  32. package/lib/_data.js.map +1 -0
  33. package/lib/analyze.d.ts +3 -0
  34. package/lib/analyze.js +69 -0
  35. package/lib/analyze.js.map +1 -0
  36. package/lib/api.d.ts +34 -0
  37. package/lib/api.js +117 -0
  38. package/lib/api.js.map +1 -0
  39. package/lib/cli.d.ts +1 -0
  40. package/lib/cli.js +386 -0
  41. package/lib/cli.js.map +1 -0
  42. package/lib/cohesive.d.ts +4 -0
  43. package/lib/cohesive.js +132 -0
  44. package/lib/cohesive.js.map +1 -0
  45. package/lib/compact.d.ts +4 -0
  46. package/lib/compact.js +183 -0
  47. package/lib/compact.js.map +1 -0
  48. package/lib/constants.js +367 -0
  49. package/lib/constants.js.map +1 -0
  50. package/lib/data.js +188 -0
  51. package/lib/data.js.map +1 -0
  52. package/lib/equal.d.ts +4 -0
  53. package/lib/equal.js +59 -0
  54. package/lib/equal.js.map +1 -0
  55. package/lib/features.js +19 -0
  56. package/lib/features.js.map +1 -0
  57. package/lib/geofeature.js +112 -0
  58. package/lib/geofeature.js.map +1 -0
  59. package/lib/index.d.ts +5 -0
  60. package/lib/index.js +11 -0
  61. package/lib/index.js.map +1 -0
  62. package/lib/minority.d.ts +3 -0
  63. package/lib/minority.js +61 -0
  64. package/lib/minority.js.map +1 -0
  65. package/lib/political.d.ts +7 -0
  66. package/lib/political.js +88 -0
  67. package/lib/political.js.map +1 -0
  68. package/lib/preprocess.d.ts +4 -0
  69. package/lib/preprocess.js +101 -0
  70. package/lib/preprocess.js.map +1 -0
  71. package/lib/report.d.ts +14 -0
  72. package/lib/report.js +817 -0
  73. package/lib/report.js.map +1 -0
  74. package/lib/sample.d.ts +1 -0
  75. package/lib/sample.js +32 -0
  76. package/lib/sample.js.map +1 -0
  77. package/lib/scorecard.d.ts +4 -0
  78. package/lib/scorecard.js +237 -0
  79. package/lib/scorecard.js.map +1 -0
  80. package/lib/settings.d.ts +5 -0
  81. package/lib/settings.js +18 -0
  82. package/lib/settings.js.map +1 -0
  83. package/lib/types.d.ts +125 -0
  84. package/lib/types.js +7 -0
  85. package/lib/types.js.map +1 -0
  86. package/lib/utils.d.ts +20 -0
  87. package/lib/utils.js +223 -0
  88. package/lib/utils.js.map +1 -0
  89. package/lib/valid.d.ts +5 -0
  90. package/lib/valid.js +230 -0
  91. package/lib/valid.js.map +1 -0
  92. package/main.js +4 -0
  93. package/package.json +2 -7
  94. package/src/_api.ts +121 -0
  95. package/src/_data.ts +595 -0
  96. package/src/analyze.ts +92 -0
  97. package/src/cohesive.ts +156 -0
  98. package/src/compact.ts +208 -0
  99. package/src/constants.ts +371 -0
  100. package/src/equal.ts +75 -0
  101. package/src/geofeature.ts +138 -0
  102. package/src/index.ts +6 -0
  103. package/src/minority.ts +70 -0
  104. package/src/political.ts +114 -0
  105. package/src/preprocess.ts +132 -0
  106. package/src/report.ts +1022 -0
  107. package/src/settings.ts +20 -0
  108. package/src/types.ts +185 -0
  109. package/src/utils.ts +245 -0
  110. package/src/valid.ts +275 -0
  111. package/tsconfig.json +25 -0
  112. package/tslint.json +3 -0
  113. package/types/polygon-clipping/index.d.ts +1 -0
  114. package/webpack.config.js +73 -0
package/lib/data.js ADDED
@@ -0,0 +1,188 @@
1
+ "use strict";
2
+ //
3
+ // DATA ABSTRACTION LAYER
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const parse = require("csv-parse/lib/sync");
9
+ function nFeatures(s) {
10
+ return s._data.features.length;
11
+ }
12
+ exports.nFeatures = nFeatures;
13
+ function getFeature(s, i) {
14
+ return s._data.features[i];
15
+ }
16
+ exports.getFeature = getFeature;
17
+ function getFeatureID(s, f) {
18
+ return f.properties['GEOID'];
19
+ }
20
+ exports.getFeatureID = getFeatureID;
21
+ // Hide dataset & field key details from the main analytics code
22
+ function getFeatureData(s, f, dt, fk) {
23
+ let dk = s._config['datasets'][dt];
24
+ return _getFeatureData(f, dk, fk);
25
+ }
26
+ exports.getFeatureData = getFeatureData;
27
+ // NOTE - This accessor is cloned from fGetW() in dra-client/restrict.ts
28
+ // f is a direct GeoJSON feature
29
+ // p is a geoID
30
+ function _getFeatureData(f, datasetKey, p) {
31
+ // Shim to load sample data2.json from disk for command-line scaffolding
32
+ if (f.properties && f.properties['datasets']) {
33
+ return f.properties['datasets'][datasetKey][p];
34
+ }
35
+ // NOTE - The fGetW() code from dra-client below here ...
36
+ // Direct property?
37
+ if (f.properties && f.properties[p] !== undefined)
38
+ return f.properties[p];
39
+ // Joined property?
40
+ let a = _fGetJoined(f);
41
+ if (a) {
42
+ for (let i = 0; i < a.length; i++) {
43
+ let o = a[i];
44
+ if (!datasetKey) {
45
+ if (o[p] !== undefined)
46
+ return o[p];
47
+ }
48
+ else {
49
+ if (o['datasets'] && o['datasets'][datasetKey])
50
+ if (o['datasets'][datasetKey][p])
51
+ return o['datasets'][datasetKey][p];
52
+ }
53
+ }
54
+ }
55
+ return undefined;
56
+ }
57
+ function _fGetJoined(f) {
58
+ return (f.properties && f.properties.joined) ? f.properties.joined : undefined;
59
+ }
60
+ function getCounties(s) {
61
+ return s._countyFeatures.features;
62
+ }
63
+ exports.getCounties = getCounties;
64
+ function getCountyProperties(f) {
65
+ return f.properties;
66
+ }
67
+ exports.getCountyProperties = getCountyProperties;
68
+ function releaseCounties(s) {
69
+ s._countyFeatures = {};
70
+ }
71
+ exports.releaseCounties = releaseCounties;
72
+ // HELPERS TO LOAD SAMPLE DATA FROM DISK
73
+ // A clone of 'carefulRead' in DRA-CLI
74
+ function readJSONcareful(file) {
75
+ try {
76
+ let s = fs.readFileSync(file, 'utf8');
77
+ let o = JSON.parse(s);
78
+ return o;
79
+ }
80
+ catch (err) {
81
+ console.log("Error reading JSON file ...");
82
+ return null;
83
+ }
84
+ }
85
+ exports.readJSONcareful = readJSONcareful;
86
+ function readJSON(file) {
87
+ let fullPath;
88
+ if (path.isAbsolute(file)) {
89
+ fullPath = file;
90
+ }
91
+ else {
92
+ fullPath = path.join(__dirname, file);
93
+ }
94
+ return readJSONcareful(fullPath);
95
+ }
96
+ exports.readJSON = readJSON;
97
+ // Following the clone above, except for CSV, using the csv-parse/sync API
98
+ function readCSV(file) {
99
+ try {
100
+ let input = fs.readFileSync(file, 'utf8');
101
+ let dictRows = parse(input, {
102
+ columns: true,
103
+ skip_empty_lines: true
104
+ });
105
+ return dictRows;
106
+ }
107
+ catch (err) {
108
+ console.log("Error reading CSV file ...");
109
+ return null;
110
+ }
111
+ }
112
+ exports.readCSV = readCSV;
113
+ // Read a plan from a .csv file
114
+ function readPlanCSV(file) {
115
+ var plan = {};
116
+ let fullPath;
117
+ if (path.isAbsolute(file)) {
118
+ fullPath = file;
119
+ }
120
+ else {
121
+ fullPath = path.join(__dirname, file);
122
+ }
123
+ var csvArray = readCSV(fullPath);
124
+ for (let dictRow of csvArray) {
125
+ let geoID = dictRow['GEOID'];
126
+ let districtID = Number(dictRow['DISTRICT']);
127
+ // TODO - DISTRICT_ID
128
+ // let districtID: number = dictRow['DISTRICT'];
129
+ plan[geoID] = districtID;
130
+ }
131
+ return plan;
132
+ }
133
+ exports.readPlanCSV = readPlanCSV;
134
+ // Read Census data from a .csv file
135
+ function readCensusCSV(file) {
136
+ var census = {};
137
+ let fullPath;
138
+ if (path.isAbsolute(file)) {
139
+ fullPath = file;
140
+ }
141
+ else {
142
+ fullPath = path.join(__dirname, file);
143
+ }
144
+ var csvArray = readCSV(fullPath);
145
+ for (let dictRow of csvArray) {
146
+ let geoID = dictRow['GEOID'];
147
+ let censusSelect = {};
148
+ censusSelect['total'] = Number(dictRow['TOTAL']);
149
+ censusSelect['white'] = Number(dictRow['WHITE']);
150
+ censusSelect['black'] = Number(dictRow['BLACK']);
151
+ censusSelect['hispanic'] = Number(dictRow['HISPANIC']);
152
+ // TODO - INTEGRATION: data2.json - Minority breakdowns
153
+ censusSelect['whiteHispanic'] = 0;
154
+ censusSelect['total18'] = Number(dictRow['TOTAL18']);
155
+ censusSelect['white18'] = Number(dictRow['WHITE18']);
156
+ censusSelect['black18'] = Number(dictRow['BLACK18']);
157
+ censusSelect['hispanic18'] = Number(dictRow['HISPANIC18']);
158
+ // TODO - INTEGRATION: data2.json - Minority breakdowns
159
+ censusSelect['whiteHispanic18'] = 0;
160
+ census[geoID] = censusSelect;
161
+ }
162
+ return census;
163
+ }
164
+ exports.readCensusCSV = readCensusCSV;
165
+ // Read election data from a .csv file
166
+ function readElectionCSV(file) {
167
+ var election = {};
168
+ let fullPath;
169
+ if (path.isAbsolute(file)) {
170
+ fullPath = file;
171
+ }
172
+ else {
173
+ fullPath = path.join(__dirname, file);
174
+ }
175
+ var csvArray = readCSV(fullPath);
176
+ for (let dictRow of csvArray) {
177
+ let geoID = dictRow['GEOID'];
178
+ // TODO - This should be '[]', I think.
179
+ let electionSelect = {};
180
+ electionSelect[0 /* Democratic */] = Number(dictRow['DEM']);
181
+ electionSelect[1 /* Republican */] = Number(dictRow['REP']);
182
+ electionSelect[2 /* Total */] = Number(dictRow['TOT']);
183
+ election[geoID] = electionSelect;
184
+ }
185
+ return election;
186
+ }
187
+ exports.readElectionCSV = readElectionCSV;
188
+ //# sourceMappingURL=data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../src/data.ts"],"names":[],"mappings":"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"}
package/lib/equal.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import * as T from './types';
2
+ import { AnalyticsSession } from './api';
3
+ export declare function doPopulationDeviation(s: AnalyticsSession): T.TestEntry;
4
+ export declare function doHasEqualPopulations(s: AnalyticsSession): T.TestEntry;
package/lib/equal.js ADDED
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ //
3
+ // EQUAL POPULATION
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const U = require("./utils");
7
+ const D = require("./_data");
8
+ function doPopulationDeviation(s) {
9
+ let test = s.getTest(4 /* PopulationDeviation */);
10
+ // Compute the min, max, and average district populations,
11
+ // excluding the dummy 'unassigned' 0 and N+1 summary "districts."
12
+ let totPopByDistrict = s.districts.statistics[D.DistrictField.TotalPop];
13
+ totPopByDistrict = totPopByDistrict.slice(1, -1);
14
+ let min = U.minArray(totPopByDistrict);
15
+ let max = U.maxArray(totPopByDistrict);
16
+ let total = U.sumArray(totPopByDistrict);
17
+ // Calculate the raw population deviation.
18
+ // The target size is the average population.
19
+ let avg = total / s.state.nDistricts;
20
+ let popDev = (max - min) / avg;
21
+ // Round the raw value to the desired level of precision
22
+ popDev = U.trim(popDev);
23
+ // Populate the test entry
24
+ test['score'] = popDev;
25
+ test['details'] = { 'maxDeviation': max - min };
26
+ // Populate the N+1 summary "district" in district.statistics
27
+ let totalPop = s.districts.statistics[D.DistrictField.TotalPop];
28
+ let popDevPct = s.districts.statistics[D.DistrictField.PopDevPct];
29
+ let summaryRow = s.districts.numberOfRows() - 1;
30
+ totalPop[summaryRow] = avg; // aka "target size"
31
+ popDevPct[summaryRow] = popDev;
32
+ return test;
33
+ }
34
+ exports.doPopulationDeviation = doPopulationDeviation;
35
+ // NOTE - This validity check is *derived* and depends on population deviation %
36
+ // being computed (above) and normalized in test log & scorecard generation.
37
+ function doHasEqualPopulations(s) {
38
+ let test = s.getTest(3 /* EqualPopulation */);
39
+ // Get the normalized population deviation %
40
+ let popDevTest = s.getTest(4 /* PopulationDeviation */);
41
+ let popDevPct = popDevTest['score'];
42
+ let popDevNormalized = popDevTest['normalizedScore'];
43
+ // Populate the test entry
44
+ if (popDevNormalized > 0) {
45
+ test['score'] = true;
46
+ }
47
+ else {
48
+ test['score'] = false;
49
+ }
50
+ test['details']['deviation'] = popDevPct;
51
+ test['details']['thresholds'] = popDevTest['details']['scale'];
52
+ // Populate the N+1 summary "district" in district.statistics
53
+ let bEqualPop = s.districts.statistics[D.DistrictField.bEqualPop];
54
+ let summaryRow = s.districts.numberOfRows() - 1;
55
+ bEqualPop[summaryRow] = test['score'];
56
+ return test;
57
+ }
58
+ exports.doHasEqualPopulations = doHasEqualPopulations;
59
+ //# sourceMappingURL=equal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"equal.js","sourceRoot":"","sources":["../src/equal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ //
3
+ // GEO-FEATURES UTILITIES
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // SHIM OVER 'POLY' FUNCTIONS
7
+ function featureArea() {
8
+ console.log("featureArea() - NIY ");
9
+ }
10
+ exports.featureArea = featureArea;
11
+ function featurePerimeter() {
12
+ console.log("featurePerimeter() - NIY ");
13
+ }
14
+ exports.featurePerimeter = featurePerimeter;
15
+ function featureDiameter() {
16
+ console.log("featureDiameter() - NIY ");
17
+ }
18
+ exports.featureDiameter = featureDiameter;
19
+ //# sourceMappingURL=features.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"features.js","sourceRoot":"","sources":["../src/features.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,yBAAyB;AACzB,EAAE;;AAOF,6BAA6B;AAE7B,SAAgB,WAAW;IACzB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAA;AACrC,CAAC;AAFD,kCAEC;AAED,SAAgB,gBAAgB;IAC9B,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;AAC1C,CAAC;AAFD,4CAEC;AAED,SAAgB,eAAe;IAC7B,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAA;AACzC,CAAC;AAFD,0CAEC"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ //
3
+ // GEO-FEATURES UTILITIES
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const Poly = require("@dra2020/poly");
7
+ // CARTESIAN SHIMS OVER 'POLY' FUNCTIONS
8
+ // TODO - Terry: Confirm Cartesian calculations
9
+ function gfArea(poly) {
10
+ let area = _polygonArea(poly);
11
+ // let polyOptions = { noLatitudeCorrection: false } DELETE
12
+ // let area: number = Poly.polyArea(poly, polyOptions);
13
+ return area;
14
+ }
15
+ exports.gfArea = gfArea;
16
+ // Algorithm for the area of a simple/single planar polygon:
17
+ // https://algorithmtutor.com/Computational-Geometry/Area-of-a-polygon-given-a-set-of-points/
18
+ // https://mathopenref.com/coordpolygonarea2.html
19
+ //
20
+ // function polygonArea(X, Y, numPoints)
21
+ // {
22
+ // area = 0; // Accumulates area in the loop
23
+ // j = numPoints-1; // The last vertex is the 'previous' one to the first
24
+ // for (i=0; i<numPoints; i++)
25
+ // { area = area + (X[j]+X[i]) * (Y[j]-Y[i]);
26
+ // j = i; //j is previous vertex to i
27
+ // }
28
+ // return area/2;
29
+ // }
30
+ // Reimplemented to use polygons vs. X & Y vectors
31
+ function _polygonSimpleArea(p) {
32
+ let area = 0; // Accumulates area in the loop
33
+ let n = p.length;
34
+ let j = n - 1; // The last vertex is the 'previous' one to the first
35
+ for (let i = 0; i < n; i++) {
36
+ area = area + (p[j][0] + p[i][0]) * (p[j][1] - p[i][1]);
37
+ // area = area + (X[j] + X[i]) * (Y[j] - Y[i]);
38
+ j = i; // j is previous vertex to i
39
+ }
40
+ return Math.abs(area / 2);
41
+ }
42
+ // Generalizes the above for MultiPolygons -- cloned from polyArea() in 'poly'
43
+ function _polygonArea(poly) {
44
+ let polyOptions = { noLatitudeCorrection: true }; // NO-OP?
45
+ poly = Poly.polyNormalize(poly, polyOptions); // TODO - Discuss w/ Terry
46
+ let a = 0;
47
+ // A MultiPolygon is a set of polygons
48
+ for (let i = 0; poly && i < poly.length; i++) {
49
+ // A single polygon is an exterior ring with interior holes. Holes are subtracted.
50
+ let p = poly[i];
51
+ for (let j = 0; j < p.length; j++) {
52
+ let sp = p[j];
53
+ a += _polygonSimpleArea(sp) * (j == 0 ? 1 : -1);
54
+ }
55
+ }
56
+ return a;
57
+ }
58
+ // TODO - Terry: Confirm Cartesian calculations
59
+ // The perimeter calculation already just computes cartesian distance if you
60
+ // pass in the noLatitudeCorrection flag. You would need to divide by
61
+ // Poly.EARTH_RADIUS to go from the returned units of meters to Lat/Lon “units”.
62
+ function gfPerimeter(poly) {
63
+ let perimeter = _polygonPerimeter(poly);
64
+ // let polyOptions = { noLatitudeCorrection: true } // Cartesian distance
65
+ // let perimeter: number = Poly.polyPerimeter(poly, polyOptions); DELETE
66
+ return perimeter;
67
+ // return perimeter / Poly.EARTH_RADIUS; DELETE
68
+ }
69
+ exports.gfPerimeter = gfPerimeter;
70
+ // TODO - Terry: Confirm Cartesian calculations
71
+ // Cloned from polyPerimeter() in 'poly' and revised to use Cartesian distance
72
+ // NOTE: No conversion of degrees to radians!
73
+ function _polygonPerimeter(poly) {
74
+ let polyOptions = { noLatitudeCorrection: true }; // Cartesian distance
75
+ poly = Poly.polyNormalize(poly, polyOptions);
76
+ let perimeter = 0;
77
+ for (let i = 0; poly && i < poly.length; i++) {
78
+ // Ignore holes so only look at first polyline
79
+ let p = poly[i][0];
80
+ for (let j = 0; j < p.length - 1; j++)
81
+ perimeter += _distance(p[j][0], p[j][1], p[j + 1][0], p[j + 1][1]);
82
+ // perimeter += haversine(p[j][0], p[j][1], p[j + 1][0], p[j + 1][1], options); DELETE
83
+ if (p.length > 2 && (p[0][0] != p[p.length - 1][0] || p[0][1] != p[p.length - 1][1]))
84
+ perimeter += _distance(p[0][0], p[0][1], p[p.length - 1][0], p[p.length - 1][1]);
85
+ // perimeter += haversine(p[0][0], p[0][1], p[p.length - 1][0], p[p.length - 1][1], options); DELETE
86
+ }
87
+ return perimeter;
88
+ }
89
+ function _distance(x1, y1, x2, y2) {
90
+ let dLat = y2 - y1;
91
+ let dLon = x2 - x1;
92
+ let d;
93
+ d = Math.sqrt((dLat * dLat) + (dLon * dLon));
94
+ return d;
95
+ }
96
+ // TODO - Terry: Confirm Cartesian calculations
97
+ // As I mentioned, the polyCircle code was already just treating the coordinate
98
+ // system as Cartesian. I then did polyFromCircle to convert it to a polygon that
99
+ // then could be passed to polyArea in order to take into account the projection.
100
+ // If instead, you compute area directly from the circle as PI R squared, then
101
+ // you should have your cartesian circular area.
102
+ function gfDiameter(poly) {
103
+ let polyOptions = { noLatitudeCorrection: true }; // NO-OP
104
+ let circle = Poly.polyToCircle(poly, polyOptions);
105
+ // let circleArea: number = Poly.polyArea(Poly.polyFromCircle(circle, undefined, polyOptions), polyOptions);
106
+ // let circleRadius: number = Math.sqrt(circleArea / Math.PI);
107
+ // let diameter: number = circleRadius * 2; DELETE
108
+ let diameter = circle.r * 2;
109
+ return diameter;
110
+ }
111
+ exports.gfDiameter = gfDiameter;
112
+ //# sourceMappingURL=geofeature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geofeature.js","sourceRoot":"","sources":["../src/geofeature.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { AnalyticsSession } from './api';
2
+ declare const _default: {
3
+ AnalyticsSession: typeof AnalyticsSession;
4
+ };
5
+ export default _default;
package/lib/index.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ //
3
+ // THE DISTRICT-ANALYTICS NODE PACKAGE API
4
+ //
5
+ function __export(m) {
6
+ for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
7
+ }
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ __export(require("./_api"));
10
+ __export(require("./types"));
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,0CAA0C;AAC1C,EAAE;;;;;AAEF,4BAAuB;AACvB,6BAAwB"}
@@ -0,0 +1,3 @@
1
+ import * as T from './types';
2
+ import { AnalyticsSession } from './api';
3
+ export declare function doMajorityMinorityDistricts(s: AnalyticsSession): T.TestEntry;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ //
3
+ // PROTECTS MINORITIES
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ // TODO - This definition is wrong. Need to fix it.
7
+ //
8
+ // MINORITY-PROTECTION ANALYTICS NEED THE FOLLOWING DATA:
9
+ //
10
+ // The TOTAL, WHITE, BLACK, and HISPANIC counts from the Census, aggregated by
11
+ // district. We *might* also ultimately need TOTAL18, WHITE18, BLACK18, and
12
+ // HISPANIC18 counts by feature for these analytics.
13
+ //
14
+ // The minority population of a feature will probably be calculated as everyone
15
+ // exceot non-Hispanic Whites:
16
+ //
17
+ // MINORITY = TOTAL - (WHITE - HISPANIC)
18
+ //
19
+ // That could be calculated as part of preprocessing the Census data, or it
20
+ // could be computed on the fly. Since it's derived data and the formula might
21
+ // change, it's probably best to compute it on the fly.
22
+ //
23
+ // In addition to the Census extract, these analytics need:
24
+ // - The # of districts in the map, for determining minority proportionality
25
+ // - Minorities as a % of the total population; possibly the voting age share
26
+ //
27
+ // TODO - Is the # of districts passed as a parameter or inferred from the # in
28
+ // the map?
29
+ // TODO - Is minority share preprocessed once and passed as a parameter or
30
+ // computed in a initialization routine?
31
+ function doMajorityMinorityDistricts(s) {
32
+ let test = s.getTest(14 /* MajorityMinorityDistricts */);
33
+ console.log("TODO - Calculating # of majority-minority districts ...");
34
+ return test;
35
+ }
36
+ exports.doMajorityMinorityDistricts = doMajorityMinorityDistricts;
37
+ // SAVE THESE NOTES, IN CASE WE NEED TO REWORK HOW WE DO PERFORM THESE CALCS.
38
+ // THEY REFLECT HOW I/ALEC DID THESE IN PYTHON.
39
+ //
40
+ // MINORITY-PROTECTION ANALYTICS WILL NEED THE FOLLOWING DATA,
41
+ // IN ADDITION TO THE MAP (IDEALLY, GEO_IDS INDEXED BY DISTRICT_ID)
42
+ //
43
+ // Census data by geo_id - { total population | white | black | hispanic }
44
+ //
45
+ // The minority population of a feature will probably be calculated as the # of
46
+ // non-White Hispanics:
47
+ //
48
+ // MINORITY = TOTAL - (WHITE - HISPANIC)
49
+ //
50
+ // That could be calculated as part of preprocessing the Census data, or it
51
+ // could be computed on the fly.
52
+ //
53
+ // And probably:
54
+ // 'districts' - The # of districts for determining minority proportionality.
55
+ // 'minority_share' - Minorities as a % of the total population
56
+ //
57
+ // TODO - Is the # of districts passed as a parameter or inferred from the # in
58
+ // the map?
59
+ // TODO - Is minority share preprocessed once and passed as a parameter or
60
+ // computed in a initialization routine?
61
+ //# sourceMappingURL=minority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"minority.js","sourceRoot":"","sources":["../src/minority.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,sBAAsB;AACtB,EAAE;;AASF,mDAAmD;AACnD,EAAE;AACF,yDAAyD;AACzD,EAAE;AACF,8EAA8E;AAC9E,2EAA2E;AAC3E,oDAAoD;AACpD,EAAE;AACF,+EAA+E;AAC/E,8BAA8B;AAC9B,EAAE;AACF,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,8EAA8E;AAC9E,uDAAuD;AACvD,EAAE;AACF,2DAA2D;AAC3D,4EAA4E;AAC5E,6EAA6E;AAC7E,EAAE;AACF,+EAA+E;AAC/E,aAAa;AACb,0EAA0E;AAC1E,0CAA0C;AAG1C,SAAgB,2BAA2B,CAAC,CAAmB;IAC7D,IAAI,IAAI,GAAG,CAAC,CAAC,OAAO,oCAAiD,CAAC;IAEtE,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IAEvE,OAAO,IAAI,CAAC;AACd,CAAC;AAND,kEAMC;AAED,6EAA6E;AAC7E,+CAA+C;AAC/C,EAAE;AACF,8DAA8D;AAC9D,mEAAmE;AACnE,EAAE;AACF,0EAA0E;AAC1E,EAAE;AACF,+EAA+E;AAC/E,uBAAuB;AACvB,EAAE;AACF,wCAAwC;AACxC,EAAE;AACF,2EAA2E;AAC3E,gCAAgC;AAChC,EAAE;AACF,gBAAgB;AAChB,6EAA6E;AAC7E,+DAA+D;AAC/D,EAAE;AACF,+EAA+E;AAC/E,aAAa;AACb,0EAA0E;AAC1E,0CAA0C"}
@@ -0,0 +1,7 @@
1
+ import * as T from './types';
2
+ import { AnalyticsSession } from './api';
3
+ export declare function doSeatsBias(s: AnalyticsSession): T.TestEntry;
4
+ export declare function doVotesBias(s: AnalyticsSession): T.TestEntry;
5
+ export declare function doResponsiveness(s: AnalyticsSession): T.TestEntry;
6
+ export declare function doResponsiveDistricts(s: AnalyticsSession): T.TestEntry;
7
+ export declare function doEfficiencyGap(s: AnalyticsSession): T.TestEntry;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ //
3
+ // FAIR/PROPORTIONAL
4
+ //
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const assert_1 = require("assert");
7
+ const U = require("./utils");
8
+ const D = require("./_data");
9
+ // Partisan analytics need the following data:
10
+ //
11
+ // An "election model" by geo_id, where each item has 4 pieces of data:
12
+ //
13
+ // { geo_id, Democratic votes, Republican votes, Total votes }
14
+ //
15
+ // NOTE: D + R <= Total, because there could be third-party or write-in votes.
16
+ //
17
+ // An election model can simply represent one election, e.g., President 2012,
18
+ // or combine multiple elections in some fashion. An election model is used to
19
+ // computer a single index of the likely partisan weight / lean / preference
20
+ // for the districts in a plan. An election model and the associated index go
21
+ // hand in hand. So much so that the index frequently stands in as the name for
22
+ // both, e.g., Cook's PVI is one example, Nagle's 7s, Hofeller's Formula, NDRC's
23
+ // DPI.
24
+ //
25
+ // I'm labelling this general concept a "Voter Preference Index (VPI)," a
26
+ // conscious +1 letter play on Cook's "PVI" acronymn.
27
+ // MEASURING BIAS & RESPONSIVENESS (NAGLE'S METHOD)
28
+ function doSeatsBias(s) {
29
+ let test = s.getTest(9 /* SeatsBias */);
30
+ console.log("TODO - Calculating seats bias ...");
31
+ return test;
32
+ }
33
+ exports.doSeatsBias = doSeatsBias;
34
+ function doVotesBias(s) {
35
+ let test = s.getTest(10 /* VotesBias */);
36
+ console.log("TODO - Calculating votes bias ...");
37
+ return test;
38
+ }
39
+ exports.doVotesBias = doVotesBias;
40
+ function doResponsiveness(s) {
41
+ let test = s.getTest(11 /* Responsiveness */);
42
+ console.log("TODO - Calculating responsiveness ...");
43
+ return test;
44
+ }
45
+ exports.doResponsiveness = doResponsiveness;
46
+ function doResponsiveDistricts(s) {
47
+ let test = s.getTest(12 /* ResponsiveDistricts */);
48
+ console.log("TODO - Calculating # of responsive districts ...");
49
+ return test;
50
+ }
51
+ exports.doResponsiveDistricts = doResponsiveDistricts;
52
+ // OTHER MEASURES OF PARTISAN BIAS
53
+ // TODO - This formula might need to be inverted for D vs. R +/-
54
+ // TODO - Normalize the results.
55
+ function doEfficiencyGap(s) {
56
+ console.log("TODO - Calculating the efficiency gap ...");
57
+ let test = s.getTest(13 /* EfficiencyGap */);
58
+ // Get partisan statistics by districts.
59
+ // Use Democratic votes, seats, and shares by convention.
60
+ let DVotes = s.districts.statistics[D.DistrictField.DemVotes];
61
+ let DSeats = s.districts.statistics[D.DistrictField.DemSeat];
62
+ let TPVotes = s.districts.statistics[D.DistrictField.TwoPartyVote];
63
+ // Exclude the dummy unassigned '0' and N+1 summary "districts"
64
+ DVotes = DVotes.slice(1, -1);
65
+ DSeats = DSeats.slice(1, -1);
66
+ TPVotes = TPVotes.slice(1, -1);
67
+ // Calculate D vote share & D seat share
68
+ let DVoteShare = U.sumArray(DVotes) / U.sumArray(TPVotes);
69
+ let DSeatShare = U.sumArray(DSeats) / s.state.nDistricts;
70
+ // Finally, calculate the Efficiency Gap
71
+ let efficiencyGap = (DSeatShare - 0.5) - (2.0 * (DVoteShare - 0.5));
72
+ // Round the raw value to the desired level of precision
73
+ efficiencyGap = U.trim(efficiencyGap);
74
+ // Populate the test entry
75
+ test['score'] = efficiencyGap;
76
+ // test['normalizedScore'] = 0; /* TODO - Normalize the raw score */
77
+ test['details'] = {}; /* TODO - Add details, if any */
78
+ return test;
79
+ }
80
+ exports.doEfficiencyGap = doEfficiencyGap;
81
+ // HELPERS
82
+ function fptpWin(demPct) {
83
+ // Vote shares should be fractions in the range [0.0 – 1.0]
84
+ assert_1.strict((demPct <= 1.0) && (demPct >= 0.));
85
+ return ((demPct > 0.5) ? 1 : 0);
86
+ }
87
+ exports.fptpWin = fptpWin;
88
+ //# sourceMappingURL=political.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"political.js","sourceRoot":"","sources":["../src/political.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import * as T from './types';
2
+ import { AnalyticsSession } from './api';
3
+ export declare function doPreprocessData(s: AnalyticsSession): void;
4
+ export declare function invertPlan(plan: T.PlanByGeoID): T.PlanByDistrictID;