@@ -29,17 +29,14 @@ const MAX_DISTANCE = 130000
29
29
const MAX_TRAVEL_TIME = 120
30
30
const MIN_QUINTILE = 1
31
31
const MAX_QUINTILE = 5
32
- // stored profile importance is offset by one from MAX_IMPORTANCE
33
- const PROFILE_MAX_IMPORTANCE = MAX_IMPORTANCE - 1
34
32
35
33
// default to worst, if unknown
36
34
const DEFAULT_EDUCATION_QUINTILE = 5
37
35
const DEFAULT_CRIME_QUINTILE = 5
38
36
39
37
// extra constant weighting always given to travel time over the other two factors
40
- const EXTRA_ACCESS_WEIGHT = 2
38
+ const EXTRA_ACCESS_WEIGHT = 1
41
39
42
- /* eslint complexity: 0 */
43
40
export default createSelector (
44
41
selectNeighborhoodRoutes ,
45
42
neighborhoodTravelTimes ,
@@ -67,12 +64,7 @@ export default createSelector(
67
64
accessibilityImportance = crimeImportance = schoolsImportance = 1
68
65
}
69
66
70
- if ( accessibilityImportance === PROFILE_MAX_IMPORTANCE ) {
71
- // if set to very important, add more extra weight to travel time
72
- accessibilityImportance += 1
73
- }
74
-
75
- // Alwasy give accessibility (travel time) some extra weighting
67
+ // Give accessibility (travel time) extra weighting
76
68
accessibilityImportance += EXTRA_ACCESS_WEIGHT
77
69
78
70
const totalImportance = accessibilityImportance + crimeImportance + schoolsImportance
@@ -86,70 +78,49 @@ export default createSelector(
86
78
const route = neighborhoodRoutes [ index ]
87
79
const segments = useTransit ? route . routeSegments : [ ]
88
80
const time = useTransit ? travelTimes [ index ] : distanceTime ( origin , n )
81
+
82
+ // Map weighting values to percentages
83
+
89
84
// Routable neighborhoods outside the max travel time window will be filtered out.
90
85
// Smaller travel time is better; larger timeWeight is better (reverse range).
91
86
const timeWeight = time < MAX_TRAVEL_TIME ? scale ( time , 0 , MAX_TRAVEL_TIME , 1 , 0 ) : 1
87
+
92
88
// Weight schools either by percentile binned into quarters if given max importance,
93
89
// or otherwise weight by quintile.
94
90
let educationWeight
95
- if ( schoolsImportance === PROFILE_MAX_IMPORTANCE ) {
96
- // "very important": instead of quintiles, group percentile ranking into quarters
91
+ if ( schoolsImportance === ( MAX_IMPORTANCE - 1 ) ) {
92
+ // Group percentile ranking into quarters instead of using quintiles
93
+ // if the importance of schools is the max importance.
97
94
const edPercent = properties . education_percentile
98
95
? properties . education_percentile
99
96
: ( DEFAULT_EDUCATION_QUINTILE - 1 ) * 20
100
- let edPercentQuarter = Math . round ( scale ( edPercent , 0 , 100 , 3 , 0 ) )
101
- // Treat all schools not in the top quarter as being in the bottom quarter
102
- // to strongly prioritize the top quarter
103
- if ( edPercentQuarter > 0 ) {
104
- edPercentQuarter = 3
105
- }
97
+ const edPercentQuarter = Math . round ( scale ( edPercent , 0 , 100 , 3 , 0 ) )
106
98
educationWeight = scale ( edPercentQuarter , 0 , 3 , 1 , 0 )
107
- } else if ( schoolsImportance > 0 ) {
108
- // For "somewhat important", prioritize quintile 2 and below
109
- // For "important", quintile 3 and below (lower is better)
110
- const prioritizeQuintile = schoolsImportance === 1 ? 2 : 3
111
- let educationQuintile = properties . education_percentile_quintile
99
+ } else {
100
+ // Use quintiles if the importance of schools is anything less than the max importance.
101
+ const educationQuintile = properties . education_percentile_quintile
112
102
? properties . education_percentile_quintile
113
103
: DEFAULT_EDUCATION_QUINTILE
114
- // Treat all quintiles above the maximum to prioritize as being in the worst quintile
115
- if ( educationQuintile > prioritizeQuintile ) {
116
- educationQuintile = MAX_QUINTILE
117
- }
104
+
118
105
// Lowest education quintile is best (reverse range).
119
106
educationWeight = scale ( educationQuintile , MIN_QUINTILE , MAX_QUINTILE , 1 , 0 )
120
- } else {
121
- educationWeight = 0 // Not important
122
107
}
123
- let crimeWeight = 0
108
+ let crimeQuintile = properties . violentcrime_quintile
109
+ ? properties . violentcrime_quintile : DEFAULT_CRIME_QUINTILE
110
+ // Treat lowest two (safest) violent crime quintiles equally
111
+ if ( crimeQuintile === 2 ) {
112
+ crimeQuintile = 1
113
+ }
114
+ // Lowest crime quintile is best (reverse range).
115
+ const crimeWeight = scale ( crimeQuintile , MIN_QUINTILE , MAX_QUINTILE , 1 , 0 )
116
+
124
117
// Handle missing values (zero in spreadsheet) by re-assigning crime weight
125
- // evenly to the other two factors. Also do so if crime set as unimportant.
126
- if ( properties . violentcrime_quintile === 0 || crimeImportance === 0 ) {
118
+ // evenly to the other two factors
119
+ if ( properties . violentcrime_quintile === 0 ) {
127
120
const halfCrimePercent = crimePercent / 2
128
121
schoolPercent += halfCrimePercent
129
122
accessibilityPercent += halfCrimePercent
130
123
crimePercent = 0
131
- } else {
132
- let crimeQuintile = properties . violentcrime_quintile
133
- ? properties . violentcrime_quintile : DEFAULT_CRIME_QUINTILE
134
- // Treat lowest two (safest) violent crime quintiles equally
135
- if ( crimeQuintile === 2 ) {
136
- crimeQuintile = 1
137
- }
138
- if ( crimeImportance === 1 && crimeQuintile < 5 ) {
139
- // somewhat important; treat all but worst quintile the same
140
- crimeQuintile = 1
141
- } else if ( crimeImportance === 2 && crimeQuintile < 4 ) {
142
- // "important"; treat all but worst two quintiles the same
143
- crimeQuintile = 1
144
- } else if ( crimeImportance === PROFILE_MAX_IMPORTANCE && crimeQuintile > 3 ) {
145
- // "very important"; push results for worst two quintiles to bottom
146
- // by reassigning weights for those quintiles to be 90% crime
147
- crimePercent = 90
148
- schoolPercent /= 10
149
- accessibilityPercent /= 10
150
- }
151
- // Lowest crime quintile is best (reverse range).
152
- crimeWeight = scale ( crimeQuintile , MIN_QUINTILE , MAX_QUINTILE , 1 , 0 )
153
124
}
154
125
155
126
// Calculate weighted overall score from the percentages. Larger score is better.
0 commit comments