@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.
- package/dist/district-analytics.js +140 -90
- package/dist/district-analytics.js.map +1 -1
- package/dist/src/_api.d.ts +2 -1
- package/dist/src/_data.d.ts +2 -1
- package/dist/src/minority.d.ts +2 -1
- package/dist/src/types.d.ts +0 -41
- package/package.json +2 -1
|
@@ -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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
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
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
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
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
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
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
const
|
|
1555
|
-
|
|
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" ***!
|