-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhexbin-processing.js
137 lines (109 loc) · 4.29 KB
/
hexbin-processing.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// load libraries
const fs = require("fs")
const turf = require("@turf/turf")
const turfMeta = require("@turf/meta")
const simpleStats = require("simple-statistics")
const d3 = require("d3-array")
const dataDirectory = "./data"
function getMultiplier(value, breaks, multipliers) {
if (!value) {
return null;
}
let multiplier;
let found = false;
let i = 1;
while (found == false && i <= multipliers.length) {
if (value <= breaks[i]) {
multiplier = multipliers[i - 1];
found = true;
} else {
i ++;
}
}
return multiplier ? multiplier : null;
}
function output_aggregated_geodata(inputFilename, outputFilename, hexSide, hex=true, wurman=false) {
// load our data
const data = require(`${dataDirectory}/${inputFilename}`)
// rough geographic bounding box of North Carolina
const bbox = [-84.821869, 33.842316, -74.960621, 36.588117]
// size in miles we want each side of our hex grids
const cellSide = hexSide // 2 for large grid, .2 for small grid
// create the hexbin geometry for the given bbox and cell resolution
const options = {triangles: false, units: 'miles'}
const hexGrid = turf.hexGrid(bbox, cellSide, options)
// perform a "spatial join" on our hexGrid geometry and our crashes point data
const collected = turf.collect(hexGrid, data, "residences", "values")
// get rid of polygons with no joined data, to reduce our final output file size
collected.features = collected.features.filter(d => d.properties.values.length)
// count the number of crashes per hexbin
turfMeta.propEach(collected, props => {
props.count = props.values.reduce((acc, cur) => acc += 1, 0)
})
// reduce our count values to a new array of numbers
const reduced = turfMeta.featureReduce(collected, (acc, cur) => {
acc.push(cur.properties.count)
return acc
}, [])
// compute the ckMeans binning for data into 7 classes from reduced values
const numBins = 7;
const ck = simpleStats.ckmeans(reduced, numBins)
// tack on the bin number to our data, as well as its min and max values
turfMeta.propEach(collected, props => {
ck.forEach((bin, index) => {
if (bin.indexOf(props.count) > -1) {
props.bin = index
props.binVal = d3.extent(bin)
}
})
})
// remove the "values" property from our hexBins as it's no longer needed
turfMeta.propEach(collected, props => {
delete props.values
})
// write output data
let outputFilepath = `${dataDirectory}/${outputFilename}`;
fs.writeFileSync(outputFilepath, JSON.stringify(collected));
console.log(`Output hexagon file: ${outputFilepath}`);
if (wurman) {
create_wurman_dots(collected);
}
}
function create_wurman_dots(collected) {
let innerCircles = {
"type": "FeatureCollection",
"features": []
}
let outerCircles = {
"type": "FeatureCollection",
"features": []
}
let innerMultipliers = [.3, .6, .8, 1, 1, 1, 1]
// let breaks = [1, 2, 10, 50, 100, 500, 1000, 100000]
let breaks = [1, 2, 3, 5, 10, 20, 200, 100000]
collected.features.forEach(polygon => {
let properties = polygon.properties
let centroid = turf.centroid(polygon);
let center = centroid.geometry.coordinates;
// This would be the outer circle grid of the Wurman dot
let outerDistance = Math.sqrt(3)/2 * cellSide *.95;
let outerCircle = turf.circle(center, outerDistance, options);
outerCircle.properties = properties
outerCircles.features.push(outerCircle)
// This would be the inner circle of the Wurman dot
let innerMultiplier = getMultiplier(properties.count, breaks, innerMultipliers)
let innerDistance = outerDistance * innerMultiplier;
let innerCircle = turf.circle(center, innerDistance, options);
innerCircle.properties = polygon.properties
innerCircles.features.push(innerCircle)
})
fs.writeFileSync(`${dataDirectory}/wurmanOuterCircles.json`, JSON.stringify(outerCircles))
fs.writeFileSync(`${dataDirectory}/wurmanInnerCircles.json`, JSON.stringify(innerCircles))
}
// Reading in simple command line args
// USAGE: node hexbin-processing.js --data=investor_owned_residences --side=2
const args = require('minimist')(process.argv.slice(2));
let inputFilename = args.input;
let hexSideLength = args.side;
let outputFilename = args?.output;
output_aggregated_geodata(inputFilename, outputFilename, hexSideLength)