@dra2020/district-analytics 10.2.8 → 10.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -122,7 +122,6 @@ const analyze_1 = __webpack_require__(/*! ./analyze */ "./src/analyze.ts");
122
122
  const score_1 = __webpack_require__(/*! ./score */ "./src/score.ts");
123
123
  const results_1 = __webpack_require__(/*! ./results */ "./src/results.ts");
124
124
  const results_2 = __webpack_require__(/*! ./results */ "./src/results.ts");
125
- // 11-03-2020 - Added for racially polarized voting analysis
126
125
  const minority_1 = __webpack_require__(/*! ./minority */ "./src/minority.ts");
127
126
  const Poly = __importStar(__webpack_require__(/*! @dra2020/poly */ "@dra2020/poly"));
128
127
  const D = __importStar(__webpack_require__(/*! ./_data */ "./src/_data.ts"));
@@ -1430,7 +1429,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
1430
1429
  return (mod && mod.__esModule) ? mod : { "default": mod };
1431
1430
  };
1432
1431
  Object.defineProperty(exports, "__esModule", { value: true });
1433
- const U = __importStar(__webpack_require__(/*! ./utils */ "./src/utils.ts"));
1432
+ const RPV = __importStar(__webpack_require__(/*! @dra2020/racial-voting */ "@dra2020/racial-voting"));
1434
1433
  const majority_minority_json_1 = __importDefault(__webpack_require__(/*! ../static/majority-minority.json */ "./static/majority-minority.json"));
1435
1434
  const vra5_preclearance_json_1 = __importDefault(__webpack_require__(/*! ../static/vra5-preclearance.json */ "./static/vra5-preclearance.json"));
1436
1435
  // TODO - 2020: Update/revise this, when the update comes out in September:
@@ -1452,111 +1451,151 @@ function getVRASection5(s) {
1452
1451
  return stateVRAPre;
1453
1452
  }
1454
1453
  exports.getVRASection5 = getVRASection5;
1455
- // 11-03-2020 - Added for racially polarized voting analysis
1456
- // Analyze the degree of racially polarized voting for a district
1454
+ // RPV - pulled into a separate component 11-17-2020
1457
1455
  function doAnalyzeRacialPolarization(s, districtID, groups, bLog = false) {
1458
- // Either take take the minorities to analyze in as selections -or- infer them
1459
- // from the % VAP/CVAP for the district (not the state).
1460
- if (groups == undefined) {
1461
- const RPV_THRESHOLD = 0.35; // Using ~ the Bethune–Hill threshold
1462
- groups = {
1463
- white: true,
1464
- minority: false,
1465
- black: (s.districts.table.blackPct[districtID] > RPV_THRESHOLD) ? true : false,
1466
- hispanic: (s.districts.table.hispanicPct[districtID] > RPV_THRESHOLD) ? true : false,
1467
- pacific: (s.districts.table.pacificPct[districtID] > RPV_THRESHOLD) ? true : false,
1468
- asian: (s.districts.table.asianPct[districtID] > RPV_THRESHOLD) ? true : false,
1469
- native: (s.districts.table.nativePct[districtID] > RPV_THRESHOLD) ? true : false
1470
- };
1471
- }
1456
+ // At least one minority group must be specified
1472
1457
  if (!(groups.black || groups.hispanic || groups.pacific || groups.asian || groups.native))
1473
1458
  return undefined;
1474
1459
  const points = s.districts.extractVotesByDemographic(districtID, groups, bLog);
1475
- if (points === undefined)
1476
- return undefined;
1477
- // Make sure there are enough points to do a regression
1478
- if (points.white.length <= 10)
1479
- return undefined;
1480
- // At this point, at least one single-race/ethnicity minority demographic needs
1481
- // to be analyzed along with white.
1482
- const result = {
1483
- ids: points.ids,
1484
- white: characterizeDemographicVoting(points.white),
1485
- minority: groups.minority ? characterizeDemographicVoting(points.minority) : undefined,
1486
- black: groups.black ? characterizeDemographicVoting(points.black) : undefined,
1487
- hispanic: groups.hispanic ? characterizeDemographicVoting(points.hispanic) : undefined,
1488
- pacific: groups.pacific ? characterizeDemographicVoting(points.pacific) : undefined,
1489
- asian: groups.asian ? characterizeDemographicVoting(points.asian) : undefined,
1490
- native: groups.native ? characterizeDemographicVoting(points.native) : undefined
1491
- };
1492
- return result;
1460
+ return RPV.analyzeRacialVoting(points, districtID, groups);
1493
1461
  }
1494
1462
  exports.doAnalyzeRacialPolarization = doAnalyzeRacialPolarization;
