The Southern Tier of New York consists of fourteen counties that are considered part of Northern Appalachia, according to the Appalachian Regional Commission. These counties have experienced some of the most drastic population declines in New York State outside of New York City (McMahon, 2024). On top of the decline in population, communities in much of the Southern Tier suffer from relatively high poverty and low income levels compared to the rest of the United States as a whole (ARC, 2024 County-Level Distressed Area Study).
Some areas in Appalachia - such as Eastern Kentucky - have undergone extensive land reclamation efforts in an attempt to repair land that had been damaged during the era of intense coal mining operations, converting much of the reclaimed land into infrastructure, industry, and other development despite consistent population decline (KC, Gyawali, Lucas, et al., 2024). Coal mining was not a large industry in this area at any time, and much of the manufacturing was limited to cities such as Jamestown and Binghamton.
While the need of a study concerning land cover for the purposes of land reclamation may not be necessary for the Southern Tier, an analysis of the region could lead to interesting insights about how the population decline may have impacted land cover changes. The purpose of this analysis is to get a general idea of the changes in population/economic variables and land cover in New York’s Southern Tier between 2010 and 2019 and how they may relate to each other. Specifically, are areas with a higher population decline more likely to have had an increase in natural barren land and/or a decrease in developed area?
Materials and Methods
The analysis looked at various population-related variables. Specifically, data concerning total population, total households, median age, median family income, number of people below the poverty level, unemployment among civilian workforce over the age of 16, and households with no vehicles were pulled and/or aggregated at the U.S., county, and census tract levels.
Census data was pulled for years between 2010 and 2019. All data was gathered using the tidycensus package, and a majority of it came from American Community Survey (ACS) 5-year estimates. U.S. data for 2010 had to be pulled from the decennial census or sourced from governmental reports and news releases since ACS data was not available for this year at the country-level. Data for years other than 2010 and 2019 were pulled to allow for additional analysis in the future.
Primary land cover data for 2010 and 2019 comes from the USGS LCMAP project and were downloaded from the CONUS Mosaic website. This data was processed using the terra package.
The methodology used to determine distressed status of each census tract was taken from the Appalachian Regional Commission’s Distressed Areas Classification System. According to the ARC, the key attributes of a distressed census tract are:
A median family income no greater than 67% of the U.S. average.
A poverty rate of 150% of the U.S. average or greater.
The correlation analysis was conducted on the census-tract level data and used the Pearson method. The cor function of the base R stats package was used to calculate correlation coefficients.
The tidyverse collection of packages was primarily used to easily process large amount of data. The tigris package was used directly to pull study counties and census tracts to create a map of the study area. The sf package helped with processing spatial features, including data pulled from the ACS. The maps were created using either leaflet, mapview, or ggplot2. The gt package allowed for the creation of better looking tables. The heatmaply package was used to visualize the correlation coefficients between all variables.
An Overview of the Analysis Workflow
Below is an outline of how the analysis was conducted:
Create a map of study area for reference.
Pull Census data at US, census tract, and county levels for years between 2010 and 2019, then simplify datasets so only variables for the years 2010 and 2019 are included.
Certain data at the tract level (e.g., median family income) could not simply be aggregated to include in the county-level dataset, which required pulling that data separately at the county level.
U.S. data was pulled for comparison purposes in the distressed population analysis.
U.S. data for 2010 had to be sourced from governmental reports since they were not available for direct download using the tidycensus package. The only variable that was pulled using tidycensus in this case was total population.
Data for 2015 are also included in the consolidated datasets for the purposes of future work. They do not have any relevance to the analysis at this time.
Download land cover datasets for years 2010 and 2019, then show side-by-side plot of both images. Show map of areas where the land cover type has changed between the years.
Calculate zonal statistics of each of the 8 land cover classifications over the entire study area, then create a table and bar graph showing the changes in each of the classifications between 2010 and 2019.
Determine distressed status of each of the census tracts for each year using criteria from the ARC by comparing median family income and poverty levels to the U.S. values. Determine which census tracts improved (i.e., were distressed in 2010 and no longer distressed in 2019) and which census tracts became distressed. Create maps to show tracts that improved and tracts that became distressed. Also show table breakdown by county of the number of tracts that became distressed and the number of tracts that improved.
Merge base data variables, distressed variable data, and land cover classification data into single datasets at both the census tract and county levels. Calculate percent changes between 2010 and 2019 for each variable in each of the datasets. Create tables for both to show the percent changes by census tract and by county.
Run basic correlation analysis on census tract-level dataset to figure out relationships between variables, and create a heatmap of correlation results. Lastly, create a table of correlation results between the percentage population change and all other percentage change variables.
Since there are only 14 counties, a county-level correlation analysis would have a very large margin of error. For this reason, this step was only done on the census tract-level data.
Data Gathering and Processing
Code
# load necessary librarieslibrary(tidyverse)library(tidycensus)library(sf)library(tigris)library(basemaps)library(leaflet)library(mapview)library(terra)library(tidyterra)library(gt)library(heatmaply)library(stringr)library(RColorBrewer)library(gridExtra)library(reshape2)library(here)library(knitr)knitr::opts_chunk$set(echo=TRUE) # cache the results for quick compiling# pull in census api tokencensus_token =Sys.getenv("CENSUS_TOKEN")census_api_key(census_token)
Map of Study Area
The map below shows the 14 counties in New York’s Southern Tier (Allegany, Broome, Cattaraugus, Chautauqua, Chemung, Chenango, Cortland, Delaware, Otsego, Schoharie, Schuyler, Steuben, Tioga, and Tompkins) and all 277 census tracts.
Code
# increase timeout time to download files and cache tigris filesoptions(timeout =500, tigris_use_cache =TRUE)# set vector of southern tier countiessouthern_tier_counties =c('Allegany', 'Broome', 'Cattaraugus', 'Chautauqua', 'Chemung', 'Chenango', 'Cortland', 'Delaware', 'Otsego', 'Schoharie', 'Schuyler', 'Steuben', 'Tioga', 'Tompkins')# get study geographies and basemap focused on ny stateny_state <-states(cb =TRUE, year =2019) %>%filter(NAME =='New York')study_counties <-counties(state ='NY', cb =TRUE, year =2019) %>%filter(NAME %in% southern_tier_counties)study_tracts <-tracts(state ='NY', county = southern_tier_counties, cb =TRUE, year =2019)base_ny <-basemap_raster(ext = ny_state, map_service ='carto', map_type ='light')
Loading basemap 'light' from map service 'carto'...
Code
# create study area mapstudy_area_map <-leaflet() %>%addTiles() %>%addPolygons(data =st_transform(study_counties, crs ='+proj=longlat +datum=WGS84'),fillOpacity =0, label =~study_counties$NAME) %>%addPolygons(data =st_transform(study_tracts, crs ='+proj=longlat +datum=WGS84'),fillOpacity =0, color ='black', weight ='0.75')study_area_map
Download and Process All Required Data
Census data and land cover data are downloaded and processed here. The census data comes primarily from the American Community Survey (ACS) 5-year surveys, and the land cover data comes from the USGS.
ACS Data
Set function to download ACS data based on geography
# get certain decennial 2010 census data at state level# then sum population and add additional data points taken from governmental reportsus_data.2010<-get_decennial(geography ='state',variables =c(tot_pop ='P001001'),year =2010,output ='wide',cache_table =TRUE,geometry =TRUE) %>%mutate(NAME ='United States') %>%group_by(NAME) %>%summarize(tot_popE =sum(tot_pop)) %>%mutate(tot_hhsE =116716292,median_ageE =37.2,pct_below_povertyE =15.3,median_incomeE =64400 ) %>%relocate(geometry, .after =last_col()) %>%as_tibble()# pull acs data at national levelus_data.2014_2019 <-map2(2014:2019, rep('us', times =6), get_acs_data) %>%bind_rows() %>%as_tibble()# separate 2014-2019 us data into 2015 and 2019 data framesus_data.2015<- us_data.2014_2019 %>%filter(year ==2015)us_data.2019<- us_data.2014_2019 %>%filter(year ==2019)# merge us data for 2010, 2015, and 2019 into a single data frameus_data.2010_2019 <-left_join(us_data.2010, us_data.2015, by ='NAME', keep =FALSE, suffix =c('', '_2015')) %>%left_join(us_data.2019, by ='NAME', keep =TRUE, suffix =c('_2010', '_2019')) %>%select(!all_of(grep('M_', names(.), value =TRUE))) %>%# remove margin of error columnsrename(GEOID = GEOID_2010,NAME = NAME_2010,geometry = geometry_2010,year = year_2010,pct_below_povertyE_2010 = pct_below_povertyE,tot_below_povertyE_2015 = tot_below_povertyE_2010,hhs_no_vehicleE_2015 = hhs_no_vehicleE_2010 ) %>%relocate(GEOID, .after = NAME) %>%select(-c('GEOID_2019', 'NAME_2019', 'geometry_2015', 'geometry_2019', 'year', 'year_2019')) %>%mutate(pct_below_poverty_2015 = (tot_below_povertyE_2015 / tot_popE_2015) *100,pct_below_poverty_2019 = (tot_below_povertyE_2019 / tot_popE_2019) *100,pct_hhs_no_vehicle_2015 = (hhs_no_vehicleE_2015 / tot_hhsE_2015) *100,pct_hhs_no_vehicle_2019 = (hhs_no_vehicleE_2019 / tot_hhsE_2019) *100,pct_tot_pop_chg_2010_2019 = ((tot_popE_2019 - tot_popE_2010) / tot_popE_2010) *100,pct_median_age_chg_2015_2019 = ((median_ageE_2015 - median_ageE_2010) / median_ageE_2015) *100,pct_median_income_chg_2010_2019 = ((median_incomeE_2019 - median_incomeE_2010) / median_incomeE_2010) *100,pct_below_poverty_chg_2010_2019 = ((pct_below_poverty_2019 - pct_below_povertyE_2010) / pct_below_povertyE_2010) *100,pct_hhs_no_vehicle_chg_2015_2019 = ((pct_hhs_no_vehicle_2019 - pct_hhs_no_vehicle_2015) / pct_hhs_no_vehicle_2015) *100 ) %>%lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>%as_tibble() %>%relocate(geometry, .after =last_col()) %>%st_as_sf(crs ="EPSG: 4269")
Census Tract Data
Code
# get census tract data for 2010-2019# isolate data for 2010, 2015, and 2019 and put into separate dfsst_tracts <-map2(2010:2019, rep('tract', times =10), get_acs_data) %>%bind_rows() %>%as_tibble()# show point plot of median income and pct below poverty level for each year# colored by countyggplot(st_tracts, aes(median_incomeE, pct_below_poverty, color = county)) +geom_jitter(na.rm =TRUE) +facet_wrap(~year) +labs(x ='Median Income', y ='% Below Poverty Level', color ='County') +theme(axis.text.x =element_text(angle =45, hjust =1))
There is a clear negative relationship between median family income and percent below poverty level, where tracts that have higher median family incomes tend to have a lower percentage of people below poverty. Most of the outliers for each year are in Tompkins County.
Remaining Census Tract Data
Code
# get economic data (unemployed civilians > 16) for 2010-2019# data for 2018 returned a server errorst_tracts.economic <-map(c(2010, 2011, 2013, 2014, 2015, 2016, 2017, 2019), function(x) {return(get_acs(geography ='tract',variables =c('DP03_0003', 'DP03_0005'),state ='NY',geometry =TRUE,year = x,output ='wide',cache_table =TRUE,key = census_token ) %>%rename('pop_gt_16_in_civilian_labor_force_{x}':= DP03_0003E,'pop_gt_16_in_civilian_labor_force_unemployed_{x}':= DP03_0005E ) %>%mutate(year = x,county =str_split(NAME, ' ', simplify =TRUE)[,4] ) )}) %>%bind_rows()%>%filter(county %in% southern_tier_counties &!st_is_empty(geometry)) %>%as_tibble()# filter data for years 2010, 2015, and 2019, join with that year's economic data,# and store in separate data frames for each yearst_tracts.2010<-# health insurance coverage data not available for 2010 st_tracts %>%filter(year ==2010) %>%left_join(select(filter(st_tracts.economic, year ==2010), GEOID, pop_gt_16_in_civilian_labor_force_2010, pop_gt_16_in_civilian_labor_force_unemployed_2010 ) ) %>%relocate(geometry, .after =last_col())st_tracts.2015<- st_tracts %>%filter(year ==2015) %>%left_join(select(filter(st_tracts.economic, year ==2015), GEOID, pop_gt_16_in_civilian_labor_force_2015, pop_gt_16_in_civilian_labor_force_unemployed_2015 ) ) %>%relocate(geometry, .after =last_col())st_tracts.2019<- st_tracts %>%filter(year ==2019) %>%left_join(select(filter(st_tracts.economic, year ==2019), GEOID, pop_gt_16_in_civilian_labor_force_2019, pop_gt_16_in_civilian_labor_force_unemployed_2019 ) ) %>%relocate(geometry, .after =last_col())# merge 2010, 2015, & 2019 data into single sf# compute pct chgs, convert to sf, and change infinite values to NAst_tracts.2010_2019 <-left_join(st_tracts.2010, st_tracts.2015, by ='GEOID', keep =FALSE, suffix =c('', '_2015')) %>%left_join(st_tracts.2019, by ='GEOID', keep =FALSE, suffix =c('_2010', '_2019')) %>%select(-c('NAME_2015', 'geometry_2015', 'year_2015', 'county_2015', 'NAME_2019', 'geometry_2019', 'year_2019', 'county_2019')) %>%rename(NAME = NAME_2010,geometry = geometry_2010,county = county_2010,year = year_2010 ) %>%mutate(across(starts_with('pop_gt_16'), ~as.numeric(as.character(.))),pct_pop_chg_2010_2019 = ((tot_popE_2019 - tot_popE_2010) / tot_popE_2010) *100,pct_poverty_chg_2010_2019 = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) *100,pct_hhs_no_vehicles_chg_2010_2019 = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) *100,pct_pop_gt_16_in_civilian_labor_force_unemployed_2010 = pop_gt_16_in_civilian_labor_force_unemployed_2010 / pop_gt_16_in_civilian_labor_force_2010,pct_pop_gt_16_in_civilian_labor_force_unemployed_2015 = pop_gt_16_in_civilian_labor_force_unemployed_2015 / pop_gt_16_in_civilian_labor_force_2015,pct_pop_gt_16_in_civilian_labor_force_unemployed_2019 = pop_gt_16_in_civilian_labor_force_unemployed_2019 / pop_gt_16_in_civilian_labor_force_2019,pct_pop_gt_16_in_civilian_labor_force_unemployed_chg_2010_2019 = ((pct_pop_gt_16_in_civilian_labor_force_unemployed_2019 - pct_pop_gt_16_in_civilian_labor_force_unemployed_2010) / pct_pop_gt_16_in_civilian_labor_force_unemployed_2010) *100 ) %>%lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>%as_tibble() %>%relocate(geometry, .after =last_col()) %>%st_as_sf(crs ="EPSG: 4269")######################################################################## REMOVED 36013990000 Census Tract 9900, Chautauqua County, New York## Had no estimated population AND had empty geometry######################################################################
County Data
Code
# pull southern tier county data and calculate area in square milesst_counties <-map2(2010:2019, rep('county', times =10), get_acs_data) %>%bind_rows() %>%as_tibble() %>%st_as_sf(crs ="EPSG: 4269") %>%mutate(area_sqmi =st_area(.) /2589988.110336) %>%relocate(geometry, .after =last_col())# separate st_counties for 2010, 2015, and 2019 into separate dataframesst_counties.2010<- st_counties %>%filter(year ==2010) %>%as_tibble()st_counties.2015<- st_counties %>%filter(year ==2015) %>%as_tibble()st_counties.2019<- st_counties %>%filter(year ==2019) %>%as_tibble()# merge 2010, 2015, & 2019 data into single sf# compute pct chgs, convert to sf, and change infinite values to NA# will merge with grouped st_tracts.2010_2019 data belowst_counties_base.2010_2019 <-left_join(st_counties.2010, st_counties.2015, by ='GEOID', keep =FALSE, suffix =c('', '_2015')) %>%left_join(st_counties.2019, by ='GEOID', keep =FALSE, suffix =c('_2010', '_2019')) %>%select(-c('NAME_2015', 'geometry_2015', 'year_2015', 'county_2015', 'NAME_2019', 'geometry_2019', 'year_2019', 'county_2019')) %>%rename(NAME = NAME_2010,geometry = geometry_2010,county = county_2010,year = year_2010 ) %>%mutate(pct_median_age_chg_2010_2019 = ((median_ageE_2019 - median_ageE_2010) / median_ageE_2010) *100,pct_median_income_chg_2010_2019 = ((median_incomeE_2019 - median_incomeE_2010) / median_incomeE_2010) *100 ) %>%lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>%as_tibble() %>%relocate(geometry, .after =last_col()) %>%st_as_sf(crs ="EPSG: 4269")# get list of all pct columnspct_cols <-grep('pct', names(st_tracts.2010_2019), value =TRUE)# calculate data from st_tracts.2010_2019 by grouping by county, then merge with st_counties_base.2010_2019# create data frame of all county-level datast_counties.2010_2019 <- st_tracts.2010_2019 %>%select(!all_of(pct_cols)) %>%group_by(county) %>%reframe(tot_pop_2010 =sum(tot_popE_2010),tot_pop_2015 =sum(tot_popE_2015),tot_pop_2019 =sum(tot_popE_2019),tot_hhs_2010 =sum(tot_hhsE_2010),tot_hhs_2015 =sum(tot_hhsE_2015),tot_hhs_2019 =sum(tot_hhsE_2019),tot_below_poverty_2010 =sum(tot_below_povertyE_2010),tot_below_poverty_2015 =sum(tot_below_povertyE_2015),tot_below_poverty_2019 =sum(tot_below_povertyE_2019),hhs_no_vehicles_2010 =sum(hhs_no_vehicleE_2010),hhs_no_vehicles_2015 =sum(hhs_no_vehicleE_2015),hhs_no_vehicles_2019 =sum(hhs_no_vehicleE_2019),pop_gt_16_in_civ_lab_force_2010 =sum(pop_gt_16_in_civilian_labor_force_2010),pop_gt_16_in_civ_lab_force_2015 =sum(pop_gt_16_in_civilian_labor_force_2015),pop_gt_16_in_civ_lab_force_2019 =sum(pop_gt_16_in_civilian_labor_force_2019),pop_gt_16_in_civ_lab_force_unemployed_2010 = pop_gt_16_in_civilian_labor_force_unemployed_2010,pop_gt_16_in_civ_lab_force_unemployed_2015 = pop_gt_16_in_civilian_labor_force_unemployed_2015,pop_gt_16_in_civ_lab_force_unemployed_2019 = pop_gt_16_in_civilian_labor_force_unemployed_2019,pct_below_poverty_2010 = (tot_below_poverty_2010 / tot_pop_2010) *100,pct_below_poverty_2015 = (tot_below_poverty_2015 / tot_pop_2015) *100,pct_below_poverty_2019 = (tot_below_poverty_2019 / tot_pop_2019) *100,pct_hhs_no_vehicles_2010 = (hhs_no_vehicles_2010 / tot_hhs_2010) *100,pct_hhs_no_vehicles_2015 = (hhs_no_vehicles_2015 / tot_hhs_2015) *100,pct_hhs_no_vehicles_2019 = (hhs_no_vehicles_2019 / tot_hhs_2019) *100,pct_pop_gt_16_in_civ_lab_force_unemployed_2010 = (pop_gt_16_in_civ_lab_force_unemployed_2010 / pop_gt_16_in_civ_lab_force_2010) *100,pct_pop_gt_16_in_civ_lab_force_unemployed_2015 = (pop_gt_16_in_civ_lab_force_unemployed_2015 / pop_gt_16_in_civ_lab_force_2015) *100,pct_pop_gt_16_in_civ_lab_force_unemployed_2019 = (pop_gt_16_in_civ_lab_force_unemployed_2019 / pop_gt_16_in_civ_lab_force_2019) *100,pct_pop_chg_2010_2019 = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) *100,geometry =st_union(geometry) ) %>%distinct(county, .keep_all =TRUE) %>%left_join(st_drop_geometry(st_counties_base.2010_2019), by =join_by(county == county), suffix =c('', ''), keep =TRUE) %>%st_as_sf(crs =st_crs(st_counties_base.2010_2019))
Land Cover Data
Land Cover Set Up
Code
# set urls to land cover imagesurl_2010 <-'https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/lcmap/public/full_extent_downloads/version_13/primary-landcover_conus_year_data/LCMAP_CU_2010_V13_LCPRI/LCMAP_CU_2010_V13_LCPRI.tif'url_2019 <-'https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/lcmap/public/full_extent_downloads/version_13/primary-landcover_conus_year_data/LCMAP_CU_2019_V13_LCPRI/LCMAP_CU_2019_V13_LCPRI.tif'# dissolve counties into single study are polygonst_full_study_area <- st_counties.2010_2019 %>%st_union()# define crop_raster function - crop land cover rasters to full study area# return both cropped and masked resultscrop_raster <-function(lc_file, study_area) { crp <-crop(lc_file, vect(st_transform(study_area, crs =st_crs(lc_file)))) msk <-mask(crp, vect(st_transform(study_area, crs =st_crs(lc_file))))return(msk)}# define calculate_zonal_stats function - calculate total area of each# land cover category in square miles over the entire study areacalculate_zonal_stats <-function(lc_file) { z <-zonal(cellSize(lc_file, unit ='km'), lc_file,fun=sum ) z <- z %>%mutate(area_sqmi = area *0.386102) %>%rename(land_cover_category =names(lc_file)[[1]]) %>%subset(select =-area)}# set land cover description listland_cover_type <-c(Developed =1,Cropland =2,`Grassland/Shrubland`=3,`Tree Cover`=4,Water =5,Wetlands =6,`Snow and Ice`=7,`Natural Barren`=8)# load three land cover rasters and crop each to study area polygon# find total area of each land cover categories in entire study arealand_cover_2010 <-rast(url_2010)st_lc_2010_masked <-crop_raster(land_cover_2010, st_full_study_area)
This section pertains to land cover over the entire 14-county study area. The interpretation of the land cover images’ pixel values and corresponding land cover classes were taken from p. 7 of the LCMAP Collection 1.3 Data Format Control Book.
Code
# create data base of land cover descriptions and their colorslc.desc <-data.frame(ID = land_cover_type,landcover =names(land_cover_type),color =c('red', 'yellow', 'lightgreen', 'darkgreen', 'lightblue', 'blue', 'white', 'lightgray'),stringsAsFactors =FALSE)# define create_lc_plot function - create a ggplot of masked land cover objectcreate_lc_plot <-function(lc_file, year) {# convert file to factors lc <-as.factor(lc_file)# create plot plt <-ggplot() +geom_spatraster(data = lc) +scale_fill_manual(values =setNames(lc.desc$color, lc.desc$ID),labels = lc.desc$landcover,breaks = lc.desc$ID,name ='Landcover Type') +ggtitle(paste('Land Cover ', '(', year, ')', sep ='')) +theme(legend.position ='right',plot.title =element_text(hjust =0.5)) +guides(fill =guide_legend(ncol =1, byrow =TRUE))}# generate plots for 2010 and 2019 land cover imageslc_2010_plt <-create_lc_plot(st_lc_2010_masked, 2010)lc_2019_plt <-create_lc_plot(st_lc_2019_masked, 2019)# display stacked plot of both land cover imagesgridExtra::grid.arrange(lc_2010_plt, lc_2019_plt, ncol =1)
Areas shown in black in the map below are areas where the land cover has changed between 2010 and 2019. The actual change in classification is not depicted.
Code
# compare 2019 and 2010 land cover images to see where changes occurredchg <- (st_lc_2019_masked == st_lc_2010_masked)
# land cover changes from 2010 to 2019 in entire study arealand_cover_chg_study_area.2010_2019 <-left_join( zonal_stats_2010_study_area, zonal_stats_2019_study_area,by ='land_cover_category', suffix =c('_2010', '_2019')) %>%mutate(pct_of_tot_area_2010 = (area_sqmi_2010 /sum(area_sqmi_2010)) *100,pct_of_tot_area_2019 = (area_sqmi_2019 /sum(area_sqmi_2019)) *100,chg_in_area_sqmi = ((area_sqmi_2019 - area_sqmi_2010) / area_sqmi_2010) *100 )# convert land_cover_type vector into a dataframe to merge with land_cover_chg data frame# so land cover descriptions are includedlc.type <-data.frame(land_cover_category = land_cover_type, land_cover_desc =rownames(as.data.frame(land_cover_type)))rownames(lc.type) <-1:nrow(lc.type)# join lc.type df with land cover chg results df, then remove numbered category column# and replace all NAs with 0lc_chg.2010_2019 <-left_join(lc.type, land_cover_chg_study_area.2010_2019, by ='land_cover_category') %>%select(-land_cover_category) %>%replace(is.na(.), 0)# create table of land cover changelc_chg.2010_2019 %>%arrange(desc(area_sqmi_2010)) %>%gt(rowname_col ='land_cover_desc') %>%tab_header(title =md('**Land Cover Change in NY Southern Tier**')) %>%cols_label(area_sqmi_2010 =md('**Area (2010)**'),area_sqmi_2019 =md('**Area (2019)**'),pct_of_tot_area_2010 =md('**% of Area (2010)**'),pct_of_tot_area_2019 =md('**% of Area (2019)**'),chg_in_area_sqmi =md('**% Change**') ) %>%fmt_number(columns =c('area_sqmi_2010', 'area_sqmi_2019'), decimals =1) %>%fmt_percent(columns =c('pct_of_tot_area_2010', 'pct_of_tot_area_2019', 'chg_in_area_sqmi'), decimals =2, scale_values =FALSE)
Land Cover Change in NY Southern Tier
Area (2010)
Area (2019)
% of Area (2010)
% of Area (2019)
% Change
Tree Cover
7,387.1
7,386.8
62.36%
62.36%
−0.00%
Cropland
3,416.5
3,417.0
28.84%
28.85%
0.02%
Developed
387.2
387.1
3.27%
3.27%
−0.02%
Wetlands
378.5
378.4
3.19%
3.19%
−0.03%
Water
141.6
141.2
1.20%
1.19%
−0.27%
Grassland/Shrubland
109.6
106.5
0.93%
0.90%
−2.81%
Natural Barren
25.6
29.0
0.22%
0.24%
13.23%
Snow and Ice
0.0
0.0
0.00%
0.00%
0.00%
Code
# create bar graph of land cover change between 2019 and 2019ggplot(lc_chg.2010_2019, aes(x = land_cover_desc, y = chg_in_area_sqmi)) +geom_col(fill ='blue') +labs(x ='Land Cover Type', y ='% Change (sq mi)',title ='Change in Area by Land Cover Classification') +theme(plot.title =element_text(hjust =0.5),axis.text.x =element_text(angle =45, hjust =1))
A majority of the study area is covered by trees and cropland, with much smaller amounts of other land cover classes. The images of land cover change in 2010 and 2019 would not suggest any major land cover changes between that time period. There was an over 13% (about 3.4 square miles) increase in natural barren land and an almost 3% (about 2.9 square miles) decrease in grassland/shrubland. There were very small changes in other land cover types, and no snow and ice cover in either of the two years.
Results
The final analysis involved calculating the number of people who live in distressed areas. Using the criteria defined in the ARC’s Distressed Areas Classification System, the distressed status of each census tract was determined for 2010 and 2019. Using these statuses, it was then possible to see if each census tract improved or became distressed within the same time period. This data was used to figure out how many people lived in distressed areas in each county. The area of each land cover classification was then calculated for each census tract and county.
The above data was combined into separate data frames for census tracts and counties. The percentage change of each study variable was also calculated, except for the percentage change of distressed population at the census-tract level since these values would either be 0% or infinite. A small correlation analysis was conducted to determine relationships between any of the percentage change variables at both the tract level and the correlation coefficients were visualized using a heat map. A separate table was created to see if the percentage change in population was related to any of the other percentage change variables.
Distressed Area Analysis
Code
# get list of columns that are involved in distressed area classificationdistressed_cols <-c(grep('tot_popE', names(st_tracts.2010_2019), value =TRUE),grep('median_income', names(st_tracts.2010_2019), value =TRUE), grep('pct_below_poverty', names(st_tracts.2010_2019), value =TRUE))# determined distressed area classification of each census tractst_tracts.distressed <- st_tracts.2010_2019[,c('GEOID', 'NAME', 'county', distressed_cols)] %>%mutate(if_Distressed_2010 = (((median_incomeE_2010 / us_data.2010_2019$median_incomeE_2010) <=0.67) & ((pct_below_poverty_2010 / ((us_data.2010_2019$pct_below_povertyE_2010) /100)) >=1.50)),if_Distressed_2015 = (((median_incomeE_2015 / us_data.2010_2019$median_incomeE_2015) <=0.67) & ((pct_below_poverty_2015 / ((us_data.2010_2019$pct_below_poverty_2015) /100)) >=1.50)),if_Distressed_2019 = (((median_incomeE_2019 / us_data.2010_2019$median_incomeE_2019) <=0.67) & ((pct_below_poverty_2019 / ((us_data.2010_2019$pct_below_poverty_2019) /100)) >=1.50)),if_Became_Distressed_2010_2019 = (if_Distressed_2010 ==FALSE& if_Distressed_2019 ==TRUE),if_Distressed_Then_Improved_2010_2019 = (if_Distressed_2010 ==TRUE& if_Distressed_2019 ==FALSE) ) %>%relocate(geometry, .after =last_col())# create spatial table of distressed statuses for each census tractdistressed.tab <- st_tracts.distressed %>%select(GEOID, NAME, county, grep('Distressed', colnames(st_tracts.distressed), value =TRUE))# map which tracts were distressed in 2010mapview( distressed.tab, zcol ='if_Distressed_2010',alpha.regions =0.5,popup ="NAME",layer.name =c("Distressed (2010)"))
Code
# map which tracts were distressed in 2010mapview( distressed.tab, zcol ='if_Distressed_2019',alpha.regions =0.5,popup ="NAME",layer.name =c("Distressed (2019)"))
Code
# create table of number of worsened and improved tracts by county, then displaydistressed.tab %>%group_by(county) %>%summarize(tot_tracts =n(),across(grep('2010', colnames(.), value =TRUE), \(x) sum(x, na.rm =TRUE) ),across(grep('2019', colnames(.), value =TRUE), \(x) sum(x, na.rm =TRUE) ) ) %>%st_drop_geometry() %>%relocate(if_Distressed_2019, .after = if_Distressed_2010) %>%arrange(desc(tot_tracts)) %>%gt() %>%cols_label(county =md('**County**'),tot_tracts =md('**# Tracts**'),if_Distressed_2010 =md('**Distressed (2010)**'),if_Distressed_2019 =md('**Distressed (2019)**'),if_Became_Distressed_2010_2019 =md('**Became Distressed**'),if_Distressed_Then_Improved_2010_2019 =md('**Distressed Then Improved**') )
County
# Tracts
Distressed (2010)
Distressed (2019)
Became Distressed
Distressed Then Improved
Broome
55
10
14
5
1
Chautauqua
35
6
9
4
1
Steuben
30
1
3
2
0
Tompkins
23
1
0
0
0
Chemung
22
3
4
1
0
Cattaraugus
21
1
3
2
0
Otsego
17
0
0
0
0
Delaware
14
0
1
1
0
Allegany
13
0
2
2
0
Chenango
12
0
1
1
0
Cortland
12
0
2
2
0
Tioga
10
0
0
0
0
Schoharie
8
0
0
0
0
Schuyler
5
0
0
0
0
Across the study area there were 39 census tracts (14.1%) that were distressed in 2019, an increase from the 22 census tracts (7.9%) that were distressed in 2010. Nine of the fourteen counties had census tracts that became distressed, while only two counties had a tract that improved. In total, 20 census tracts (7.2%) became distressed and only 2 census tracts (0.7%) improved. Cortland County had the largest percentage of census tracts that became distressed (16.7%), followed by Allegany County (15.4%) and Chautauqua County (11.4%).
Most cities in the Southern Tier are at least mostly distressed in terms of number of distressed census tracts. The only cities that did not have distressed areas are Ithaca (Tompkins County) and Oneonta (Otsego County). In contrast, Binghamton, Jamestown, Dunkirk, and Elmira were all significantly distressed.
Otsego, Tioga, Schoharie, and Schuyler Counties had no distressed census tracts in 2010 or 2019. Tompkins County had 1 census tract that was distressed in 2010, but its distressed status could not be determined in 2019.
The map below shows the census tracts that became distressed between 2010 and 2019.
Code
# map which tracts became distressed between 2010 and 2019mapview( distressed.tab, zcol ='if_Became_Distressed_2010_2019',alpha.regions =0.5,popup ="NAME",layer.name =c("Became Distressed (2010 -> 2019)"))
There are a few census tracts that do not appear on the map, although their popup labels work. The table below shows the three census tracts that have an “NA” value in the “if_Became_Distressed_2010_2019” column. These three tracts are missing at least 1 data point that was used to determine distressed status.
Code
# display median income and pct below poverty data data for tracts# that have NA 'if_Became_Distressed_2010_2019' valuest_tracts.distressed %>%filter(is.na(if_Became_Distressed_2010_2019)) %>%select(NAME, median_incomeE_2010, median_incomeE_2019, pct_below_poverty_2010, pct_below_poverty_2019) %>%st_drop_geometry() %>%gt()
NAME
median_incomeE_2010
median_incomeE_2019
pct_below_poverty_2010
pct_below_poverty_2019
Census Tract 9402, Cattaraugus County, New York
NA
NA
NaN
NaN
Census Tract 9400, Cattaraugus County, New York
NA
NA
0.5420290
0.2436709
Census Tract 2, Tompkins County, New York
110795
NA
0.6491352
0.6059628
The map below shows the census tracts that were distressed in 2010 and were no longer distressed in 2019.
Code
# map which tracts improved between 2010 and 2019mapview( distressed.tab, zcol ='if_Distressed_Then_Improved_2010_2019',alpha.regions =0.5,popup ="NAME",layer.name =c("Improved (2010 -> 2019)"))
As is the case with census tracts that became distressed, some of the tracts do not show up. The table below shows which tracts have an “NA” value in the ‘if_Distressed_Then_Improved_2010_2019’ column. These 4 census tracts are missing at least 1 data point that was used to determine distressed status.
Code
# display median income and pct below poverty data data for tracts# that have NA 'if_Distressed_Then_Improved_2010_2019' valuest_tracts.distressed %>%filter(is.na(if_Distressed_Then_Improved_2010_2019)) %>%select(NAME, median_incomeE_2010, median_incomeE_2019, pct_below_poverty_2010, pct_below_poverty_2019) %>%st_drop_geometry() %>%gt()
NAME
median_incomeE_2010
median_incomeE_2019
pct_below_poverty_2010
pct_below_poverty_2019
Census Tract 9402, Cattaraugus County, New York
NA
NA
NaN
NaN
Census Tract 9402, Allegany County, New York
NA
NA
NaN
0.0000000
Census Tract 9400, Cattaraugus County, New York
NA
NA
0.5420290
0.2436709
Census Tract 1, Tompkins County, New York
35833
NA
0.3029074
0.2594142
Most of the census tracts that became distressed between 2010 and 2019 are located in built-up areas, such as Binghamton, Jamestown, Dunkirk, Cortland, and Hornell. There were additionally a few rural tracts that became distressed, as well as the Allegany Indian Reservation centered around Salamanca in Cattaraugus County.
There were only 2 census tracts that improved from a distressed status: 1 in Broome County in between Binghamton and Johnson City (Census Tract 1) and 1 in eastern Dunkirk (Census Tract 354). In Census Tract 1, the median family income increased by over 64% and the percentage below poverty level increased by less than 4%. In Census Tract 354, the median family income increased by almost 46% and the percentage below poverty level decreased by over 20%.
Distressed Population and Land Cover Change Analysis
Analysis Set Up
Some percentage change values were calculated to be infinite values, which occurred when the value of some variable was 0 in 2010 and had increased by 2019. These values were edited to reflect a change of (an arbitrary value of) 1,000,000% so that they could be used in the correlation analysis.
Code
# define add_land_cover_type_area functionadd_land_cover_type_area <-function(summarize_df, df, col, lc_num) { summarize_df[1,as.character(col)] =ifelse(nrow(filter(df, land_cover_category == lc_num)) ==1,filter(df, land_cover_category == lc_num)$area_sqmi,0 )}# define gather_data functiongather_data <-function(lc_file, year, geog) {# set column names for different land cover categories developed_col =as.symbol(paste('developed_area_sqmi_', as.character(year), sep ='')) natural_barren_col =as.symbol(paste('natural_barren_area_sqmi_', as.character(year), sep ='')) cropland_col =as.symbol(paste('cropland_area_sqmi_', as.character(year), sep ='')) tree_cover_col =as.symbol(paste('tree_cover_area_sqmi_', as.character(year), sep ='')) grassland_col =as.symbol(paste('grassland_area_sqmi_', as.character(year), sep ='')) wetland_col =as.symbol(paste('wetland_area_sqmi_', as.character(year), sep ='')) water_col =as.symbol(paste('water_area_sqmi_', as.character(year), sep =''))# set distressed column name for the year distressed_col_yr =as.symbol(paste('if_Distressed_', as.character(year), sep =''))# set name of tot_pop_distressed column with year appended to end tot_pop_distressed_col <-as.symbol(paste('tot_pop_distressed_', as.character(year), sep =''))# set columns only used in tracts data gathering tot_below_poverty_est_col =as.symbol(paste('tot_below_povertyE_', as.character(year), sep='')) hhs_no_vehicles_est_col =as.symbol(paste('hhs_no_vehicleE_', as.character(year), sep =''))# set total population column to use in calculations tot_pop_est_col =as.symbol(paste('tot_popE_', as.character(year), sep ='')) tot_pop_col =as.symbol(paste('tot_pop_', as.character(year), sep ='')) tot_hhs_col =as.symbol(paste('tot_hhs_', as.character(year), sep ='')) tot_hhs_est_col =as.symbol(paste('tot_hhsE_', as.character(year), sep ='')) tot_below_poverty_col =as.symbol(paste('tot_below_poverty_', as.character(year), sep ='')) pop_civ_lab_force_col =as.symbol(paste('pop_gt_16_in_civ_lab_force_', as.character(year), sep ='')) pop_unemployed_col =as.symbol(paste('pop_gt_16_in_civ_lab_force_unemployed_', as.character(year), sep ='')) pop_distressed_col =as.symbol(paste('tot_pop_distressed_', as.character(year), sep ='')) hhs_no_vehicles_col =as.symbol(paste('hhs_no_vehicles_', as.character(year), sep ='')) area_col =as.symbol(paste('area_sqmi_', as.character(year), sep =''))# set names of new columns to be calculated pct_below_poverty_col =as.symbol(paste('pct_below_poverty_', as.character(year), sep ='')) pct_unemployed_col =as.symbol(paste('pct_unemployed_', as.character(year), sep ='')) pct_pop_distressed_col =as.symbol(paste('pct_pop_distressed_', as.character(year), sep ='')) pct_hhs_no_vehicles_col =as.symbol(paste('pct_hhs_no_vehicles_', as.character(year), sep ='')) pct_developed_col =as.symbol(paste('pct_developed_area_sqmi_', as.character(year), sep ='')) pct_natural_barren_col =as.symbol(paste('pct_natural_barren_area_sqmi_', as.character(year), sep ='')) pct_cropland_col =as.symbol(paste('pct_cropland_area_sqmi_', as.character(year), sep ='')) pct_tree_cover_col =as.symbol(paste('pct_tree_cover_area_sqmi_', as.character(year), sep ='')) pct_grassland_col =as.symbol(paste('pct_grassland_area_sqmi_', as.character(year), sep ='')) pct_wetland_col =as.symbol(paste('pct_wetland_area_sqmi_', as.character(year), sep ='')) pct_water_col =as.symbol(paste('pct_water_area_sqmi_', as.character(year), sep =''))# set names of columns to be edited or removed median_age_est_col =as.symbol(paste('median_ageE_', as.character(year), sep ='')) median_income_est_col =as.symbol(paste('median_incomeE_', as.character(year), sep ='')) new_median_age_est_col =as.symbol(paste('median_age_', as.character(year), sep ='')) new_median_income_est_col =as.symbol(paste('median_income_', as.character(year), sep ='')) median_age_moe_col =as.symbol(paste('median_ageM_', as.character(year), sep ='')) median_income_moe_col =as.symbol(paste('median_incomeM_', as.character(year), sep =''))# initialize index to use in data_list index =1# # initialize list to hold dataframe for each county or tractif (geog =='county') { data_list =vector('list', length =length(southern_tier_counties)) } else { data_list =vector('list', length =length(st_tracts.2010_2019)) }# run this if geog is set to 'county'if (geog =='county') {# iterate over each study county and get population, distressed, and zonal stats data,# then store resulting data frame in df object df <-for (i in southern_tier_counties) {# get county geography county_sf <- study_counties %>%filter(NAME == i)# get cropped & masked land cover raster for county county_lc_masked <-crop_raster(lc_file, county_sf)# calculate area of each land cover category in county county_zonal_stats <-calculate_zonal_stats(county_lc_masked) %>%summarize(!!developed_col :=filter(., land_cover_category ==1)$area_sqmi,!!natural_barren_col :=filter(., land_cover_category ==8)$area_sqmi,!!cropland_col :=filter(., land_cover_category ==2)$area_sqmi,!!tree_cover_col :=filter(., land_cover_category ==4)$area_sqmi,!!grassland_col :=filter(., land_cover_category ==3)$area_sqmi,!!wetland_col :=filter(., land_cover_category ==6)$area_sqmi,!!water_col :=filter(., land_cover_category ==5)$area_sqmi ) %>%mutate(county = i,geometry = county_sf$geometry) %>%st_as_sf(crs =st_crs(st_counties.2010_2019))# get county stats county_pop_data <- st_counties.2010_2019 %>%filter(county == i) %>%select(county, contains(as.character(year)) &!contains('pct'))# calculate number of people in each county that lived in tracts that# were distressed and improved and in tracts that became distressed county_distressed <- st_tracts.distressed %>%filter(county == i) %>%select(GEOID, NAME, county, contains('tot_popE'), contains('Distressed'))# total number of people living in distress for this year pop_distressed <- county_distressed %>%filter(!!distressed_col_yr ==TRUE) %>%summarize(!!tot_pop_distressed_col :=sum(!!tot_pop_est_col, na.rm =TRUE) ) %>%mutate(county = i) %>%relocate(geometry, .after =last_col())# get number of people who lived in areas that became distressed by 2019 pop_became_distressed <- county_distressed %>%filter(if_Became_Distressed_2010_2019 ==TRUE) %>%summarize(tot_pop_became_distressed_2010_2019 =sum(!!tot_pop_est_col, na.rm =TRUE) ) %>%mutate(county = i) %>%relocate(geometry, .after =last_col())# get number of people who lived in areas that improved by 2019 pop_improved <- county_distressed %>%filter(if_Distressed_Then_Improved_2010_2019 ==TRUE) %>%summarize(tot_pop_improved_2010_2019 =sum(!!tot_pop_est_col, na.rm =TRUE) ) %>%mutate(county = i) %>%relocate(geometry, .after =last_col())# join distressed data-related data frames together county_distressed.data <-st_join(pop_distressed, pop_became_distressed) %>%st_join(pop_improved)# join 3 dataframes, then add to list of county data frames d <-st_join(county_pop_data, county_distressed.data, suffix =c('', '.y')) %>%st_join(county_zonal_stats, suffix =c('', '.z')) %>%select(-c('county.y...17', 'county.y...19', 'county.x', 'county.z', !!median_age_moe_col, !!median_income_moe_col)) %>%rename(!!new_median_age_est_col :=!!median_age_est_col,!!new_median_income_est_col :=!!median_income_est_col ) %>%mutate(!!pct_below_poverty_col := (!!tot_below_poverty_col /!!tot_pop_col) *100,!!pct_unemployed_col := (!!pop_unemployed_col /!!pop_civ_lab_force_col) *100,!!pct_pop_distressed_col := (!!pop_distressed_col /!!tot_pop_col) *100,!!pct_hhs_no_vehicles_col := (!!hhs_no_vehicles_col /!!tot_hhs_col) *100,!!pct_developed_col := (!!developed_col /!!area_col) *100,!!pct_natural_barren_col := (!!natural_barren_col /!!area_col) *100,!!pct_cropland_col := (!!cropland_col /!!area_col) *100,!!pct_tree_cover_col := (!!tree_cover_col /!!area_col) *100,!!pct_grassland_col := (!!grassland_col /!!area_col) *100,!!pct_wetland_col := (!!wetland_col /!!area_col) *100,!!pct_water_col := (!!water_col /!!area_col) *100 )# add data frame to county data list data_list[[index]] <- d# add 1 to index index = index +1 } } else { # run this if geography is set to 'tract'# iterate over each study tract and get population, distressed, and zonal stats data,# then store resulting data frame in df object df <-for (i in st_tracts.2010_2019$GEOID) {# get tract geography tract_sf <- st_tracts.2010_2019 %>%filter(GEOID == i)# get cropped & masked land cover raster for tract tract_lc_masked <-crop_raster(lc_file, tract_sf)# calculate area of each land cover category in tract tract_zonal_stats <-calculate_zonal_stats(tract_lc_masked)# create vector of column names in summarized area table col.names <-c(developed_col, natural_barren_col, cropland_col, tree_cover_col, grassland_col, wetland_col, water_col)# create new single-row data frame with column names called tr.zs# to store area stats for census tract tr.zs <-as.data.frame(matrix(rep(0, length(col.names)), nrow=1))names(tr.zs) <- col.names# add area for each land cover type to new df tr.zs[1, as.character(developed_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, developed_col, 1) tr.zs[1, as.character(cropland_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, cropland_col, 2) tr.zs[1, as.character(grassland_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, developed_col, 3) tr.zs[1, as.character(tree_cover_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, tree_cover_col, 4) tr.zs[1, as.character(water_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, water_col, 5) tr.zs[1, as.character(wetland_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, wetland_col, 6) tr.zs[1, as.character(natural_barren_col)] <-add_land_cover_type_area(tr.zs, tract_zonal_stats, natural_barren_col, 8)# add GEOID, total area, and geometry columns to tr.zs then turn into sf tr.zs <- tr.zs %>%mutate(tract = i,!!area_col :=!!developed_col +!!natural_barren_col +!!cropland_col +!!tree_cover_col +!!grassland_col +!!wetland_col +!!water_col,geometry = tract_sf$geometry) %>%st_as_sf(crs =st_crs(st_tracts.2010_2019))# get tracts stats tract_pop_data <-filter(st_tracts.2010_2019, GEOID == i) %>%select(GEOID, NAME, county, contains(as.character(year))) %>%rename(!!pop_civ_lab_force_col :=as.symbol(paste('pop_gt_16_in_civilian_labor_force_', as.character(year), sep ='')),!!pop_unemployed_col :=as.symbol(paste('pop_gt_16_in_civilian_labor_force_unemployed_', as.character(year), sep ='')) )# get distressed data for tract tract_distressed <- st_tracts.distressed %>%filter(GEOID == i) %>%select(GEOID, contains('Became_Distressed'), contains('Improved'))# join 3 dataframes, then add to list of county data frames d <-st_join(tract_pop_data, tract_distressed, suffix =c('', '.y')) %>%st_join(tr.zs, suffix =c('', '.z')) %>%select(-c(GEOID.y, tract, !!median_age_moe_col, !!median_income_moe_col)) %>%rename(!!new_median_age_est_col :=!!median_age_est_col,!!new_median_income_est_col :=!!median_income_est_col ) %>%mutate(!!pct_below_poverty_col := (!!tot_below_poverty_est_col /!!tot_pop_est_col) *100,!!pct_unemployed_col := (!!pop_unemployed_col /!!pop_civ_lab_force_col) *100,!!pct_hhs_no_vehicles_col := (!!hhs_no_vehicles_est_col /!!tot_hhs_est_col) *100,!!pct_developed_col := (!!developed_col /!!area_col) *100,!!pct_natural_barren_col := (!!natural_barren_col /!!area_col) *100,!!pct_cropland_col := (!!cropland_col /!!area_col) *100,!!pct_tree_cover_col := (!!tree_cover_col /!!area_col) *100,!!pct_grassland_col := (!!grassland_col /!!area_col) *100,!!pct_wetland_col := (!!wetland_col /!!area_col) *100,!!pct_water_col := (!!water_col /!!area_col) *100 )# add data frame to county data list data_list[[index]] <- d# add 1 to index index = index +1 } }# bind geography data frames together then return data data <-bind_rows(data_list)return(data)}
Tract-Level Population and Land Cover Change Data
Code
# get full counties sfs for 2010 and 2019 and fill NA with 0, then join them into a single sffinal_tracts_df.2010<-gather_data(st_lc_2010_masked, 2010, 'tract')final_tracts_df.2010[is.na(final_tracts_df.2010)] <-0final_tracts_df.2019<-gather_data(st_lc_2019_masked, 2019, 'tract')final_tracts_df.2019[is.na(final_tracts_df.2019)] <-0final_tracts_df <-st_join(final_tracts_df.2010, final_tracts_df.2019, suffix =c('', '.y'), largest =TRUE) %>%select(-contains('.y'), -contains('M_'), -contains('chg')) %>%rename_with(~str_replace(., 'E_', '_'), grep('E_', colnames(.), value =TRUE)) %>%mutate(pct_pop_chg = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) *100,pct_hhs_chg = ((tot_hhs_2019 - tot_hhs_2010) / tot_hhs_2010) *100,pct_median_age_chg = ((median_age_2019 - median_age_2010) / median_age_2010) *100,pct_median_income_chg = ((median_income_2019 - median_income_2010) / median_income_2010) *100,pct_below_poverty_chg = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) *100,pct_unemployed_chg = ((pct_unemployed_2019 - pct_unemployed_2010) / pct_unemployed_2010) *100,pct_hhs_no_vehicles_chg = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) *100,pct_developed_chg = ((pct_developed_area_sqmi_2019 - pct_developed_area_sqmi_2010) / pct_developed_area_sqmi_2010) *100,pct_natural_barren_chg = ((pct_natural_barren_area_sqmi_2019 - pct_natural_barren_area_sqmi_2010) / pct_natural_barren_area_sqmi_2010) *100,pct_cropland_chg = ((pct_cropland_area_sqmi_2019 - pct_cropland_area_sqmi_2010) / pct_cropland_area_sqmi_2010) *100,pct_tree_cover_chg = ((pct_tree_cover_area_sqmi_2019 - pct_tree_cover_area_sqmi_2010) / pct_tree_cover_area_sqmi_2010) *100,pct_grassland_chg = ((pct_grassland_area_sqmi_2019 - pct_grassland_area_sqmi_2010) / pct_grassland_area_sqmi_2010) *100,pct_wetland_chg = ((pct_wetland_area_sqmi_2019 - pct_wetland_area_sqmi_2010) / pct_wetland_area_sqmi_2010) *100,pct_water_chg = ((pct_water_area_sqmi_2019 - pct_water_area_sqmi_2010) / pct_water_area_sqmi_2010) *100 ) %>%mutate_if(is.numeric, ~replace_na(., 0) %>%replace(., is.infinite(.), 1000000)) %>%relocate(geometry, .after =last_col())final_tracts_df[is.na(final_tracts_df)] <-0# display county-level table of datafinal_tracts_df %>%select(NAME, county, grep('chg', colnames(.), value =TRUE), contains('Became'), contains('Improved')) %>%relocate(if_Became_Distressed_2010_2019, .after = pct_below_poverty_chg) %>%relocate(if_Distressed_Then_Improved_2010_2019, .after = if_Became_Distressed_2010_2019) %>%mutate(NAME =str_split(.$NAME, ',', simplify =TRUE)) %>%st_drop_geometry() %>%gt(groupname_col ='county') %>%tab_options(row_group.as_column =TRUE, container.height =1500,container.overflow.y =TRUE) %>%tab_stubhead(label ='county') %>%tab_header(title =md('**Changes in Population Characteristics, Economic Indicators, and Land Cover**'),subtitle =md('By Southern Tier Census Tract (2010 - 2019)') ) %>%cols_label(pct_pop_chg =md('**% Pop Change**'),pct_hhs_chg =md('**% HHs Change**'),pct_median_age_chg =md('**% Median Age Change**'),pct_median_income_chg =md('**% Median Income Change**'),pct_below_poverty_chg =md('**% Pop Below Poverty Change**'),if_Became_Distressed_2010_2019 =md('**If Became Distressed**'),if_Distressed_Then_Improved_2010_2019 =md('**If Improved**'),pct_unemployed_chg =md('**% Unemployment Rate Change**'),pct_hhs_no_vehicles_chg =md('**% HHs No Vehicle Change**'),pct_developed_chg =md('**% Developed Change**'),pct_natural_barren_chg =md('**% Natural Barren Change**'),pct_cropland_chg =md('**% Cropland Change**'),pct_tree_cover_chg =md('**% Tree Cover Change**'),pct_grassland_chg =md('**% Grassland Change**'),pct_wetland_chg =md('**% Wetland Change**'),pct_water_chg =md('**% Water Change**') ) %>%fmt_percent(decimals =1, scale_values =FALSE)
Changes in Population Characteristics, Economic Indicators, and Land Cover
By Southern Tier Census Tract (2010 - 2019)
county
NAME
% Pop Change
% HHs Change
% Median Age Change
% Median Income Change
% Pop Below Poverty Change
If Became Distressed
If Improved
% Unemployment Rate Change
% HHs No Vehicle Change
% Developed Change
% Natural Barren Change
% Cropland Change
% Tree Cover Change
% Grassland Change
% Wetland Change
% Water Change
Cortland
Census Tract 9703
−7.5%
−4.4%
15.8%
−2.0%
−52.2%
FALSE
FALSE
−66.6%
−66.0%
−0.6%
85.7%
1.0%
0.0%
50.0%
0.0%
0.0%
Census Tract 9706
−3.9%
−13.0%
−13.0%
10.9%
68.2%
FALSE
FALSE
−53.1%
−30.7%
−0.2%
−0.0%
16.7%
0.0%
50.0%
0.0%
0.0%
Census Tract 9701
−16.7%
−3.1%
13.9%
32.4%
15.3%
FALSE
FALSE
−50.8%
57.1%
1.2%
17.5%
0.0%
−0.4%
20.5%
−0.1%
4.6%
Census Tract 9702
−1.4%
1.9%
19.9%
53.8%
3.6%
FALSE
FALSE
−63.5%
12.4%
0.9%
18.8%
−0.1%
0.2%
−5.8%
0.0%
0.1%
Census Tract 9704
−5.3%
−1.7%
3.8%
8.9%
−19.6%
FALSE
FALSE
34.3%
20.7%
0.1%
2.8%
−0.3%
0.5%
−16.8%
0.1%
9.7%
Census Tract 9705
7.4%
8.2%
−2.4%
−8.3%
26.2%
TRUE
FALSE
−28.8%
−43.1%
−0.4%
28.6%
0.5%
2.3%
−27.3%
−0.0%
−0.0%
Census Tract 9707
3.7%
−1.7%
−18.3%
18.6%
56.1%
FALSE
FALSE
−34.9%
−26.2%
0.0%
100.0%
−2.3%
0.0%
0.0%
0.0%
0.0%
Census Tract 9708
−17.3%
5.3%
1.5%
171.4%
1,000,000.0%
FALSE
FALSE
217.1%
−100.0%
−0.3%
66.7%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 9709
−6.6%
−3.0%
−12.2%
−8.8%
−8.9%
TRUE
FALSE
−25.2%
−30.0%
−0.5%
68.7%
−0.5%
1.6%
−13.6%
0.0%
0.0%
Census Tract 9710
−2.0%
−4.0%
−5.7%
29.2%
−20.1%
FALSE
FALSE
3.4%
122.5%
0.3%
32.7%
−0.2%
0.2%
−18.0%
−0.2%
18.7%
Census Tract 9711
−1.5%
4.0%
12.5%
29.9%
10.8%
FALSE
FALSE
−9.8%
−35.2%
0.8%
248.6%
−0.1%
0.0%
−2.6%
−0.0%
−0.9%
Census Tract 9712
7.1%
7.6%
0.2%
31.8%
84.0%
FALSE
FALSE
38.9%
44.2%
2.8%
32.8%
−0.2%
−0.2%
10.7%
0.0%
−4.8%
Delaware
Census Tract 9703
4.7%
5.7%
8.4%
4.6%
15.1%
FALSE
FALSE
−40.9%
−81.4%
0.2%
20.0%
0.0%
0.4%
−27.1%
−0.1%
1.4%
Census Tract 9709
171.4%
0.0%
2.6%
0.0%
0.0%
FALSE
FALSE
−37.3%
0.0%
−0.9%
25.0%
−0.0%
0.3%
50.0%
0.0%
0.0%
Census Tract 9701
−8.9%
0.3%
4.3%
10.8%
12.7%
FALSE
FALSE
−54.4%
−10.6%
−0.4%
37.6%
−0.1%
0.0%
−6.4%
−0.1%
−0.1%
Census Tract 9714
−7.3%
−6.0%
4.3%
22.4%
−12.6%
FALSE
FALSE
7.7%
56.4%
−0.6%
8.5%
0.4%
−0.1%
11.3%
−0.2%
0.4%
Census Tract 9702
−0.3%
0.2%
8.0%
18.9%
25.3%
FALSE
FALSE
−17.6%
96.8%
0.1%
83.3%
−0.0%
0.1%
−9.1%
0.0%
−1.6%
Census Tract 9704
−7.4%
−9.8%
9.0%
24.1%
56.5%
FALSE
FALSE
−37.3%
24.0%
−0.3%
72.6%
−0.2%
0.4%
−30.8%
0.5%
−0.9%
Census Tract 9705
−14.1%
−11.7%
23.0%
23.2%
−3.0%
FALSE
FALSE
−29.7%
48.7%
−0.5%
1.7%
−0.1%
0.2%
−13.6%
0.1%
−0.8%
Census Tract 9706
−7.6%
−1.9%
2.2%
2.8%
33.4%
TRUE
FALSE
−54.3%
−8.0%
−0.2%
11.6%
−0.0%
−0.1%
10.7%
−0.0%
−0.9%
Census Tract 9707
0.4%
−1.8%
6.5%
23.7%
9.2%
FALSE
FALSE
−30.9%
−36.1%
−0.2%
5.4%
−0.0%
0.1%
−9.4%
−0.2%
−0.8%
Census Tract 9708
−27.2%
−26.6%
3.1%
38.0%
31.2%
FALSE
FALSE
−46.2%
3.8%
−0.7%
41.3%
−0.1%
0.1%
−7.3%
−0.0%
−0.0%
Census Tract 9710
0.9%
7.6%
16.7%
28.7%
59.1%
FALSE
FALSE
−15.9%
56.9%
−0.2%
38.8%
−0.2%
0.1%
−11.8%
0.0%
0.7%
Census Tract 9711
−13.0%
−4.0%
7.7%
10.5%
89.8%
FALSE
FALSE
−62.6%
39.4%
−0.3%
4.0%
0.0%
0.0%
−10.7%
0.0%
−4.9%
Census Tract 9712
−8.5%
4.4%
26.9%
32.9%
−3.9%
FALSE
FALSE
−5.4%
160.2%
−0.5%
14.6%
0.2%
0.0%
−13.4%
−0.2%
−12.0%
Census Tract 9713
−12.7%
−17.0%
8.8%
62.0%
42.6%
FALSE
FALSE
−87.9%
25.3%
−0.3%
3.6%
0.4%
−0.1%
6.1%
−0.4%
−0.1%
Broome
Census Tract 2
−7.1%
−4.9%
−3.4%
34.6%
11.7%
TRUE
FALSE
−24.7%
58.5%
−0.2%
75.0%
−0.0%
−0.0%
−0.0%
0.0%
0.0%
Census Tract 18
−10.6%
−19.0%
4.9%
8.0%
−29.6%
FALSE
FALSE
−74.1%
−26.2%
−0.1%
20.0%
0.0%
0.1%
0.0%
0.0%
0.0%
Census Tract 122.01
−2.6%
1.1%
−4.8%
7.9%
7.8%
FALSE
FALSE
−34.0%
−100.0%
−0.6%
4.2%
−0.1%
−0.3%
76.9%
−0.2%
1.8%
Census Tract 122.02
−7.2%
−7.7%
−4.4%
20.5%
84.9%
FALSE
FALSE
11.0%
−54.9%
−0.3%
−7.9%
−0.1%
0.2%
−10.3%
−0.1%
1.5%
Census Tract 125
−4.9%
4.0%
4.5%
60.0%
−17.0%
FALSE
FALSE
−12.7%
88.5%
−0.4%
46.0%
−0.0%
−0.1%
−16.0%
−0.3%
0.1%
Census Tract 131
−1.4%
1.6%
6.9%
14.3%
13.4%
FALSE
FALSE
−22.0%
64.0%
−0.4%
70.0%
4.5%
0.0%
0.0%
0.0%
0.0%
Census Tract 134
0.4%
−5.9%
−16.0%
−0.6%
−4.2%
FALSE
FALSE
13.1%
0.9%
0.3%
1,150.0%
5.0%
−11.9%
−0.0%
0.0%
0.0%
Census Tract 138
−13.2%
−6.3%
5.8%
5.7%
−53.7%
FALSE
FALSE
−10.0%
3.6%
0.1%
−20.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 143.02
−3.5%
20.7%
0.0%
14.6%
322.1%
FALSE
FALSE
37.6%
1,000,000.0%
−1.1%
162.5%
1.8%
−0.1%
60.0%
−3.4%
7.5%
Census Tract 145
−3.9%
−2.9%
10.7%
−6.0%
85.1%
FALSE
FALSE
−39.0%
−29.4%
0.2%
200.0%
−0.1%
−0.1%
14.3%
−0.2%
−0.2%
Census Tract 146
5.1%
−0.1%
6.6%
14.8%
113.0%
FALSE
FALSE
−63.2%
−11.1%
1.0%
26.7%
0.0%
−0.0%
−10.9%
−0.2%
−22.0%
Census Tract 1
17.6%
0.8%
6.8%
64.2%
3.8%
FALSE
TRUE
469.0%
40.4%
0.0%
−0.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 3
−22.3%
−14.5%
−37.3%
87.0%
30.3%
FALSE
FALSE
−28.6%
−18.8%
−2.4%
2,466.7%
−0.8%
−0.5%
1,000,000.0%
−0.0%
−17.5%
Census Tract 4
−21.4%
−25.5%
7.6%
77.1%
56.5%
TRUE
FALSE
24.5%
50.8%
−2.1%
800.0%
100.0%
12.5%
−0.0%
−0.0%
−1.2%
Census Tract 5
11.0%
−2.4%
−20.1%
−2.4%
26.6%
FALSE
FALSE
−8.0%
1.5%
−0.3%
107.1%
25.0%
0.0%
0.0%
0.0%
−6.0%
Census Tract 6
−4.5%
−4.4%
4.6%
35.8%
−11.7%
FALSE
FALSE
−1.5%
35.2%
−1.0%
14.2%
50.0%
0.0%
0.0%
−0.0%
−0.0%
Census Tract 7
−8.7%
−10.1%
−3.8%
16.4%
173.7%
TRUE
FALSE
8.8%
−63.1%
0.1%
60.0%
−1.2%
−0.1%
−50.0%
0.0%
0.0%
Census Tract 9
12.4%
8.8%
−1.4%
4.9%
−27.3%
FALSE
FALSE
−26.0%
25.6%
−0.1%
25.0%
0.0%
0.0%
0.0%
0.0%
−0.2%
Census Tract 12
1.7%
−9.8%
−41.8%
13.0%
−7.0%
FALSE
FALSE
−8.5%
−4.9%
0.0%
6.2%
−100.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 13
5.5%
0.7%
3.5%
−16.5%
1.4%
FALSE
FALSE
75.4%
16.2%
−0.0%
0.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 14
1.2%
−3.4%
−0.3%
47.0%
62.9%
FALSE
FALSE
197.6%
−13.8%
−0.1%
100.0%
0.0%
−0.0%
0.0%
−1.2%
−0.0%
Census Tract 15
−11.2%
−4.3%
−6.2%
67.3%
−63.4%
FALSE
FALSE
12.3%
15.5%
−0.0%
300.0%
−5.3%
0.0%
0.0%
0.0%
0.0%
Census Tract 16
−15.6%
−21.5%
6.9%
27.3%
2.3%
FALSE
FALSE
−64.8%
−39.5%
−0.2%
0.0%
2.2%
0.1%
50.0%
0.0%
0.0%
Census Tract 17
−4.2%
2.8%
−11.8%
−18.5%
33.4%
TRUE
FALSE
76.1%
−8.3%
−0.0%
25.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 102
−4.4%
1.3%
17.0%
33.1%
−23.0%
FALSE
FALSE
−37.3%
102.3%
−0.2%
16.0%
−0.1%
−0.0%
7.0%
−0.0%
−1.0%
Census Tract 119.01
−4.6%
1.3%
2.3%
6.8%
−6.6%
FALSE
FALSE
109.5%
10.5%
0.0%
22.6%
−0.1%
0.2%
−20.5%
−0.1%
0.2%
Census Tract 119.02
−3.5%
5.5%
20.6%
35.2%
−5.9%
FALSE
FALSE
−53.1%
205.5%
0.4%
1.1%
−0.1%
−0.2%
36.0%
0.0%
0.6%
Census Tract 119.03
−3.0%
1.7%
−0.5%
9.4%
−57.2%
FALSE
FALSE
−37.7%
72.8%
0.9%
15.0%
−0.1%
−0.1%
12.7%
1.4%
−8.6%
Census Tract 120
3.9%
9.8%
5.6%
22.6%
−36.8%
FALSE
FALSE
−31.6%
23.2%
0.6%
13.5%
−0.1%
−0.0%
−3.7%
0.0%
0.0%
Census Tract 121.01
−6.0%
−12.1%
3.4%
17.4%
204.3%
FALSE
FALSE
−40.0%
24.2%
0.2%
−2.3%
0.3%
−0.1%
−0.4%
0.4%
0.4%
Census Tract 121.02
−3.7%
−6.6%
5.6%
19.0%
−21.6%
FALSE
FALSE
−38.7%
60.6%
0.1%
22.7%
−0.9%
0.4%
−15.7%
−0.2%
−1.1%
Census Tract 121.03
−5.8%
−10.6%
6.3%
12.8%
360.8%
FALSE
FALSE
−19.9%
−26.5%
0.1%
78.8%
−0.1%
−0.1%
11.9%
−1.5%
6.2%
Census Tract 123
−4.1%
18.0%
20.1%
28.0%
−24.7%
FALSE
FALSE
−20.5%
1.8%
0.2%
25.9%
−0.2%
0.1%
−8.0%
0.0%
−0.7%
Census Tract 124
−9.7%
−0.2%
24.9%
33.4%
−16.4%
FALSE
FALSE
−54.0%
−51.1%
−0.4%
38.6%
−0.1%
0.2%
−25.6%
−0.2%
−0.1%
Census Tract 126
−3.8%
−2.2%
6.4%
14.9%
23.7%
FALSE
FALSE
78.2%
250.3%
−0.1%
7.0%
0.0%
−0.0%
−2.8%
0.0%
−0.2%
Census Tract 127.01
−6.3%
−3.2%
6.0%
2.5%
−36.7%
FALSE
FALSE
28.2%
−12.0%
1.2%
80.2%
−0.7%
−0.8%
24.7%
0.0%
0.4%
Census Tract 127.02
−3.5%
3.8%
11.6%
11.0%
−53.0%
FALSE
FALSE
−43.2%
−31.4%
−0.1%
15.1%
0.0%
0.0%
−12.1%
0.0%
0.0%
Census Tract 128
−4.2%
26.5%
3.7%
22.1%
−31.9%
FALSE
FALSE
−19.5%
−8.1%
−0.0%
8.8%
0.1%
−0.2%
13.8%
0.0%
−0.4%
Census Tract 129
49.2%
58.3%
45.6%
12.2%
−84.0%
FALSE
FALSE
−38.1%
187.8%
2.4%
−22.6%
−0.4%
0.0%
6.8%
1.3%
−3.3%
Census Tract 130
−4.8%
−12.1%
6.8%
14.3%
161.4%
FALSE
FALSE
−47.6%
−84.8%
−1.0%
25.8%
6.9%
−1.2%
129.4%
−0.2%
0.0%
Census Tract 132.01
7.5%
3.5%
−4.5%
31.3%
184.4%
FALSE
FALSE
32.1%
−70.1%
−0.1%
1,000,000.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 132.02
−12.2%
−3.7%
13.5%
21.8%
−26.6%
FALSE
FALSE
135.1%
8.8%
−0.5%
1,000,000.0%
1.2%
−0.0%
−0.0%
−0.0%
0.0%
Census Tract 133.01
4.1%
−5.3%
−1.9%
8.8%
17.9%
FALSE
FALSE
−4.2%
−55.8%
1.6%
123.5%
−6.9%
−0.4%
−8.7%
0.0%
0.0%
Census Tract 133.03
−6.5%
7.4%
14.4%
−4.9%
17.6%
FALSE
FALSE
−72.6%
81.5%
−0.0%
−4.8%
−0.0%
0.0%
−4.1%
−0.1%
7.0%
Census Tract 133.04
−18.2%
−4.8%
15.1%
57.9%
−16.9%
FALSE
FALSE
−7.2%
166.2%
−0.0%
180.0%
−0.1%
−0.2%
8.9%
0.0%
−4.5%
Census Tract 135
−4.7%
−36.6%
−12.0%
21.3%
102.9%
TRUE
FALSE
−35.7%
7.4%
−0.3%
1,000,000.0%
1,000,000.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 136
−3.0%
−13.0%
13.2%
54.0%
26.1%
FALSE
FALSE
−10.8%
2.8%
−0.2%
1,000,000.0%
0.0%
0.0%
1,000,000.0%
0.0%
0.0%
Census Tract 137
−10.2%
2.9%
11.1%
44.8%
−23.8%
FALSE
FALSE
1.7%
51.7%
−0.4%
52.6%
0.0%
0.8%
−4.6%
0.0%
0.0%
Census Tract 139
18.2%
4.4%
−8.0%
25.5%
−1.9%
FALSE
FALSE
−28.0%
−24.6%
−0.7%
100.0%
100.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 140
−9.1%
−16.8%
−14.0%
23.5%
−23.1%
FALSE
FALSE
−45.9%
54.0%
−0.4%
1,000,000.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 141
−0.1%
−8.9%
−9.4%
21.0%
54.8%
FALSE
FALSE
31.2%
−4.7%
−0.3%
200.0%
1.4%
0.0%
100.0%
0.0%
0.0%
Census Tract 142
−15.3%
−8.6%
0.2%
19.6%
70.9%
FALSE
FALSE
−67.0%
−54.7%
0.2%
9.6%
−1.0%
−0.6%
100.0%
0.0%
0.0%
Census Tract 143.01
3.7%
−1.4%
−4.6%
−1.0%
89.6%
FALSE
FALSE
−59.3%
82.7%
−0.3%
3.4%
0.6%
−0.1%
8.6%
−0.4%
−1.0%
Census Tract 144
7.3%
5.5%
−8.1%
−3.9%
353.7%
FALSE
FALSE
−25.3%
−47.6%
0.1%
34.8%
0.0%
−0.3%
6.3%
0.0%
0.0%
Census Tract 11
13.7%
−10.6%
−24.9%
−49.0%
31.4%
FALSE
FALSE
169.2%
17.4%
−0.5%
29.4%
0.0%
0.0%
1,000,000.0%
−0.0%
−0.7%
Cattaraugus
Census Tract 9402
0.0%
0.0%
0.0%
0.0%
0.0%
FALSE
FALSE
0.0%
0.0%
17.9%
1,000,000.0%
−6.0%
0.1%
0.0%
0.0%
−0.0%
Census Tract 9603
−0.1%
0.0%
10.8%
38.8%
−11.6%
FALSE
FALSE
−60.4%
−39.7%
0.9%
6.6%
−0.0%
−0.1%
8.4%
0.0%
−2.5%
Census Tract 9612
−8.0%
−5.1%
−0.2%
13.5%
2.1%
FALSE
FALSE
−14.2%
50.5%
0.3%
16.0%
0.7%
−0.1%
4.8%
−2.3%
−4.7%
Census Tract 9400
−8.4%
2.0%
17.1%
0.0%
−55.0%
FALSE
FALSE
52.2%
−100.0%
1.5%
−17.5%
1.6%
0.1%
27.7%
0.2%
−2.0%
Census Tract 9403
−10.5%
−14.5%
−8.0%
2.2%
26.4%
TRUE
FALSE
−32.9%
29.7%
−0.5%
0.1%
1.4%
−0.1%
15.5%
−0.1%
−0.0%
Census Tract 9601
−7.0%
−6.0%
7.4%
19.5%
−2.4%
FALSE
FALSE
−67.9%
368.6%
4.2%
32.8%
0.1%
−0.4%
1.2%
0.0%
−0.7%
Census Tract 9602
−12.7%
−10.8%
22.2%
15.8%
−3.3%
FALSE
FALSE
12.0%
98.2%
−0.2%
51.9%
0.1%
−0.5%
26.2%
−0.2%
−0.9%
Census Tract 9604
−6.2%
−3.9%
−0.7%
32.3%
21.4%
FALSE
FALSE
−48.8%
158.6%
−0.0%
3.7%
0.0%
0.0%
−11.0%
−0.1%
−1.2%
Census Tract 9605
−5.9%
7.6%
−2.0%
1.9%
−6.8%
TRUE
FALSE
−1.5%
28.4%
2.3%
24.6%
−0.0%
−0.3%
11.1%
0.0%
4.1%
Census Tract 9606
2.7%
0.8%
0.2%
24.8%
−8.2%
FALSE
FALSE
−35.1%
2.4%
−0.3%
46.7%
0.0%
−0.3%
10.0%
−0.1%
8.7%
Census Tract 9607.02
−14.8%
−14.0%
8.1%
25.8%
28.3%
FALSE
FALSE
−36.5%
−44.9%
−0.4%
11.2%
0.1%
−0.3%
19.5%
−0.2%
16.3%
Census Tract 9608
−2.8%
−2.4%
4.8%
17.4%
−6.6%
FALSE
FALSE
−10.4%
−19.8%
−0.3%
2.4%
−0.0%
−0.0%
5.2%
0.1%
−7.4%
Census Tract 9610
4.5%
4.1%
5.5%
−0.5%
93.8%
FALSE
FALSE
84.8%
203.4%
−0.4%
30.5%
0.3%
−0.1%
−2.9%
0.2%
13.0%
Census Tract 9611
9.4%
11.5%
3.5%
23.2%
−5.0%
FALSE
FALSE
−59.0%
−53.2%
−0.6%
54.7%
−0.6%
−0.0%
0.5%
1.5%
3.2%
Census Tract 9613
−9.1%
13.4%
48.9%
11.1%
−9.1%
FALSE
FALSE
−55.0%
−29.9%
−0.5%
12.5%
−0.1%
−0.1%
8.2%
−0.0%
0.2%
Census Tract 9614
−2.8%
0.3%
−1.7%
29.9%
−6.5%
FALSE
FALSE
−50.1%
116.4%
0.7%
22.5%
−0.0%
−0.4%
12.8%
0.1%
0.5%
Census Tract 9615
−5.1%
−11.9%
−8.9%
3.8%
114.8%
FALSE
FALSE
−52.9%
12.0%
−0.8%
150.0%
3.8%
−0.2%
−24.2%
0.0%
0.0%
Census Tract 9616
−11.3%
−6.3%
6.1%
34.5%
−0.2%
FALSE
FALSE
−47.0%
81.9%
−0.8%
244.4%
2.5%
−1.7%
−10.0%
0.0%
3.5%
Census Tract 9617
−6.7%
−1.0%
−4.6%
9.5%
32.2%
FALSE
FALSE
−42.0%
20.6%
−3.8%
587.5%
85.4%
0.0%
−68.0%
−0.0%
−0.0%
Census Tract 9618
−1.7%
−10.9%
3.6%
37.2%
−28.3%
FALSE
FALSE
−26.6%
35.4%
−0.1%
57.9%
−0.2%
−0.4%
4.5%
0.0%
0.0%
Census Tract 9622
11.5%
4.8%
2.9%
23.9%
16.3%
FALSE
FALSE
−52.5%
17.6%
0.3%
32.0%
−0.1%
−0.2%
15.1%
−0.6%
9.9%
Chautauqua
Census Tract 306
−8.9%
−6.5%
1.9%
20.1%
−27.5%
FALSE
FALSE
−49.1%
−10.8%
−0.5%
24.3%
0.9%
0.1%
33.3%
0.0%
0.0%
Census Tract 354
−2.9%
−7.6%
−3.1%
45.9%
−20.1%
FALSE
TRUE
−0.9%
−19.8%
−0.0%
−3.2%
0.0%
1.1%
0.0%
0.0%
0.0%
Census Tract 359.02
−18.1%
−9.6%
1.5%
−46.4%
118.4%
FALSE
FALSE
−32.3%
−32.7%
0.4%
0.0%
−6.3%
0.0%
0.0%
0.0%
0.0%
Census Tract 367
−5.2%
−3.6%
−2.4%
45.4%
−42.6%
FALSE
FALSE
−56.9%
21.0%
0.9%
78.6%
−0.0%
0.0%
−1.2%
−0.0%
−1.2%
Census Tract 370
−3.8%
7.4%
10.1%
46.8%
69.4%
FALSE
FALSE
−38.6%
−100.0%
−0.4%
−5.6%
0.1%
−0.1%
1.3%
0.0%
12.8%
Census Tract 301
−3.6%
0.5%
24.9%
39.6%
5.2%
FALSE
FALSE
−54.5%
9.2%
−0.5%
7.5%
5.0%
0.5%
200.0%
0.0%
0.0%
Census Tract 302
4.8%
−3.4%
−8.9%
19.7%
117.6%
TRUE
FALSE
−53.1%
32.1%
0.0%
0.0%
0.0%
−0.6%
25.0%
0.0%
0.0%
Census Tract 303
−7.6%
−3.9%
−10.5%
−9.0%
43.1%
FALSE
FALSE
−70.7%
−18.7%
−1.5%
13.1%
0.2%
0.2%
40.0%
0.0%
0.0%
Census Tract 304
−4.5%
−7.8%
−1.0%
0.3%
2.6%
FALSE
FALSE
−44.7%
−54.5%
−0.3%
4.0%
9.3%
0.0%
−0.0%
−0.0%
−0.0%
Census Tract 305
9.8%
2.7%
−12.7%
−10.7%
3.0%
FALSE
FALSE
−41.7%
9.4%
−1.7%
42.9%
150.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 307
−17.4%
−3.8%
17.1%
27.4%
−3.9%
FALSE
FALSE
−65.5%
−12.9%
−0.4%
40.0%
0.3%
0.2%
0.0%
−0.0%
0.0%
Census Tract 308
−12.1%
−18.1%
4.0%
−0.4%
178.3%
TRUE
FALSE
166.1%
83.2%
−0.0%
100.0%
−0.5%
−0.7%
28.6%
0.0%
0.0%
Census Tract 351
−12.4%
−8.4%
0.9%
23.1%
−13.7%
FALSE
FALSE
−25.7%
−7.8%
−0.4%
−1.4%
0.1%
−0.0%
2.2%
0.0%
3.3%
Census Tract 353
−3.6%
−1.0%
6.9%
14.5%
−34.9%
FALSE
FALSE
−38.3%
96.4%
−0.9%
−17.6%
0.3%
0.0%
−6.5%
−0.0%
2.0%
Census Tract 355
−9.5%
−2.5%
20.3%
13.4%
−17.0%
TRUE
FALSE
112.3%
31.6%
−1.2%
−8.2%
30.1%
3.2%
58.3%
−0.0%
27.3%
Census Tract 356
−5.7%
−7.6%
2.1%
−4.1%
87.8%
TRUE
FALSE
−66.7%
53.7%
−0.6%
9.7%
11.3%
−1.6%
22.7%
0.0%
−0.5%
Census Tract 357
−5.6%
−9.5%
25.4%
25.4%
−13.0%
FALSE
FALSE
116.7%
−47.1%
−0.1%
−25.0%
1.5%
−0.6%
−0.0%
−0.0%
0.0%
Census Tract 358
−9.1%
−20.4%
−10.0%
30.3%
−29.5%
FALSE
FALSE
58.3%
−61.5%
−0.4%
62.5%
0.4%
1.0%
−28.9%
0.0%
0.0%
Census Tract 359.01
−0.4%
−7.3%
15.3%
19.6%
77.6%
FALSE
FALSE
171.1%
91.3%
0.0%
40.0%
−0.1%
0.5%
−18.6%
−0.0%
0.0%
Census Tract 360
−2.6%
7.5%
6.3%
29.9%
−13.2%
FALSE
FALSE
−35.0%
92.3%
0.4%
2.7%
0.0%
0.0%
−5.6%
0.0%
0.3%
Census Tract 361
−11.1%
−5.8%
14.9%
31.3%
17.8%
FALSE
FALSE
−25.9%
36.6%
1.1%
259.4%
0.3%
−0.5%
11.1%
−0.1%
6.8%
Census Tract 363
−5.6%
−7.8%
−6.0%
0.0%
58.5%
FALSE
FALSE
39.1%
−22.8%
−0.3%
−30.2%
0.6%
−0.3%
−0.9%
−0.1%
−0.6%
Census Tract 364.01
−7.8%
−11.7%
0.5%
19.7%
45.8%
FALSE
FALSE
−9.5%
135.0%
−0.4%
26.6%
0.2%
0.0%
−1.8%
−0.0%
−0.0%
Census Tract 364.02
4.9%
13.2%
1.9%
30.3%
−6.7%
FALSE
FALSE
−54.8%
56.5%
0.2%
70.6%
−0.1%
−0.1%
1.3%
−0.0%
0.4%
Census Tract 365
−6.1%
−8.3%
5.9%
51.7%
−1.1%
FALSE
FALSE
−3.0%
179.2%
0.2%
64.2%
0.0%
−0.1%
0.0%
−0.1%
−0.2%
Census Tract 366
6.3%
10.5%
2.3%
21.9%
−3.7%
FALSE
FALSE
17.0%
71.3%
−0.4%
84.8%
0.2%
−0.3%
3.7%
0.0%
−0.0%
Census Tract 368
2.8%
−2.4%
1.1%
44.1%
64.0%
FALSE
FALSE
−24.5%
28.9%
0.0%
5.5%
0.3%
−0.2%
1.5%
−0.1%
0.1%
Census Tract 369.01
−8.4%
−5.9%
16.7%
51.7%
−65.7%
FALSE
FALSE
−73.6%
49.2%
1.1%
48.9%
0.0%
−0.5%
6.5%
−0.1%
4.8%
Census Tract 369.02
−12.7%
13.8%
−0.6%
19.2%
176.6%
FALSE
FALSE
−24.7%
−39.2%
0.1%
29.5%
0.1%
0.2%
−7.1%
0.0%
−0.0%
Census Tract 371
0.1%
1.5%
7.8%
40.1%
−27.9%
FALSE
FALSE
−67.7%
−4.4%
−0.1%
123.7%
−0.2%
−0.7%
−11.1%
−0.1%
−0.0%
Census Tract 372
8.4%
7.1%
15.7%
18.4%
−51.9%
FALSE
FALSE
−13.1%
0.9%
0.2%
44.1%
0.3%
−2.1%
46.2%
0.0%
0.0%
Census Tract 373
−12.0%
−11.1%
−2.8%
27.7%
−8.8%
FALSE
FALSE
−44.1%
80.6%
−0.9%
37.4%
0.1%
−0.2%
8.4%
−0.0%
5.6%
Census Tract 374
−0.7%
−4.6%
−2.8%
20.6%
−26.3%
FALSE
FALSE
−49.3%
217.2%
0.0%
27.2%
0.0%
−0.1%
2.8%
0.0%
1.2%
Census Tract 375
−6.4%
4.5%
24.3%
22.1%
130.7%
FALSE
FALSE
37.2%
−6.6%
−0.4%
54.0%
−0.1%
−0.1%
6.8%
0.0%
0.4%
Census Tract 376
2.9%
8.0%
10.2%
40.4%
−33.5%
FALSE
FALSE
−11.8%
66.7%
0.4%
−21.4%
0.1%
0.0%
−4.6%
−0.1%
−3.8%
Chemung
Census Tract 1
−4.9%
−17.7%
10.8%
19.6%
10.9%
FALSE
FALSE
−3.1%
44.0%
−1.1%
61.5%
9.3%
−0.9%
57.1%
0.0%
−3.5%
Census Tract 6
−18.9%
−24.8%
−5.8%
1.5%
−15.3%
FALSE
FALSE
12.7%
12.7%
−0.5%
600.0%
33.3%
0.0%
0.0%
−0.0%
−0.0%
Census Tract 104
1.5%
3.1%
1.6%
20.2%
319.5%
FALSE
FALSE
−27.8%
218.0%
−0.5%
1,000,000.0%
8.3%
−2.5%
150.0%
0.0%
0.0%
Census Tract 109
−4.4%
−0.6%
9.5%
3.4%
−41.6%
FALSE
FALSE
106.5%
−62.1%
−0.4%
−20.0%
1.6%
0.3%
−66.0%
0.3%
−0.5%
Census Tract 2
−2.0%
−16.8%
−12.1%
17.7%
−20.0%
FALSE
FALSE
−39.3%
−3.8%
−0.2%
100.0%
33.3%
0.0%
100.0%
0.0%
0.0%
Census Tract 3
21.1%
0.0%
10.1%
0.0%
0.0%
FALSE
FALSE
0.0%
0.0%
−3.4%
250.0%
−0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 5
−12.2%
−4.1%
−11.8%
38.1%
35.8%
FALSE
FALSE
−53.4%
−10.9%
0.0%
0.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 7
−16.6%
−13.6%
−3.8%
242.1%
3.0%
FALSE
FALSE
−36.6%
3.1%
−0.7%
38.5%
32.2%
−6.7%
150.0%
0.0%
−0.9%
Census Tract 9
−12.1%
−10.8%
1.9%
23.3%
−7.6%
FALSE
FALSE
−29.8%
39.3%
−0.3%
25.0%
7.8%
−75.0%
100.0%
−0.0%
−2.2%
Census Tract 10
−0.9%
−7.4%
−11.8%
7.7%
39.3%
TRUE
FALSE
−65.6%
36.3%
−0.1%
50.0%
7.1%
0.0%
0.0%
0.0%
−1.2%
Census Tract 11
−5.6%
−10.2%
−4.5%
42.9%
−14.4%
FALSE
FALSE
−40.2%
−29.8%
−0.2%
−0.0%
10.8%
−0.0%
0.0%
−0.0%
−0.0%
Census Tract 101
6.6%
8.8%
4.3%
29.2%
−39.9%
FALSE
FALSE
−36.3%
−4.1%
−0.4%
6.6%
0.2%
0.0%
−13.4%
−0.3%
1.7%
Census Tract 102
5.4%
−2.5%
1.3%
35.1%
−4.3%
FALSE
FALSE
−28.9%
9.5%
0.4%
57.1%
0.0%
−0.1%
19.2%
0.0%
−5.5%
Census Tract 103
0.6%
2.4%
−0.2%
21.4%
−24.7%
FALSE
FALSE
−5.9%
−79.6%
−0.1%
8.0%
0.2%
−0.1%
28.6%
0.0%
−0.8%
Census Tract 105
−2.6%
−1.1%
−13.6%
4.1%
5.2%
FALSE
FALSE
−57.6%
−3.2%
2.1%
−5.2%
−14.4%
2.1%
−35.9%
−0.8%
−50.0%
Census Tract 106
−8.6%
0.2%
24.3%
69.1%
−66.2%
FALSE
FALSE
−50.8%
−48.8%
−0.2%
14.3%
0.2%
0.0%
66.7%
0.0%
0.0%
Census Tract 107
1.4%
0.7%
7.3%
17.4%
−23.4%
FALSE
FALSE
−18.0%
144.4%
0.3%
1.1%
−0.2%
−0.0%
−20.7%
−0.1%
8.5%
Census Tract 108
−0.9%
−1.7%
13.3%
30.2%
−18.6%
FALSE
FALSE
−9.1%
44.3%
−0.6%
64.3%
4.6%
3.8%
160.0%
−1.6%
−100.0%
Census Tract 110
−15.9%
−9.3%
19.9%
21.7%
−31.7%
FALSE
FALSE
2.0%
−13.2%
−0.8%
2.0%
0.3%
−0.1%
34.0%
−0.0%
−0.1%
Census Tract 111
−7.9%
−1.1%
7.8%
49.7%
−3.9%
FALSE
FALSE
−68.3%
−15.2%
−0.8%
77.8%
1.9%
−0.8%
21.4%
0.0%
1.5%
Census Tract 112
−13.4%
−1.7%
14.8%
14.7%
144.9%
FALSE
FALSE
1.6%
−24.4%
−1.0%
−8.4%
0.3%
−0.0%
−6.4%
0.6%
−5.5%
Census Tract 4
14.3%
0.1%
2.8%
−21.6%
129.2%
FALSE
FALSE
1,074.5%
82.2%
−0.4%
23.5%
1.7%
0.0%
0.0%
0.0%
0.0%
Chenango
Census Tract 9704
−11.9%
−12.6%
13.2%
−2.5%
57.1%
TRUE
FALSE
−31.7%
50.2%
−0.0%
0.0%
0.3%
0.0%
−0.0%
0.0%
0.0%
Census Tract 9701
−2.2%
5.6%
4.2%
3.3%
36.0%
FALSE
FALSE
−48.5%
21.6%
0.8%
18.7%
−0.1%
0.8%
−9.4%
−0.1%
5.1%
Census Tract 9702
−8.6%
5.3%
12.4%
0.3%
7.6%
FALSE
FALSE
−9.8%
124.1%
1.0%
65.0%
−0.0%
0.1%
−5.3%
−0.0%
1.5%
Census Tract 9703
−4.5%
7.2%
−16.1%
45.0%
−9.4%
FALSE
FALSE
−27.8%
63.7%
0.1%
−5.0%
−0.2%
0.4%
−9.1%
0.0%
0.0%
Census Tract 9705
−5.1%
2.0%
6.6%
16.1%
−18.0%
FALSE
FALSE
10.2%
133.1%
0.1%
30.1%
−0.1%
0.4%
−10.9%
−0.0%
1.8%
Census Tract 9706.01
−4.5%
3.7%
−1.2%
44.3%
−38.9%
FALSE
FALSE
−61.3%
26.4%
0.3%
9.1%
−0.2%
0.1%
−6.2%
−0.1%
5.0%
Census Tract 9706.02
−10.0%
21.3%
2.2%
21.0%
−3.9%
FALSE
FALSE
−68.8%
88.4%
0.4%
25.8%
−0.1%
0.1%
−11.0%
−0.0%
0.7%
Census Tract 9707
−0.8%
23.0%
12.3%
10.0%
96.7%
FALSE
FALSE
41.6%
241.9%
−0.1%
194.1%
0.0%
−0.1%
8.8%
0.2%
−0.2%
Census Tract 9708.01
−6.2%
3.6%
7.3%
15.9%
−44.3%
FALSE
FALSE
−36.0%
54.5%
0.2%
13.5%
−0.1%
0.0%
−2.9%
−0.2%
0.4%
Census Tract 9708.02
−4.4%
0.7%
0.2%
35.2%
2.8%
FALSE
FALSE
−15.7%
−10.4%
0.4%
35.6%
−0.1%
−0.0%
−2.2%
0.0%
0.2%
Census Tract 9709
−8.1%
−8.0%
11.4%
25.1%
−8.8%
FALSE
FALSE
−17.3%
−38.2%
0.2%
6.4%
−0.1%
0.2%
−16.3%
−0.1%
0.3%
Census Tract 9710
−7.4%
5.0%
17.2%
37.7%
−12.1%
FALSE
FALSE
22.5%
66.6%
0.5%
5.3%
−0.1%
0.1%
−8.0%
−0.2%
0.4%
Otsego
Census Tract 5905
−4.8%
−6.0%
0.7%
45.8%
−14.6%
FALSE
FALSE
−44.5%
56.3%
0.2%
9.3%
−0.2%
0.7%
−36.6%
0.3%
−1.5%
Census Tract 5909
2.4%
−2.0%
14.2%
12.3%
−28.9%
FALSE
FALSE
−9.4%
−31.8%
−1.1%
12.5%
1.6%
0.4%
266.7%
0.0%
−2.6%
Census Tract 5910
4.6%
−12.0%
−11.5%
8.8%
−14.0%
FALSE
FALSE
−5.1%
−44.6%
−0.6%
1,900.0%
21.4%
−6.9%
100.0%
−0.0%
0.0%
Census Tract 5913
18.9%
−10.0%
−1.0%
0.0%
0.0%
FALSE
FALSE
34.1%
0.0%
−3.2%
400.0%
−33.3%
2.3%
0.0%
0.0%
0.0%
Census Tract 5901
0.2%
−0.9%
6.3%
16.7%
0.3%
FALSE
FALSE
10.8%
−10.9%
0.4%
44.5%
−0.1%
0.1%
−3.2%
−0.1%
0.7%
Census Tract 5902.01
−13.8%
−3.7%
−0.7%
21.0%
−13.0%
FALSE
FALSE
−35.0%
31.0%
0.2%
63.8%
−0.2%
0.4%
−18.7%
−0.1%
4.5%
Census Tract 5902.02
−4.5%
−4.0%
3.2%
44.5%
−53.2%
FALSE
FALSE
22.2%
29.6%
−0.2%
51.5%
−0.2%
0.6%
−10.8%
0.0%
−0.2%
Census Tract 5903
−5.6%
−2.6%
−0.4%
30.5%
29.0%
FALSE
FALSE
−43.1%
−3.8%
0.1%
89.8%
−0.1%
1.0%
−12.5%
0.0%
−0.3%
Census Tract 5904
−8.6%
−9.5%
4.9%
16.6%
−1.5%
FALSE
FALSE
−31.9%
15.1%
0.2%
61.6%
−0.1%
0.4%
−11.5%
−0.0%
−1.6%
Census Tract 5906
−9.2%
−15.7%
−0.2%
13.0%
11.1%
FALSE
FALSE
−42.3%
−22.9%
0.1%
166.7%
−0.2%
0.1%
−2.2%
0.1%
−4.6%
Census Tract 5907
−7.9%
−6.1%
13.9%
26.4%
−5.7%
FALSE
FALSE
−33.8%
−66.9%
−0.3%
59.1%
0.0%
0.1%
−5.9%
0.0%
−1.2%
Census Tract 5908
−3.9%
−10.2%
18.5%
25.0%
27.2%
FALSE
FALSE
−22.4%
0.6%
−0.5%
35.6%
0.2%
−0.0%
−9.6%
0.1%
−1.6%
Census Tract 5911
−12.8%
−8.3%
32.0%
27.3%
−0.1%
FALSE
FALSE
−63.2%
38.7%
−1.3%
56.3%
−2.8%
2.2%
19.4%
0.0%
1.6%
Census Tract 5912
−17.0%
1.0%
0.0%
102.2%
−42.5%
FALSE
FALSE
−72.6%
−63.6%
−0.5%
375.0%
0.6%
−0.6%
−40.0%
0.0%
0.0%
Census Tract 5914
−2.3%
−7.0%
5.5%
9.9%
−3.0%
FALSE
FALSE
−57.6%
51.0%
−0.3%
50.0%
−0.0%
0.1%
−14.0%
0.1%
−1.7%
Census Tract 5915
−0.2%
0.5%
7.6%
29.5%
2.9%
FALSE
FALSE
16.7%
35.4%
0.1%
64.2%
−0.1%
0.2%
−13.5%
−0.0%
0.1%
Census Tract 5916
−6.4%
−5.5%
18.8%
4.2%
84.9%
FALSE
FALSE
−55.9%
65.4%
−0.1%
8.4%
−0.1%
0.2%
−23.2%
0.0%
−0.7%
Tioga
Census Tract 204.02
−16.1%
−10.0%
6.3%
23.9%
−60.4%
FALSE
FALSE
−90.1%
11.1%
−0.1%
120.0%
−0.1%
−0.1%
20.0%
0.0%
−0.2%
Census Tract 207.03
−7.9%
−13.1%
−6.2%
6.1%
7.2%
FALSE
FALSE
37.8%
−24.7%
−0.2%
40.5%
−4.9%
−12.3%
−18.7%
0.0%
233.3%
Census Tract 201
−8.4%
−5.2%
7.1%
41.4%
−31.8%
FALSE
FALSE
−14.1%
20.4%
0.6%
112.0%
−0.0%
0.0%
−2.5%
−0.0%
−4.7%
Census Tract 202
−5.0%
−7.2%
6.5%
23.6%
−22.4%
FALSE
FALSE
117.1%
−37.2%
−0.2%
13.9%
−0.0%
−0.0%
4.6%
−0.5%
10.5%
Census Tract 203
−5.1%
−0.2%
10.0%
37.0%
94.6%
FALSE
FALSE
9.1%
−1.7%
0.7%
8.4%
−0.1%
−0.1%
13.8%
−0.1%
0.1%
Census Tract 204.01
−1.4%
2.3%
9.5%
35.7%
−1.2%
FALSE
FALSE
−28.9%
−4.6%
0.3%
21.3%
−0.0%
−0.1%
0.9%
0.1%
0.3%
Census Tract 205
−1.8%
17.9%
5.1%
6.5%
76.6%
FALSE
FALSE
−23.5%
27.7%
−0.9%
0.0%
5.6%
−0.3%
16.7%
0.0%
−0.3%
Census Tract 206
−0.4%
8.0%
12.1%
33.9%
19.9%
FALSE
FALSE
−4.2%
62.4%
0.3%
12.4%
−0.2%
−0.0%
1.5%
0.2%
0.1%
Census Tract 207.01
−6.3%
−7.2%
−1.0%
19.0%
−14.1%
FALSE
FALSE
−4.2%
69.3%
0.8%
41.7%
0.3%
−0.3%
6.5%
−0.2%
0.1%
Census Tract 207.02
−2.3%
−6.3%
−0.2%
40.5%
17.3%
FALSE
FALSE
−56.4%
−53.3%
0.3%
14.8%
0.1%
−0.1%
−11.0%
−0.0%
−1.2%
Tompkins
Census Tract 7
−2.2%
−0.2%
−1.4%
22.7%
14.1%
FALSE
FALSE
64.8%
30.2%
0.1%
−37.5%
0.0%
0.0%
6.7%
0.0%
0.6%
Census Tract 12
−34.0%
−48.6%
0.0%
0.0%
1,000,000.0%
FALSE
FALSE
289.3%
0.0%
0.6%
20.7%
−9.8%
−1.1%
100.0%
−0.0%
1,000,000.0%
Census Tract 13
1.6%
12.1%
0.7%
1.1%
−26.4%
FALSE
FALSE
4.5%
116.5%
−0.8%
44.8%
0.5%
0.1%
−5.5%
0.0%
−4.3%
Census Tract 16
3.0%
13.2%
21.8%
12.0%
−37.6%
FALSE
FALSE
−35.2%
−13.0%
0.4%
48.3%
−0.0%
0.5%
−9.4%
−0.2%
0.0%
Census Tract 14
−4.8%
−0.1%
−11.4%
13.2%
10.7%
FALSE
FALSE
−10.9%
−20.8%
−0.0%
11.0%
−0.0%
0.0%
−3.4%
−0.2%
−0.0%
Census Tract 15
7.1%
11.3%
16.4%
−14.1%
11.1%
FALSE
FALSE
−74.5%
36.2%
0.8%
5.0%
0.2%
−1.0%
−0.8%
0.0%
−0.2%
Census Tract 17
4.6%
7.0%
8.5%
30.7%
−42.8%
FALSE
FALSE
−83.8%
−15.0%
0.9%
94.7%
−0.0%
0.1%
−14.2%
−0.1%
−2.6%
Census Tract 18
−0.8%
3.4%
22.4%
19.3%
166.1%
FALSE
FALSE
−35.3%
−51.6%
0.7%
10.2%
0.1%
−0.1%
0.9%
−0.3%
30.7%
Census Tract 19
5.8%
4.0%
−8.0%
16.5%
9.0%
FALSE
FALSE
−45.8%
−69.6%
0.4%
2.0%
0.0%
0.1%
−6.3%
−0.0%
2.4%
Census Tract 20
15.1%
4.4%
−5.9%
38.9%
71.9%
FALSE
FALSE
−57.4%
56.6%
1.0%
16.8%
−0.1%
0.2%
−15.8%
−0.0%
−4.2%
Census Tract 21
−11.3%
−7.7%
8.8%
17.5%
53.4%
FALSE
FALSE
44.9%
−10.8%
0.1%
14.2%
−0.0%
−0.1%
−0.2%
−0.0%
13.5%
Census Tract 23
4.9%
−0.7%
−4.1%
27.4%
177.3%
FALSE
FALSE
−40.2%
109.8%
0.2%
4.7%
0.0%
0.4%
−6.5%
−0.1%
0.1%
Census Tract 22
−2.0%
12.1%
6.8%
6.9%
−29.7%
FALSE
FALSE
−64.3%
−1.6%
−0.2%
76.5%
−0.0%
0.3%
−14.7%
−0.0%
18.7%
Census Tract 1
13.1%
8.5%
−5.1%
−100.0%
−14.4%
FALSE
FALSE
112.4%
−13.3%
−0.2%
20.0%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 2
−7.1%
−6.0%
−2.3%
−100.0%
−6.7%
FALSE
FALSE
−29.7%
41.2%
−0.2%
12.5%
0.0%
0.0%
0.0%
0.0%
0.0%
Census Tract 3
65.1%
28.2%
−2.0%
−15.5%
130.1%
FALSE
FALSE
69.9%
13.5%
0.0%
12.5%
−0.3%
0.0%
7.1%
0.0%
0.0%
Census Tract 4
−12.1%
−31.7%
0.0%
15.9%
−20.5%
FALSE
FALSE
−7.3%
4.8%
−0.1%
−100.0%
0.1%
0.1%
−4.8%
0.0%
0.0%
Census Tract 5
−1.4%
2.9%
9.0%
3.6%
−18.6%
FALSE
FALSE
15.3%
78.7%
0.1%
50.0%
−0.5%
−0.8%
41.2%
0.0%
−9.1%
Census Tract 6
−8.2%
−12.1%
0.3%
40.4%
−43.0%
FALSE
FALSE
76.0%
53.2%
0.3%
57.1%
−1.0%
0.5%
−5.4%
0.0%
−0.0%
Census Tract 8
18.3%
−4.7%
0.7%
86.0%
−12.1%
FALSE
FALSE
−68.8%
−3.8%
−0.1%
1,000,000.0%
−0.0%
0.0%
1,000,000.0%
−0.0%
−0.0%
Census Tract 9
15.9%
8.6%
9.6%
14.1%
−26.2%
FALSE
FALSE
319.1%
−51.5%
0.5%
650.0%
0.5%
−0.3%
−9.6%
0.0%
0.0%
Census Tract 10
−1.0%
0.2%
2.6%
23.2%
110.0%
FALSE
FALSE
35.0%
8.0%
0.5%
−14.6%
−0.1%
1.3%
−13.2%
−0.2%
7.4%
Census Tract 11
35.4%
10.2%
−5.8%
11.9%
−19.5%
FALSE
FALSE
126.5%
−37.4%
0.5%
41.0%
0.4%
−0.2%
−1.1%
0.2%
−6.3%
Schoharie
Census Tract 7402
1.6%
−7.9%
5.5%
2.9%
−25.8%
FALSE
FALSE
−50.0%
−3.0%
−0.2%
13.9%
−0.2%
−0.1%
−0.8%
0.0%
−0.6%
Census Tract 7403
−25.8%
−100.0%
−1.5%
0.0%
0.0%
FALSE
FALSE
−52.5%
0.0%
0.8%
0.0%
−3.0%
0.0%
1,000,000.0%
0.0%
0.0%
Census Tract 7401
−6.3%
−10.1%
6.2%
14.7%
9.7%
FALSE
FALSE
−40.5%
27.6%
0.2%
7.8%
−0.0%
0.1%
−9.6%
0.0%
−0.4%
Census Tract 7404
3.6%
6.6%
4.8%
−3.8%
111.6%
FALSE
FALSE
−27.3%
22.1%
−0.1%
47.7%
0.0%
0.1%
2.3%
0.1%
−17.7%
Census Tract 7405
−4.3%
−6.8%
2.4%
52.3%
15.7%
FALSE
FALSE
−36.5%
13.9%
0.1%
23.6%
0.0%
0.4%
−19.6%
−0.1%
1.1%
Census Tract 7406
−16.1%
−10.9%
7.6%
17.0%
−8.2%
FALSE
FALSE
−15.3%
26.8%
−0.4%
35.2%
0.3%
−0.1%
1.5%
−0.0%
−2.2%
Census Tract 7407
−6.2%
3.8%
21.2%
7.0%
0.7%
FALSE
FALSE
−64.5%
0.8%
0.2%
26.8%
0.0%
−0.2%
76.4%
0.0%
−8.4%
Census Tract 7408
0.0%
4.4%
9.2%
11.3%
3.9%
FALSE
FALSE
3.0%
113.7%
−0.0%
25.1%
0.5%
−0.5%
64.9%
−0.1%
−1.8%
Schuyler
Census Tract 9501
−0.7%
8.8%
11.3%
32.0%
360.5%
FALSE
FALSE
−18.2%
−47.9%
1.1%
36.5%
0.6%
0.1%
−21.8%
−0.0%
0.0%
Census Tract 9502
−7.4%
−7.1%
0.9%
8.2%
533.7%
FALSE
FALSE
183.7%
−58.3%
−0.2%
95.7%
0.4%
−0.1%
−17.4%
0.0%
0.4%
Census Tract 9503
−13.7%
−3.4%
25.8%
11.9%
33.8%
FALSE
FALSE
−32.2%
−25.3%
0.3%
15.7%
0.0%
−0.0%
1.7%
0.2%
−0.2%
Census Tract 9504
−1.1%
−11.2%
−0.2%
32.0%
121.7%
FALSE
FALSE
85.6%
−40.6%
−0.4%
52.0%
0.2%
0.1%
−18.1%
−0.1%
−4.1%
Census Tract 9505
0.7%
−2.2%
8.6%
42.4%
17.0%
FALSE
FALSE
−44.0%
41.2%
0.5%
37.8%
1.0%
−0.5%
6.8%
−0.3%
−0.1%
Steuben
Census Tract 9607
−6.1%
−9.8%
−8.4%
−24.8%
5.5%
FALSE
FALSE
−30.5%
−11.2%
−0.7%
0.0%
5.1%
−0.7%
37.5%
−0.0%
−0.0%
Census Tract 9612
−5.0%
0.5%
10.4%
18.9%
−29.6%
FALSE
FALSE
−7.1%
42.4%
0.4%
5.3%
−0.4%
−0.7%
−60.0%
0.0%
0.0%
Census Tract 9616
23.1%
18.7%
−1.0%
30.0%
−43.3%
FALSE
FALSE
−70.8%
0.0%
−0.4%
7.3%
0.2%
0.0%
−9.0%
0.1%
−14.3%
Census Tract 9622
0.7%
−9.1%
−9.3%
37.1%
14.1%
FALSE
FALSE
−15.6%
59.1%
0.2%
31.4%
0.2%
−0.3%
65.5%
0.1%
−3.4%
Census Tract 9626
−9.6%
4.1%
19.3%
32.8%
−69.4%
FALSE
FALSE
−9.5%
−16.8%
−0.1%
−0.0%
0.6%
0.0%
8.3%
0.0%
0.0%
Census Tract 9601
−15.8%
−12.5%
−1.0%
16.5%
3.2%
FALSE
FALSE
38.9%
547.5%
0.1%
3.9%
0.2%
0.2%
−17.7%
0.0%
−0.0%
Census Tract 9602
6.8%
1.1%
3.1%
18.5%
−26.2%
FALSE
FALSE
−42.0%
18.2%
0.8%
83.3%
0.0%
0.2%
−12.3%
0.0%
−6.3%
Census Tract 9603
−4.1%
−2.5%
3.8%
13.2%
57.4%
FALSE
FALSE
3.3%
−17.4%
0.1%
11.9%
0.1%
−0.1%
−2.3%
0.0%
−29.4%
Census Tract 9604
−4.6%
3.0%
27.3%
25.5%
−12.9%
FALSE
FALSE
−21.2%
25.8%
−0.1%
5.5%
0.0%
0.3%
−15.2%
−0.1%
0.2%
Census Tract 9605
5.2%
1.1%
−0.7%
14.0%
44.0%
FALSE
FALSE
−23.4%
18.7%
0.4%
31.3%
0.0%
−0.0%
−2.6%
−0.0%
0.2%
Census Tract 9606
−2.0%
0.4%
11.1%
16.7%
53.9%
FALSE
FALSE
10.1%
−53.7%
−0.4%
7.8%
0.1%
0.1%
−17.5%
0.0%
−1.2%
Census Tract 9608
1.8%
−10.3%
−11.8%
38.1%
7.9%
TRUE
FALSE
−63.0%
90.9%
−0.1%
23.8%
0.5%
−0.8%
16.7%
0.0%
0.0%
Census Tract 9609
−9.2%
−12.3%
5.1%
−2.3%
88.6%
TRUE
FALSE
11.6%
2.4%
−0.3%
44.4%
20.0%
−3.4%
−50.0%
0.0%
0.0%
Census Tract 9610
−2.7%
2.9%
18.2%
27.4%
3.0%
FALSE
FALSE
35.3%
−47.8%
0.2%
21.1%
−0.0%
−0.0%
−4.2%
−0.0%
−6.7%
Census Tract 9611
0.0%
−6.9%
7.2%
1.4%
76.9%
FALSE
FALSE
−38.9%
17.5%
0.7%
1.2%
0.3%
−0.3%
−6.1%
0.2%
−4.2%
Census Tract 9613
−2.1%
4.3%
4.5%
3.0%
48.2%
FALSE
FALSE
−13.5%
189.8%
0.1%
9.1%
0.2%
−0.2%
15.7%
0.0%
−1.3%
Census Tract 9614
−4.2%
−4.8%
16.8%
8.3%
58.4%
FALSE
FALSE
−42.7%
38.9%
−0.2%
20.2%
0.2%
−0.0%
−1.4%
−0.1%
−0.1%
Census Tract 9615
−13.3%
−3.4%
16.7%
27.0%
−47.4%
FALSE
FALSE
−54.9%
−27.9%
0.3%
0.9%
0.1%
−0.1%
1.2%
0.0%
−0.0%
Census Tract 9617
−5.0%
10.1%
25.2%
54.9%
1.8%
FALSE
FALSE
−50.8%
1.8%
−0.6%
1.1%
0.5%
−0.1%
−1.7%
0.0%
−4.2%
Census Tract 9618
−5.3%
−4.4%
10.0%
21.9%
18.6%
FALSE
FALSE
−22.1%
49.4%
0.1%
34.4%
0.1%
−0.2%
33.7%
−0.0%
−1.9%
Census Tract 9619
−4.5%
4.9%
6.2%
42.0%
20.7%
FALSE
FALSE
−41.2%
10.1%
−0.0%
9.1%
−0.1%
−0.0%
4.5%
−0.0%
−1.5%
Census Tract 9620
1.5%
−4.8%
−3.5%
18.2%
16.3%
FALSE
FALSE
−29.5%
50.8%
0.7%
50.8%
−0.0%
−0.0%
0.4%
−0.0%
1.4%
Census Tract 9621
−5.4%
−7.1%
10.0%
26.9%
−12.3%
FALSE
FALSE
−28.1%
−7.6%
0.6%
24.3%
−0.0%
0.1%
−17.8%
−0.2%
−7.7%
Census Tract 9623
5.0%
3.8%
0.0%
61.7%
−27.6%
FALSE
FALSE
44.1%
3.8%
0.5%
3.8%
−0.4%
−0.2%
7.4%
−0.3%
3.0%
Census Tract 9624
−1.9%
−6.4%
−0.3%
25.0%
−30.0%
FALSE
FALSE
−84.8%
−0.0%
−0.5%
9.1%
9.0%
−0.0%
0.0%
−0.0%
−0.0%
Census Tract 9625
5.2%
1.3%
−19.9%
20.5%
12.1%
FALSE
FALSE
287.5%
171.4%
−1.7%
69.2%
12.1%
−0.0%
20.0%
−0.0%
−0.0%
Census Tract 9627
−6.2%
−3.5%
11.5%
104.6%
−5.3%
FALSE
FALSE
2.9%
−31.1%
−1.1%
−0.0%
13.2%
1.6%
700.0%
0.0%
0.0%
Census Tract 9628
−4.0%
−1.0%
9.5%
16.7%
−66.7%
FALSE
FALSE
−18.4%
1.0%
0.9%
−5.2%
−0.0%
0.0%
−5.4%
0.1%
−2.0%
Census Tract 9629
5.2%
8.0%
−2.4%
33.8%
−32.8%
FALSE
FALSE
−5.2%
208.7%
−0.1%
94.2%
−0.3%
−0.2%
78.6%
0.0%
−0.8%
Census Tract 9630
−14.9%
−15.3%
1.4%
33.6%
−12.1%
FALSE
FALSE
22.6%
23.8%
1.7%
6.1%
0.1%
−0.2%
10.4%
−0.1%
−0.8%
Allegany
Census Tract 9510
−1.6%
−8.7%
−1.4%
0.6%
18.9%
TRUE
FALSE
−82.2%
−8.9%
−0.4%
4.8%
0.0%
0.4%
−17.4%
−0.6%
−1.8%
Census Tract 9511
1.8%
13.0%
6.9%
11.7%
−12.7%
FALSE
FALSE
34.5%
0.8%
−1.4%
41.8%
0.1%
0.2%
−19.3%
0.0%
−4.5%
Census Tract 9512
−8.6%
−8.6%
9.6%
10.0%
24.7%
FALSE
FALSE
−21.8%
50.5%
−0.7%
44.1%
0.2%
0.1%
−14.5%
−0.2%
0.0%
Census Tract 9513
−14.2%
−9.8%
16.5%
24.8%
−20.8%
FALSE
FALSE
−61.4%
35.1%
−1.1%
−0.5%
−0.2%
0.2%
−9.1%
0.0%
−1.8%
Census Tract 9402
1,000,000.0%
1,000,000.0%
0.0%
0.0%
0.0%
FALSE
FALSE
0.0%
0.0%
−0.0%
0.0%
−2.9%
0.1%
−0.0%
0.0%
−0.0%
Census Tract 9501
−12.5%
−10.0%
10.3%
18.7%
6.4%
FALSE
FALSE
5.2%
−32.1%
0.8%
6.1%
−0.1%
0.1%
−2.5%
0.0%
−12.6%
Census Tract 9503
2.8%
2.9%
13.4%
15.0%
0.5%
FALSE
FALSE
−49.0%
−33.0%
2.0%
41.6%
−0.1%
−0.1%
9.5%
−0.1%
−1.3%
Census Tract 9504
9.4%
−4.5%
−10.0%
14.5%
15.1%
FALSE
FALSE
−30.8%
85.1%
−0.2%
25.6%
−0.1%
−0.0%
5.3%
0.0%
−0.1%
Census Tract 9505
−6.7%
−3.4%
2.0%
8.5%
30.4%
FALSE
FALSE
38.5%
−22.7%
−0.4%
9.3%
−0.2%
0.1%
−9.3%
3.6%
1.1%
Census Tract 9506
−1.2%
1.2%
15.3%
16.4%
−12.6%
TRUE
FALSE
−35.0%
−32.9%
−0.4%
−3.2%
0.0%
0.4%
−33.6%
−0.4%
−10.2%
Census Tract 9507
−17.8%
−14.6%
21.6%
36.1%
−14.4%
FALSE
FALSE
−46.8%
75.9%
−0.5%
21.1%
−0.2%
0.2%
−13.9%
−0.3%
−2.4%
Census Tract 9508
−2.1%
−20.9%
1.0%
25.0%
9.1%
FALSE
FALSE
−77.7%
−0.5%
−0.3%
3.8%
−0.2%
0.1%
−2.5%
0.0%
−4.5%
Census Tract 9509
−9.9%
−0.1%
17.5%
25.2%
−7.3%
FALSE
FALSE
−66.6%
122.2%
0.0%
32.7%
−0.2%
0.2%
−5.2%
0.1%
2.0%
County-Level Distressed Population and Land Cover Change Data
Code
# get full counties sfs for 2010 and 2019 and fill NA with 0, then join them into a single sffinal_counties_df.2010<-gather_data(st_lc_2010_masked, 2010, 'county')final_counties_df.2010[is.na(final_counties_df.2010)] <-0final_counties_df.2019<-gather_data(st_lc_2019_masked, 2019, 'county')final_counties_df.2019[is.na(final_counties_df.2019)] <-0final_counties_df <-st_join(final_counties_df.2010, final_counties_df.2019, suffix =c('', '.y'), largest =TRUE) %>%select(-c(county.y, tot_pop_became_distressed_2010_2019, tot_pop_improved_2010_2019)) %>%rename(tot_pop_became_distressed_2010_2019 = tot_pop_became_distressed_2010_2019.y, tot_pop_improved_2010_2019 = tot_pop_improved_2010_2019.y ) %>%mutate(pct_pop_chg = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) *100,pct_hhs_chg = ((tot_hhs_2019 - tot_hhs_2010) / tot_hhs_2010) *100,pct_median_age_chg = ((median_age_2019 - median_age_2010) / median_age_2010) *100,pct_median_income_chg = ((median_income_2019 - median_income_2010) / median_income_2010) *100,pct_below_poverty_chg = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) *100,pct_unemployed_chg = ((pct_unemployed_2019 - pct_unemployed_2010) / pct_unemployed_2010) *100,pct_pop_distressed_chg = ((pct_pop_distressed_2019 - pct_pop_distressed_2010) / pct_pop_distressed_2010) *100,pct_hhs_no_vehicles_chg = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) *100,pct_developed_chg = ((pct_developed_area_sqmi_2019 - pct_developed_area_sqmi_2010) / pct_developed_area_sqmi_2010) *100,pct_natural_barren_chg = ((pct_natural_barren_area_sqmi_2019 - pct_natural_barren_area_sqmi_2010) / pct_natural_barren_area_sqmi_2010) *100,pct_cropland_chg = ((pct_cropland_area_sqmi_2019 - pct_cropland_area_sqmi_2010) / pct_cropland_area_sqmi_2010) *100,pct_tree_cover_chg = ((pct_tree_cover_area_sqmi_2019 - pct_tree_cover_area_sqmi_2010) / pct_tree_cover_area_sqmi_2010) *100,pct_grassland_chg = ((pct_grassland_area_sqmi_2019 - pct_grassland_area_sqmi_2010) / pct_grassland_area_sqmi_2010) *100,pct_wetland_chg = ((pct_wetland_area_sqmi_2019 - pct_wetland_area_sqmi_2010) / pct_wetland_area_sqmi_2010) *100,pct_water_chg = ((pct_water_area_sqmi_2019 - pct_water_area_sqmi_2010) / pct_water_area_sqmi_2010) *100 ) %>%mutate_if(is.numeric, ~replace_na(., 0) %>%replace(., is.infinite(.), 1000000))final_counties_df[is.na(final_counties_df)] <-0# display county-level table of datafinal_counties_df %>%select(county, grep('chg', colnames(.), value =TRUE)) %>%st_drop_geometry() %>%gt(rowname_col ='county') %>%tab_header(title =md('**Changes in Population Characteristics, Economic Indicators, and Land Cover**'),subtitle =md('By Southern Tier County (2010 - 2019)') ) %>%cols_label(pct_pop_chg =md('**% Pop Change**'),pct_hhs_chg =md('**% HHs Change**'),pct_median_age_chg =md('**% Median Age Change**'),pct_median_income_chg =md('**% Median Income Change**'),pct_below_poverty_chg =md('**% Pop Below Poverty Change**'),pct_unemployed_chg =md('**% Unemployment Rate Change**'),pct_pop_distressed_chg =md('**% Pop Distressed Change**'),pct_hhs_no_vehicles_chg =md('**% HHs No Vehicle Change**'),pct_developed_chg =md('**% Developed Change**'),pct_natural_barren_chg =md('**% Natural Barren Change**'),pct_cropland_chg =md('**% Cropland Change**'),pct_tree_cover_chg =md('**% Tree Cover Change**'),pct_grassland_chg =md('**% Grassland Change**'),pct_wetland_chg =md('**% Wetland Change**'),pct_water_chg =md('**% Water Change**') ) %>%fmt_percent(decimals =1, scale_values =FALSE)
Changes in Population Characteristics, Economic Indicators, and Land Cover
By Southern Tier County (2010 - 2019)
% Pop Change
% HHs Change
% Median Age Change
% Median Income Change
% Pop Below Poverty Change
% Unemployment Rate Change
% Pop Distressed Change
% HHs No Vehicle Change
% Developed Change
% Natural Barren Change
% Cropland Change
% Tree Cover Change
% Grassland Change
% Wetland Change
% Water Change
Allegany
−4.9%
−5.5%
5.3%
18.9%
1.2%
−80.7%
1,000,000.0%
17.2%
−0.3%
9.8%
−0.1%
0.1%
−9.8%
−0.1%
−1.6%
Broome
−3.8%
−2.8%
0.0%
20.7%
12.4%
−19.7%
57.4%
4.6%
−0.0%
20.8%
−0.1%
−0.0%
−5.7%
0.0%
−0.2%
Cattaraugus
−4.5%
−2.7%
4.2%
21.7%
4.2%
0.0%
331.7%
32.2%
−0.1%
9.0%
0.0%
−0.2%
9.2%
−0.1%
−0.0%
Chautauqua
−5.0%
−3.6%
5.7%
22.8%
6.7%
−47.6%
61.0%
9.6%
−0.3%
33.1%
0.0%
−0.3%
1.5%
−0.1%
−0.0%
Chemung
−4.3%
−4.0%
2.0%
28.8%
−8.0%
−10.3%
20.5%
−0.4%
−0.2%
8.4%
0.2%
−0.1%
2.2%
−0.0%
−0.5%
Chenango
−6.1%
3.5%
6.1%
19.9%
−0.4%
−37.0%
1,000,000.0%
39.0%
0.4%
21.5%
−0.1%
0.1%
−7.3%
−0.0%
1.1%
Cortland
−3.2%
−0.9%
2.2%
23.3%
15.5%
−72.1%
1,000,000.0%
−22.9%
0.5%
22.7%
−0.1%
−0.1%
5.4%
−0.1%
0.8%
Delaware
−6.7%
−5.7%
7.3%
20.6%
21.6%
−36.5%
1,000,000.0%
21.2%
−0.4%
5.2%
−0.0%
0.1%
−8.8%
−0.0%
−0.7%
Otsego
−4.2%
−6.1%
6.2%
21.8%
−1.4%
−54.8%
0.0%
6.9%
−0.2%
43.2%
−0.1%
0.3%
−10.4%
0.0%
−0.3%
Schoharie
−4.8%
−3.3%
9.6%
14.3%
7.8%
−43.6%
0.0%
8.3%
−0.0%
22.2%
0.1%
−0.1%
6.9%
−0.0%
−3.2%
Schuyler
−3.5%
−2.1%
9.1%
30.3%
88.2%
−12.8%
0.0%
−23.6%
0.3%
40.8%
0.5%
−0.1%
−12.8%
−0.1%
−0.2%
Steuben
−2.3%
−1.7%
5.1%
25.0%
0.8%
−43.7%
268.3%
15.3%
0.1%
10.4%
0.1%
−0.0%
−2.2%
−0.0%
−0.6%
Tioga
−5.2%
−1.8%
6.4%
31.2%
5.8%
−91.2%
0.0%
−0.8%
0.2%
18.1%
−0.0%
−0.1%
1.1%
−0.1%
0.1%
Tompkins
2.0%
3.0%
5.0%
15.9%
0.3%
56.5%
−100.0%
9.1%
0.3%
11.6%
0.0%
0.1%
−6.6%
−0.1%
0.0%
All counties except for Tompkins County had a population decline and an increase in the proportion of distressed people. Tompkins County was the only county where the civilian unemployment rate increased. All counties got older with the exception of Broome County. Additionally, median family income increased by at least 14% in all counties.
There were marginal changes in developed land, cropland, tree cover, wetland, and water areas in all counties. There were more significant changes in natural barren and (to a lesser extent) grassland areas in all counties. Grassland decreased by over 10% in Schuyler County (-12.8%) and Otsego County (-10.4%). All counties had much more natural barren land by 2019. However, the actual amount of land that became barren is relatively small given the very small amount of total natural barren land in the study area.
Analysis Correlations
This correlation analysis used the Pearson method.
Code
# filter for only pct chg columnstracts.pct_chg <- final_tracts_df %>%select(NAME, grep('chg', colnames(.), value =TRUE)) %>%st_drop_geometry()# calculate correlation coefficients between all variablestract_correlations <-cor(select(tracts.pct_chg, -c(NAME)))# display heatmap of correlationsheatmaply( tract_correlations, colors =colorRampPalette(c('blue', 'white', 'orange'))(100), dendrogram ='none', limits =c(-1, 1), branches.lwd =0.5)
Code
# create data frame of correlation coefficients between # pct distressed pop chg and other variablestract_cor.df <-melt(tract_correlations) %>%filter(Var1 =='pct_pop_chg', Var2 !='pct_pop_chg') %>%select(-Var1) %>%rename(Variable = Var2,Coefficient = value ) %>%arrange(desc(Coefficient))# display table of correlation with pct distressed pop chg in descending order of correlationtract_cor.df %>%gt() %>%tab_header(title =md('**Tract-Level Correlation with Percent Population Change**')) %>%cols_align(align ='center') %>%cols_label(Variable =md('**Variable**'),Coefficient =md('**Coefficient**') ) %>%fmt_number(columns = Coefficient, decimals =3)
Tract-Level Correlation with Percent Population Change
Variable
Coefficient
pct_hhs_chg
1.000
pct_wetland_chg
0.005
pct_tree_cover_chg
0.005
pct_unemployed_chg
0.003
pct_developed_chg
−0.001
pct_cropland_chg
−0.004
pct_hhs_no_vehicles_chg
−0.004
pct_water_chg
−0.004
pct_below_poverty_chg
−0.005
pct_grassland_chg
−0.008
pct_natural_barren_chg
−0.010
pct_median_age_chg
−0.025
pct_median_income_chg
−0.047
The most significant correlation is between population change and household change, which has a direct relationship. Other strong correlations are between poverty rate change and water area change which have a strong positive correlation, as well as the change in percentage of households with no vehicle and wetland area change which have a strong negative correlation.
The change in population variable is not strongly correlated with any of the other percentage change variables, with the exception of the percentage change in households.
Conclusions
This study was severely limited in the variables that were analyzed, since the study was centered around an analysis of the distressed population based on the two-variable criteria outlined by the Appalachian Regional Commission. A much deeper statistical analysis of the Southern Tier could be conducted to evaluate additional trends and gain better insights into the area, like the study by Ludke et al. (2012) which considered many other demographic variables such as employment by worker class and occupation, educational attainment, dependency ratio, marital status, and more granular poverty level variables (e.g., individual poverty, childhood poverty, senior adult poverty, and female household poverty). This study was also limited in its methodology related to the land cover change analysis. Methods employed by KC et al. (2024) in their analysis of eastern Kentucky would allow for better identification of land cover changes and how it changed, including the use of a random tree classifier, hot spot analysis, and the creation of a map of the areas that changed and what the land became.
The ACS 5-year data sets are generally viewed as the most accurate given the larger sample sizes. There could still be questions regarding the accuracy of certain estimates in many of the census tracts included in this study, especially in rural census tracts with smaller populations and larger margins of error. Despite this possible limitation, this study is still able to provide some valuable insights into how the New York Southern Tier region has changed between 2010 and 2019. Land cover did not change too drastically, with the largest changes being the additional 3.4 square miles of natural barren land and the 2.9 square miles of land that are no longer grasslands in the entire 14-county study area. There were no significant relationships between the change in population and changes in land cover and other population variables, suggesting that one could not accurately predict how a census tract’s population and land cover change based on the rate of population change. While median family income increased in all counties, every county except Tompkins County became older, less populated, and more distressed. Built-up areas in the Southern Tier (especially Binghamton, Jamestown, Dunkirk, Elmira, and Salamanca) are considerably more distressed than rural areas, with Ithaca and Oneonta being the only cities that do not have a significant risk.
The distressed population for each individual census tract could be calculated by determining the distressed status of the block groups within each census tract, and then summing up the total population that lives within distressed block groups in each census tract. Also, a separate study that evaluates the 14-county Southern Tier region in the post-COVID era (2020 - present) could offer valuable information about how the demographics of the Southern Tier have changed further since the onset of the pandemic, and if COVID has increased the number of distressed people.
Galili, T., O’Callaghan, A., Sidi, J., & Sievert, C. (2017). heatmaply: an R package for creating interactive cluster heatmaps for online publishing. Bioinformatics, 34(9), 1600-1602. https://doi.org/10.1093/bioinformatics/btx657
K C, S., Gyawali, B. R., Lucas, S., Antonious, G. F., Chiluwal, A., & Zourarakis, D. (2024). Assessing Land-Cover Change Trends, Patterns, and Transitions in Coalfield Counties of Eastern Kentucky, USA. Land, 13(9), 1541. https://doi.org/10.3390/land13091541
Ludke, R. L., Obermiller, P. J., & Rademacher, E. W. (2012). Demographic Change in Appalachia: A Tentative Analysis. Journal of Appalachian Studies, 18(1/2), 48–92. http://www.jstor.org/stable/23337708
Walker, K. & Herman, M. (2024). tidycensus: Load US Census Boundary and Attribute Data as ‘tidyverse’ and ‘sf’-Ready Data Frames. R package version 1.6.6. https://walker-data.com/tidycensus
Median Age: U.S. Census Bureau. (26 May 2011). “Census Bureau Releases 2010 Census Demographic Profiles for the United States, Arkansas, Illinois, Indiana, Iowa, Louisiana, Maryland, New Jersey, Oklahoma, Oregon, South Dakota, Texas, Vermont and Virginia,” CB11-CN.144. https://www.census.gov/newsroom/releases/archives/2010_census/cb11-cn144.html
Pengra, B.W., Stehman, S.V., Horton, J.A., Auch, R.F., Kambly, S., Knuppe, M., Sorenson, D., Robison, C., and Taylor, J.L. (2023). LCMAP CONUS Reference Data Product 1984-2021 land cover, land use and change process attributes: U.S. Geological Survey data release, https://doi.org/10.5066/P933Z1TK
---title: "Analyzing Distressed Population and Land Cover Changes in New York Appalachia (2010-2019)"subtitle: 'GEO511'author: Stephen C. Sandersdate: todaydate-format: longformat: html: smooth-scroll: true toc: true toc-location: left toc-title: 'Table of Contents' code-fold: true code-tools: true embed-resources: true self-contained-math: trueexecute: message: false warning: false---# IntroductionThe Southern Tier of New York consists of fourteen counties that are considered part of Northern Appalachia, according to the Appalachian Regional Commission. These counties have experienced some of the most drastic population declines in New York State outside of New York City (McMahon, 2024). On top of the decline in population, communities in much of the Southern Tier suffer from relatively high poverty and low income levels compared to the rest of the United States as a whole (ARC, 2024 County-Level Distressed Area Study).![Map of three subregions in Appalachian NY (NY Department of State)](https://dos.ny.gov/sites/g/files/oee926/files/styles/wysiwyg/public/media/2021/04/arc-map-.png?itok=Jf3ZpQA9){fig-alt="Map of three subregions of the New York Southern Tier region."}Some areas in Appalachia - such as Eastern Kentucky - have undergone extensive land reclamation efforts in an attempt to repair land that had been damaged during the era of intense coal mining operations, converting much of the reclaimed land into infrastructure, industry, and other development despite consistent population decline (KC, Gyawali, Lucas, et al., 2024). Coal mining was not a large industry in this area at any time, and much of the manufacturing was limited to cities such as Jamestown and Binghamton.While the need of a study concerning land cover for the purposes of land reclamation may not be necessary for the Southern Tier, an analysis of the region could lead to interesting insights about how the population decline may have impacted land cover changes. The purpose of this analysis is to get a general idea of the changes in population/economic variables and land cover in New York’s Southern Tier between 2010 and 2019 and how they may relate to each other. Specifically, are areas with a higher population decline more likely to have had an increase in natural barren land and/or a decrease in developed area?# Materials and MethodsThe analysis looked at various population-related variables. Specifically, data concerning total population, total households, median age, median family income, number of people below the poverty level, unemployment among civilian workforce over the age of 16, and households with no vehicles were pulled and/or aggregated at the U.S., county, and census tract levels. Census data was pulled for years between 2010 and 2019. All data was gathered using the [tidycensus](https://walker-data.com/tidycensus/) package, and a majority of it came from American Community Survey (ACS) 5-year estimates. U.S. data for 2010 had to be pulled from the decennial census or sourced from governmental reports and news releases since ACS data was not available for this year at the country-level. Data for years other than 2010 and 2019 were pulled to allow for additional analysis in the future.Primary land cover data for 2010 and 2019 comes from the [USGS](https://www.usgs.gov/special-topics/lcmap/collection-13-conus-science-products) LCMAP project and were downloaded from the [CONUS Mosaic](https://eros.usgs.gov/lcmap/apps/data-downloads) website. This data was processed using the [terra](https://rspatial.github.io/terra/) package.The methodology used to determine distressed status of each census tract was taken from the [Appalachian Regional Commission](https://www.arc.gov/distressed-areas-classification-system/)'s Distressed Areas Classification System. According to the ARC, the key attributes of a distressed census tract are:1. A median family income no greater than 67% of the U.S. average.2. A poverty rate of 150% of the U.S. average or greater.The correlation analysis was conducted on the census-tract level data and used the [Pearson method](https://www.sciencedirect.com/topics/computer-science/pearson-correlation). The [cor](https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/cor) function of the base R [stats](https://rdrr.io/r/stats/stats-package.html) package was used to calculate correlation coefficients.The [tidyverse](https://www.tidyverse.org/) collection of packages was primarily used to easily process large amount of data. The [tigris](https://github.com/walkerke/tigris) package was used directly to pull study counties and census tracts to create a map of the study area. The [sf](https://r-spatial.github.io/sf/) package helped with processing spatial features, including data pulled from the ACS. The maps were created using either [leaflet](https://rstudio.github.io/leaflet/), [mapview](https://r-spatial.github.io/mapview/), or [ggplot2](https://ggplot2.tidyverse.org/). The [gt](https://gt.rstudio.com/) package allowed for the creation of better looking tables. The [heatmaply](https://github.com/talgalili/heatmaply) package was used to visualize the correlation coefficients between all variables.## An Overview of the Analysis WorkflowBelow is an outline of how the analysis was conducted:1. Create a map of study area for reference.2. Pull Census data at US, census tract, and county levels for years between 2010 and 2019, then simplify datasets so only variables for the years 2010 and 2019 are included. + Certain data at the tract level (e.g., median family income) could not simply be aggregated to include in the county-level dataset, which required pulling that data separately at the county level. + U.S. data was pulled for comparison purposes in the distressed population analysis. + U.S. data for 2010 had to be sourced from governmental reports since they were not available for direct download using the tidycensus package. The only variable that was pulled using tidycensus in this case was total population. + Data for 2015 are also included in the consolidated datasets for the purposes of future work. They do not have any relevance to the analysis at this time.3. Download land cover datasets for years 2010 and 2019, then show side-by-side plot of both images. Show map of areas where the land cover type has changed between the years.4. Calculate zonal statistics of each of the 8 land cover classifications over the entire study area, then create a table and bar graph showing the changes in each of the classifications between 2010 and 2019.5. Determine distressed status of each of the census tracts for each year using criteria from the ARC by comparing median family income and poverty levels to the U.S. values. Determine which census tracts improved (i.e., were distressed in 2010 and no longer distressed in 2019) and which census tracts became distressed. Create maps to show tracts that improved and tracts that became distressed. Also show table breakdown by county of the number of tracts that became distressed and the number of tracts that improved.6. Merge base data variables, distressed variable data, and land cover classification data into single datasets at both the census tract and county levels. Calculate percent changes between 2010 and 2019 for each variable in each of the datasets. Create tables for both to show the percent changes by census tract and by county.7. Run basic correlation analysis on census tract-level dataset to figure out relationships between variables, and create a heatmap of correlation results. Lastly, create a table of correlation results between the percentage population change and all other percentage change variables. + Since there are only 14 counties, a county-level correlation analysis would have a very large margin of error. For this reason, this step was only done on the census tract-level data.# Data Gathering and Processing```{r libraries, message=F, warning=F}# load necessary librarieslibrary(tidyverse)library(tidycensus)library(sf)library(tigris)library(basemaps)library(leaflet)library(mapview)library(terra)library(tidyterra)library(gt)library(heatmaply)library(stringr)library(RColorBrewer)library(gridExtra)library(reshape2)library(here)library(knitr)knitr::opts_chunk$set(echo=TRUE) # cache the results for quick compiling# pull in census api tokencensus_token = Sys.getenv("CENSUS_TOKEN")census_api_key(census_token)```## Map of Study AreaThe map below shows the 14 counties in New York's Southern Tier (Allegany, Broome, Cattaraugus, Chautauqua, Chemung, Chenango, Cortland, Delaware, Otsego, Schoharie, Schuyler, Steuben, Tioga, and Tompkins) and all 277 census tracts.```{r study_area_map, message=F, warning=F}# increase timeout time to download files and cache tigris filesoptions(timeout = 500, tigris_use_cache = TRUE)# set vector of southern tier countiessouthern_tier_counties = c('Allegany', 'Broome', 'Cattaraugus', 'Chautauqua', 'Chemung', 'Chenango', 'Cortland', 'Delaware', 'Otsego', 'Schoharie', 'Schuyler', 'Steuben', 'Tioga', 'Tompkins')# get study geographies and basemap focused on ny stateny_state <- states(cb = TRUE, year = 2019) %>% filter(NAME == 'New York')study_counties <- counties(state = 'NY', cb = TRUE, year = 2019) %>% filter(NAME %in% southern_tier_counties)study_tracts <- tracts(state = 'NY', county = southern_tier_counties, cb = TRUE, year = 2019)base_ny <- basemap_raster(ext = ny_state, map_service = 'carto', map_type = 'light')# create study area mapstudy_area_map <- leaflet() %>% addTiles() %>% addPolygons(data = st_transform(study_counties, crs = '+proj=longlat +datum=WGS84'), fillOpacity = 0, label = ~study_counties$NAME) %>% addPolygons(data = st_transform(study_tracts, crs = '+proj=longlat +datum=WGS84'), fillOpacity = 0, color = 'black', weight = '0.75')study_area_map```## Download and Process All Required DataCensus data and land cover data are downloaded and processed here. The census data comes primarily from the American Community Survey (ACS) 5-year surveys, and the land cover data comes from the USGS.### ACS Data#### Set function to download ACS data based on geography```{r get_acs_func, message=F, warning=F}# create function to download acs data for multiple years# create function to download acs data for multiple yearsget_acs_data <- function(year, geom) { if (geom == 'tract') { return( get_acs( geography = geom, variables = c( tot_pop = 'B01003_001', tot_hhs = 'B08202_001', median_age = 'B07002_001', median_income = 'B19113A_001', tot_below_poverty = 'B17001_002', hhs_no_vehicle = 'B08201_002' ), state = 'NY', geometry = TRUE, year = year, output = 'wide', cache_table = TRUE, key = census_token ) %>% mutate( year = year, county = str_split(str_split(NAME, ', ', simplify = TRUE)[,2], ' ', simplify = TRUE)[,1], pct_below_poverty = tot_below_povertyE / tot_popE, pct_hhs_no_vehicles = hhs_no_vehicleE / tot_hhsE ) %>% filter(county %in% southern_tier_counties & !st_is_empty(geometry)) ) } else if (geom == 'county') { return( get_acs( geography = geom, variables = c( median_age = 'B07002_001', median_income = 'B19113A_001' ), state = 'NY', geometry = TRUE, year = year, output = 'wide', cache_table = TRUE, key = census_token ) %>% mutate( year = year, county = str_split(str_split(NAME, ', ', simplify = TRUE)[,1], ' ', simplify = TRUE)[,1] ) %>% filter(county %in% southern_tier_counties & !st_is_empty(geometry)) ) } else { return( get_acs( geography = 'us', variables = c( tot_pop = 'B01003_001', tot_hhs = 'B08202_001', median_age = 'B07002_001', median_income = 'B19113A_001', tot_below_poverty = 'B17001_002', hhs_no_vehicle = 'B08201_002' ), geometry = TRUE, year = year, output = 'wide', cache_table = TRUE, key = census_token ) %>% mutate( year = year ) ) }}```#### US Data```{r us_data, message=F, warning=F, cache=T}# get certain decennial 2010 census data at state level# then sum population and add additional data points taken from governmental reportsus_data.2010 <- get_decennial(geography = 'state', variables = c(tot_pop = 'P001001'), year = 2010, output = 'wide', cache_table = TRUE, geometry = TRUE) %>% mutate(NAME = 'United States') %>% group_by(NAME) %>% summarize(tot_popE = sum(tot_pop)) %>% mutate( tot_hhsE = 116716292, median_ageE = 37.2, pct_below_povertyE = 15.3, median_incomeE = 64400 ) %>% relocate(geometry, .after = last_col()) %>% as_tibble()# pull acs data at national levelus_data.2014_2019 <- map2(2014:2019, rep('us', times = 6), get_acs_data) %>% bind_rows() %>% as_tibble()# separate 2014-2019 us data into 2015 and 2019 data framesus_data.2015 <- us_data.2014_2019 %>% filter(year == 2015)us_data.2019 <- us_data.2014_2019 %>% filter(year == 2019)# merge us data for 2010, 2015, and 2019 into a single data frameus_data.2010_2019 <- left_join(us_data.2010, us_data.2015, by = 'NAME', keep = FALSE, suffix = c('', '_2015')) %>% left_join(us_data.2019, by = 'NAME', keep = TRUE, suffix = c('_2010', '_2019')) %>% select(!all_of(grep('M_', names(.), value = TRUE))) %>% # remove margin of error columns rename( GEOID = GEOID_2010, NAME = NAME_2010, geometry = geometry_2010, year = year_2010, pct_below_povertyE_2010 = pct_below_povertyE, tot_below_povertyE_2015 = tot_below_povertyE_2010, hhs_no_vehicleE_2015 = hhs_no_vehicleE_2010 ) %>% relocate(GEOID, .after = NAME) %>% select(-c('GEOID_2019', 'NAME_2019', 'geometry_2015', 'geometry_2019', 'year', 'year_2019')) %>% mutate( pct_below_poverty_2015 = (tot_below_povertyE_2015 / tot_popE_2015) * 100, pct_below_poverty_2019 = (tot_below_povertyE_2019 / tot_popE_2019) * 100, pct_hhs_no_vehicle_2015 = (hhs_no_vehicleE_2015 / tot_hhsE_2015) * 100, pct_hhs_no_vehicle_2019 = (hhs_no_vehicleE_2019 / tot_hhsE_2019) * 100, pct_tot_pop_chg_2010_2019 = ((tot_popE_2019 - tot_popE_2010) / tot_popE_2010) * 100, pct_median_age_chg_2015_2019 = ((median_ageE_2015 - median_ageE_2010) / median_ageE_2015) * 100, pct_median_income_chg_2010_2019 = ((median_incomeE_2019 - median_incomeE_2010) / median_incomeE_2010) * 100, pct_below_poverty_chg_2010_2019 = ((pct_below_poverty_2019 - pct_below_povertyE_2010) / pct_below_povertyE_2010) * 100, pct_hhs_no_vehicle_chg_2015_2019 = ((pct_hhs_no_vehicle_2019 - pct_hhs_no_vehicle_2015) / pct_hhs_no_vehicle_2015) * 100 ) %>% lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>% as_tibble() %>% relocate(geometry, .after = last_col()) %>% st_as_sf(crs = "EPSG: 4269")```#### Census Tract Data```{r tract_data_map, message=F, warning=F, cache=T}# get census tract data for 2010-2019# isolate data for 2010, 2015, and 2019 and put into separate dfsst_tracts <- map2(2010:2019, rep('tract', times = 10), get_acs_data) %>% bind_rows() %>% as_tibble()# show point plot of median income and pct below poverty level for each year# colored by countyggplot(st_tracts, aes(median_incomeE, pct_below_poverty, color = county)) + geom_jitter(na.rm = TRUE) + facet_wrap(~year) + labs(x = 'Median Income', y = '% Below Poverty Level', color = 'County') + theme(axis.text.x = element_text(angle = 45, hjust = 1))```There is a clear negative relationship between median family income and percent below poverty level, where tracts that have higher median family incomes tend to have a lower percentage of people below poverty. Most of the outliers for each year are in Tompkins County.##### Remaining Census Tract Data```{r tract_remaining, message=F, warning=F, cache=T}# get economic data (unemployed civilians > 16) for 2010-2019# data for 2018 returned a server errorst_tracts.economic <- map(c(2010, 2011, 2013, 2014, 2015, 2016, 2017, 2019), function(x) { return( get_acs( geography = 'tract', variables = c('DP03_0003', 'DP03_0005'), state = 'NY', geometry = TRUE, year = x, output = 'wide', cache_table = TRUE, key = census_token ) %>% rename( 'pop_gt_16_in_civilian_labor_force_{x}' := DP03_0003E, 'pop_gt_16_in_civilian_labor_force_unemployed_{x}' := DP03_0005E ) %>% mutate( year = x, county = str_split(NAME, ' ', simplify = TRUE)[,4] ) )}) %>% bind_rows()%>% filter(county %in% southern_tier_counties & !st_is_empty(geometry)) %>% as_tibble()# filter data for years 2010, 2015, and 2019, join with that year's economic data,# and store in separate data frames for each yearst_tracts.2010 <- # health insurance coverage data not available for 2010 st_tracts %>% filter(year == 2010) %>% left_join( select( filter(st_tracts.economic, year == 2010), GEOID, pop_gt_16_in_civilian_labor_force_2010, pop_gt_16_in_civilian_labor_force_unemployed_2010 ) ) %>% relocate(geometry, .after = last_col())st_tracts.2015 <- st_tracts %>% filter(year == 2015) %>% left_join( select( filter(st_tracts.economic, year == 2015), GEOID, pop_gt_16_in_civilian_labor_force_2015, pop_gt_16_in_civilian_labor_force_unemployed_2015 ) ) %>% relocate(geometry, .after = last_col())st_tracts.2019 <- st_tracts %>% filter(year == 2019) %>% left_join( select( filter(st_tracts.economic, year == 2019), GEOID, pop_gt_16_in_civilian_labor_force_2019, pop_gt_16_in_civilian_labor_force_unemployed_2019 ) ) %>% relocate(geometry, .after = last_col())# merge 2010, 2015, & 2019 data into single sf# compute pct chgs, convert to sf, and change infinite values to NAst_tracts.2010_2019 <- left_join(st_tracts.2010, st_tracts.2015, by = 'GEOID', keep = FALSE, suffix = c('', '_2015')) %>% left_join(st_tracts.2019, by = 'GEOID', keep = FALSE, suffix = c('_2010', '_2019')) %>% select(-c('NAME_2015', 'geometry_2015', 'year_2015', 'county_2015', 'NAME_2019', 'geometry_2019', 'year_2019', 'county_2019')) %>% rename( NAME = NAME_2010, geometry = geometry_2010, county = county_2010, year = year_2010 ) %>% mutate( across(starts_with('pop_gt_16'), ~ as.numeric(as.character(.))), pct_pop_chg_2010_2019 = ((tot_popE_2019 - tot_popE_2010) / tot_popE_2010) * 100, pct_poverty_chg_2010_2019 = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) * 100, pct_hhs_no_vehicles_chg_2010_2019 = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) * 100, pct_pop_gt_16_in_civilian_labor_force_unemployed_2010 = pop_gt_16_in_civilian_labor_force_unemployed_2010 / pop_gt_16_in_civilian_labor_force_2010, pct_pop_gt_16_in_civilian_labor_force_unemployed_2015 = pop_gt_16_in_civilian_labor_force_unemployed_2015 / pop_gt_16_in_civilian_labor_force_2015, pct_pop_gt_16_in_civilian_labor_force_unemployed_2019 = pop_gt_16_in_civilian_labor_force_unemployed_2019 / pop_gt_16_in_civilian_labor_force_2019, pct_pop_gt_16_in_civilian_labor_force_unemployed_chg_2010_2019 = ((pct_pop_gt_16_in_civilian_labor_force_unemployed_2019 - pct_pop_gt_16_in_civilian_labor_force_unemployed_2010) / pct_pop_gt_16_in_civilian_labor_force_unemployed_2010) * 100 ) %>% lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>% as_tibble() %>% relocate(geometry, .after = last_col()) %>% st_as_sf(crs = "EPSG: 4269")######################################################################## REMOVED 36013990000 Census Tract 9900, Chautauqua County, New York## Had no estimated population AND had empty geometry######################################################################```#### County Data```{r county_data, message=F, warning=F, cache=T}# pull southern tier county data and calculate area in square milesst_counties <- map2(2010:2019, rep('county', times = 10), get_acs_data) %>% bind_rows() %>% as_tibble() %>% st_as_sf(crs = "EPSG: 4269") %>% mutate(area_sqmi = st_area(.) / 2589988.110336) %>% relocate(geometry, .after = last_col())# separate st_counties for 2010, 2015, and 2019 into separate dataframesst_counties.2010 <- st_counties %>% filter(year == 2010) %>% as_tibble()st_counties.2015 <- st_counties %>% filter(year == 2015) %>% as_tibble()st_counties.2019 <- st_counties %>% filter(year == 2019) %>% as_tibble()# merge 2010, 2015, & 2019 data into single sf# compute pct chgs, convert to sf, and change infinite values to NA# will merge with grouped st_tracts.2010_2019 data belowst_counties_base.2010_2019 <- left_join(st_counties.2010, st_counties.2015, by = 'GEOID', keep = FALSE, suffix = c('', '_2015')) %>% left_join(st_counties.2019, by = 'GEOID', keep = FALSE, suffix = c('_2010', '_2019')) %>% select(-c('NAME_2015', 'geometry_2015', 'year_2015', 'county_2015', 'NAME_2019', 'geometry_2019', 'year_2019', 'county_2019')) %>% rename( NAME = NAME_2010, geometry = geometry_2010, county = county_2010, year = year_2010 ) %>% mutate( pct_median_age_chg_2010_2019 = ((median_ageE_2019 - median_ageE_2010) / median_ageE_2010) * 100, pct_median_income_chg_2010_2019 = ((median_incomeE_2019 - median_incomeE_2010) / median_incomeE_2010) * 100 ) %>% lapply(function(i) if(is.numeric(i)) ifelse(is.infinite(i), 0, i) else i) %>% as_tibble() %>% relocate(geometry, .after = last_col()) %>% st_as_sf(crs = "EPSG: 4269")# get list of all pct columnspct_cols <- grep('pct', names(st_tracts.2010_2019), value = TRUE)# calculate data from st_tracts.2010_2019 by grouping by county, then merge with st_counties_base.2010_2019# create data frame of all county-level datast_counties.2010_2019 <- st_tracts.2010_2019 %>% select(!all_of(pct_cols)) %>% group_by(county) %>% reframe( tot_pop_2010 = sum(tot_popE_2010), tot_pop_2015 = sum(tot_popE_2015), tot_pop_2019 = sum(tot_popE_2019), tot_hhs_2010 = sum(tot_hhsE_2010), tot_hhs_2015 = sum(tot_hhsE_2015), tot_hhs_2019 = sum(tot_hhsE_2019), tot_below_poverty_2010 = sum(tot_below_povertyE_2010), tot_below_poverty_2015 = sum(tot_below_povertyE_2015), tot_below_poverty_2019 = sum(tot_below_povertyE_2019), hhs_no_vehicles_2010 = sum(hhs_no_vehicleE_2010), hhs_no_vehicles_2015 = sum(hhs_no_vehicleE_2015), hhs_no_vehicles_2019 = sum(hhs_no_vehicleE_2019), pop_gt_16_in_civ_lab_force_2010 = sum(pop_gt_16_in_civilian_labor_force_2010), pop_gt_16_in_civ_lab_force_2015 = sum(pop_gt_16_in_civilian_labor_force_2015), pop_gt_16_in_civ_lab_force_2019 = sum(pop_gt_16_in_civilian_labor_force_2019), pop_gt_16_in_civ_lab_force_unemployed_2010 = pop_gt_16_in_civilian_labor_force_unemployed_2010, pop_gt_16_in_civ_lab_force_unemployed_2015 = pop_gt_16_in_civilian_labor_force_unemployed_2015, pop_gt_16_in_civ_lab_force_unemployed_2019 = pop_gt_16_in_civilian_labor_force_unemployed_2019, pct_below_poverty_2010 = (tot_below_poverty_2010 / tot_pop_2010) * 100, pct_below_poverty_2015 = (tot_below_poverty_2015 / tot_pop_2015) * 100, pct_below_poverty_2019 = (tot_below_poverty_2019 / tot_pop_2019) * 100, pct_hhs_no_vehicles_2010 = (hhs_no_vehicles_2010 / tot_hhs_2010) * 100, pct_hhs_no_vehicles_2015 = (hhs_no_vehicles_2015 / tot_hhs_2015) * 100, pct_hhs_no_vehicles_2019 = (hhs_no_vehicles_2019 / tot_hhs_2019) * 100, pct_pop_gt_16_in_civ_lab_force_unemployed_2010 = (pop_gt_16_in_civ_lab_force_unemployed_2010 / pop_gt_16_in_civ_lab_force_2010) * 100, pct_pop_gt_16_in_civ_lab_force_unemployed_2015 = (pop_gt_16_in_civ_lab_force_unemployed_2015 / pop_gt_16_in_civ_lab_force_2015) * 100, pct_pop_gt_16_in_civ_lab_force_unemployed_2019 = (pop_gt_16_in_civ_lab_force_unemployed_2019 / pop_gt_16_in_civ_lab_force_2019) * 100, pct_pop_chg_2010_2019 = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) * 100, geometry = st_union(geometry) ) %>% distinct(county, .keep_all = TRUE) %>% left_join(st_drop_geometry(st_counties_base.2010_2019), by = join_by(county == county), suffix = c('', ''), keep = TRUE) %>% st_as_sf(crs = st_crs(st_counties_base.2010_2019))```### Land Cover Data#### Land Cover Set Up```{r land_cover_setup, message=F, warning=F}# set urls to land cover imagesurl_2010 <- 'https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/lcmap/public/full_extent_downloads/version_13/primary-landcover_conus_year_data/LCMAP_CU_2010_V13_LCPRI/LCMAP_CU_2010_V13_LCPRI.tif'url_2019 <- 'https://edcintl.cr.usgs.gov/downloads/sciweb1/shared/lcmap/public/full_extent_downloads/version_13/primary-landcover_conus_year_data/LCMAP_CU_2019_V13_LCPRI/LCMAP_CU_2019_V13_LCPRI.tif'# dissolve counties into single study are polygonst_full_study_area <- st_counties.2010_2019 %>% st_union()# define crop_raster function - crop land cover rasters to full study area# return both cropped and masked resultscrop_raster <- function(lc_file, study_area) { crp <- crop(lc_file, vect(st_transform(study_area, crs = st_crs(lc_file)))) msk <- mask(crp, vect(st_transform(study_area, crs = st_crs(lc_file)))) return(msk)}# define calculate_zonal_stats function - calculate total area of each# land cover category in square miles over the entire study areacalculate_zonal_stats <- function(lc_file) { z <- zonal( cellSize(lc_file, unit = 'km'), lc_file, fun=sum ) z <- z %>% mutate(area_sqmi = area * 0.386102) %>% rename(land_cover_category = names(lc_file)[[1]]) %>% subset(select = -area)}# set land cover description listland_cover_type <- c( Developed = 1, Cropland = 2, `Grassland/Shrubland` = 3, `Tree Cover` = 4, Water = 5, Wetlands = 6, `Snow and Ice` = 7, `Natural Barren` = 8)# load three land cover rasters and crop each to study area polygon# find total area of each land cover categories in entire study arealand_cover_2010 <- rast(url_2010)st_lc_2010_masked <- crop_raster(land_cover_2010, st_full_study_area)zonal_stats_2010_study_area <- calculate_zonal_stats(st_lc_2010_masked)land_cover_2019 <- rast(url_2019)st_lc_2019_masked <- crop_raster(land_cover_2019, st_full_study_area)zonal_stats_2019_study_area <- calculate_zonal_stats(st_lc_2019_masked)```#### Land Cover Processing and Change CalculationThis section pertains to land cover over the entire 14-county study area. The interpretation of the land cover images' pixel values and corresponding land cover classes were taken from p. 7 of the [LCMAP Collection 1.3 Data Format Control Book](https://d9-wret.s3.us-west-2.amazonaws.com/assets/palladium/production/s3fs-public/media/files/LSDS-2346%20Land%20Change%20Monitoring%2C%20Assessment%2C%20and%20Projection%20%28LCMAP%29%20Collection%201.3%20Data%20Format%20Control%20Book%20%28DFCB%29%20-v1.0%20%202022_07_12.pdf).```{r land_cover_maps, message=F, warning=F}# create data base of land cover descriptions and their colorslc.desc <- data.frame( ID = land_cover_type, landcover = names(land_cover_type), color = c('red', 'yellow', 'lightgreen', 'darkgreen', 'lightblue', 'blue', 'white', 'lightgray'), stringsAsFactors = FALSE)# define create_lc_plot function - create a ggplot of masked land cover objectcreate_lc_plot <- function(lc_file, year) { # convert file to factors lc <- as.factor(lc_file) # create plot plt <- ggplot() + geom_spatraster(data = lc) + scale_fill_manual(values = setNames(lc.desc$color, lc.desc$ID), labels = lc.desc$landcover, breaks = lc.desc$ID, name = 'Landcover Type') + ggtitle(paste('Land Cover ', '(', year, ')', sep = '')) + theme(legend.position = 'right', plot.title = element_text(hjust = 0.5)) + guides(fill = guide_legend(ncol = 1, byrow = TRUE))}# generate plots for 2010 and 2019 land cover imageslc_2010_plt <- create_lc_plot(st_lc_2010_masked, 2010)lc_2019_plt <- create_lc_plot(st_lc_2019_masked, 2019)# display stacked plot of both land cover imagesgridExtra::grid.arrange(lc_2010_plt, lc_2019_plt, ncol = 1)```Areas shown in black in the map below are areas where the land cover has changed between 2010 and 2019. The actual change in classification is not depicted.```{r land_cover_chg_map, message=F, warning=F, cache=T}# compare 2019 and 2010 land cover images to see where changes occurredchg <- (st_lc_2019_masked == st_lc_2010_masked)# create color palette for mappalette <- colorNumeric(c('black', 'black', 'black', 'white', 'white', 'white'), values(chg), na.color = 'transparent')# display what areas have changed in land coverleaflet() %>% addTiles %>% addRasterImage(chg, colors = palette, opacity = 0.75, maxBytes = 5000000) %>% addPolygons(data = st_transform(st_counties.2010_2019$geometry, crs = '+proj=longlat +datum=WGS84'), color = 'red', opacity = 1, weight = 1, fillOpacity = 0)``````{r land_cover_chg_table, message=F, warning=F}# land cover changes from 2010 to 2019 in entire study arealand_cover_chg_study_area.2010_2019 <- left_join( zonal_stats_2010_study_area, zonal_stats_2019_study_area, by = 'land_cover_category', suffix = c('_2010', '_2019')) %>% mutate( pct_of_tot_area_2010 = (area_sqmi_2010 / sum(area_sqmi_2010)) * 100, pct_of_tot_area_2019 = (area_sqmi_2019 / sum(area_sqmi_2019)) * 100, chg_in_area_sqmi = ((area_sqmi_2019 - area_sqmi_2010) / area_sqmi_2010) * 100 )# convert land_cover_type vector into a dataframe to merge with land_cover_chg data frame# so land cover descriptions are includedlc.type <- data.frame( land_cover_category = land_cover_type, land_cover_desc = rownames(as.data.frame(land_cover_type)))rownames(lc.type) <- 1:nrow(lc.type)# join lc.type df with land cover chg results df, then remove numbered category column# and replace all NAs with 0lc_chg.2010_2019 <- left_join(lc.type, land_cover_chg_study_area.2010_2019, by = 'land_cover_category') %>% select(-land_cover_category) %>% replace(is.na(.), 0)# create table of land cover changelc_chg.2010_2019 %>% arrange(desc(area_sqmi_2010)) %>% gt(rowname_col = 'land_cover_desc') %>% tab_header(title = md('**Land Cover Change in NY Southern Tier**')) %>% cols_label( area_sqmi_2010 = md('**Area (2010)**'), area_sqmi_2019 = md('**Area (2019)**'), pct_of_tot_area_2010 = md('**% of Area (2010)**'), pct_of_tot_area_2019 = md('**% of Area (2019)**'), chg_in_area_sqmi = md('**% Change**') ) %>% fmt_number(columns = c('area_sqmi_2010', 'area_sqmi_2019'), decimals = 1) %>% fmt_percent(columns = c('pct_of_tot_area_2010', 'pct_of_tot_area_2019', 'chg_in_area_sqmi'), decimals = 2, scale_values = FALSE)# create bar graph of land cover change between 2019 and 2019ggplot(lc_chg.2010_2019, aes(x = land_cover_desc, y = chg_in_area_sqmi)) + geom_col(fill = 'blue') + labs(x = 'Land Cover Type', y = '% Change (sq mi)', title = 'Change in Area by Land Cover Classification') + theme(plot.title = element_text(hjust = 0.5), axis.text.x = element_text(angle = 45, hjust = 1))```A majority of the study area is covered by trees and cropland, with much smaller amounts of other land cover classes. The images of land cover change in 2010 and 2019 would not suggest any major land cover changes between that time period. There was an over 13% (about 3.4 square miles) increase in natural barren land and an almost 3% (about 2.9 square miles) decrease in grassland/shrubland. There were very small changes in other land cover types, and no snow and ice cover in either of the two years.# ResultsThe final analysis involved calculating the number of people who live in distressed areas. Using the criteria defined in the ARC's Distressed Areas Classification System, the distressed status of each census tract was determined for 2010 and 2019. Using these statuses, it was then possible to see if each census tract improved or became distressed within the same time period. This data was used to figure out how many people lived in distressed areas in each county. The area of each land cover classification was then calculated for each census tract and county.The above data was combined into separate data frames for census tracts and counties. The percentage change of each study variable was also calculated, except for the percentage change of distressed population at the census-tract level since these values would either be 0% or infinite. A small correlation analysis was conducted to determine relationships between any of the percentage change variables at both the tract level and the correlation coefficients were visualized using a heat map. A separate table was created to see if the percentage change in population was related to any of the other percentage change variables.## Distressed Area Analysis```{r distressed_setup, message=F, warning=F}# get list of columns that are involved in distressed area classificationdistressed_cols <- c( grep('tot_popE', names(st_tracts.2010_2019), value = TRUE), grep('median_income', names(st_tracts.2010_2019), value = TRUE), grep('pct_below_poverty', names(st_tracts.2010_2019), value = TRUE))# determined distressed area classification of each census tractst_tracts.distressed <- st_tracts.2010_2019[,c('GEOID', 'NAME', 'county', distressed_cols)] %>% mutate( if_Distressed_2010 = (((median_incomeE_2010 / us_data.2010_2019$median_incomeE_2010) <= 0.67) & ((pct_below_poverty_2010 / ((us_data.2010_2019$pct_below_povertyE_2010) / 100)) >= 1.50)), if_Distressed_2015 = (((median_incomeE_2015 / us_data.2010_2019$median_incomeE_2015) <= 0.67) & ((pct_below_poverty_2015 / ((us_data.2010_2019$pct_below_poverty_2015) / 100)) >= 1.50)), if_Distressed_2019 = (((median_incomeE_2019 / us_data.2010_2019$median_incomeE_2019) <= 0.67) & ((pct_below_poverty_2019 / ((us_data.2010_2019$pct_below_poverty_2019) / 100)) >= 1.50)), if_Became_Distressed_2010_2019 = (if_Distressed_2010 == FALSE & if_Distressed_2019 == TRUE), if_Distressed_Then_Improved_2010_2019 = (if_Distressed_2010 == TRUE & if_Distressed_2019 == FALSE) ) %>% relocate(geometry, .after = last_col())# create spatial table of distressed statuses for each census tractdistressed.tab <- st_tracts.distressed %>% select(GEOID, NAME, county, grep('Distressed', colnames(st_tracts.distressed), value = TRUE))# map which tracts were distressed in 2010mapview( distressed.tab, zcol = 'if_Distressed_2010', alpha.regions = 0.5, popup = "NAME", layer.name = c("Distressed (2010)"))# map which tracts were distressed in 2010mapview( distressed.tab, zcol = 'if_Distressed_2019', alpha.regions = 0.5, popup = "NAME", layer.name = c("Distressed (2019)"))# create table of number of worsened and improved tracts by county, then displaydistressed.tab %>% group_by(county) %>% summarize( tot_tracts = n(), across( grep('2010', colnames(.), value = TRUE), \(x) sum(x, na.rm = TRUE) ), across( grep('2019', colnames(.), value = TRUE), \(x) sum(x, na.rm = TRUE) ) ) %>% st_drop_geometry() %>% relocate(if_Distressed_2019, .after = if_Distressed_2010) %>% arrange(desc(tot_tracts)) %>% gt() %>% cols_label( county = md('**County**'), tot_tracts = md('**# Tracts**'), if_Distressed_2010 = md('**Distressed (2010)**'), if_Distressed_2019 = md('**Distressed (2019)**'), if_Became_Distressed_2010_2019 = md('**Became Distressed**'), if_Distressed_Then_Improved_2010_2019 = md('**Distressed Then Improved**') )```Across the study area there were 39 census tracts (14.1%) that were distressed in 2019, an increase from the 22 census tracts (7.9%) that were distressed in 2010. Nine of the fourteen counties had census tracts that became distressed, while only two counties had a tract that improved. In total, 20 census tracts (7.2%) became distressed and only 2 census tracts (0.7%) improved. Cortland County had the largest percentage of census tracts that became distressed (16.7%), followed by Allegany County (15.4%) and Chautauqua County (11.4%).Most cities in the Southern Tier are at least mostly distressed in terms of number of distressed census tracts. The only cities that did not have distressed areas are Ithaca (Tompkins County) and Oneonta (Otsego County). In contrast, Binghamton, Jamestown, Dunkirk, and Elmira were all significantly distressed.Otsego, Tioga, Schoharie, and Schuyler Counties had no distressed census tracts in 2010 or 2019. Tompkins County had 1 census tract that was distressed in 2010, but its distressed status could not be determined in 2019.The map below shows the census tracts that became distressed between 2010 and 2019.```{r became_distressed_tracts, message=F, warning=F}# map which tracts became distressed between 2010 and 2019mapview( distressed.tab, zcol = 'if_Became_Distressed_2010_2019', alpha.regions = 0.5, popup = "NAME", layer.name = c("Became Distressed (2010 -> 2019)"))```There are a few census tracts that do not appear on the map, although their popup labels work. The table below shows the three census tracts that have an "NA" value in the "if_Became_Distressed_2010_2019" column. These three tracts are missing at least 1 data point that was used to determine distressed status.```{r NA_distressed_tracts, message=F, warning=F}# display median income and pct below poverty data data for tracts# that have NA 'if_Became_Distressed_2010_2019' valuest_tracts.distressed %>% filter(is.na(if_Became_Distressed_2010_2019)) %>% select(NAME, median_incomeE_2010, median_incomeE_2019, pct_below_poverty_2010, pct_below_poverty_2019) %>% st_drop_geometry() %>% gt()```The map below shows the census tracts that were distressed in 2010 and were no longer distressed in 2019.```{r improved_tracts, message=F, warning=F}# map which tracts improved between 2010 and 2019mapview( distressed.tab, zcol = 'if_Distressed_Then_Improved_2010_2019', alpha.regions = 0.5, popup = "NAME", layer.name = c("Improved (2010 -> 2019)"))```As is the case with census tracts that became distressed, some of the tracts do not show up. The table below shows which tracts have an "NA" value in the 'if_Distressed_Then_Improved_2010_2019' column. These 4 census tracts are missing at least 1 data point that was used to determine distressed status. ```{r NA_improved_tracts, message=F, warning=F}# display median income and pct below poverty data data for tracts# that have NA 'if_Distressed_Then_Improved_2010_2019' valuest_tracts.distressed %>% filter(is.na(if_Distressed_Then_Improved_2010_2019)) %>% select(NAME, median_incomeE_2010, median_incomeE_2019, pct_below_poverty_2010, pct_below_poverty_2019) %>% st_drop_geometry() %>% gt()```Most of the census tracts that became distressed between 2010 and 2019 are located in built-up areas, such as Binghamton, Jamestown, Dunkirk, Cortland, and Hornell. There were additionally a few rural tracts that became distressed, as well as the Allegany Indian Reservation centered around Salamanca in Cattaraugus County.There were only 2 census tracts that improved from a distressed status: 1 in Broome County in between Binghamton and Johnson City (Census Tract 1) and 1 in eastern Dunkirk (Census Tract 354). In Census Tract 1, the median family income increased by over 64% and the percentage below poverty level increased by less than 4%. In Census Tract 354, the median family income increased by almost 46% and the percentage below poverty level decreased by over 20%.## Distressed Population and Land Cover Change Analysis### Analysis Set UpSome percentage change values were calculated to be infinite values, which occurred when the value of some variable was 0 in 2010 and had increased by 2019. These values were edited to reflect a change of (an arbitrary value of) 1,000,000% so that they could be used in the correlation analysis.```{r gather_data_function, message=F, warning=F}# define add_land_cover_type_area functionadd_land_cover_type_area <- function(summarize_df, df, col, lc_num) { summarize_df[1,as.character(col)] = ifelse( nrow(filter(df, land_cover_category == lc_num)) == 1, filter(df, land_cover_category == lc_num)$area_sqmi, 0 )}# define gather_data functiongather_data <- function(lc_file, year, geog) { # set column names for different land cover categories developed_col = as.symbol(paste('developed_area_sqmi_', as.character(year), sep = '')) natural_barren_col = as.symbol(paste('natural_barren_area_sqmi_', as.character(year), sep = '')) cropland_col = as.symbol(paste('cropland_area_sqmi_', as.character(year), sep = '')) tree_cover_col = as.symbol(paste('tree_cover_area_sqmi_', as.character(year), sep = '')) grassland_col = as.symbol(paste('grassland_area_sqmi_', as.character(year), sep = '')) wetland_col = as.symbol(paste('wetland_area_sqmi_', as.character(year), sep = '')) water_col = as.symbol(paste('water_area_sqmi_', as.character(year), sep = '')) # set distressed column name for the year distressed_col_yr = as.symbol(paste('if_Distressed_', as.character(year), sep = '')) # set name of tot_pop_distressed column with year appended to end tot_pop_distressed_col <- as.symbol(paste('tot_pop_distressed_', as.character(year), sep = '')) # set columns only used in tracts data gathering tot_below_poverty_est_col = as.symbol(paste('tot_below_povertyE_', as.character(year), sep='')) hhs_no_vehicles_est_col = as.symbol(paste('hhs_no_vehicleE_', as.character(year), sep = '')) # set total population column to use in calculations tot_pop_est_col = as.symbol(paste('tot_popE_', as.character(year), sep = '')) tot_pop_col = as.symbol(paste('tot_pop_', as.character(year), sep = '')) tot_hhs_col = as.symbol(paste('tot_hhs_', as.character(year), sep = '')) tot_hhs_est_col = as.symbol(paste('tot_hhsE_', as.character(year), sep = '')) tot_below_poverty_col = as.symbol(paste('tot_below_poverty_', as.character(year), sep = '')) pop_civ_lab_force_col = as.symbol(paste('pop_gt_16_in_civ_lab_force_', as.character(year), sep = '')) pop_unemployed_col = as.symbol(paste('pop_gt_16_in_civ_lab_force_unemployed_', as.character(year), sep = '')) pop_distressed_col = as.symbol(paste('tot_pop_distressed_', as.character(year), sep = '')) hhs_no_vehicles_col = as.symbol(paste('hhs_no_vehicles_', as.character(year), sep = '')) area_col = as.symbol(paste('area_sqmi_', as.character(year), sep = '')) # set names of new columns to be calculated pct_below_poverty_col = as.symbol(paste('pct_below_poverty_', as.character(year), sep = '')) pct_unemployed_col = as.symbol(paste('pct_unemployed_', as.character(year), sep = '')) pct_pop_distressed_col = as.symbol(paste('pct_pop_distressed_', as.character(year), sep = '')) pct_hhs_no_vehicles_col = as.symbol(paste('pct_hhs_no_vehicles_', as.character(year), sep = '')) pct_developed_col = as.symbol(paste('pct_developed_area_sqmi_', as.character(year), sep = '')) pct_natural_barren_col = as.symbol(paste('pct_natural_barren_area_sqmi_', as.character(year), sep = '')) pct_cropland_col = as.symbol(paste('pct_cropland_area_sqmi_', as.character(year), sep = '')) pct_tree_cover_col = as.symbol(paste('pct_tree_cover_area_sqmi_', as.character(year), sep = '')) pct_grassland_col = as.symbol(paste('pct_grassland_area_sqmi_', as.character(year), sep = '')) pct_wetland_col = as.symbol(paste('pct_wetland_area_sqmi_', as.character(year), sep = '')) pct_water_col = as.symbol(paste('pct_water_area_sqmi_', as.character(year), sep = '')) # set names of columns to be edited or removed median_age_est_col = as.symbol(paste('median_ageE_', as.character(year), sep = '')) median_income_est_col = as.symbol(paste('median_incomeE_', as.character(year), sep = '')) new_median_age_est_col = as.symbol(paste('median_age_', as.character(year), sep = '')) new_median_income_est_col = as.symbol(paste('median_income_', as.character(year), sep = '')) median_age_moe_col = as.symbol(paste('median_ageM_', as.character(year), sep = '')) median_income_moe_col = as.symbol(paste('median_incomeM_', as.character(year), sep = '')) # initialize index to use in data_list index = 1 # # initialize list to hold dataframe for each county or tract if (geog == 'county') { data_list = vector('list', length = length(southern_tier_counties)) } else { data_list = vector('list', length = length(st_tracts.2010_2019)) } # run this if geog is set to 'county' if (geog == 'county') { # iterate over each study county and get population, distressed, and zonal stats data, # then store resulting data frame in df object df <- for (i in southern_tier_counties) { # get county geography county_sf <- study_counties %>% filter(NAME == i) # get cropped & masked land cover raster for county county_lc_masked <- crop_raster(lc_file, county_sf) # calculate area of each land cover category in county county_zonal_stats <- calculate_zonal_stats(county_lc_masked) %>% summarize( !!developed_col := filter(., land_cover_category == 1)$area_sqmi, !!natural_barren_col := filter(., land_cover_category == 8)$area_sqmi, !!cropland_col := filter(., land_cover_category == 2)$area_sqmi, !!tree_cover_col := filter(., land_cover_category == 4)$area_sqmi, !!grassland_col := filter(., land_cover_category == 3)$area_sqmi, !!wetland_col := filter(., land_cover_category == 6)$area_sqmi, !!water_col := filter(., land_cover_category == 5)$area_sqmi ) %>% mutate(county = i, geometry = county_sf$geometry) %>% st_as_sf(crs = st_crs(st_counties.2010_2019)) # get county stats county_pop_data <- st_counties.2010_2019 %>% filter(county == i) %>% select(county, contains(as.character(year)) & !contains('pct')) # calculate number of people in each county that lived in tracts that # were distressed and improved and in tracts that became distressed county_distressed <- st_tracts.distressed %>% filter(county == i) %>% select(GEOID, NAME, county, contains('tot_popE'), contains('Distressed')) # total number of people living in distress for this year pop_distressed <- county_distressed %>% filter(!!distressed_col_yr == TRUE) %>% summarize( !!tot_pop_distressed_col := sum(!!tot_pop_est_col, na.rm = TRUE) ) %>% mutate(county = i) %>% relocate(geometry, .after = last_col()) # get number of people who lived in areas that became distressed by 2019 pop_became_distressed <- county_distressed %>% filter(if_Became_Distressed_2010_2019 == TRUE) %>% summarize( tot_pop_became_distressed_2010_2019 = sum(!!tot_pop_est_col, na.rm = TRUE) ) %>% mutate(county = i) %>% relocate(geometry, .after = last_col()) # get number of people who lived in areas that improved by 2019 pop_improved <- county_distressed %>% filter(if_Distressed_Then_Improved_2010_2019 == TRUE) %>% summarize( tot_pop_improved_2010_2019 = sum(!!tot_pop_est_col, na.rm = TRUE) ) %>% mutate(county = i) %>% relocate(geometry, .after = last_col()) # join distressed data-related data frames together county_distressed.data <- st_join(pop_distressed, pop_became_distressed) %>% st_join(pop_improved) # join 3 dataframes, then add to list of county data frames d <- st_join(county_pop_data, county_distressed.data, suffix = c('', '.y')) %>% st_join(county_zonal_stats, suffix = c('', '.z')) %>% select(-c('county.y...17', 'county.y...19', 'county.x', 'county.z', !!median_age_moe_col, !!median_income_moe_col)) %>% rename( !!new_median_age_est_col := !!median_age_est_col, !!new_median_income_est_col := !!median_income_est_col ) %>% mutate( !!pct_below_poverty_col := (!!tot_below_poverty_col / !!tot_pop_col) * 100, !!pct_unemployed_col := (!!pop_unemployed_col / !!pop_civ_lab_force_col) * 100, !!pct_pop_distressed_col := (!!pop_distressed_col / !!tot_pop_col) * 100, !!pct_hhs_no_vehicles_col := (!!hhs_no_vehicles_col / !!tot_hhs_col) * 100, !!pct_developed_col := (!!developed_col / !!area_col) * 100, !!pct_natural_barren_col := (!!natural_barren_col / !!area_col) * 100, !!pct_cropland_col := (!!cropland_col / !!area_col) * 100, !!pct_tree_cover_col := (!!tree_cover_col / !!area_col) * 100, !!pct_grassland_col := (!!grassland_col / !!area_col) * 100, !!pct_wetland_col := (!!wetland_col / !!area_col) * 100, !!pct_water_col := (!!water_col / !!area_col) * 100 ) # add data frame to county data list data_list[[index]] <- d # add 1 to index index = index + 1 } } else { # run this if geography is set to 'tract' # iterate over each study tract and get population, distressed, and zonal stats data, # then store resulting data frame in df object df <- for (i in st_tracts.2010_2019$GEOID) { # get tract geography tract_sf <- st_tracts.2010_2019 %>% filter(GEOID == i) # get cropped & masked land cover raster for tract tract_lc_masked <- crop_raster(lc_file, tract_sf) # calculate area of each land cover category in tract tract_zonal_stats <- calculate_zonal_stats(tract_lc_masked) # create vector of column names in summarized area table col.names <- c(developed_col, natural_barren_col, cropland_col, tree_cover_col, grassland_col, wetland_col, water_col) # create new single-row data frame with column names called tr.zs # to store area stats for census tract tr.zs <- as.data.frame(matrix(rep(0, length(col.names)), nrow=1)) names(tr.zs) <- col.names # add area for each land cover type to new df tr.zs[1, as.character(developed_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, developed_col, 1) tr.zs[1, as.character(cropland_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, cropland_col, 2) tr.zs[1, as.character(grassland_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, developed_col, 3) tr.zs[1, as.character(tree_cover_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, tree_cover_col, 4) tr.zs[1, as.character(water_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, water_col, 5) tr.zs[1, as.character(wetland_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, wetland_col, 6) tr.zs[1, as.character(natural_barren_col)] <- add_land_cover_type_area(tr.zs, tract_zonal_stats, natural_barren_col, 8) # add GEOID, total area, and geometry columns to tr.zs then turn into sf tr.zs <- tr.zs %>% mutate(tract = i, !!area_col := !!developed_col + !!natural_barren_col + !!cropland_col + !!tree_cover_col + !!grassland_col + !!wetland_col + !!water_col, geometry = tract_sf$geometry) %>% st_as_sf(crs = st_crs(st_tracts.2010_2019)) # get tracts stats tract_pop_data <- filter(st_tracts.2010_2019, GEOID == i) %>% select(GEOID, NAME, county, contains(as.character(year))) %>% rename( !!pop_civ_lab_force_col := as.symbol(paste('pop_gt_16_in_civilian_labor_force_', as.character(year), sep = '')), !!pop_unemployed_col := as.symbol(paste('pop_gt_16_in_civilian_labor_force_unemployed_', as.character(year), sep = '')) ) # get distressed data for tract tract_distressed <- st_tracts.distressed %>% filter(GEOID == i) %>% select(GEOID, contains('Became_Distressed'), contains('Improved')) # join 3 dataframes, then add to list of county data frames d <- st_join(tract_pop_data, tract_distressed, suffix = c('', '.y')) %>% st_join(tr.zs, suffix = c('', '.z')) %>% select(-c(GEOID.y, tract, !!median_age_moe_col, !!median_income_moe_col)) %>% rename( !!new_median_age_est_col := !!median_age_est_col, !!new_median_income_est_col := !!median_income_est_col ) %>% mutate( !!pct_below_poverty_col := (!!tot_below_poverty_est_col / !!tot_pop_est_col) * 100, !!pct_unemployed_col := (!!pop_unemployed_col / !!pop_civ_lab_force_col) * 100, !!pct_hhs_no_vehicles_col := (!!hhs_no_vehicles_est_col / !!tot_hhs_est_col) * 100, !!pct_developed_col := (!!developed_col / !!area_col) * 100, !!pct_natural_barren_col := (!!natural_barren_col / !!area_col) * 100, !!pct_cropland_col := (!!cropland_col / !!area_col) * 100, !!pct_tree_cover_col := (!!tree_cover_col / !!area_col) * 100, !!pct_grassland_col := (!!grassland_col / !!area_col) * 100, !!pct_wetland_col := (!!wetland_col / !!area_col) * 100, !!pct_water_col := (!!water_col / !!area_col) * 100 ) # add data frame to county data list data_list[[index]] <- d # add 1 to index index = index + 1 } } # bind geography data frames together then return data data <- bind_rows(data_list) return(data)}```### Tract-Level Population and Land Cover Change Data```{r combine_tract_land_cover_chg_distressed, warning=F, message=F}# get full counties sfs for 2010 and 2019 and fill NA with 0, then join them into a single sffinal_tracts_df.2010 <- gather_data(st_lc_2010_masked, 2010, 'tract')final_tracts_df.2010[is.na(final_tracts_df.2010)] <- 0final_tracts_df.2019 <- gather_data(st_lc_2019_masked, 2019, 'tract')final_tracts_df.2019[is.na(final_tracts_df.2019)] <- 0final_tracts_df <- st_join(final_tracts_df.2010, final_tracts_df.2019, suffix = c('', '.y'), largest = TRUE) %>% select(-contains('.y'), -contains('M_'), -contains('chg')) %>% rename_with(~ str_replace(., 'E_', '_'), grep('E_', colnames(.), value = TRUE)) %>% mutate( pct_pop_chg = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) * 100, pct_hhs_chg = ((tot_hhs_2019 - tot_hhs_2010) / tot_hhs_2010) * 100, pct_median_age_chg = ((median_age_2019 - median_age_2010) / median_age_2010) * 100, pct_median_income_chg = ((median_income_2019 - median_income_2010) / median_income_2010) * 100, pct_below_poverty_chg = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) * 100, pct_unemployed_chg = ((pct_unemployed_2019 - pct_unemployed_2010) / pct_unemployed_2010) * 100, pct_hhs_no_vehicles_chg = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) * 100, pct_developed_chg = ((pct_developed_area_sqmi_2019 - pct_developed_area_sqmi_2010) / pct_developed_area_sqmi_2010) * 100, pct_natural_barren_chg = ((pct_natural_barren_area_sqmi_2019 - pct_natural_barren_area_sqmi_2010) / pct_natural_barren_area_sqmi_2010) * 100, pct_cropland_chg = ((pct_cropland_area_sqmi_2019 - pct_cropland_area_sqmi_2010) / pct_cropland_area_sqmi_2010) * 100, pct_tree_cover_chg = ((pct_tree_cover_area_sqmi_2019 - pct_tree_cover_area_sqmi_2010) / pct_tree_cover_area_sqmi_2010) * 100, pct_grassland_chg = ((pct_grassland_area_sqmi_2019 - pct_grassland_area_sqmi_2010) / pct_grassland_area_sqmi_2010) * 100, pct_wetland_chg = ((pct_wetland_area_sqmi_2019 - pct_wetland_area_sqmi_2010) / pct_wetland_area_sqmi_2010) * 100, pct_water_chg = ((pct_water_area_sqmi_2019 - pct_water_area_sqmi_2010) / pct_water_area_sqmi_2010) * 100 ) %>% mutate_if(is.numeric, ~ replace_na(., 0) %>% replace(., is.infinite(.), 1000000)) %>% relocate(geometry, .after = last_col())final_tracts_df[is.na(final_tracts_df)] <- 0# display county-level table of datafinal_tracts_df %>% select(NAME, county, grep('chg', colnames(.), value = TRUE), contains('Became'), contains('Improved')) %>% relocate(if_Became_Distressed_2010_2019, .after = pct_below_poverty_chg) %>% relocate(if_Distressed_Then_Improved_2010_2019, .after = if_Became_Distressed_2010_2019) %>% mutate(NAME = str_split(.$NAME, ',', simplify = TRUE)) %>% st_drop_geometry() %>% gt(groupname_col = 'county') %>% tab_options(row_group.as_column = TRUE, container.height = 1500, container.overflow.y = TRUE) %>% tab_stubhead(label = 'county') %>% tab_header( title = md('**Changes in Population Characteristics, Economic Indicators, and Land Cover**'), subtitle = md('By Southern Tier Census Tract (2010 - 2019)') ) %>% cols_label( pct_pop_chg = md('**% Pop Change**'), pct_hhs_chg = md('**% HHs Change**'), pct_median_age_chg = md('**% Median Age Change**'), pct_median_income_chg = md('**% Median Income Change**'), pct_below_poverty_chg = md('**% Pop Below Poverty Change**'), if_Became_Distressed_2010_2019 = md('**If Became Distressed**'), if_Distressed_Then_Improved_2010_2019 = md('**If Improved**'), pct_unemployed_chg = md('**% Unemployment Rate Change**'), pct_hhs_no_vehicles_chg = md('**% HHs No Vehicle Change**'), pct_developed_chg = md('**% Developed Change**'), pct_natural_barren_chg = md('**% Natural Barren Change**'), pct_cropland_chg = md('**% Cropland Change**'), pct_tree_cover_chg = md('**% Tree Cover Change**'), pct_grassland_chg = md('**% Grassland Change**'), pct_wetland_chg = md('**% Wetland Change**'), pct_water_chg = md('**% Water Change**') ) %>% fmt_percent(decimals = 1, scale_values = FALSE)```### County-Level Distressed Population and Land Cover Change Data```{r combine_county_land_cover_chg_distressed, warning=F, message=F}# get full counties sfs for 2010 and 2019 and fill NA with 0, then join them into a single sffinal_counties_df.2010 <- gather_data(st_lc_2010_masked, 2010, 'county')final_counties_df.2010[is.na(final_counties_df.2010)] <- 0final_counties_df.2019 <- gather_data(st_lc_2019_masked, 2019, 'county')final_counties_df.2019[is.na(final_counties_df.2019)] <- 0final_counties_df <- st_join(final_counties_df.2010, final_counties_df.2019, suffix = c('', '.y'), largest = TRUE) %>% select(-c(county.y, tot_pop_became_distressed_2010_2019, tot_pop_improved_2010_2019)) %>% rename( tot_pop_became_distressed_2010_2019 = tot_pop_became_distressed_2010_2019.y, tot_pop_improved_2010_2019 = tot_pop_improved_2010_2019.y ) %>% mutate( pct_pop_chg = ((tot_pop_2019 - tot_pop_2010) / tot_pop_2010) * 100, pct_hhs_chg = ((tot_hhs_2019 - tot_hhs_2010) / tot_hhs_2010) * 100, pct_median_age_chg = ((median_age_2019 - median_age_2010) / median_age_2010) * 100, pct_median_income_chg = ((median_income_2019 - median_income_2010) / median_income_2010) * 100, pct_below_poverty_chg = ((pct_below_poverty_2019 - pct_below_poverty_2010) / pct_below_poverty_2010) * 100, pct_unemployed_chg = ((pct_unemployed_2019 - pct_unemployed_2010) / pct_unemployed_2010) * 100, pct_pop_distressed_chg = ((pct_pop_distressed_2019 - pct_pop_distressed_2010) / pct_pop_distressed_2010) * 100, pct_hhs_no_vehicles_chg = ((pct_hhs_no_vehicles_2019 - pct_hhs_no_vehicles_2010) / pct_hhs_no_vehicles_2010) * 100, pct_developed_chg = ((pct_developed_area_sqmi_2019 - pct_developed_area_sqmi_2010) / pct_developed_area_sqmi_2010) * 100, pct_natural_barren_chg = ((pct_natural_barren_area_sqmi_2019 - pct_natural_barren_area_sqmi_2010) / pct_natural_barren_area_sqmi_2010) * 100, pct_cropland_chg = ((pct_cropland_area_sqmi_2019 - pct_cropland_area_sqmi_2010) / pct_cropland_area_sqmi_2010) * 100, pct_tree_cover_chg = ((pct_tree_cover_area_sqmi_2019 - pct_tree_cover_area_sqmi_2010) / pct_tree_cover_area_sqmi_2010) * 100, pct_grassland_chg = ((pct_grassland_area_sqmi_2019 - pct_grassland_area_sqmi_2010) / pct_grassland_area_sqmi_2010) * 100, pct_wetland_chg = ((pct_wetland_area_sqmi_2019 - pct_wetland_area_sqmi_2010) / pct_wetland_area_sqmi_2010) * 100, pct_water_chg = ((pct_water_area_sqmi_2019 - pct_water_area_sqmi_2010) / pct_water_area_sqmi_2010) * 100 ) %>% mutate_if(is.numeric, ~ replace_na(., 0) %>% replace(., is.infinite(.), 1000000))final_counties_df[is.na(final_counties_df)] <- 0# display county-level table of datafinal_counties_df %>% select(county, grep('chg', colnames(.), value = TRUE)) %>% st_drop_geometry() %>% gt(rowname_col = 'county') %>% tab_header( title = md('**Changes in Population Characteristics, Economic Indicators, and Land Cover**'), subtitle = md('By Southern Tier County (2010 - 2019)') ) %>% cols_label( pct_pop_chg = md('**% Pop Change**'), pct_hhs_chg = md('**% HHs Change**'), pct_median_age_chg = md('**% Median Age Change**'), pct_median_income_chg = md('**% Median Income Change**'), pct_below_poverty_chg = md('**% Pop Below Poverty Change**'), pct_unemployed_chg = md('**% Unemployment Rate Change**'), pct_pop_distressed_chg = md('**% Pop Distressed Change**'), pct_hhs_no_vehicles_chg = md('**% HHs No Vehicle Change**'), pct_developed_chg = md('**% Developed Change**'), pct_natural_barren_chg = md('**% Natural Barren Change**'), pct_cropland_chg = md('**% Cropland Change**'), pct_tree_cover_chg = md('**% Tree Cover Change**'), pct_grassland_chg = md('**% Grassland Change**'), pct_wetland_chg = md('**% Wetland Change**'), pct_water_chg = md('**% Water Change**') ) %>% fmt_percent(decimals = 1, scale_values = FALSE)```All counties except for Tompkins County had a population decline and an increase in the proportion of distressed people. Tompkins County was the only county where the civilian unemployment rate increased. All counties got older with the exception of Broome County. Additionally, median family income increased by at least 14% in all counties.There were marginal changes in developed land, cropland, tree cover, wetland, and water areas in all counties. There were more significant changes in natural barren and (to a lesser extent) grassland areas in all counties. Grassland decreased by over 10% in Schuyler County (-12.8%) and Otsego County (-10.4%). All counties had much more natural barren land by 2019. However, the actual amount of land that became barren is relatively small given the very small amount of total natural barren land in the study area.### Analysis CorrelationsThis correlation analysis used the Pearson method.```{r tract_correlations_main, warning=F, message=F}# filter for only pct chg columnstracts.pct_chg <- final_tracts_df %>% select(NAME, grep('chg', colnames(.), value = TRUE)) %>% st_drop_geometry()# calculate correlation coefficients between all variablestract_correlations <- cor(select(tracts.pct_chg, -c(NAME)))# display heatmap of correlationsheatmaply( tract_correlations, colors = colorRampPalette(c('blue', 'white', 'orange'))(100), dendrogram = 'none', limits = c(-1, 1), branches.lwd = 0.5)``````{r tract_correlations_distressed, warning=F, message=F}# create data frame of correlation coefficients between # pct distressed pop chg and other variablestract_cor.df <- melt(tract_correlations) %>% filter(Var1 == 'pct_pop_chg', Var2 != 'pct_pop_chg') %>% select(-Var1) %>% rename( Variable = Var2, Coefficient = value ) %>% arrange(desc(Coefficient))# display table of correlation with pct distressed pop chg in descending order of correlationtract_cor.df %>% gt() %>% tab_header(title = md('**Tract-Level Correlation with Percent Population Change**')) %>% cols_align(align = 'center') %>% cols_label( Variable = md('**Variable**'), Coefficient = md('**Coefficient**') ) %>% fmt_number(columns = Coefficient, decimals = 3)```The most significant correlation is between population change and household change, which has a direct relationship. Other strong correlations are between poverty rate change and water area change which have a strong positive correlation, as well as the change in percentage of households with no vehicle and wetland area change which have a strong negative correlation.The change in population variable is not strongly correlated with any of the other percentage change variables, with the exception of the percentage change in households.# ConclusionsThis study was severely limited in the variables that were analyzed, since the study was centered around an analysis of the distressed population based on the two-variable criteria outlined by the Appalachian Regional Commission. A much deeper statistical analysis of the Southern Tier could be conducted to evaluate additional trends and gain better insights into the area, like the study by Ludke et al. (2012) which considered many other demographic variables such as employment by worker class and occupation, educational attainment, dependency ratio, marital status, and more granular poverty level variables (e.g., individual poverty, childhood poverty, senior adult poverty, and female household poverty). This study was also limited in its methodology related to the land cover change analysis. Methods employed by KC et al. (2024) in their analysis of eastern Kentucky would allow for better identification of land cover changes and how it changed, including the use of a random tree classifier, hot spot analysis, and the creation of a map of the areas that changed and what the land became.The ACS 5-year data sets are generally viewed as the most accurate given the larger sample sizes. There could still be questions regarding the accuracy of certain estimates in many of the census tracts included in this study, especially in rural census tracts with smaller populations and larger margins of error. Despite this possible limitation, this study is still able to provide some valuable insights into how the New York Southern Tier region has changed between 2010 and 2019. Land cover did not change too drastically, with the largest changes being the additional 3.4 square miles of natural barren land and the 2.9 square miles of land that are no longer grasslands in the entire 14-county study area. There were no significant relationships between the change in population and changes in land cover and other population variables, suggesting that one could not accurately predict how a census tract's population and land cover change based on the rate of population change. While median family income increased in all counties, every county except Tompkins County became older, less populated, and more distressed. Built-up areas in the Southern Tier (especially Binghamton, Jamestown, Dunkirk, Elmira, and Salamanca) are considerably more distressed than rural areas, with Ithaca and Oneonta being the only cities that do not have a significant risk.The distressed population for each individual census tract could be calculated by determining the distressed status of the block groups within each census tract, and then summing up the total population that lives within distressed block groups in each census tract. Also, a separate study that evaluates the 14-county Southern Tier region in the post-COVID era (2020 - present) could offer valuable information about how the demographics of the Southern Tier have changed further since the onset of the pandemic, and if COVID has increased the number of distressed people.# References## Works CitedAppalachian Regional Commission. (2023). County Economic Status and Distressed Areas by State, FY 2024. <https://www.arc.gov/about-the-appalachian-region/county-economic-status-and-distressed-areas-by-state-fy-2024>Galili, T., O'Callaghan, A., Sidi, J., & Sievert, C. (2017). heatmaply: an R package for creating interactive cluster heatmaps for online publishing. Bioinformatics, 34(9), 1600-1602. <https://doi.org/10.1093/bioinformatics/btx657>Hijmans, R. (2024). terra: Spatial Data Analysis. R package version 1.8-6. <https://github.com/rspatial/terra>K C, S., Gyawali, B. R., Lucas, S., Antonious, G. F., Chiluwal, A., & Zourarakis, D. (2024). Assessing Land-Cover Change Trends, Patterns, and Transitions in Coalfield Counties of Eastern Kentucky, USA. Land, 13(9), 1541. <https://doi.org/10.3390/land13091541>Ludke, R. L., Obermiller, P. J., & Rademacher, E. W. (2012). Demographic Change in Appalachia: A Tentative Analysis. Journal of Appalachian Studies, 18(1/2), 48–92. <http://www.jstor.org/stable/23337708>McMahon, E.J. (2024). Eight in 10 New York towns and cities have lost population since 2020. *Empire Center*. <https://www.empirecenter.org/publications/eight-in-10-new-york-towns-and-cities-have-lost-population-since-2020>Walker, K. & Herman, M. (2024). tidycensus: Load US Census Boundary and Attribute Data as 'tidyverse' and 'sf'-Ready Data Frames. R package version 1.6.6. <https://walker-data.com/tidycensus>## Data Sources and Methodology[2010 U.S. Data]{.underline}* Total Population: U.S. Census Bureau. (2010). 2010 Summary File 1 Tables [All 50 States & DC]. <https://api.census.gov/data/2010/dec/sf1?>* Total Households: Lofquist, D., Lugaila, T., O'Connell, M., & Felix, S. (April 2012). "Households and Families: 2010," 2010 Census Briefs, C2010BR-14. U.S. Census Bureau, Washington, DC. <https://www2.census.gov/library/publications/cen2010/briefs/c2010br-14.pdf>, pg. 5.* Median Age: U.S. Census Bureau. (26 May 2011). "Census Bureau Releases 2010 Census Demographic Profiles for the United States, Arkansas, Illinois, Indiana, Iowa, Louisiana, Maryland, New Jersey, Oklahoma, Oregon, South Dakota, Texas, Vermont and Virginia," CB11-CN.144. <https://www.census.gov/newsroom/releases/archives/2010_census/cb11-cn144.html>* Median Family Income: U.S. Department of Housing and Urban Development. (14 May 2010). "Estimated Median Family Incomes for Fiscal Year 2010," PDR-2010-01. <https://www.huduser.gov/portal/datasets/il/il10/Medians2010.pdf>* Poverty Rate: Bishaw, A. (September 2012). "Poverty: 2010 and 2011," American Community Survey Briefs, ACSBR/11-01. U.S. Census Bureau, Washington, DC. <https://www2.census.gov/library/publications/2012/acs/acsbr11-01.pdf>, pg. 3.[American Community Survey (ACS) Data]{.underline}* U.S. Census Bureau. (2010). American Community Survey 5-Year Estimates: Comparison Profiles 5-Year. <http://api.census.gov/data/2010/acs/acs5>* U.S. Census Bureau. (2019). American Community Survey 5-Year Estimates: Comparison Profiles 5-Year. <http://api.census.gov/data/2019/acs/acs5>* U.S. Census Bureau. (2010). "Selected Economic Characteristics." American Community Survey 5-Year Estimates Subject Tables, Table DP03. <https://data.census.gov/table/ACSDP5YSPT2010.DP03>* U.S. Census Bureau. (2019). "Selected Economic Characteristics." American Community Survey 5-Year Estimates Subject Tables, Table DP03. <https://data.census.gov/table/ACSDP5Y2019.DP03>[Land Cover Data]{.underline}Pengra, B.W., Stehman, S.V., Horton, J.A., Auch, R.F., Kambly, S., Knuppe, M., Sorenson, D., Robison, C., and Taylor, J.L. (2023). LCMAP CONUS Reference Data Product 1984-2021 land cover, land use and change process attributes: U.S. Geological Survey data release, <https://doi.org/10.5066/P933Z1TK>* Primary Land Cover data downloaded from: <https://www.usgs.gov/special-topics/lcmap/collection-13-conus-science-products>* Land Cover Classifications from the [LCMAP Collection 1.3 Data Format Control Book](https://d9-wret.s3.us-west-2.amazonaws.com/assets/palladium/production/s3fs-public/media/files/LSDS-2346%20Land%20Change%20Monitoring%2C%20Assessment%2C%20and%20Projection%20%28LCMAP%29%20Collection%201.3%20Data%20Format%20Control%20Book%20%28DFCB%29%20-v1.0%20%202022_07_12.pdf)[Distressed Area Classification System]{.underline}Appalachian Regional Commission. (2024). Distressed Areas Classification System. <https://www.arc.gov/distressed-areas-classification-system/>