Merge branch 'usds:main' into main

This commit is contained in:
Saran Ahluwalia 2021-12-07 16:01:52 -05:00 committed by GitHub
commit e30b32fe07
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 851 additions and 260 deletions

View file

@ -12,24 +12,26 @@ import * as constants from '../../data/constants';
import * as EXPLORE_COPY from '../../data/copy/explore'; import * as EXPLORE_COPY from '../../data/copy/explore';
import * as METHODOLOGY_COPY from '../../data/copy/methodology'; import * as METHODOLOGY_COPY from '../../data/copy/methodology';
export const readablePercentile = (percentile: number) => { export const readablePercentile = (percentile: number | null) => {
return Math.round(percentile * 100); return percentile ? Math.round(percentile * 100) : 'N/A';
}; };
// Todo: Add internationalization to superscript ticket #582 // Todo: Add internationalization to superscript ticket #582
const getSuperscriptOrdinal = (percentile: number) => { const getSuperscriptOrdinal = (percentile: number | string) => {
const englishOrdinalRules = new Intl.PluralRules('en', { if (typeof percentile === "number") {
type: 'ordinal', const englishOrdinalRules = new Intl.PluralRules('en', {
}); type: 'ordinal',
const suffixes = { });
zero: 'th', const suffixes = {
one: 'st', zero: 'th',
two: 'nd', one: 'st',
few: 'rd', two: 'nd',
many: 'th', few: 'rd',
other: 'th', many: 'th',
}; other: 'th',
return suffixes[englishOrdinalRules.select(percentile)]; };
return suffixes[englishOrdinalRules.select(percentile)];
}
}; };
interface IAreaDetailProps { interface IAreaDetailProps {
@ -40,11 +42,13 @@ const AreaDetail = ({properties}:IAreaDetailProps) => {
const intl = useIntl(); const intl = useIntl();
const [isCommunityFocus, setIsCommunityFocus] = React.useState<boolean>(true); const [isCommunityFocus, setIsCommunityFocus] = React.useState<boolean>(true);
const score = properties[constants.SCORE_PROPERTY_HIGH] as number; console.log("Area Detail properies: ", properties);
const blockGroup = properties[constants.GEOID_PROPERTY];
const population = properties[constants.TOTAL_POPULATION]; const score = properties[constants.SCORE_PROPERTY_HIGH] ? properties[constants.SCORE_PROPERTY_HIGH] as number : 0;
const countyName = properties[constants.COUNTY_NAME]; const blockGroup = properties[constants.GEOID_PROPERTY] ? properties[constants.GEOID_PROPERTY] : "N/A";
const stateName = properties[constants.STATE_NAME]; const population = properties[constants.TOTAL_POPULATION] ? properties[constants.TOTAL_POPULATION] : "N/A";
const countyName = properties[constants.COUNTY_NAME] ? properties[constants.COUNTY_NAME] : "N/A";
const stateName = properties[constants.STATE_NAME] ? properties[constants.STATE_NAME] : "N/A";
useEffect(() => { useEffect(() => {
if (score >= constants.SCORE_BOUNDARY_PRIORITIZED ) { if (score >= constants.SCORE_BOUNDARY_PRIORITIZED ) {
@ -65,77 +69,92 @@ const AreaDetail = ({properties}:IAreaDetailProps) => {
const areaMedianIncome:indicatorInfo = { const areaMedianIncome:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.AREA_MEDIAN_INCOME), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.AREA_MEDIAN_INCOME),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.AREA_MEDIAN_INCOME), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.AREA_MEDIAN_INCOME),
value: properties[constants.AREA_MEDIAN_INCOME_PERCENTILE], value: properties[constants.AREA_MEDIAN_INCOME_PERCENTILE] ?
properties[constants.AREA_MEDIAN_INCOME_PERCENTILE] : null,
}; };
const eduInfo:indicatorInfo = { const eduInfo:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.EDUCATION), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.EDUCATION),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.EDUCATION), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.EDUCATION),
value: properties[constants.EDUCATION_PROPERTY_PERCENTILE], value: properties[constants.EDUCATION_PROPERTY_PERCENTILE] ?
properties[constants.EDUCATION_PROPERTY_PERCENTILE] : null,
}; };
const poverty:indicatorInfo = { const poverty:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.POVERTY), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.POVERTY),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.POVERTY), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.POVERTY),
value: properties[constants.POVERTY_PROPERTY_PERCENTILE], value: properties[constants.POVERTY_PROPERTY_PERCENTILE] ?
properties[constants.POVERTY_PROPERTY_PERCENTILE] : null,
}; };
const asthma:indicatorInfo = { const asthma:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.ASTHMA), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.ASTHMA),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.ASTHMA), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.ASTHMA),
value: properties[constants.ASTHMA_PERCENTILE], value: properties[constants.ASTHMA_PERCENTILE] ?
properties[constants.ASTHMA_PERCENTILE] : null,
}; };
const diabetes:indicatorInfo = { const diabetes:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.DIABETES), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.DIABETES),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.DIABETES), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.DIABETES),
value: properties[constants.DIABETES_PERCENTILE], value: properties[constants.DIABETES_PERCENTILE] ?
properties[constants.DIABETES_PERCENTILE] : null,
}; };
const dieselPartMatter:indicatorInfo = { const dieselPartMatter:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.DIESEL_PARTICULATE_MATTER), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.DIESEL_PARTICULATE_MATTER),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.DIESEL_PARTICULATE_MATTER), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.DIESEL_PARTICULATE_MATTER),
value: properties[constants.DIESEL_MATTER_PERCENTILE], value: properties[constants.DIESEL_MATTER_PERCENTILE] ?
properties[constants.DIESEL_MATTER_PERCENTILE] : null,
}; };
const lifeExpect:indicatorInfo = { const lifeExpect:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.LIFE_EXPECT), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.LIFE_EXPECT),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.LIFE_EXPECT), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.LIFE_EXPECT),
value: properties[constants.LIFE_PERCENTILE], value: properties[constants.LIFE_PERCENTILE] ?
properties[constants.LIFE_PERCENTILE] : null,
}; };
const energyBurden:indicatorInfo = { const energyBurden:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.ENERGY_BURDEN), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.ENERGY_BURDEN),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.ENERGY_BURDEN), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.ENERGY_BURDEN),
value: properties[constants.ENERGY_PERCENTILE], value: properties[constants.ENERGY_PERCENTILE] ?
properties[constants.ENERGY_PERCENTILE] : null,
}; };
const pm25:indicatorInfo = { const pm25:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.PM_2_5), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.PM_2_5),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.PM_2_5), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.PM_2_5),
value: properties[constants.PM25_PERCENTILE], value: properties[constants.PM25_PERCENTILE] ?
properties[constants.PM25_PERCENTILE] : null,
}; };
const leadPaint:indicatorInfo = { const leadPaint:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.LEAD_PAINT), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.LEAD_PAINT),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.LEAD_PAINT), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.LEAD_PAINT),
value: properties[constants.LEAD_PAINT_PERCENTILE], value: properties[constants.LEAD_PAINT_PERCENTILE] ?
properties[constants.LEAD_PAINT_PERCENTILE] : null,
}; };
const trafficVolume:indicatorInfo = { const trafficVolume:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.TRAFFIC_VOLUME), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.TRAFFIC_VOLUME),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.TRAFFIC_VOLUME), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.TRAFFIC_VOLUME),
value: properties[constants.TRAFFIC_PERCENTILE], value: properties[constants.TRAFFIC_PERCENTILE] ?
properties[constants.TRAFFIC_PERCENTILE] : null,
}; };
const wasteWater:indicatorInfo = { const wasteWater:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.WASTE_WATER), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.WASTE_WATER),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.WASTE_WATER), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.WASTE_WATER),
value: properties[constants.WASTEWATER_PERCENTILE], value: properties[constants.WASTEWATER_PERCENTILE] ?
properties[constants.WASTEWATER_PERCENTILE] : null,
}; };
const femaRisk:indicatorInfo = { const femaRisk:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.FEMA_RISK), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.FEMA_RISK),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.FEMA_RISK), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.FEMA_RISK),
value: properties[constants.FEMA_PERCENTILE], value: properties[constants.FEMA_PERCENTILE] ?
properties[constants.FEMA_PERCENTILE] : null,
}; };
const heartDisease:indicatorInfo = { const heartDisease:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.HEART_DISEASE), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.HEART_DISEASE),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.HEART_DISEASE), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.HEART_DISEASE),
value: properties[constants.HEART_PERCENTILE], value: properties[constants.HEART_PERCENTILE] ?
properties[constants.HEART_PERCENTILE] : null,
}; };
const houseBurden:indicatorInfo = { const houseBurden:indicatorInfo = {
label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.HOUSE_BURDEN), label: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATORS.HOUSE_BURDEN),
description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.HOUSE_BURDEN), description: intl.formatMessage(EXPLORE_COPY.SIDE_PANEL_INDICATOR_DESCRIPTION.HOUSE_BURDEN),
value: properties[constants.HOUSING_BURDEN_PROPERTY_PERCENTILE], value: properties[constants.HOUSING_BURDEN_PROPERTY_PERCENTILE] ?
properties[constants.HOUSING_BURDEN_PROPERTY_PERCENTILE] : null,
}; };

View file

