@dra2020/dra-analytics 4.1.2 → 4.1.5

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.
@@ -1,4 +1,5 @@
1
1
  import * as GeoJSON from 'geojson';
2
2
  import * as T from '../types/all';
3
+ export declare function excessivelyFragmented(shapes: GeoJSON.FeatureCollection): boolean;
3
4
  export declare function makeCompactnessScorecard(shapes: GeoJSON.FeatureCollection, bLog?: boolean): T.CompactnessScorecard;
4
5
  export declare function calcCompactness(shapes: GeoJSON.FeatureCollection): T.CompactnessJSONReady;
@@ -7,4 +7,6 @@ export declare function calcBoundingBox(poly: any): number;
7
7
  export declare function calcPolsbyPopper(area: number, perimeter: number): number;
8
8
  export declare function calcConvexHullFeature(area: number, chArea: number): number;
9
9
  export declare function calcSchwartzberg(area: number, perimeter: number): number;
10
- export declare function featureizePoly(poly: any, options?: Poly.PolyOptions): T.CompactnessFeatures;
10
+ export declare function featureizePoly(poly: any, options?: Poly.PolyOptions, { bKIWYSIFeatures }?: {
11
+ bKIWYSIFeatures?: boolean;
12
+ }): T.CompactnessFeatures;
@@ -1,10 +1,10 @@
1
1
  import * as T from '../types/all';
2
2
  declare const enum Demographic {
3
- Minority = 0,
4
- Black = 1,
5
- Hispanic = 2,
6
- Pacific = 3,
7
- Asian = 4,
3
+ Minority = 0,// 'Minority'
4
+ Black = 1,// 'Black'
5
+ Hispanic = 2,// 'Hispanic'
6
+ Pacific = 3,// 'Pacific'
7
+ Asian = 4,// 'Asian'
8
8
  Native = 5
9
9
  }
10
10
  export declare function makeMinorityScorecard(statewideDemos: T.Demographics, demosByDistrict: T.Demographics[], bLog?: boolean): T.MinorityScorecard;
