-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use estimated data for trend charts #707
Changes from 11 commits
4e82e14
fe6c5fd
d029170
70cd81a
7b52cb5
a694b8d
3ac93bd
42c75fb
38f172a
9e2aaa4
a6ef64c
40bad4c
436fd26
8919e4c
cb4a83b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import snakeCase from 'lodash.snakecase' | ||
import startCase from 'lodash.startcase' | ||
import PropTypes from 'prop-types' | ||
import React from 'react' | ||
|
@@ -6,51 +7,33 @@ import Loading from './Loading' | |
import NoData from './NoData' | ||
import TrendChart from './TrendChart' | ||
import TrendSourceText from './TrendSourceText' | ||
import mungeSummaryData from '../util/summary' | ||
|
||
|
||
const dataByYear = data => ( | ||
Object.assign( | ||
...Object.keys(data).map(k => ({ | ||
[k]: Object.assign(...data[k].map(d => ({ [d.year]: d }))), | ||
})), | ||
) | ||
) | ||
|
||
const mungeSummaryData = (summaries, ucr, place) => { | ||
if (!summaries || !summaries[place]) return false | ||
|
||
const keys = Object.keys(summaries) | ||
const summaryByYear = dataByYear(summaries) | ||
const ucrByYear = dataByYear(ucr) | ||
|
||
return summaries[place].map(d => ( | ||
Object.assign( | ||
{ date: d.year }, | ||
...keys.map(k => { | ||
const count = summaryByYear[k][d.year].actual | ||
const pop = ucrByYear[k][d.year].total_population | ||
return { [k]: { count, pop, rate: (count / pop) * 100000 } } | ||
}), | ||
) | ||
)) | ||
const filterDataWithinYears = ({ data, since, until }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i wonder if this function should be in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think this could do the trick:
note the |
||
const places = Object.keys(data) | ||
const yearData = places.map(place => ({ | ||
[place]: data[place].filter(d => d.year <= until && d.year >= since) | ||
})) | ||
return Object.assign(...yearData) | ||
} | ||
|
||
const TrendContainer = ({ | ||
crime, | ||
dispatch, | ||
place, | ||
placeType, | ||
dispatch, | ||
since, | ||
summaries, | ||
ucr, | ||
until, | ||
}) => { | ||
const loading = summaries.loading || ucr.loading | ||
const loading = summaries.loading | ||
|
||
let content = null | ||
if (loading) content = <Loading /> | ||
else { | ||
const data = mungeSummaryData(summaries.data, ucr.data, place) | ||
const dataWithinYears = filterDataWithinYears({ data: summaries.data, since, until }) | ||
const data = mungeSummaryData(snakeCase(crime), dataWithinYears, place) | ||
if (!data || data.length === 0) content = <NoData /> | ||
else { | ||
content = ( | ||
|
@@ -100,11 +83,7 @@ TrendContainer.propTypes = { | |
data: PropTypes.object, | ||
loading: PropTypes.boolean, | ||
}).isRequired, | ||
ucr: PropTypes.shape({ | ||
data: PropTypes.object, | ||
loading: PropTypes.boolean, | ||
}).isRequired, | ||
until: PropTypes.number.isRequired, | ||
until: React.PropTypes.number.isRequired, | ||
} | ||
|
||
export default TrendContainer |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
import upperFirst from 'lodash.upperfirst' | ||
|
||
import { get } from './http' | ||
import { mapToApiOffense, mapToApiOffenseParam } from './offenses' | ||
import { mapToApiOffense } from './offenses' | ||
import lookupUsa, { nationalKey } from './usa' | ||
|
||
|
||
|
@@ -50,46 +50,31 @@ const getNibrsRequests = params => { | |
return slices.map(s => getNibrs({ ...s, crime, place })) | ||
} | ||
|
||
const buildSummaryQueryString = params => { | ||
const { crime, place, since, until } = params | ||
const offense = mapToApiOffense(crime) | ||
const offenseParam = mapToApiOffenseParam(crime) | ||
|
||
const qs = [ | ||
`${offenseParam}=${offense}`, | ||
`per_page=${(until - since) + 1}`, | ||
`year>=${since}`, | ||
`year<=${until}`, | ||
] | ||
|
||
if (place && place !== nationalKey) { | ||
qs.push(`state=${lookupUsa(params.place)}`) | ||
} | ||
|
||
return qs.join('&') | ||
} | ||
|
||
const getSummary = params => { | ||
const { place } = params | ||
const endpoint = `${API}/counts` | ||
const qs = buildSummaryQueryString(params) | ||
let endpoint | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would use ternary here to save a few lines:
|
||
if (place === nationalKey) { | ||
endpoint = `${API}/estimates/national` | ||
} else { | ||
endpoint = `${API}/estimates/states/${lookupUsa(place).toUpperCase()}` | ||
} | ||
|
||
return get(`${endpoint}?${qs}`).then(response => ({ | ||
return get(`${endpoint}?per_page=50`).then(response => ({ | ||
place, | ||
results: response.results, | ||
})) | ||
} | ||
|
||
const getSummaryRequests = params => { | ||
const { crime, place, since, until } = params | ||
const { place, since, until } = params | ||
|
||
const requests = [ | ||
getSummary({ crime, place, since, until }), | ||
getSummary({ place, since, until }), | ||
] | ||
|
||
// add national summary request (unless you already did) | ||
if (place !== nationalKey) { | ||
requests.push(getSummary({ crime, place: nationalKey, since, until })) | ||
requests.push(getSummary({ place: nationalKey, since, until })) | ||
} | ||
|
||
return requests | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const mungeSummaryData = (crime, summaries, place) => { | ||
if (!summaries || !summaries[place]) return false | ||
|
||
const keys = Object.keys(summaries) | ||
return summaries[place].map(year => { | ||
const data = { date: year.year } | ||
keys.forEach(key => { | ||
const source = key !== place ? summaries[key].find(d => d.year === data.date) : year | ||
data[key] = { | ||
pop: source.population, | ||
count: source[crime], | ||
rate: (source[crime] / source.population) * 100000, | ||
} | ||
}) | ||
return data | ||
}) | ||
} | ||
|
||
export default mungeSummaryData |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* eslint no-undef: 0 */ | ||
|
||
import mungeSummaryData from '../../src/util/summary' | ||
|
||
|
||
describe('summary data munging utility', () => { | ||
it('should return false if summaries is not supplied', () => { | ||
const crime = 'violent-crime' | ||
expect(mungeSummaryData(null, crime)).toEqual(false) | ||
}) | ||
|
||
it('should return false if summaries[place] is not supplied', () => { | ||
const crime = 'violent-crime' | ||
const summaries = {} | ||
const place = 'california' | ||
expect(mungeSummaryData(crime, summaries, place)).toEqual(false) | ||
}) | ||
|
||
it('should reshape the data', () => { | ||
const crime = 'violent-crime' | ||
const summaries = { | ||
california: [{ year: 2014, 'violent-crime': 10, population: 100 }], | ||
'united-states': [{ year: 2014, 'violent-crime': 10, population: 100 }], | ||
} | ||
const place = 'california' | ||
expect(mungeSummaryData(crime, summaries, place)).toEqual([ | ||
{ | ||
date: 2014, | ||
california: { count: 10, pop: 100, rate: 10000 }, | ||
'united-states': { count: 10, pop: 100, rate: 10000 }, | ||
} | ||
]) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did u replace the
getPlaceInfo
method incomponentDidMount
andrender
? i think that helps consolidate this place assignment logicThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, I think that just got removed when I was fixing rebase conflicts. I'll look for it and take a second look