1463
+ /* TODO - RPV: DELETE
1464
+ // 11-03-2020 - Added for racially polarized voting analysis
1465
+ // Analyze the degree of racially polarized voting for a district
1466
+ export function doAnalyzeRacialPolarization(s: AnalyticsSession, districtID: number, groups?: T.MinorityFilter, bLog: boolean = false): T.RPVAnalysis | undefined
1467
+ {
1468
+ // Either take take the minorities to analyze in as selections -or- infer them
1469
+ // from the % VAP/CVAP for the district (not the state).
1470
+ if (groups == undefined)
1471
+ {
1472
+ const RPV_THRESHOLD = 0.35; // Using ~ the Bethune–Hill threshold
1473
+ groups = {
1474
+ white: true,
1475
+ minority: false,
1476
+ black: (s.districts.table.blackPct[districtID] > RPV_THRESHOLD) ? true : false,
1477
+ hispanic: (s.districts.table.hispanicPct[districtID] > RPV_THRESHOLD) ? true : false,
1478
+ pacific: (s.districts.table.pacificPct[districtID] > RPV_THRESHOLD) ? true : false,
1479
+ asian: (s.districts.table.asianPct[districtID] > RPV_THRESHOLD) ? true : false,
1480
+ native: (s.districts.table.nativePct[districtID] > RPV_THRESHOLD) ? true : false
1481
+ };
1482
+ }
1483
+
1484
+ if (!(groups.black || groups.hispanic || groups.pacific || groups.asian || groups.native)) return undefined;
1485
+
1486
+ const points = s.districts.extractVotesByDemographic(districtID, groups, bLog);
1487
+
1488
+ if (points === undefined) return undefined;
1489
+
1490
+ // Make sure there are enough points to do a regression
1491
+ if (points.white.length <= 10) return undefined;
1492
+
1493
+ // At this point, at least one single-race/ethnicity minority demographic needs
1494
+ // to be analyzed along with white.
1495
+
1496
+ const result: T.RPVAnalysis = {
1497
+ ids: points.ids,
1498
+ white: characterizeDemographicVoting(points.white),
1499
+ minority: groups.minority ? characterizeDemographicVoting(points.minority) : undefined,
1500
+ black: groups.black ? characterizeDemographicVoting(points.black) : undefined,
1501
+ hispanic: groups.hispanic ? characterizeDemographicVoting(points.hispanic) : undefined,
1502
+ pacific: groups.pacific ? characterizeDemographicVoting(points.pacific) : undefined,
1503
+ asian: groups.asian ? characterizeDemographicVoting(points.asian) : undefined,
1504
+ native: groups.native ? characterizeDemographicVoting(points.native) : undefined
1505
+ }
1506
+
1507
+ return result;
1508
+ }
1509
+
1495
1510
  // Cloned from dra-score
1496
- function calcProportionalDistricts(proportion, nDistricts) {
1497
- const roundUp = 0.0;
1498
- const fractional = proportion * nDistricts;
1499
- const integral = Math.round(fractional + roundUp);
1500
- return integral;
1511
+ function calcProportionalDistricts(proportion: number, nDistricts: number): number
1512
+ {
1513
+ const roundUp = 0.0;
1514
+ const fractional = proportion * nDistricts;
1515
+ const integral = Math.round(fractional + roundUp);
1516
+
1517
+ return integral;
1501
1518
  }
1519
+
1502
1520
  // https://trentrichardson.com/compute-linear-regressions-in-javascript.html
1503
- function linearRegression(points) {
1504
- let result = {};
1505
- const n = points.length;
1506
- let sum_x = 0;
1507
- let sum_y = 0;
1508
- let sum_xy = 0;
1509
- let sum_xx = 0;
1510
- let sum_yy = 0;
1511
- for (let i = 0; i < n; i++) {
1512
- const pt = points[i];
1513
- sum_x += pt.x;
1514
- sum_y += pt.y;
1515
- sum_xy += (pt.x * pt.y);
1516
- sum_xx += (pt.x * pt.x);
1517
- sum_yy += (pt.y * pt.y);
1518
- }
1519
- // y = mx + b
1520
- result['m'] = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
1521
- result['b'] = (sum_y - result.m * sum_x) / n;
1522
- result['r2'] = Math.pow((n * sum_xy - sum_x * sum_y) / Math.sqrt((n * sum_xx - sum_x * sum_x) * (n * sum_yy - sum_y * sum_y)), 2);
1523
- return result;
1521
+ function linearRegression(points: T.Point[]): any
1522
+ {
1523
+ let result: any = {};
1524
+
1525
+ const n: number = points.length;
1526
+ let sum_x = 0;
1527
+ let sum_y = 0;
1528
+ let sum_xy = 0;
1529
+ let sum_xx = 0;
1530
+ let sum_yy = 0;
1531
+
1532
+ for (let i = 0; i < n; i++)
1533
+ {
1534
+ const pt = points[i];
1535
+
1536
+ sum_x += pt.x;
1537
+ sum_y += pt.y;
1538
+ sum_xy += (pt.x * pt.y);
1539
+ sum_xx += (pt.x * pt.x);
1540
+ sum_yy += (pt.y * pt.y);
1541
+ }
1542
+
1543
+ // y = mx + b
1544
+ result['m'] = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
1545
+ result['b'] = (sum_y - result.m * sum_x) / n;
1546
+ result['r2'] = Math.pow((n * sum_xy - sum_x * sum_y) / Math.sqrt((n * sum_xx - sum_x * sum_x) * (n * sum_yy - sum_y * sum_y)), 2);
1547
+
1548
+ return result;
1524
1549
  }
1525
- function characterizeDemographicVoting(points) {
1526
- const { m, b, r2 } = linearRegression(points);
1527
- const maxVAPPct = 1.0; // 100%
1528
- const maxDemPct = (m * maxVAPPct) + b;
1529
- // NOTE - You can't trim the implied max D %, because it's a regression line!
1530
- // const maxDemPct: number = Math.max(0.0, Math.min(1.0, (m * maxVAPPct) + b));
1531
- const result = {
1532
- m: U.trim(m),
1533
- b: U.trim(b),
1534
- r2: U.trim(r2),
1535
- sterr: U.trim(standardError(points, m, b)),
1536
- f1: U.trim(maxDemPct),
1537
- points: points
1538
- };
1539
- return result;
1550
+
1551
+ function characterizeDemographicVoting(points: T.Point[]): T.RPVLine
1552
+ {
1553
+ const { m, b, r2 }: any = linearRegression(points);
1554
+ const maxVAPPct = 1.0; // 100%
1555
+ const maxDemPct: number = (m * maxVAPPct) + b;
1556
+ // NOTE - You can't trim the implied max D %, because it's a regression line!
1557
+ // const maxDemPct: number = Math.max(0.0, Math.min(1.0, (m * maxVAPPct) + b));
1558
+
1559
+ const result = {
1560
+ m: U.trim(m),
1561
+ b: U.trim(b),
1562
+ r2: U.trim(r2),
1563
+ sterr: U.trim(standardError(points, m, b)),
1564
+ f1: U.trim(maxDemPct),
1565
+ points: points
1566
+ }
1567
+
1568
+ return result;
1540
1569
  }
1570
+
1541
1571
  // TODO - RPV: Review with Stephen Ansolabehere
1542
1572
  // https://www.wikihow.com/Calculate-the-Standard-Error-of-Estimate
1543
1573
  // https://www.stat.cmu.edu/~hseltman/309/Book/chapter9.pdf
1544
1574
  // y = mx + b
1545
- function standardError(points, m, b) {
1546
- const n = points.length;
1547
- let sse = 0;
1548
- for (let i = 0; i < n; i++) {
1549
- const pt = points[i];
1550
- const yPrime = yOnLine(pt.x, m, b);
1551
- const deltaY = pt.y - yPrime;
1552
- sse += Math.pow(deltaY, 2);
1553
- }
1554
- const sigma = Math.sqrt(sse / n);
1555
- return sigma;
1575
+ function standardError(points: T.Point[], m: number, b: number): number
1576
+ {
1577
+ const n: number = points.length;
1578
+ let sse: number = 0;
1579
+
1580
+ for (let i = 0; i < n; i++)
1581
+ {
1582
+ const pt = points[i];
1583
+
1584
+ const yPrime = yOnLine(pt.x, m, b);
1585
+ const deltaY = pt.y - yPrime;
1586
+
1587
+ sse += Math.pow(deltaY, 2);
1588
+ }
1589
+
1590
+ const sigma = Math.sqrt(sse / n);
1591
+
1592
+ return sigma;
1556
1593
  }
1594
+
1557
1595
  // For interpolating points on a line
1558
- const yOnLine = (x, m, b) => { return (m * x) + b; };
1559
- const xOnLine = (y, m, b) => { return (y - b) / m; };
1596
+ const yOnLine = (x: number, m: number, b: number): number => { return (m * x) + b; }
1597
+ const xOnLine = (y: number, m: number, b: number): number => { return (y - b) / m; }
1598
+ */
1560
1599
 
1561
1600
 
1562
1601
  /***/ }),
@@ -2672,6 +2711,17 @@ module.exports = require("@dra2020/poly");
2672
2711
 
2673
2712
  /***/ }),
2674
2713
 
2714
+ /***/ "@dra2020/racial-voting":
2715
+ /*!*****************************************!*\
2716
+ !*** external "@dra2020/racial-voting" ***!
2717
+ \*****************************************/
2718
+ /*! no static exports found */
2719
+ /***/ (function(module, exports) {
2720
+
2721
+ module.exports = require("@dra2020/racial-voting");
2722
+
2723
+ /***/ }),
2724
+
2675
2725
  /***/ "@dra2020/util":
2676
2726
  /*!********************************!*\
2677
2727
  !*** external "@dra2020/util" ***!