@ -19,7 +19,7 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
County: County:
</span> </span>
<span> <span>
undefined N/A
</span> </span>
</li> </li>
<li> <li>
@ -27,7 +27,7 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
State: State:
</span> </span>
<span> <span>
undefined N/A
</span> </span>
</li> </li>
<li> <li>
@ -134,11 +134,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Asthma Asthma
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -156,11 +154,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Diabetes Diabetes
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -178,11 +174,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Diesel particulate matter Diesel particulate matter
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -200,11 +194,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Energy burden Energy burden
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -222,11 +214,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
FEMA Risk Index FEMA Risk Index
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -244,11 +234,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Heart disease Heart disease
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -288,11 +276,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Lead paint Lead paint
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -310,11 +296,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Life expectancy Life expectancy
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -332,11 +316,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
PM2.5 PM2.5
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -354,11 +336,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Traffic proximity and volume Traffic proximity and volume
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>
@ -376,11 +356,9 @@ exports[`rendering of the AreaDetail checks if various text fields are visible 1
Wastewater discharge Wastewater discharge
</h4> </h4>
<div> <div>
NaN N/A
<sup> <sup>
<span> <span />
th
</span>
</sup> </sup>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
// External Libs: // External Libs:
import React, {MouseEvent, useRef, useState, useMemo} from 'react'; import React, {useRef, useState, useMemo} from 'react';
import {Map, MapboxGeoJSONFeature, LngLatBoundsLike} from 'maplibre-gl'; import {Map, MapboxGeoJSONFeature, LngLatBoundsLike} from 'maplibre-gl';
import ReactMapGL, { import ReactMapGL, {
MapEvent, MapEvent,
@ -136,29 +136,6 @@ const J40Map = ({location}: IJ40Interface) => {
}); });
}; };
const onClickTerritoryFocusButton = (event: MouseEvent<HTMLButtonElement>) => {
event.stopPropagation();
const buttonID = event.target && (event.target as HTMLElement).id;
switch (buttonID) {
case '48':
goToPlace(constants.LOWER_48_BOUNDS);
break;
case 'AK':
goToPlace(constants.ALASKA_BOUNDS);
break;
case 'HI':
goToPlace(constants.HAWAII_BOUNDS);
break;
case 'PR':
goToPlace(constants.PUERTO_RICO_BOUNDS);
break;
default:
break;
}
};
const onTransitionStart = () => { const onTransitionStart = () => {
setTransitionInProgress(true); setTransitionInProgress(true);
}; };
@ -273,7 +250,7 @@ const J40Map = ({location}: IJ40Interface) => {
onClick={onClickGeolocate} onClick={onClickGeolocate}
/> : ''} /> : ''}
{geolocationInProgress ? <div>Geolocation in progress...</div> : ''} {geolocationInProgress ? <div>Geolocation in progress...</div> : ''}
<TerritoryFocusControl onClickTerritoryFocusButton={onClickTerritoryFocusButton}/> <TerritoryFocusControl goToPlace={goToPlace}/>
{'fs' in flags ? <FullscreenControl className={styles.fullscreenControl}/> :'' } {'fs' in flags ? <FullscreenControl className={styles.fullscreenControl}/> :'' }
</ReactMapGL> </ReactMapGL>

View file

@ -1,21 +1,53 @@
import {useIntl} from 'gatsby-plugin-intl'; import {useIntl} from 'gatsby-plugin-intl';
import React, {MouseEventHandler} from 'react'; import React from 'react';
import {_useMapControl as useMapControl} from 'react-map-gl'; import {LngLatBoundsLike} from 'mapbox-gl';
import * as styles from './territoryFocusControl.module.scss'; import * as styles from './territoryFocusControl.module.scss';
import * as EXPLORE_COPY from '../data/copy/explore'; import * as EXPLORE_COPY from '../data/copy/explore';
import * as constants from '../data/constants';
interface ITerritoryFocusControl { interface ITerritoryFocusControl {
onClickTerritoryFocusButton: MouseEventHandler<HTMLButtonElement>; goToPlace(bounds: LngLatBoundsLike): void;
} }
const TerritoryFocusControl = ({onClickTerritoryFocusButton}: ITerritoryFocusControl) => {
const TerritoryFocusControl = ({goToPlace}: ITerritoryFocusControl) => {
const intl = useIntl(); const intl = useIntl();
const {containerRef} = useMapControl({ const onClickTerritoryFocusButton = (event: React.MouseEvent<HTMLButtonElement>) => {
// @ts-ignore // Types have not caught up yet, see https://github.com/visgl/react-map-gl/issues/1492 event.stopPropagation();
onClick: onClickTerritoryFocusButton, const buttonID = event.target && (event.target as HTMLElement).id;
});
switch (buttonID) {
case '48':
goToPlace(constants.LOWER_48_BOUNDS);
break;
case 'AK':
goToPlace(constants.ALASKA_BOUNDS);
break;
case 'HI':
goToPlace(constants.HAWAII_BOUNDS);
break;
case 'PR':
goToPlace(constants.PUERTO_RICO_BOUNDS);
break;
case 'GU':
goToPlace(constants.GUAM_BOUNDS);
break;
case 'AS':
goToPlace(constants.AMERICAN_SAMOA_BOUNDS);
break;
case 'MP':
goToPlace(constants.MARIANA_ISLAND_BOUNDS);
break;
case 'VI':
goToPlace(constants.US_VIRGIN_ISLANDS_BOUNDS);
break;
default:
break;
}
};
const territories = [ const territories = [
{ {
@ -34,6 +66,22 @@ const TerritoryFocusControl = ({onClickTerritoryFocusButton}: ITerritoryFocusCon
short: intl.formatMessage(EXPLORE_COPY.MAP.PR_SHORT), short: intl.formatMessage(EXPLORE_COPY.MAP.PR_SHORT),
long: intl.formatMessage(EXPLORE_COPY.MAP.PR_LONG), long: intl.formatMessage(EXPLORE_COPY.MAP.PR_LONG),
}, },
{
short: intl.formatMessage(EXPLORE_COPY.MAP.GU_SHORT),
long: intl.formatMessage(EXPLORE_COPY.MAP.GU_LONG),
},
{
short: intl.formatMessage(EXPLORE_COPY.MAP.AS_SHORT),
long: intl.formatMessage(EXPLORE_COPY.MAP.AS_LONG),
},
{
short: intl.formatMessage(EXPLORE_COPY.MAP.MP_SHORT),
long: intl.formatMessage(EXPLORE_COPY.MAP.MP_LONG),
},
{
short: intl.formatMessage(EXPLORE_COPY.MAP.VI_SHORT),
long: intl.formatMessage(EXPLORE_COPY.MAP.VI_LONG),
},
]; ];
// the offset for this array should map the territories variable // the offset for this array should map the territories variable
const territoriesIconClassName = [ const territoriesIconClassName = [
@ -41,16 +89,20 @@ const TerritoryFocusControl = ({onClickTerritoryFocusButton}: ITerritoryFocusCon
'mapboxgl-ctrl-zoom-to-ak', 'mapboxgl-ctrl-zoom-to-ak',
'mapboxgl-ctrl-zoom-to-hi', 'mapboxgl-ctrl-zoom-to-hi',
'mapboxgl-ctrl-zoom-to-pr', 'mapboxgl-ctrl-zoom-to-pr',
'mapboxgl-ctrl-zoom-to-gu',
'mapboxgl-ctrl-zoom-to-as',
'mapboxgl-ctrl-zoom-to-mp',
'mapboxgl-ctrl-zoom-to-vi',
]; ];
return ( return (
<div ref={containerRef} className={styles.territoryFocusContainer}> <div className={styles.territoryFocusContainer}>
<div className={'mapboxgl-ctrl mapboxgl-ctrl-group'}> <div className={'mapboxgl-ctrl mapboxgl-ctrl-group'}>
{territories.map((territory, index) => {territories.map((territory, index) =>
<button <button
id={territory.short} id={territory.short}
key={territory.short} key={territory.short}
onClick={onClickTerritoryFocusButton} onClick={(e) => onClickTerritoryFocusButton(e)}
className={'mapboxgl-ctrl-icon ' + territoriesIconClassName[index]} className={'mapboxgl-ctrl-icon ' + territoriesIconClassName[index]}
aria-label={intl.formatMessage( aria-label={intl.formatMessage(
{ {

View file

@ -121,6 +121,11 @@ export const AMERICAN_SAMOA_BOUNDS: LngLatBoundsLike = [
[-168.1433, -11.046934], [-168.1433, -11.046934],
]; ];
export const US_VIRGIN_ISLANDS_BOUNDS: LngLatBoundsLike = [
[-65.5782239, 17.6739145],
[-64.2704123, 18.7495796],
];
export const DEFAULT_CENTER = [32.4687126, -86.502136]; export const DEFAULT_CENTER = [32.4687126, -86.502136];
// Opacity // Opacity

View file

@ -57,6 +57,16 @@ export const MAP = defineMessages({
defaultMessage: 'Zoom in to the state or regional level to see prioritized communities on the map.', defaultMessage: 'Zoom in to the state or regional level to see prioritized communities on the map.',
description: 'zoom warning on map', description: 'zoom warning on map',
}, },
SEARCH_PLACEHOLDER: {
id: 'map.search.placeholder.text',
defaultMessage: 'Enter a city, state or ZIP',
description: 'placeholder text for search',
},
SEARCH_RESULTS_EMPTY_MESSAGE: {
id: 'map.search.results.empty.text',
defaultMessage: 'No location found. Please try another location.',
description: 'text displaying message for no search results found',
},
LOWER48_SHORT: { LOWER48_SHORT: {
id: 'map.territoryFocus.lower48.short', id: 'map.territoryFocus.lower48.short',
defaultMessage: '48', defaultMessage: '48',
@ -97,15 +107,45 @@ export const MAP = defineMessages({
defaultMessage: 'Puerto Rico', defaultMessage: 'Puerto Rico',
description: 'The full name indicating the bounds of Puerto Rico', description: 'The full name indicating the bounds of Puerto Rico',
}, },
SEARCH_PLACEHOLDER: { GU_SHORT: {
id: 'map.search.placeholder.text', id: 'map.territoryFocus.guam.short',
defaultMessage: 'Enter a city, state or ZIP', defaultMessage: 'GU',
description: 'placeholder text for search', description: 'The abbreviated name indicating the bounds of Guam',
}, },
SEARCH_RESULTS_EMPTY_MESSAGE: { GU_LONG: {
id: 'map.search.results.empty.text', id: 'map.territoryFocus.guam.long',
defaultMessage: 'No location found. Please try another location.', defaultMessage: 'Guam',
description: 'text displaying message for no search results found', description: 'The full name indicating the bounds of Guam',
},
AS_SHORT: {
id: 'map.territoryFocus.american.samoa.short',
defaultMessage: 'AS',
description: 'The abbreviated name indicating the bounds of American Somoa',
},
AS_LONG: {
id: 'map.territoryFocus.american.samoa.long',
defaultMessage: 'American Somoa',
description: 'The full name indicating the bounds of American Somoa',
},
MP_SHORT: {
id: 'map.territoryFocus.commonwealth.nmp.short',
defaultMessage: 'MP',
description: 'The abbreviated name indicating the bounds of Commonwealth of Northern Mariana Islands',
},
MP_LONG: {
id: 'map.territoryFocus.commonwealth.nmp.long',
defaultMessage: 'Commonwealth of Northern Mariana Islands',
description: 'The full name indicating the bounds of Commonwealth of Northern Mariana Islands',
},
VI_SHORT: {
id: 'map.territoryFocus.us.virgin.islands.short',
defaultMessage: 'VI',
description: 'The abbreviated name indicating the bounds of US Virgin Islands',
},
VI_LONG: {
id: 'map.territoryFocus.us.virgin.islands.long',
defaultMessage: 'US Virgin Islands',
description: 'The full name indicating the bounds of US Virgin Islands',
}, },
}); });

View file

@ -1 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-.54.11h24v24h-24Z" transform="translate(0.54 -0.11)" style="fill:none"/><path d="M11.74,13.46H10.18V16H8.61V13.46H4.67V12.31L8.79,6.83h1.39v5.28h1.56ZM8.61,9.22,6.34,12.11H8.61Z" transform="translate(0.54 -0.11)"/><path d="M12.74,13.77a2.23,2.23,0,0,1,.15-.83,2.62,2.62,0,0,1,.39-.67,3.51,3.51,0,0,1,.55-.54,6.51,6.51,0,0,1,.64-.43,4,4,0,0,1-1.08-.89A2,2,0,0,1,13,9.12a2.21,2.21,0,0,1,.22-.95,2.54,2.54,0,0,1,.62-.77,3.13,3.13,0,0,1,.94-.5,3.8,3.8,0,0,1,1.19-.18,4,4,0,0,1,1.1.15,3.14,3.14,0,0,1,.9.44,2.15,2.15,0,0,1,.61.7,1.82,1.82,0,0,1,.22.9,2.26,2.26,0,0,1-.4,1.34,3.46,3.46,0,0,1-1.08,1,4,4,0,0,1,1.24.95,2.07,2.07,0,0,1,.46,1.4,2.21,2.21,0,0,1-.25,1.06,2.54,2.54,0,0,1-.68.81A3.14,3.14,0,0,1,17,16a3.86,3.86,0,0,1-1.23.19A3.93,3.93,0,0,1,14.6,16a3.14,3.14,0,0,1-1-.48,2.15,2.15,0,0,1-.65-.76A2,2,0,0,1,12.74,13.77Zm4.63-.22A1,1,0,0,0,17.2,13a1.82,1.82,0,0,0-.42-.41,4.34,4.34,0,0,0-.56-.33c-.2-.1-.4-.2-.59-.31a2.45,2.45,0,0,0-1,.74,1.37,1.37,0,0,0-.35.85,1.08,1.08,0,0,0,.41.9,1.9,1.9,0,0,0,1.16.32,1.78,1.78,0,0,0,1.09-.31A1,1,0,0,0,17.37,13.55ZM14.58,9.2a1,1,0,0,0,.13.53,1.53,1.53,0,0,0,.35.37,2.64,2.64,0,0,0,.49.29l.55.26a2.13,2.13,0,0,0,.41-.26,1.88,1.88,0,0,0,.35-.34,2.2,2.2,0,0,0,.26-.39,1,1,0,0,0,.09-.41,1,1,0,0,0-.11-.47,1.15,1.15,0,0,0-.31-.35,1.19,1.19,0,0,0-.42-.21,1.59,1.59,0,0,0-.48-.07,1.51,1.51,0,0,0-.53.09,1.46,1.46,0,0,0-.41.23,1.13,1.13,0,0,0-.28.34A.92.92,0,0,0,14.58,9.2Z" transform="translate(0.54 -0.11)"/></svg> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M8.9,15.6v-2.3H5v-1.1l3.5-5.5h1.9V12h1.1v1.2h-1.1v2.3H8.9z M6.5,12h2.3v-2c0-0.3,0-0.6,0-0.9c0-0.4,0-0.7,0-0.9H8.9
C8.8,8.4,8.7,8.6,8.5,8.9C8.4,9.1,8.3,9.3,8.2,9.6L6.5,12z"/>
<path d="M15.5,15.8c-0.6,0-1.1-0.1-1.6-0.3c-0.5-0.2-0.8-0.5-1.1-0.9s-0.4-0.8-0.4-1.3c0-0.6,0.2-1,0.5-1.4
c0.3-0.4,0.7-0.7,1.1-0.9V11c-0.3-0.2-0.6-0.5-0.9-0.9c-0.2-0.3-0.4-0.7-0.4-1.2c0-0.5,0.1-0.9,0.3-1.3s0.6-0.6,1-0.8
c0.4-0.2,0.9-0.3,1.4-0.3c0.8,0,1.4,0.2,1.9,0.7c0.5,0.4,0.7,1,0.7,1.7c0,0.4-0.1,0.8-0.4,1.2c-0.3,0.4-0.5,0.6-0.8,0.9V11
c0.4,0.2,0.8,0.5,1.1,0.9c0.3,0.4,0.5,0.8,0.5,1.4c0,0.5-0.1,0.9-0.4,1.2c-0.3,0.4-0.6,0.7-1.1,0.9C16.6,15.6,16.1,15.8,15.5,15.8z
M15.5,14.6c0.4,0,0.8-0.1,1.1-0.4s0.4-0.6,0.4-1c0-0.3-0.1-0.6-0.3-0.8c-0.2-0.2-0.4-0.4-0.8-0.5s-0.7-0.3-1.1-0.5
c-0.3,0.2-0.5,0.4-0.7,0.7c-0.2,0.3-0.3,0.6-0.3,0.9c0,0.4,0.2,0.8,0.5,1.1S15,14.6,15.5,14.6z M16.1,10.6c0.2-0.2,0.4-0.5,0.6-0.7
s0.2-0.5,0.2-0.8c0-0.4-0.1-0.7-0.3-1c-0.2-0.3-0.6-0.4-1-0.4c-0.3,0-0.6,0.1-0.9,0.3c-0.2,0.2-0.4,0.5-0.4,0.9
c0,0.3,0.1,0.5,0.2,0.7c0.2,0.2,0.4,0.4,0.7,0.5C15.4,10.3,15.7,10.4,16.1,10.6z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -1 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-.54.11h24v24h-24Z" transform="translate(0.54 -0.11)" style="fill:none"/><path d="M9.34,14H6.62L6,16H4.22L7.16,6.9H8.94L11.86,16H10ZM7,12.55H9l-.92-3H8Z" transform="translate(0.54 -0.11)"/><path d="M15.39,12.2h-.93V16H12.68V6.9h1.78v3.72h.93L17.47,6.9h2l-2.57,4.39L19.82,16h-2.2Z" transform="translate(0.54 -0.11)"/></svg> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M3.8,15.6l3-9.2h1.9l3,9.2H9.9l-0.7-2.5H6.1l-0.7,2.5H3.8z M6.8,10.7l-0.3,1.1h2.3l-0.3-1.1c-0.1-0.5-0.3-1-0.4-1.5
C8,8.7,7.8,8.2,7.7,7.7H7.6c-0.1,0.5-0.2,1-0.4,1.5S7,10.2,6.8,10.7z"/>
<path d="M12.8,15.6V6.4h1.6v4.2h0l3.3-4.2h1.8L16.7,10l3.3,5.6h-1.8l-2.5-4.3l-1.3,1.6v2.7H12.8z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 747 B

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M4.2,15.6l3-9.2h1.9l3,9.2h-1.7l-0.7-2.5H6.6l-0.7,2.5H4.2z M7.3,10.7L7,11.8h2.3L9,10.7c-0.1-0.5-0.3-1-0.4-1.5
c-0.1-0.5-0.3-1-0.4-1.5H8.1C8,8.2,7.8,8.7,7.7,9.2S7.4,10.2,7.3,10.7z"/>
<path d="M15.9,15.8c-0.6,0-1.2-0.1-1.8-0.3c-0.6-0.2-1.1-0.6-1.5-1l1-1.1c0.3,0.3,0.7,0.6,1.1,0.7c0.4,0.2,0.8,0.3,1.3,0.3
c0.5,0,0.9-0.1,1.2-0.3c0.3-0.2,0.4-0.5,0.4-0.9c0-0.4-0.1-0.7-0.4-0.8c-0.3-0.2-0.6-0.3-1-0.5l-1.3-0.5c-0.3-0.1-0.6-0.3-0.9-0.5
c-0.3-0.2-0.5-0.5-0.7-0.8C13.1,9.7,13,9.3,13,8.8c0-0.5,0.1-0.9,0.4-1.3c0.3-0.4,0.6-0.7,1.1-0.9c0.5-0.2,1-0.3,1.6-0.3
c0.5,0,1,0.1,1.5,0.3c0.5,0.2,0.9,0.5,1.3,0.8l-0.8,1c-0.3-0.2-0.6-0.4-0.9-0.6c-0.3-0.1-0.7-0.2-1.1-0.2c-0.4,0-0.8,0.1-1,0.3
c-0.3,0.2-0.4,0.5-0.4,0.8c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.3,0.3,0.5,0.4c0.2,0.1,0.5,0.2,0.7,0.3l1.2,0.5c0.5,0.2,1,0.5,1.3,0.9
c0.3,0.4,0.5,0.9,0.5,1.6c0,0.5-0.1,0.9-0.4,1.4c-0.3,0.4-0.6,0.7-1.1,1C17.2,15.6,16.6,15.8,15.9,15.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M7.9,15.8c-0.8,0-1.6-0.2-2.2-0.5c-0.7-0.4-1.2-0.9-1.5-1.6C3.8,12.9,3.6,12,3.6,11c0-1,0.2-1.9,0.6-2.6
c0.4-0.7,0.9-1.3,1.6-1.6s1.4-0.6,2.2-0.6c0.7,0,1.2,0.1,1.7,0.4c0.5,0.2,0.8,0.5,1.1,0.8L9.8,8.5C9.6,8.3,9.3,8.1,9,7.9
C8.8,7.8,8.4,7.7,8,7.7C7.2,7.7,6.5,8,6,8.6C5.5,9.2,5.2,10,5.2,11c0,1,0.2,1.9,0.7,2.5s1.2,0.9,2.1,0.9c0.3,0,0.5,0,0.7-0.1
c0.2-0.1,0.4-0.2,0.6-0.3v-2H7.6v-1.3h3.2v4c-0.3,0.3-0.7,0.6-1.2,0.8C9.1,15.7,8.5,15.8,7.9,15.8z"/>
<path d="M16.3,15.8c-0.7,0-1.3-0.1-1.8-0.4s-0.9-0.7-1.2-1.3c-0.3-0.6-0.4-1.4-0.4-2.4V6.4h1.6v5.3c0,0.7,0.1,1.2,0.2,1.6
c0.2,0.4,0.4,0.7,0.7,0.8c0.3,0.2,0.6,0.2,1,0.2c0.4,0,0.7-0.1,1-0.2c0.3-0.2,0.5-0.4,0.7-0.8c0.2-0.4,0.2-0.9,0.2-1.6V6.4h1.6v5.1
c0,1-0.1,1.8-0.4,2.4c-0.3,0.6-0.7,1.1-1.2,1.3C17.6,15.6,17,15.8,16.3,15.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-.54.11h24v24h-24Z" transform="translate(0.54 -0.11)" style="fill:none"/><path d="M9.64,12.19H6.7V16H4.92V6.9H6.7v3.7H9.64V6.9h1.78V16H9.64Z" transform="translate(0.54 -0.11)"/><path d="M12.63,14.41h2.31V8.48H12.63V6.9H19V8.48H16.72v5.93H19V16h-6.4Z" transform="translate(0.54 -0.11)"/></svg> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M6.4,15.6V6.4H8v3.7h3.7V6.4h1.6v9.2h-1.6v-4.1H8v4.1H6.4z"/>
<path d="M15.7,15.6V6.4h1.6v9.2H15.7z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 385 B

After

Width:  |  Height:  |  Size: 566 B

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M3.7,15.6V6.4h1.8l1.6,4.5c0.1,0.3,0.2,0.6,0.3,0.9c0.1,0.3,0.2,0.6,0.3,0.9h0.1c0.1-0.3,0.2-0.6,0.3-0.9
c0.1-0.3,0.2-0.6,0.3-0.9L10,6.4h1.8v9.2h-1.5v-4.2c0-0.3,0-0.6,0-0.9c0-0.3,0.1-0.7,0.1-1c0-0.3,0.1-0.7,0.1-0.9h-0.1l-0.7,2.1
l-1.5,4.1h-1l-1.5-4.1L5,8.5H5C5,8.8,5,9.1,5.1,9.4c0,0.3,0.1,0.7,0.1,1c0,0.3,0,0.7,0,0.9v4.2H3.7z"/>
<path d="M14.1,15.6V6.4H17c0.7,0,1.3,0.1,1.8,0.3c0.5,0.2,1,0.5,1.3,0.9s0.5,1,0.5,1.7c0,0.7-0.2,1.2-0.5,1.7
c-0.3,0.4-0.7,0.8-1.2,1c-0.5,0.2-1.1,0.3-1.8,0.3h-1.3v3.4H14.1z M15.8,10.9h1.2c1.3,0,2-0.6,2-1.7c0-0.6-0.2-1-0.5-1.2
c-0.3-0.2-0.9-0.3-1.5-0.3h-1.1V10.9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M-.54.11h24v24h-24Z" transform="translate(0.54 -0.11)" style="fill:none"/><path d="M5.25,7a12.1,12.1,0,0,1,1.2-.16c.44,0,.87-.06,1.31-.06a7.88,7.88,0,0,1,1.36.11,3.3,3.3,0,0,1,1.22.44,2.54,2.54,0,0,1,.89.92,3.05,3.05,0,0,1,.35,1.54,3.15,3.15,0,0,1-.3,1.43,2.79,2.79,0,0,1-.79,1,3.24,3.24,0,0,1-1.13.56,4.69,4.69,0,0,1-1.3.18H7.55l-.31,0-.21,0V16H5.25ZM7.9,8.3l-.49,0a2.53,2.53,0,0,0-.38,0v3l.16,0,.22,0H7.8a3.23,3.23,0,0,0,.69-.07,1.61,1.61,0,0,0,.62-.24,1.18,1.18,0,0,0,.43-.48,1.75,1.75,0,0,0,.17-.82,1.38,1.38,0,0,0-.16-.71,1.19,1.19,0,0,0-.41-.45,1.57,1.57,0,0,0-.58-.23A2.84,2.84,0,0,0,7.9,8.3Z" transform="translate(0.54 -0.11)"/><path d="M12.71,7l.64-.1L14,6.82l.67,0h.6a6.54,6.54,0,0,1,1.25.12,3.37,3.37,0,0,1,1.11.42,2.33,2.33,0,0,1,.78.81,2.55,2.55,0,0,1,.29,1.26,3.93,3.93,0,0,1-.11,1,3,3,0,0,1-.31.72,2.23,2.23,0,0,1-.47.54,4.33,4.33,0,0,1-.61.41l2.2,4H17.39l-1.84-3.56H14.49V16H12.71Zm2.73,1.36-.54,0a1.81,1.81,0,0,0-.41.05v2.64h.7a2.06,2.06,0,0,0,1.21-.34,1.3,1.3,0,0,0,.47-1.12,1.14,1.14,0,0,0-.37-.91A1.49,1.49,0,0,0,15.44,8.35Z" transform="translate(0.54 -0.11)"/></svg> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M4.7,15.6V6.4h2.9c0.7,0,1.3,0.1,1.8,0.3c0.5,0.2,1,0.5,1.3,0.9s0.5,1,0.5,1.7c0,0.7-0.2,1.2-0.5,1.7
c-0.3,0.4-0.7,0.8-1.2,1c-0.5,0.2-1.1,0.3-1.8,0.3H6.4v3.4H4.7z M6.4,10.9h1.2c1.3,0,2-0.6,2-1.7c0-0.6-0.2-1-0.5-1.2
C8.7,7.8,8.2,7.7,7.5,7.7H6.4V10.9z"/>
<path d="M12.9,15.6V6.4H16c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.8c0.3,0.4,0.4,0.9,0.4,1.6c0,0.7-0.2,1.3-0.5,1.7
c-0.3,0.4-0.8,0.7-1.3,0.9l2.2,3.8h-1.8l-2-3.6h-1.4v3.6H12.9z M14.5,10.7h1.3c0.6,0,1.1-0.1,1.4-0.4c0.3-0.3,0.5-0.7,0.5-1.2
c0-0.5-0.2-0.9-0.5-1.1c-0.3-0.2-0.8-0.3-1.4-0.3h-1.3V10.7z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1,018 B

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 26.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;}
</style>
<path class="st0" d="M0,0h24v24H0L0,0z"/>
<g>
<path d="M9,15.6L6.1,6.4h1.7L9.1,11c0.1,0.5,0.3,1,0.4,1.5c0.1,0.5,0.3,1,0.4,1.5H10c0.2-0.5,0.3-1,0.4-1.5c0.1-0.5,0.2-1,0.4-1.5
l1.3-4.6h1.7l-2.8,9.2H9z"/>
<path d="M14.8,15.6V6.4h1.6v9.2H14.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 654 B

View file

@ -262,6 +262,30 @@ This section will outline styles that are component specific
background-image: url("../images/mapbtn-PR.svg"); background-image: url("../images/mapbtn-PR.svg");
} }
} }
button.mapboxgl-ctrl-zoom-to-gu {
.mapboxgl-ctrl-icon {
background-image: url("../images/mapbtn-GU.svg");
}
}
button.mapboxgl-ctrl-zoom-to-as {
.mapboxgl-ctrl-icon {
background-image: url("../images/mapbtn-AS.svg");
}
}
button.mapboxgl-ctrl-zoom-to-mp {
.mapboxgl-ctrl-icon {
background-image: url("../images/mapbtn-MP.svg");
}
}
button.mapboxgl-ctrl-zoom-to-vi {
.mapboxgl-ctrl-icon {
background-image: url("../images/mapbtn-VI.svg");
}
}
} }
//Area Detail Component //Area Detail Component

View file

@ -49,6 +49,11 @@ DATASET_LIST = [
"module_dir": "geocorr", "module_dir": "geocorr",
"class_name": "GeoCorrETL", "class_name": "GeoCorrETL",
}, },
{
"name": "child_opportunity_index",
"module_dir": "child_opportunity_index",
"class_name": "ChildOpportunityIndex",
},
{ {
"name": "mapping_inequality", "name": "mapping_inequality",
"module_dir": "mapping_inequality", "module_dir": "mapping_inequality",

View file

@ -4,6 +4,8 @@ import datetime
import pandas as pd import pandas as pd
from data_pipeline.config import settings from data_pipeline.config import settings
from data_pipeline.score import field_names
# Base Paths # Base Paths
DATA_PATH = Path(settings.APP_ROOT) / "data" DATA_PATH = Path(settings.APP_ROOT) / "data"
TMP_PATH = DATA_PATH / "tmp" TMP_PATH = DATA_PATH / "tmp"
@ -59,88 +61,92 @@ SCORE_DOWNLOADABLE_ZIP_FILE_PATH = (
# Column subsets # Column subsets
CENSUS_COUNTIES_COLUMNS = ["USPS", "GEOID", "NAME"] CENSUS_COUNTIES_COLUMNS = ["USPS", "GEOID", "NAME"]
TILES_SCORE_COLUMNS = [ TILES_SCORE_COLUMNS = [
"GEOID10_TRACT", field_names.GEOID_TRACT_FIELD,
"State Name", field_names.STATE_FIELD,
"County Name", field_names.COUNTY_FIELD,
"Total population", field_names.TOTAL_POP_FIELD,
"Score D (percentile)", field_names.SCORE_D + field_names.PERCENTILE_FIELD_SUFFIX,
"Score D (top 25th percentile)", field_names.SCORE_D + field_names.TOP_25_PERCENTILE_SUFFIX,
"Score E (percentile)", field_names.SCORE_E + field_names.PERCENTILE_FIELD_SUFFIX,
"Score E (top 25th percentile)", field_names.SCORE_E + field_names.TOP_25_PERCENTILE_SUFFIX,
"Score G (communities)", field_names.SCORE_G_COMMUNITIES,
"Score G", field_names.SCORE_G,
"Definition L (communities)", field_names.SCORE_L_COMMUNITIES,
"Definition L (percentile)", field_names.SCORE_L + field_names.PERCENTILE_FIELD_SUFFIX,
"Poverty (Less than 200% of federal poverty line) (percentile)", field_names.POVERTY_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Percent individuals age 25 or over with less than high school degree (percentile)", field_names.HIGH_SCHOOL_ED_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Linguistic isolation (percent) (percentile)", field_names.LINGUISTIC_ISO_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Unemployed civilians (percent) (percentile)", field_names.UNEMPLOYMENT_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Housing burden (percent) (percentile)", field_names.HOUSING_BURDEN_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Diagnosed diabetes among adults aged >=18 years (percentile)", field_names.DIABETES_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Current asthma among adults aged >=18 years (percentile)", field_names.ASTHMA_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Coronary heart disease among adults aged >=18 years (percentile)", field_names.HEART_DISEASE_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Life expectancy (years) (percentile)", field_names.LIFE_EXPECTANCY_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Traffic proximity and volume (percentile)", field_names.TRAFFIC_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"FEMA Risk Index Expected Annual Loss Score (percentile)", field_names.FEMA_RISK_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Energy burden (percentile)", field_names.ENERGY_BURDEN_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Wastewater discharge (percentile)", field_names.WASTEWATER_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Percent pre-1960s housing (lead paint indicator) (percentile)", field_names.LEAD_PAINT_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Diesel particulate matter (percentile)", field_names.DIESEL_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Particulate matter (PM2.5) (percentile)", field_names.PM25_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Median household income (% of AMI) (percentile)", field_names.MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD
"Percent of individuals < 200% Federal Poverty Line (percentile)", + field_names.PERCENTILE_FIELD_SUFFIX,
field_names.POVERTY_LESS_THAN_200_FPL_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX,
] ]
# columns to round floats to 2 decimals # columns to round floats to 2 decimals
TILES_SCORE_FLOAT_COLUMNS = [ TILES_SCORE_FLOAT_COLUMNS = [
"Score D (percentile)", field_names.SCORE_D + field_names.PERCENTILE_FIELD_SUFFIX,
"Score D (top 25th percentile)", field_names.SCORE_D + field_names.TOP_25_PERCENTILE_SUFFIX,
"Score E (percentile)", field_names.SCORE_E + field_names.PERCENTILE_FIELD_SUFFIX,
"Score E (top 25th percentile)", field_names.SCORE_E + field_names.TOP_25_PERCENTILE_SUFFIX,
"Definition L (percentile)", field_names.SCORE_L + field_names.PERCENTILE_FIELD_SUFFIX,
"Poverty (Less than 200% of federal poverty line)", field_names.POVERTY_FIELD,
"Percent individuals age 25 or over with less than high school degree", field_names.HIGH_SCHOOL_ED_FIELD,
"Linguistic isolation (percent)", field_names.LINGUISTIC_ISO_FIELD,
"Unemployed civilians (percent)", field_names.UNEMPLOYMENT_FIELD,
"Housing burden (percent)", field_names.HOUSING_BURDEN_FIELD,
"Poverty (Less than 200% of federal poverty line) (percentile)", field_names.POVERTY_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Percent individuals age 25 or over with less than high school degree (percentile)", field_names.HIGH_SCHOOL_ED_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Linguistic isolation (percent) (percentile)", field_names.LINGUISTIC_ISO_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Unemployed civilians (percent) (percentile)", field_names.UNEMPLOYMENT_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Housing burden (percent) (percentile)", field_names.HOUSING_BURDEN_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Diagnosed diabetes among adults aged >=18 years (percentile)", field_names.DIABETES_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Current asthma among adults aged >=18 years (percentile)", field_names.ASTHMA_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Coronary heart disease among adults aged >=18 years (percentile)", field_names.HEART_DISEASE_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Life expectancy (years) (percentile)", field_names.LIFE_EXPECTANCY_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Traffic proximity and volume (percentile)", field_names.TRAFFIC_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"FEMA Risk Index Expected Annual Loss Score (percentile)", field_names.FEMA_RISK_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Energy burden (percentile)", field_names.ENERGY_BURDEN_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Wastewater discharge (percentile)", field_names.WASTEWATER_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Percent pre-1960s housing (lead paint indicator) (percentile)", field_names.LEAD_PAINT_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Diesel particulate matter (percentile)", field_names.DIESEL_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Particulate matter (PM2.5) (percentile)", field_names.PM25_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
"Median household income (% of AMI) (percentile)", field_names.MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD
"Percent of individuals < 200% Federal Poverty Line (percentile)", + field_names.PERCENTILE_FIELD_SUFFIX,
field_names.POVERTY_LESS_THAN_200_FPL_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX,
] ]
TILES_ROUND_NUM_DECIMALS = 2 TILES_ROUND_NUM_DECIMALS = 2
DOWNLOADABLE_SCORE_INDICATOR_COLUMNS_BASIC = [ DOWNLOADABLE_SCORE_INDICATOR_COLUMNS_BASIC = [
"Area Median Income (State or metropolitan)", field_names.AMI_FIELD,
"Percent of individuals < 100% Federal Poverty Line", field_names.POVERTY_LESS_THAN_100_FPL_FIELD,
"Percent individuals age 25 or over with less than high school degree", field_names.HIGH_SCHOOL_ED_FIELD,
"Diagnosed diabetes among adults aged >=18 years", field_names.DIABETES_FIELD,
"Current asthma among adults aged >=18 years", field_names.ASTHMA_FIELD,
"Coronary heart disease among adults aged >=18 years", field_names.HEART_DISEASE_FIELD,
"Life expectancy (years)", field_names.LIFE_EXPECTANCY_FIELD,
"Traffic proximity and volume", field_names.TRAFFIC_FIELD,
"FEMA Risk Index Expected Annual Loss Score", field_names.FEMA_RISK_FIELD,
"Energy burden", field_names.ENERGY_BURDEN_FIELD,
"Housing burden (percent)", field_names.HOUSING_BURDEN_FIELD,
"Wastewater discharge", field_names.WASTEWATER_FIELD,
"Percent pre-1960s housing (lead paint indicator)", field_names.LEAD_PAINT_FIELD,
"Diesel particulate matter", field_names.DIESEL_FIELD,
"Particulate matter (PM2.5)", field_names.PM25_FIELD,
"Total population", field_names.TOTAL_POP_FIELD,
] ]
# For every indicator above, we want to include percentile and min-max normalized variants also # For every indicator above, we want to include percentile and min-max normalized variants also
@ -155,11 +161,12 @@ DOWNLOADABLE_SCORE_INDICATOR_COLUMNS_FULL = list(
# Finally we augment with the GEOID10, county, and state # Finally we augment with the GEOID10, county, and state
DOWNLOADABLE_SCORE_COLUMNS = [ DOWNLOADABLE_SCORE_COLUMNS = [
"GEOID10_TRACT", field_names.GEOID_TRACT_FIELD,
"County Name", field_names.COUNTY_FIELD,
"State Name", field_names.STATE_FIELD,
"Score G (communities)", field_names.SCORE_G_COMMUNITIES,
"Median household income (% of AMI)", field_names.MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD,
"Median household income (% of state median household income) (percentile)", field_names.MEDIAN_INCOME_AS_PERCENT_OF_STATE_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX,
*DOWNLOADABLE_SCORE_INDICATOR_COLUMNS_FULL, *DOWNLOADABLE_SCORE_INDICATOR_COLUMNS_FULL,
] ]

View file

@ -1,4 +1,6 @@
import functools import functools
from collections import namedtuple
import pandas as pd import pandas as pd
from data_pipeline.etl.base import ExtractTransformLoad from data_pipeline.etl.base import ExtractTransformLoad
@ -29,6 +31,7 @@ class ScoreETL(ExtractTransformLoad):
self.persistent_poverty_df: pd.DataFrame self.persistent_poverty_df: pd.DataFrame
self.census_decennial_df: pd.DataFrame self.census_decennial_df: pd.DataFrame
self.census_2010_df: pd.DataFrame self.census_2010_df: pd.DataFrame
self.child_opportunity_index_df: pd.DataFrame
def extract(self) -> None: def extract(self) -> None:
logger.info("Loading data sets from disk.") logger.info("Loading data sets from disk.")
@ -162,6 +165,19 @@ class ScoreETL(ExtractTransformLoad):
low_memory=False, low_memory=False,
) )
# Load COI data
child_opportunity_index_csv = (
constants.DATA_PATH
/ "dataset"
/ "child_opportunity_index"
/ "usa.csv"
)
self.child_opportunity_index_df = pd.read_csv(
child_opportunity_index_csv,
dtype={self.GEOID_TRACT_FIELD_NAME: "string"},
low_memory=False,
)
def _join_tract_dfs(self, census_tract_dfs: list) -> pd.DataFrame: def _join_tract_dfs(self, census_tract_dfs: list) -> pd.DataFrame:
logger.info("Joining Census Tract dataframes") logger.info("Joining Census Tract dataframes")
@ -255,6 +271,7 @@ class ScoreETL(ExtractTransformLoad):
self.census_acs_median_incomes_df, self.census_acs_median_incomes_df,
self.census_decennial_df, self.census_decennial_df,
self.census_2010_df, self.census_2010_df,
self.child_opportunity_index_df,
] ]
# Sanity check each data frame before merging. # Sanity check each data frame before merging.
@ -305,7 +322,7 @@ class ScoreETL(ExtractTransformLoad):
field_names.FEMA_RISK_FIELD, field_names.FEMA_RISK_FIELD,
field_names.URBAN_HEURISTIC_FIELD, field_names.URBAN_HEURISTIC_FIELD,
field_names.AIR_TOXICS_CANCER_RISK_FIELD, field_names.AIR_TOXICS_CANCER_RISK_FIELD,
field_names.RESPITORY_HAZARD_FIELD, field_names.RESPIRATORY_HAZARD_FIELD,
field_names.DIESEL_FIELD, field_names.DIESEL_FIELD,
field_names.PM25_FIELD, field_names.PM25_FIELD,
field_names.OZONE_FIELD, field_names.OZONE_FIELD,
@ -323,6 +340,7 @@ class ScoreETL(ExtractTransformLoad):
field_names.HIGH_SCHOOL_ED_FIELD, field_names.HIGH_SCHOOL_ED_FIELD,
field_names.UNEMPLOYMENT_FIELD, field_names.UNEMPLOYMENT_FIELD,
field_names.MEDIAN_HOUSE_VALUE_FIELD, field_names.MEDIAN_HOUSE_VALUE_FIELD,
field_names.COLLEGE_ATTENDANCE_FIELD,
field_names.EXPECTED_BUILDING_LOSS_RATE_FIELD, field_names.EXPECTED_BUILDING_LOSS_RATE_FIELD,
field_names.EXPECTED_AGRICULTURE_LOSS_RATE_FIELD, field_names.EXPECTED_AGRICULTURE_LOSS_RATE_FIELD,
field_names.EXPECTED_POPULATION_LOSS_RATE_FIELD, field_names.EXPECTED_POPULATION_LOSS_RATE_FIELD,
@ -333,6 +351,9 @@ class ScoreETL(ExtractTransformLoad):
field_names.CENSUS_POVERTY_LESS_THAN_100_FPL_FIELD_2010, field_names.CENSUS_POVERTY_LESS_THAN_100_FPL_FIELD_2010,
field_names.CENSUS_DECENNIAL_TOTAL_POPULATION_FIELD_2009, field_names.CENSUS_DECENNIAL_TOTAL_POPULATION_FIELD_2009,
field_names.CENSUS_DECENNIAL_AREA_MEDIAN_INCOME_PERCENT_FIELD_2009, field_names.CENSUS_DECENNIAL_AREA_MEDIAN_INCOME_PERCENT_FIELD_2009,
field_names.EXTREME_HEAT_FIELD,
field_names.HEALTHY_FOOD_FIELD,
field_names.IMPENETRABLE_SURFACES_FIELD,
] ]
non_numeric_columns = [ non_numeric_columns = [
@ -340,7 +361,32 @@ class ScoreETL(ExtractTransformLoad):
field_names.PERSISTENT_POVERTY_FIELD, field_names.PERSISTENT_POVERTY_FIELD,
] ]
columns_to_keep = non_numeric_columns + numeric_columns # For some columns, high values are "good", so we want to reverse the percentile
# so that high values are "bad" and any scoring logic can still check if it's
# >= some threshold.
# TODO: Add more fields here.
# https://github.com/usds/justice40-tool/issues/970
ReversePercentile = namedtuple(
typename="ReversePercentile",
field_names=["field_name", "low_field_name"],
)
reverse_percentiles = [
# This dictionary follows the format:
# <field name> : <field name for low values>
# for instance, 3rd grade reading level : Low 3rd grade reading level.
# This low field will not exist yet, it is only calculated for the
# percentile.
ReversePercentile(
field_name=field_names.READING_FIELD,
low_field_name=field_names.LOW_READING_FIELD,
)
]
columns_to_keep = (
non_numeric_columns
+ numeric_columns
+ [rp.field_name for rp in reverse_percentiles]
)
df_copy = df[columns_to_keep].copy() df_copy = df[columns_to_keep].copy()
@ -375,6 +421,19 @@ class ScoreETL(ExtractTransformLoad):
df_copy[col] - min_value df_copy[col] - min_value
) / (max_value - min_value) ) / (max_value - min_value)
# Create reversed percentiles for these fields
for reverse_percentile in reverse_percentiles:
# Calculate reverse percentiles
# For instance, for 3rd grade reading level (score from 0-500),
# calculate reversed percentiles and give the result the name
# `Low 3rd grade reading level (percentile)`.
df_copy[
f"{reverse_percentile.low_field_name}"
f"{field_names.PERCENTILE_FIELD_SUFFIX}"
] = df_copy[reverse_percentile.field_name].rank(
pct=True, ascending=False
)
# Special logic: create a combined population field. # Special logic: create a combined population field.
# We sometimes run analytics on "population", and this makes a single field # We sometimes run analytics on "population", and this makes a single field
# that is either the island area's population in 2009 or the state's # that is either the island area's population in 2009 or the state's

View file

@ -276,12 +276,15 @@ class PostScoreETL(ExtractTransformLoad):
inplace=False, inplace=False,
) )
logger.info("Writing downloadable csv")
downloadable_df_copy.to_csv(csv_path, index=False)
logger.info("Writing downloadable excel") logger.info("Writing downloadable excel")
downloadable_df_copy.to_excel(excel_path, index=False) downloadable_df_copy.to_excel(excel_path, index=False)
logger.info("Writing downloadable csv")
downloadable_df_copy[self.GEOID_TRACT_FIELD_NAME] = (
'"' + downloadable_df_copy[self.GEOID_TRACT_FIELD_NAME] + '"'
)
downloadable_df_copy.to_csv(csv_path, index=False)
logger.info("Compressing files") logger.info("Compressing files")
files_to_compress = [csv_path, excel_path, pdf_path] files_to_compress = [csv_path, excel_path, pdf_path]
zip_files(zip_path, files_to_compress) zip_files(zip_path, files_to_compress)

View file

@ -114,6 +114,27 @@ class CensusACSETL(ExtractTransformLoad):
) )
self.HIGH_SCHOOL_ED_FIELD = "Percent individuals age 25 or over with less than high school degree" self.HIGH_SCHOOL_ED_FIELD = "Percent individuals age 25 or over with less than high school degree"
# College attendance fields
self.COLLEGE_ATTENDANCE_TOTAL_POPULATION_ASKED = (
"B14004_001E" # Estimate!!Total
)
self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PUBLIC = "B14004_003E" # Estimate!!Total!!Male!!Enrolled in public college or graduate school
self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PRIVATE = "B14004_008E" # Estimate!!Total!!Male!!Enrolled in private college or graduate school
self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PUBLIC = "B14004_019E" # Estimate!!Total!!Female!!Enrolled in public college or graduate school
self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PRIVATE = "B14004_024E" # Estimate!!Total!!Female!!Enrolled in private college or graduate school
self.COLLEGE_ATTENDANCE_FIELDS = [
self.COLLEGE_ATTENDANCE_TOTAL_POPULATION_ASKED,
self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PUBLIC,
self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PRIVATE,
self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PUBLIC,
self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PRIVATE,
]
self.COLLEGE_ATTENDANCE_FIELD = (
"Percent enrollment in college or graduate school"
)
self.RE_FIELDS = [ self.RE_FIELDS = [
"B02001_001E", "B02001_001E",
"B02001_002E", "B02001_002E",
@ -156,15 +177,30 @@ class CensusACSETL(ExtractTransformLoad):
self.STATE_GEOID_FIELD_NAME = "GEOID2" self.STATE_GEOID_FIELD_NAME = "GEOID2"
self.COLUMNS_TO_KEEP = (
[
self.GEOID_TRACT_FIELD_NAME,
self.UNEMPLOYED_FIELD_NAME,
self.LINGUISTIC_ISOLATION_FIELD_NAME,
self.MEDIAN_INCOME_FIELD_NAME,
self.POVERTY_LESS_THAN_100_PERCENT_FPL_FIELD_NAME,
self.POVERTY_LESS_THAN_150_PERCENT_FPL_FIELD_NAME,
self.POVERTY_LESS_THAN_200_PERCENT_FPL_FIELD_NAME,
self.MEDIAN_HOUSE_VALUE_FIELD_NAME,
self.HIGH_SCHOOL_ED_FIELD,
self.COLLEGE_ATTENDANCE_FIELD,
]
+ self.RE_OUTPUT_FIELDS
+ [self.PERCENT_PREFIX + field for field in self.RE_OUTPUT_FIELDS]
)
self.df: pd.DataFrame self.df: pd.DataFrame
def extract(self) -> None: def extract(self) -> None:
# Define the variables to retrieve # Define the variables to retrieve
variables = ( variables = (
[ [
# Income field
self.MEDIAN_INCOME_FIELD, self.MEDIAN_INCOME_FIELD,
# House value
self.MEDIAN_HOUSE_VALUE_FIELD, self.MEDIAN_HOUSE_VALUE_FIELD,
] ]
+ self.EMPLOYMENT_FIELDS + self.EMPLOYMENT_FIELDS
@ -172,6 +208,7 @@ class CensusACSETL(ExtractTransformLoad):
+ self.POVERTY_FIELDS + self.POVERTY_FIELDS
+ self.EDUCATIONAL_FIELDS + self.EDUCATIONAL_FIELDS
+ self.RE_FIELDS + self.RE_FIELDS
+ self.COLLEGE_ATTENDANCE_FIELDS
) )
self.df = retrieve_census_acs_data( self.df = retrieve_census_acs_data(
@ -308,6 +345,14 @@ class CensusACSETL(ExtractTransformLoad):
df["B03003_003E"] / df["B03003_001E"] df["B03003_003E"] / df["B03003_001E"]
) )
# Calculate college attendance:
df[self.COLLEGE_ATTENDANCE_FIELD] = (
df[self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PUBLIC]
+ df[self.COLLEGE_ATTENDANCE_MALE_ENROLLED_PRIVATE]
+ df[self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PUBLIC]
+ df[self.COLLEGE_ATTENDANCE_FEMALE_ENROLLED_PRIVATE]
) / df[self.COLLEGE_ATTENDANCE_TOTAL_POPULATION_ASKED]
# Save results to self. # Save results to self.
self.df = df self.df = df
@ -317,23 +362,7 @@ class CensusACSETL(ExtractTransformLoad):
# mkdir census # mkdir census
self.OUTPUT_PATH.mkdir(parents=True, exist_ok=True) self.OUTPUT_PATH.mkdir(parents=True, exist_ok=True)
columns_to_include = ( self.df[self.COLUMNS_TO_KEEP].to_csv(
[
self.GEOID_TRACT_FIELD_NAME,
self.UNEMPLOYED_FIELD_NAME,
self.LINGUISTIC_ISOLATION_FIELD_NAME,
self.MEDIAN_INCOME_FIELD_NAME,
self.POVERTY_LESS_THAN_100_PERCENT_FPL_FIELD_NAME,
self.POVERTY_LESS_THAN_150_PERCENT_FPL_FIELD_NAME,
self.POVERTY_LESS_THAN_200_PERCENT_FPL_FIELD_NAME,
self.MEDIAN_HOUSE_VALUE_FIELD_NAME,
self.HIGH_SCHOOL_ED_FIELD,
]
+ self.RE_OUTPUT_FIELDS
+ [self.PERCENT_PREFIX + field for field in self.RE_OUTPUT_FIELDS]
)
self.df[columns_to_include].to_csv(
path_or_buf=self.OUTPUT_PATH / "usa.csv", index=False path_or_buf=self.OUTPUT_PATH / "usa.csv", index=False
) )

View file

@ -0,0 +1,120 @@
from pathlib import Path
import pandas as pd
from data_pipeline.etl.base import ExtractTransformLoad
from data_pipeline.score import field_names
from data_pipeline.utils import get_module_logger, unzip_file_from_url
logger = get_module_logger(__name__)
class ChildOpportunityIndex(ExtractTransformLoad):
"""ETL Child Opportunity Index data.
COI compiles a number of useful data sets. In the future, we could pull these
data sets in directly from their original creators.
Data dictionary available when you download zip from `self.COI_FILE_URL`.
Data source overview: https://data.diversitydatakids.org/dataset/coi20-child-opportunity-index-2-0-database.
Full technical documents: https://www.diversitydatakids.org/sites/default/files/2020-02/ddk_coi2.0_technical_documentation_20200212.pdf.
Github repo: https://github.com/diversitydatakids/COI/
"""
def __init__(self):
self.COI_FILE_URL = (
"https://data.diversitydatakids.org/datastore/zip/f16fff12-b1e5-4f60-85d3-"
"3a0ededa30a0?format=csv"
)
self.OUTPUT_PATH: Path = (
self.DATA_PATH / "dataset" / "child_opportunity_index"
)
self.TRACT_INPUT_COLUMN_NAME = "geoid"
self.EXTREME_HEAT_INPUT_FIELD = "HE_HEAT"
self.HEALTHY_FOOD_INPUT_FIELD = "HE_FOOD"
self.IMPENETRABLE_SURFACES_INPUT_FIELD = "HE_GREEN"
self.READING_INPUT_FIELD = "ED_READING"
# Constants for output
self.COLUMNS_TO_KEEP = [
self.GEOID_TRACT_FIELD_NAME,
field_names.EXTREME_HEAT_FIELD,
field_names.HEALTHY_FOOD_FIELD,
field_names.IMPENETRABLE_SURFACES_FIELD,
field_names.READING_FIELD,
]
self.raw_df: pd.DataFrame
self.output_df: pd.DataFrame
def extract(self) -> None:
logger.info("Starting 51MB data download.")
unzip_file_from_url(
file_url=self.COI_FILE_URL,
download_path=self.TMP_PATH,
unzipped_file_path=self.TMP_PATH / "child_opportunity_index",
)
self.raw_df = pd.read_csv(
filepath_or_buffer=self.TMP_PATH
/ "child_opportunity_index"
/ "raw.csv",
# The following need to remain as strings for all of their digits, not get
# converted to numbers.
dtype={
self.TRACT_INPUT_COLUMN_NAME: "string",
},
low_memory=False,
)
def transform(self) -> None:
logger.info("Starting transforms.")
output_df = self.raw_df.rename(
columns={
self.TRACT_INPUT_COLUMN_NAME: self.GEOID_TRACT_FIELD_NAME,
self.EXTREME_HEAT_INPUT_FIELD: field_names.EXTREME_HEAT_FIELD,
self.HEALTHY_FOOD_INPUT_FIELD: field_names.HEALTHY_FOOD_FIELD,
self.IMPENETRABLE_SURFACES_INPUT_FIELD: field_names.IMPENETRABLE_SURFACES_FIELD,
self.READING_INPUT_FIELD: field_names.READING_FIELD,
}
)
# Sanity check the tract field.
if len(output_df[self.GEOID_TRACT_FIELD_NAME].str.len().unique()) != 1:
raise ValueError("Wrong tract length.")
# COI has two rows per tract: one for 2010 and one for 2015.
output_df = output_df[output_df["year"] == 2015]
# Convert percents from 0-100 to 0-1 to standardize with our other fields.
percent_fields_to_convert = [
field_names.HEALTHY_FOOD_FIELD,
field_names.IMPENETRABLE_SURFACES_FIELD,
]
for percent_field_to_convert in percent_fields_to_convert:
output_df[percent_field_to_convert] = (
output_df[percent_field_to_convert] / 100
)
self.output_df = output_df
def validate(self) -> None:
logger.info("Validating data.")
pass
def load(self) -> None:
logger.info("Saving CSV")
self.OUTPUT_PATH.mkdir(parents=True, exist_ok=True)
self.output_df[self.COLUMNS_TO_KEEP].to_csv(
path_or_buf=self.OUTPUT_PATH / "usa.csv", index=False
)

View file

@ -8,6 +8,12 @@ logger = get_module_logger(__name__)
class EJSCREENETL(ExtractTransformLoad): class EJSCREENETL(ExtractTransformLoad):
"""Load EJSCREEN data.
Data dictionary:
https://gaftp.epa.gov/EJSCREEN/2019/2019_EJSCREEN_columns_explained.csv
"""
def __init__(self): def __init__(self):
self.EJSCREEN_FTP_URL = "https://edap-arcgiscloud-data-commons.s3.amazonaws.com/EJSCREEN2020/EJSCREEN_Tract_2020_USPR.csv.zip" self.EJSCREEN_FTP_URL = "https://edap-arcgiscloud-data-commons.s3.amazonaws.com/EJSCREEN2020/EJSCREEN_Tract_2020_USPR.csv.zip"
self.EJSCREEN_CSV = self.TMP_PATH / "EJSCREEN_Tract_2020_USPR.csv" self.EJSCREEN_CSV = self.TMP_PATH / "EJSCREEN_Tract_2020_USPR.csv"
@ -19,7 +25,7 @@ class EJSCREENETL(ExtractTransformLoad):
field_names.TOTAL_POP_FIELD, field_names.TOTAL_POP_FIELD,
# pylint: disable=duplicate-code # pylint: disable=duplicate-code
field_names.AIR_TOXICS_CANCER_RISK_FIELD, field_names.AIR_TOXICS_CANCER_RISK_FIELD,
field_names.RESPITORY_HAZARD_FIELD, field_names.RESPIRATORY_HAZARD_FIELD,
field_names.DIESEL_FIELD, field_names.DIESEL_FIELD,
field_names.PM25_FIELD, field_names.PM25_FIELD,
field_names.OZONE_FIELD, field_names.OZONE_FIELD,
@ -61,7 +67,7 @@ class EJSCREENETL(ExtractTransformLoad):
# but I think that's the direction we'd like to move all ETL classes. - LMB # but I think that's the direction we'd like to move all ETL classes. - LMB
"ACSTOTPOP": field_names.TOTAL_POP_FIELD, "ACSTOTPOP": field_names.TOTAL_POP_FIELD,
"CANCER": field_names.AIR_TOXICS_CANCER_RISK_FIELD, "CANCER": field_names.AIR_TOXICS_CANCER_RISK_FIELD,
"RESP": field_names.RESPITORY_HAZARD_FIELD, "RESP": field_names.RESPIRATORY_HAZARD_FIELD,
"DSLPM": field_names.DIESEL_FIELD, "DSLPM": field_names.DIESEL_FIELD,
"PM25": field_names.PM25_FIELD, "PM25": field_names.PM25_FIELD,
"OZONE": field_names.OZONE_FIELD, "OZONE": field_names.OZONE_FIELD,

View file

@ -479,7 +479,7 @@
"comparison_fields = [\n", "comparison_fields = [\n",
" field_names.POVERTY_LESS_THAN_100_FPL_FIELD,\n", " field_names.POVERTY_LESS_THAN_100_FPL_FIELD,\n",
" field_names.POVERTY_LESS_THAN_200_FPL_FIELD,\n", " field_names.POVERTY_LESS_THAN_200_FPL_FIELD,\n",
" field_names.MEDIAN_INCOME_PERCENT_AMI_FIELD,\n", " field_names.MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD,\n",
" field_names.LINGUISTIC_ISO_FIELD,\n", " field_names.LINGUISTIC_ISO_FIELD,\n",
" field_names.UNEMPLOYMENT_FIELD,\n", " field_names.UNEMPLOYMENT_FIELD,\n",
" field_names.HIGH_SCHOOL_ED_FIELD,\n", " field_names.HIGH_SCHOOL_ED_FIELD,\n",

View file

@ -1,6 +1,12 @@
# Suffixes # Suffixes
PERCENTILE_FIELD_SUFFIX = " (percentile)" PERCENTILE_FIELD_SUFFIX = " (percentile)"
MIN_MAX_FIELD_SUFFIX = " (min-max normalized)" MIN_MAX_FIELD_SUFFIX = " (min-max normalized)"
TOP_25_PERCENTILE_SUFFIX = " (top 25th percentile)"
# Geographic field names
GEOID_TRACT_FIELD = "GEOID10_TRACT"
STATE_FIELD = "State Name"
COUNTY_FIELD = "County Name"
# Score file field names # Score file field names
SCORE_A = "Score A" SCORE_A = "Score A"
@ -21,6 +27,7 @@ SCORE_I = "Score I"
SCORE_I_COMMUNITIES = "Score I (communities)" SCORE_I_COMMUNITIES = "Score I (communities)"
SCORE_K = "NMTC (communities)" SCORE_K = "NMTC (communities)"
SCORE_K_COMMUNITIES = "Score K (communities)" SCORE_K_COMMUNITIES = "Score K (communities)"
SCORE_L = "Definition L"
SCORE_L_COMMUNITIES = "Definition L (communities)" SCORE_L_COMMUNITIES = "Definition L (communities)"
L_CLIMATE = "Climate Factor (Definition L)" L_CLIMATE = "Climate Factor (Definition L)"
L_ENERGY = "Energy Factor (Definition L)" L_ENERGY = "Energy Factor (Definition L)"
@ -45,7 +52,6 @@ POVERTY_LESS_THAN_150_FPL_FIELD = (
POVERTY_LESS_THAN_100_FPL_FIELD = ( POVERTY_LESS_THAN_100_FPL_FIELD = (
"Percent of individuals < 100% Federal Poverty Line" "Percent of individuals < 100% Federal Poverty Line"
) )
MEDIAN_INCOME_PERCENT_AMI_FIELD = "Median household income (% of AMI)"
STATE_MEDIAN_INCOME_FIELD = ( STATE_MEDIAN_INCOME_FIELD = (
"Median household income (State; 2019 inflation-adjusted dollars)" "Median household income (State; 2019 inflation-adjusted dollars)"
) )
@ -57,6 +63,8 @@ MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD = "Median household income (% of AMI)"
PERSISTENT_POVERTY_FIELD = "Persistent Poverty Census Tract" PERSISTENT_POVERTY_FIELD = "Persistent Poverty Census Tract"
AMI_FIELD = "Area Median Income (State or metropolitan)" AMI_FIELD = "Area Median Income (State or metropolitan)"
COLLEGE_ATTENDANCE_FIELD = "Percent enrollment in college or graduate school"
# Climate # Climate
FEMA_RISK_FIELD = "FEMA Risk Index Expected Annual Loss Score" FEMA_RISK_FIELD = "FEMA Risk Index Expected Annual Loss Score"
EXPECTED_BUILDING_LOSS_RATE_FIELD = ( EXPECTED_BUILDING_LOSS_RATE_FIELD = (
@ -81,6 +89,7 @@ RMP_FIELD = "Proximity to Risk Management Plan (RMP) facilities"
TSDF_FIELD = "Proximity to TSDF sites" TSDF_FIELD = "Proximity to TSDF sites"
NPL_FIELD = "Proximity to NPL sites" NPL_FIELD = "Proximity to NPL sites"
AIR_TOXICS_CANCER_RISK_FIELD = "Air toxics cancer risk" AIR_TOXICS_CANCER_RISK_FIELD = "Air toxics cancer risk"
RESPIRATORY_HAZARD_FIELD = "Respiratory hazard index"
# Housing # Housing
HOUSING_BURDEN_FIELD = "Housing burden (percent)" HOUSING_BURDEN_FIELD = "Housing burden (percent)"
@ -96,7 +105,6 @@ DIABETES_FIELD = "Diagnosed diabetes among adults aged >=18 years"
ASTHMA_FIELD = "Current asthma among adults aged >=18 years" ASTHMA_FIELD = "Current asthma among adults aged >=18 years"
HEART_DISEASE_FIELD = "Coronary heart disease among adults aged >=18 years" HEART_DISEASE_FIELD = "Coronary heart disease among adults aged >=18 years"
LIFE_EXPECTANCY_FIELD = "Life expectancy (years)" LIFE_EXPECTANCY_FIELD = "Life expectancy (years)"
RESPITORY_HAZARD_FIELD = "Respiratory hazard index"
CANCER_FIELD = "Cancer (excluding skin cancer) among adults aged >=18 years" CANCER_FIELD = "Cancer (excluding skin cancer) among adults aged >=18 years"
HEALTH_INSURANCE_FIELD = ( HEALTH_INSURANCE_FIELD = (
"Current lack of health insurance among adults aged 18-64 years" "Current lack of health insurance among adults aged 18-64 years"
@ -200,30 +208,65 @@ HOLC_GRADE_D_TRACT_50_PERCENT_FIELD: str = "Tract is >50% HOLC Grade D"
HOLC_GRADE_D_TRACT_75_PERCENT_FIELD: str = "Tract is >75% HOLC Grade D" HOLC_GRADE_D_TRACT_75_PERCENT_FIELD: str = "Tract is >75% HOLC Grade D"
# Child Opportunity Index data
# Summer days with maximum temperature above 90F.
EXTREME_HEAT_FIELD = "Summer days above 90F"
# Percentage households without a car located further than a half-mile from the
# nearest supermarket.
HEALTHY_FOOD_FIELD = "Percent low access to healthy food"
# Percentage impenetrable surface areas such as rooftops, roads or parking lots.
IMPENETRABLE_SURFACES_FIELD = "Percent impenetrable surface areas"
# Percentage third graders scoring proficient on standardized reading tests,
# converted to NAEP scale score points.
READING_FIELD = "Third grade reading proficiency"
LOW_READING_FIELD = "Low third grade reading proficiency"
# Names for individual factors being exceeded
# Climate Change # Climate Change
EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected population loss rate and is low income" EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected population loss rate and is low income"
EXPECTED_AGRICULTURE_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected agriculture loss rate and is low income" EXPECTED_AGRICULTURE_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected agriculture loss rate and is low income"
EXPECTED_BUILDING_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected building loss rate and is low income" EXPECTED_BUILDING_LOSS_RATE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for expected building loss rate and is low income"
EXTREME_HEAT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD = (
f"At or above the {PERCENTILE}th percentile for summer days above 90F and "
f"the median house value is less than {MEDIAN_HOUSE_VALUE_PERCENTILE}th "
f"percentile and is low income"
)
# Clean energy and efficiency # Clean energy and efficiency
PM25_EXPOSURE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for PM2.5 exposure and is low income" PM25_EXPOSURE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for PM2.5 exposure and is low income"
ENERGY_BURDEN_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for energy burden and is low income" ENERGY_BURDEN_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for energy burden and is low income"
# Clean transportation # Clean transportation
DIESEL_PARTICULATE_MATTER_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for diesel particulate matter and is low income" DIESEL_PARTICULATE_MATTER_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for diesel particulate matter and is low income"
TRAFFIC_PROXIMITY_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for traffic proximity and is low income" TRAFFIC_PROXIMITY_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for traffic proximity and is low income"
# Affordable and Sustainable Housing # Affordable and Sustainable Housing
LEAD_PAINT_MEDIAN_HOME_VALUE_LOW_INCOME_FIELD = ( LEAD_PAINT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD = (
f"At or above the {PERCENTILE}th percentile for lead paint and" f"At or above the {PERCENTILE}th percentile for lead paint and"
" the median house value is less than {MEDIAN_HOUSE_VALUE_PERCENTILE}th percentile and is low income" f" the median house value is less than {MEDIAN_HOUSE_VALUE_PERCENTILE}th "
f"percentile and is low income"
) )
HOUSING_BURDEN_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for housing burden and is low income" HOUSING_BURDEN_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for housing burden and is low income"
IMPENETRABLE_SURFACES_LOW_INCOME_FIELD = (
f"At or above the {PERCENTILE}th percentile for impenetrable surfaces and is low "
f"income"
)
# Remediation and Reduction of Legacy Pollution # Remediation and Reduction of Legacy Pollution
RMP_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to RMP sites and is low income" RMP_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to RMP sites and is low income"
SUPERFUND_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to superfund sites and is low income" SUPERFUND_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to superfund sites and is low income"
HAZARDOUS_WASTE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to hazardous waste facilities and is low income" HAZARDOUS_WASTE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for proximity to hazardous waste facilities and is low income"
AIR_TOXICS_CANCER_RISK_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for air toxics cancer risk and is low income"
RESPIRATORY_HAZARD_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for respiratory hazard index and is low income"
# Critical Clean Water and Waste Infrastructure # Critical Clean Water and Waste Infrastructure
WASTEWATER_DISCHARGE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for wastewater discharge and is low income" WASTEWATER_DISCHARGE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for wastewater discharge and is low income"
# Health Burden
# Health Burdens
DIABETES_LOW_INCOME_FIELD = ( DIABETES_LOW_INCOME_FIELD = (
f"At or above the {PERCENTILE}th percentile for diabetes and is low income" f"At or above the {PERCENTILE}th percentile for diabetes and is low income"
) )
@ -234,25 +277,35 @@ HEART_DISEASE_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for
LIFE_EXPECTANCY_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for life expectancy and is low income" LIFE_EXPECTANCY_LOW_INCOME_FIELD = f"At or above the {PERCENTILE}th percentile for life expectancy and is low income"
HEALTHY_FOOD_LOW_INCOME_FIELD = (
f"At or above the {PERCENTILE}th percentile for low "
f"access to healthy food and is low income"
)
# Workforce # Workforce
UNEMPLOYMENT_LOW_HS_EDUCATION_FIELD = ( UNEMPLOYMENT_LOW_HS_EDUCATION_FIELD = (
f"At or above the {PERCENTILE}th percentile for unemployment" f"At or above the {PERCENTILE}th percentile for unemployment"
" and low HS education" " and has low HS education"
) )
LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD = ( LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD = (
f"At or above the {PERCENTILE}th percentile for households in linguistic isolation" f"At or above the {PERCENTILE}th percentile for households in linguistic isolation"
" and low HS education" " and has low HS education"
) )
POVERTY_LOW_HS_EDUCATION_FIELD = ( POVERTY_LOW_HS_EDUCATION_FIELD = (
f"At or above the {PERCENTILE}th percentile for households at or below 100% federal poverty level" f"At or above the {PERCENTILE}th percentile for households at or below 100% federal poverty level"
" and low HS education" " and has low HS education"
)
LOW_READING_LOW_HS_EDUCATION_FIELD = (
f"At or above the {PERCENTILE}th percentile for low 3rd grade reading proficiency"
" and has low HS education"
) )
MEDIAN_INCOME_LOW_HS_EDUCATION_FIELD = ( MEDIAN_INCOME_LOW_HS_EDUCATION_FIELD = (
f"At or below the {PERCENTILE}th percentile for median income" f"At or below the {PERCENTILE}th percentile for median income"
" and low HS education" " and has low HS education"
) )
THRESHOLD_COUNT = "Total threshold criteria exceeded" THRESHOLD_COUNT = "Total threshold criteria exceeded"

View file

@ -54,7 +54,7 @@ class ScoreC(Score):
[ [
field_names.AIR_TOXICS_CANCER_RISK_FIELD field_names.AIR_TOXICS_CANCER_RISK_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX, + field_names.PERCENTILE_FIELD_SUFFIX,
field_names.RESPITORY_HAZARD_FIELD field_names.RESPIRATORY_HAZARD_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX, + field_names.PERCENTILE_FIELD_SUFFIX,
field_names.DIESEL_FIELD + field_names.PERCENTILE_FIELD_SUFFIX, field_names.DIESEL_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,
field_names.PM25_FIELD + field_names.PERCENTILE_FIELD_SUFFIX, field_names.PM25_FIELD + field_names.PERCENTILE_FIELD_SUFFIX,

View file

@ -36,7 +36,7 @@ class ScoreF(Score):
) )
| ( | (
self.df[ self.df[
field_names.RESPITORY_HAZARD_FIELD field_names.RESPIRATORY_HAZARD_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX + field_names.PERCENTILE_FIELD_SUFFIX
] ]
> 0.9 > 0.9

View file

@ -177,6 +177,8 @@ class ScoreL(Score):
field_names.EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD, field_names.EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD,
field_names.EXPECTED_AGRICULTURE_LOSS_RATE_LOW_INCOME_FIELD, field_names.EXPECTED_AGRICULTURE_LOSS_RATE_LOW_INCOME_FIELD,
field_names.EXPECTED_BUILDING_LOSS_RATE_LOW_INCOME_FIELD, field_names.EXPECTED_BUILDING_LOSS_RATE_LOW_INCOME_FIELD,
field_names.EXTREME_HEAT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD,
field_names.IMPENETRABLE_SURFACES_LOW_INCOME_FIELD,
] ]
expected_population_loss_threshold = ( expected_population_loss_threshold = (
@ -203,6 +205,28 @@ class ScoreL(Score):
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD >= self.ENVIRONMENTAL_BURDEN_THRESHOLD
) )
extreme_heat_median_home_value_threshold = (
self.df[
field_names.EXTREME_HEAT_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
) & (
self.df[
field_names.MEDIAN_HOUSE_VALUE_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
<= self.MEDIAN_HOUSE_VALUE_THRESHOLD
)
impenetrable_surfaces_threshold = (
self.df[
field_names.IMPENETRABLE_SURFACES_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
)
self.df[field_names.EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD] = ( self.df[field_names.EXPECTED_POPULATION_LOSS_RATE_LOW_INCOME_FIELD] = (
expected_population_loss_threshold expected_population_loss_threshold
& self.df[field_names.FPL_200_SERIES] & self.df[field_names.FPL_200_SERIES]
@ -218,6 +242,18 @@ class ScoreL(Score):
& self.df[field_names.FPL_200_SERIES] & self.df[field_names.FPL_200_SERIES]
) )
self.df[
field_names.EXTREME_HEAT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD
] = (
extreme_heat_median_home_value_threshold
& self.df[field_names.FPL_200_SERIES]
)
self.df[field_names.IMPENETRABLE_SURFACES_LOW_INCOME_FIELD] = (
impenetrable_surfaces_threshold
& self.df[field_names.FPL_200_SERIES]
)
self._increment_total_eligibility_exceeded(climate_eligibility_columns) self._increment_total_eligibility_exceeded(climate_eligibility_columns)
return self.df[climate_eligibility_columns].any(axis="columns") return self.df[climate_eligibility_columns].any(axis="columns")
@ -320,11 +356,11 @@ class ScoreL(Score):
# poverty level. Source: Census's American Community Survey] # poverty level. Source: Census's American Community Survey]
housing_eligibility_columns = [ housing_eligibility_columns = [
field_names.LEAD_PAINT_MEDIAN_HOME_VALUE_LOW_INCOME_FIELD, field_names.LEAD_PAINT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD,
field_names.HOUSING_BURDEN_LOW_INCOME_FIELD, field_names.HOUSING_BURDEN_LOW_INCOME_FIELD,
] ]
lead_paint_median_house_hold_threshold = ( lead_paint_median_home_value_threshold = (
self.df[ self.df[
field_names.LEAD_PAINT_FIELD field_names.LEAD_PAINT_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX + field_names.PERCENTILE_FIELD_SUFFIX
@ -347,8 +383,8 @@ class ScoreL(Score):
) )
# series by series indicators # series by series indicators
self.df[field_names.LEAD_PAINT_MEDIAN_HOME_VALUE_LOW_INCOME_FIELD] = ( self.df[field_names.LEAD_PAINT_MEDIAN_HOUSE_VALUE_LOW_INCOME_FIELD] = (
lead_paint_median_house_hold_threshold lead_paint_median_home_value_threshold
& self.df[field_names.FPL_200_SERIES] & self.df[field_names.FPL_200_SERIES]
) )
@ -371,6 +407,8 @@ class ScoreL(Score):
field_names.RMP_LOW_INCOME_FIELD, field_names.RMP_LOW_INCOME_FIELD,
field_names.SUPERFUND_LOW_INCOME_FIELD, field_names.SUPERFUND_LOW_INCOME_FIELD,
field_names.HAZARDOUS_WASTE_LOW_INCOME_FIELD, field_names.HAZARDOUS_WASTE_LOW_INCOME_FIELD,
field_names.AIR_TOXICS_CANCER_RISK_LOW_INCOME_FIELD,
field_names.RESPIRATORY_HAZARD_LOW_INCOME_FIELD,
] ]
rmp_sites_threshold = ( rmp_sites_threshold = (
@ -390,6 +428,22 @@ class ScoreL(Score):
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD >= self.ENVIRONMENTAL_BURDEN_THRESHOLD
) )
air_toxics_cancer_risk_threshold = (
self.df[
field_names.AIR_TOXICS_CANCER_RISK_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
)
respiratory_hazard_risk_threshold = (
self.df[
field_names.RESPIRATORY_HAZARD_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
)
# individual series-by-series # individual series-by-series
self.df[field_names.RMP_LOW_INCOME_FIELD] = ( self.df[field_names.RMP_LOW_INCOME_FIELD] = (
rmp_sites_threshold & self.df[field_names.FPL_200_SERIES] rmp_sites_threshold & self.df[field_names.FPL_200_SERIES]
@ -400,6 +454,14 @@ class ScoreL(Score):
self.df[field_names.HAZARDOUS_WASTE_LOW_INCOME_FIELD] = ( self.df[field_names.HAZARDOUS_WASTE_LOW_INCOME_FIELD] = (
tsdf_sites_threshold & self.df[field_names.FPL_200_SERIES] tsdf_sites_threshold & self.df[field_names.FPL_200_SERIES]
) )
self.df[field_names.AIR_TOXICS_CANCER_RISK_LOW_INCOME_FIELD] = (
air_toxics_cancer_risk_threshold
& self.df[field_names.FPL_200_SERIES]
)
self.df[field_names.RESPIRATORY_HAZARD_LOW_INCOME_FIELD] = (
respiratory_hazard_risk_threshold
& self.df[field_names.FPL_200_SERIES]
)
self._increment_total_eligibility_exceeded( self._increment_total_eligibility_exceeded(
pollution_eligibility_columns pollution_eligibility_columns
@ -449,6 +511,7 @@ class ScoreL(Score):
field_names.DIABETES_LOW_INCOME_FIELD, field_names.DIABETES_LOW_INCOME_FIELD,
field_names.ASTHMA_LOW_INCOME_FIELD, field_names.ASTHMA_LOW_INCOME_FIELD,
field_names.HEART_DISEASE_LOW_INCOME_FIELD, field_names.HEART_DISEASE_LOW_INCOME_FIELD,
field_names.HEALTHY_FOOD_LOW_INCOME_FIELD,
field_names.LIFE_EXPECTANCY_LOW_INCOME_FIELD, field_names.LIFE_EXPECTANCY_LOW_INCOME_FIELD,
] ]
@ -474,6 +537,14 @@ class ScoreL(Score):
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD >= self.ENVIRONMENTAL_BURDEN_THRESHOLD
) )
healthy_food_threshold = (
self.df[
field_names.HEALTHY_FOOD_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
)
life_expectancy_threshold = ( life_expectancy_threshold = (
self.df[ self.df[
field_names.LIFE_EXPECTANCY_FIELD field_names.LIFE_EXPECTANCY_FIELD
@ -496,6 +567,9 @@ class ScoreL(Score):
self.df[field_names.LIFE_EXPECTANCY_LOW_INCOME_FIELD] = ( self.df[field_names.LIFE_EXPECTANCY_LOW_INCOME_FIELD] = (
life_expectancy_threshold & self.df[field_names.FPL_200_SERIES] life_expectancy_threshold & self.df[field_names.FPL_200_SERIES]
) )
self.df[field_names.HEALTHY_FOOD_LOW_INCOME_FIELD] = (
healthy_food_threshold & self.df[field_names.FPL_200_SERIES]
)
self._increment_total_eligibility_exceeded(health_eligibility_columns) self._increment_total_eligibility_exceeded(health_eligibility_columns)
@ -513,6 +587,15 @@ class ScoreL(Score):
# Where the high school degree achievement rates for adults 25 years and older is less than 95% # Where the high school degree achievement rates for adults 25 years and older is less than 95%
# (necessary to screen out university block groups) # (necessary to screen out university block groups)
# Workforce criteria for states fields.
workforce_eligibility_columns = [
field_names.UNEMPLOYMENT_LOW_HS_EDUCATION_FIELD,
field_names.POVERTY_LOW_HS_EDUCATION_FIELD,
field_names.LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD,
field_names.MEDIAN_INCOME_LOW_HS_EDUCATION_FIELD,
field_names.LOW_READING_LOW_HS_EDUCATION_FIELD,
]
high_scool_achievement_rate_threshold = ( high_scool_achievement_rate_threshold = (
self.df[field_names.HIGH_SCHOOL_ED_FIELD] self.df[field_names.HIGH_SCHOOL_ED_FIELD]
>= self.LACK_OF_HIGH_SCHOOL_MINIMUM_THRESHOLD >= self.LACK_OF_HIGH_SCHOOL_MINIMUM_THRESHOLD
@ -528,7 +611,7 @@ class ScoreL(Score):
median_income_threshold = ( median_income_threshold = (
self.df[ self.df[
field_names.MEDIAN_INCOME_PERCENT_AMI_FIELD field_names.MEDIAN_INCOME_AS_PERCENT_OF_AMI_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX + field_names.PERCENTILE_FIELD_SUFFIX
] ]
# Note: a high median income as a % of AMI is good, so take 1 minus the threshold to invert it. # Note: a high median income as a % of AMI is good, so take 1 minus the threshold to invert it.
@ -552,6 +635,14 @@ class ScoreL(Score):
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD >= self.ENVIRONMENTAL_BURDEN_THRESHOLD
) )
low_reading_threshold = (
self.df[
field_names.LOW_READING_FIELD
+ field_names.PERCENTILE_FIELD_SUFFIX
]
>= self.ENVIRONMENTAL_BURDEN_THRESHOLD
)
self.df[field_names.LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD] = ( self.df[field_names.LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD] = (
linguistic_isolation_threshold linguistic_isolation_threshold
& high_scool_achievement_rate_threshold & high_scool_achievement_rate_threshold
@ -569,15 +660,9 @@ class ScoreL(Score):
unemployment_threshold & high_scool_achievement_rate_threshold unemployment_threshold & high_scool_achievement_rate_threshold
) )
# Workforce criteria for states fields that create indicator columns self.df[field_names.LOW_READING_LOW_HS_EDUCATION_FIELD] = (
# for each tract in order to indicate whether they met any of the four low_reading_threshold & high_scool_achievement_rate_threshold
# criteria. We will used this create individual indicator columns. )
workforce_eligibility_columns = [
field_names.UNEMPLOYMENT_LOW_HS_EDUCATION_FIELD,
field_names.POVERTY_LOW_HS_EDUCATION_FIELD,
field_names.LINGUISTIC_ISOLATION_LOW_HS_EDUCATION_FIELD,
field_names.MEDIAN_INCOME_LOW_HS_EDUCATION_FIELD,
]
workforce_combined_criteria_for_states = self.df[ workforce_combined_criteria_for_states = self.df[
workforce_eligibility_columns workforce_eligibility_columns