@@ -28,7 +28,7 @@ export type GeoProperties = {
28
28
  export type CompactnessScorecard = {
29
29
  avgReock: number;
30
30
  avgPolsby: number;
31
- avgKWIWYSI: number;
31
+ avgKIWYSI: number;
32
32
  byDistrict: Compactness[];
33
33
  details: T.Dict;
34
34
  score?: number;
@@ -48,7 +48,7 @@ export type CompactnessAlt = {
48
48
  export type CompactnessJSONReady = {
49
49
  avgReock: number;
50
50
  avgPolsby: number;
51
- avgKWIWYSI: number;
51
+ avgKIWYSI: number;
52
52
  byDistrict: CompactnessAlt[];
53
53
  };
54
54
  export type KiwysiFeatures = {
@@ -62,6 +62,6 @@ export type KiwysiFeatures = {
62
62
  kiwysiRank: number;
63
63
  };
64
64
  export type KiwysiJSONReady = {
65
- avgKWIWYSI: number;
65
+ avgKIWYSI: number;
66
66
  byDistrict: KiwysiFeatures[];
67
67
  };
package/docs/types.md CHANGED
@@ -58,7 +58,7 @@ export type MinorityScorecard = {
58
58
  export type CompactnessScorecard = {
59
59
  avgReock: number;
60
60
  avgPolsby: number;
61
- avgKWIWYSI: number;
61
+ avgKIWYSI: number;
62
62
  byDistrict: Compactness[];
63
63
  details: Dict;
64
64
  score?: number;
@@ -10,6 +10,28 @@ import {scoreFeatureSet} from './kiwysi';
10
10
  import * as T from '../types/all';
11
11
  import {ratePolsby, rateReock} from '../rate/dra-ratings';
12
12
 
13
+ export function excessivelyFragmented(shapes: GeoJSON.FeatureCollection): boolean
14
+ {
15
+ const threshold: number = 20;
16
+ let fragments: number = 0;
17
+ for (let i = 0; i < shapes.features.length; i++)
18
+ {
19
+ const f: any = shapes.features[i];
20
+ if (f.geometry.type == 'MultiPolygon')
21
+ {
22
+ fragments += f.geometry.coordinates.length;
23
+ }
24
+ }
25
+ const avgFragmentation: number = fragments / shapes.features.length;
26
+
27
+ if (avgFragmentation > threshold)
28
+ {
29
+ console.log(`Average fragmentation (${avgFragmentation}) exceeds threshold (${threshold}).`);
30
+ return true;
31
+ }
32
+
33
+ return false;
34
+ }
13
35
 
14
36
  // Use this to get average Reock, Polsby-Popper, and KIWYSI compactness and by district for a set of shapes
15
37
  // This is used by DRA
@@ -23,13 +45,17 @@ export function makeCompactnessScorecard(shapes: GeoJSON.FeatureCollection, bLog
23
45
  let totPolsby: number = 0;
24
46
  let totKIWYSI: number = 0;
25
47
 
48
+ // 12-11-24: Skip featurization for KIWYSI compactness, when the districts in a map are too fragmented on average
49
+ const bKIWYSIFeatures: boolean = excessivelyFragmented(shapes) ? false : true;
50
+
26
51
  // For returning compactness by district to DRA
27
52
  // Note, these use the Cartesian (flat earth) measurements
28
53
  let byDistrict: T.Compactness[] = [];
29
54
 
30
55
  for (let i = 0; i < shapes.features.length; i++)
31
56
  {
32
- const features: T.CompactnessFeatures = featureizePoly(shapes.features[i], options);
57
+ const f: any = shapes.features[i];
58
+ const features: T.CompactnessFeatures = featureizePoly(f, options, {bKIWYSIFeatures: bKIWYSIFeatures});
33
59
 
34
60
  const reockFlat: number = features.reockFlat;
35
61
  const polsbyFlat: number = features.polsbyFlat;
@@ -40,7 +66,7 @@ export function makeCompactnessScorecard(shapes: GeoJSON.FeatureCollection, bLog
40
66
  const normalizedReock: number = rateReock(reockFlat);
41
67
  const normalizedPolsby: number = ratePolsby(polsbyFlat);
42
68
 
43
- let kiwysiRank: number = scoreFeatureSet(features, pca);
69
+ let kiwysiRank: number = bKIWYSIFeatures ? scoreFeatureSet(features, pca) : 100;
44
70
  // Constrain values to the range [1–100]
45
71
  kiwysiRank = Math.min(Math.max(kiwysiRank, 1), 100);
46
72
  // Raw KIWYSI scores ("ranks") are 1–100 where smaller is better
@@ -64,12 +90,12 @@ export function makeCompactnessScorecard(shapes: GeoJSON.FeatureCollection, bLog
64
90
 
65
91
  const avgReock: number = totReock / shapes.features.length;
66
92
  const avgPolsby: number = totPolsby / shapes.features.length;
67
- const avgKWIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
93
+ const avgKIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
68
94
 
69
95
  const s: T.CompactnessScorecard = {
70
96
  avgReock: avgReock,
71
97
  avgPolsby: avgPolsby,
72
- avgKWIWYSI: avgKWIWYSI,
98
+ avgKIWYSI: avgKIWYSI,
73
99
  byDistrict: byDistrict, // Legacy format
74
100
  details: {}, // None
75
101
  // score?:
@@ -121,12 +147,12 @@ export function calcCompactness(shapes: GeoJSON.FeatureCollection): T.Compactnes
121
147
 
122
148
  const avgReock: number = totReock / shapes.features.length;
123
149
  const avgPolsby: number = totPolsby / shapes.features.length;
124
- const avgKWIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
150
+ const avgKIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
125
151
 
126
152
  const out: T.CompactnessJSONReady = {
127
153
  avgReock: avgReock,
128
154
  avgPolsby: avgPolsby,
129
- avgKWIWYSI: avgKWIWYSI,
155
+ avgKIWYSI: avgKIWYSI,
130
156
  byDistrict: byDistrict
131
157
  }
132
158
 
@@ -230,7 +230,7 @@ export function calcSchwartzberg(area: number, perimeter: number): number
230
230
 
231
231
  // CALCULATE THE 7 COMPACTNESS "FEATURES" FOR A POLYGON FOR THE KIWYSI COMPACTNESS MODEL
232
232
 
233
- export function featureizePoly(poly: any, options?: Poly.PolyOptions): T.CompactnessFeatures
233
+ export function featureizePoly(poly: any, options?: Poly.PolyOptions, {bKIWYSIFeatures = true}: {bKIWYSIFeatures?: boolean} = {}): T.CompactnessFeatures
234
234
  {
235
235
  if (options === undefined) options = Poly.DefaultOptions;
236
236
 
@@ -247,15 +247,17 @@ export function featureizePoly(poly: any, options?: Poly.PolyOptions): T.Compact
247
247
  const hullArea: number = Poly.polyArea(ch);
248
248
 
249
249
  const result: T.CompactnessFeatures = {
250
+ // 12-10-24: Skip featurization for KIWYSI compactness, when MultiPolygons are too fragmented
250
251
  // For the "correct" geodesic calculations that the KIWYSI AI uses
251
- sym_x: calcXSymmetry(poly),
252
- sym_y: calcYSymmetry(poly),
253
- reock: calcReock(area, diameter),
254
- bbox: calcBoundingBox(poly),
255
- polsby: calcPolsbyPopper(area, perimeter),
256
- hull: calcConvexHullFeature(area, hullArea),
257
- schwartzberg: calcSchwartzberg(area, perimeter),
258
-
252
+ sym_x: bKIWYSIFeatures ? calcXSymmetry(poly) : 0.0,
253
+ sym_y: bKIWYSIFeatures ? calcYSymmetry(poly) : 0.0,
254
+ reock: bKIWYSIFeatures ? calcReock(area, diameter) : 0.0,
255
+ bbox: bKIWYSIFeatures ? calcBoundingBox(poly) : 0.0,
256
+ polsby: bKIWYSIFeatures ? calcPolsbyPopper(area, perimeter) : 0.0,
257
+ hull: bKIWYSIFeatures ? calcConvexHullFeature(area, hullArea) : 0.0,
258
+ schwartzberg: bKIWYSIFeatures ? calcSchwartzberg(area, perimeter) : 0.0,
259
+
260
+ // But still do the basic calculations for Reock and Polsby-Popper
259
261
  // For the Cartesian (flat earth) calculations that are typically done
260
262
  reockFlat: calcReock(areaFlat, diameterFlat),
261
263
  polsbyFlat: calcPolsbyPopper(areaFlat, perimeterFlat)
@@ -83,10 +83,10 @@ export function calcKIWYSICompactness(shapes: GeoJSON.FeatureCollection): T.Kiwy
83
83
  byDistrict.push(entry);
84
84
  }
85
85
 
86
- const avgKWIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
86
+ const avgKIWYSI: number = Math.round(totKIWYSI / shapes.features.length);
87
87
 
88
88
  const out: T.KiwysiJSONReady = {
89
- avgKWIWYSI: avgKWIWYSI,
89
+ avgKIWYSI: avgKIWYSI,
90
90
  byDistrict: byDistrict
91
91
  }
92
92
 
@@ -13,7 +13,7 @@ export function isConnected(featureIDs: T.FeatureGroup, graph: T.ContiguityGraph
13
13
 
14
14
  // Start processing with the first feature in the set
15
15
  let iter = featureIDs.values();
16
- toProcess.push(iter.next().value);
16
+ toProcess.push(iter.next().value as string);
17
17
 
18
18
  // While there are features in the set that haven't been processed,
19
19
  // i.e., stop when you've visited all the features in the set
@@ -49,7 +49,7 @@ export type GeoProperties = {
49
49
  export type CompactnessScorecard = {
50
50
  avgReock: number,
51
51
  avgPolsby: number,
52
- avgKWIWYSI: number,
52
+ avgKIWYSI: number,
53
53
  byDistrict: Compactness[],
54
54
  details: T.Dict,
55
55
  score?: number
@@ -78,7 +78,7 @@ export type CompactnessAlt = {
78
78
  export type CompactnessJSONReady = {
79
79
  avgReock: number,
80
80
  avgPolsby: number,
81
- avgKWIWYSI: number,
81
+ avgKIWYSI: number,
82
82
  byDistrict: CompactnessAlt[]
83
83
  }
84
84
 
@@ -95,7 +95,7 @@ export type KiwysiFeatures = {
95
95
 
96
96
  // A minimal type for by-district KIWISI compactness features to be converted to JSON
97
97
  export type KiwysiJSONReady = {
98
- avgKWIWYSI: number,
98
+ avgKIWYSI: number,
99
99
  byDistrict: KiwysiFeatures[]
100
100
  }
101
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dra2020/dra-analytics",
3
- "version": "4.1.2",
3
+ "version": "4.1.5",
4
4
  "description": "DRA analytics",
5
5
  "main": "dist/dra-analytics.js",
6
6
  "types": "./dist/lib/all/all.d.ts",
@@ -32,28 +32,29 @@
32
32
  },
33
33
  "homepage": "https://github.com/dra2020/dra-analytics#readme",
34
34
  "devDependencies": {
35
- "@types/geojson": "^7946.0.10",
36
- "@types/jest": "^26.0.24",
37
- "@types/node": "^12.20.55",
38
- "@types/yargs": "^12.0.20",
35
+ "@types/geojson": "^7946.0.16",
36
+ "@types/jest": "^29.5.1",
37
+ "@types/node": "^18.11.17",
38
+ "@types/yargs": "^11.1.8",
39
39
  "csv-parse": "^4.16.3",
40
- "jest": "^26.6.3",
40
+ "jest": "^29.5.0",
41
41
  "json-loader": "^0.5.7",
42
- "prettier": "^2.7.1",
42
+ "prettier": "^2.8.8",
43
43
  "shapefile": "^0.6.6",
44
- "source-map-loader": "^3.0.2",
45
- "ts-jest": "^26.5.6",
46
- "ts-loader": "^9.4.1",
44
+ "source-map-loader": "^5.0.0",
45
+ "ts-jest": "^29.1.0",
46
+ "ts-loader": "^9.5.2",
47
47
  "tsify": "^5.0.4",
48
48
  "tslint": "^6.1.3",
49
49
  "tslint-config-prettier": "^1.18.0",
50
- "typescript": "^4.9.3",
51
- "webpack": "^5.75.0",
52
- "webpack-cli": "^4.10.0",
53
- "yargs": "^12.0.5"
50
+ "typescript": "^5.8.3",
51
+ "webpack": "^5.99.5",
52
+ "webpack-cli": "^6.0.1"
54
53
  },
55
54
  "dependencies": {
56
- "@dra2020/baseclient": "^1.0.89",
57
- "geojson": "^0.5.0"
55
+ "@dra2020/baseclient": "^1.0.153",
56
+ "cjs": "^0.0.11",
57
+ "geojson": "^0.5.0",
58
+ "yargs": "^12.0.5"
58
59
  }
59
60
  }