The raceland package implements a computational framework for a pattern-based, zoneless analysis and visualization of (ethno)racial topography. It is a reimagined approach for analyzing residential segregation and racial diversity based on the concept of ‘landscape’ used in the domain of landscape ecology. An overview of the implemented method is presented in the first vignette. Here we demonstrate, how the raceland package can be used for describing racial landscape at different spatial scales.
Here we demonstrate, how to use the implemented method with SocScape race-specific grids to perform analysis for different spatial scales. We use Cook county data as an example.
SocScape project provides a high resolution (30m) grids for each county in the conterminous U.S. and 351 MSA for 1990, 2000 and 2010. Data are organized as zip archives with three directories:
These grids have been calculated from the U.S. Census block-level data using dasymetric modeling with land cover as an auxiliary variable. Data is available at http://www.socscape.edu.pl/index.php?id=high-resolution-grids/.
A few steps are required to perform analysis based on the SocScape grids:
Download data: to download data, go to the website http://www.socscape.edu.pl/index.php?id=high-resolution-grids/. For example, select state: Illinois; select county: Cook. The il_cook.zip file will be downloaded.
Unzip the archive with the high-resolution grids.
Use presented below script to fully automate analysis. The script requires to define a few arguments (see example below):
nrealization = 100
)Script creates a results directory with four subdirectories:
final - contains final results:
out_data - contains three files in the *.rds format:
out_metrics - IT-metrics calculated for each defined spatial scale
shp - contains shapefiles with attribute tables for each defined spatial scale. Shapefiles can be used to prepare maps
size | shift | n | ent | ent_sd | mutinf | mutinf_sd |
---|---|---|---|---|---|---|
60 | 30 | 2245 | 1.0468 | 0.0166 | 0.0422 | 0.0051 |
120 | 60 | 584 | 1.1331 | 0.0087 | 0.0759 | 0.0036 |
240 | 120 | 145 | 1.2951 | 0.0043 | 0.1432 | 0.0027 |
480 | 240 | 37 | 1.4403 | 0.0023 | 0.2229 | 0.0019 |
ALL | ALL | 1 | 1.8393 | 0.0006 | 0.4732 | 0.0009 |
Note: This calculation could take several minutes for larger counties.
# R script calculates IT-derived metrices for different spatial scales.
# INSTALL REQUIRED PACKAGES
= c(
pkgs "raceland",
"comat",
"terra",
"sf",
"dplyr"
)= !pkgs %in% installed.packages()
to_install if(any(to_install)) {
install.packages(pkgs[to_install])
}
# REQUIRED R-PACKAGES
library(raceland)
library(terra)
library(sf)
library(dplyr)
# SET WORKING DIRECTORY
## setwd("")
################################## USER DEFINED PARAMETERS #######################################
# Please define following parameters before running a script.
# Path to race directory with downloaded data.
= "il_cook/race"
pf_to_data
# sfx indicates which dataset will be used. There are 3 options:
## sfx="1990myc" - race specific grids for 1990 year.
## sfx="2000myc" - race specific grids for 2000 year.
## sfx="2010myc" - race specific grids for 2010 year.
= "2010myc"
sfx
# Number of realizations (racial landscape) to generate.
# It is recommended to generate at least 30 realizations.
= 100
nrealization
# list with size and shift parameters: list(c(size, shift), c(size, shift),...).
# In this case calculation will be performed for 4 different spatia scale:
# 1. c(60,30) - size = 60 local ladnscape from 60x60 cells window will be calculated,
# it corresponds to the spatial scale of 1.8km (60 cells x 30m).
# 2. c(120,60) - corresponds to the scale of 3.6 km.
# 3. c(240,120) - corresponds to the scale of 7.2 km.
# 4. c(480, 240) - corresponds to the scale of 14.4 km.
= list(c(60,30), c(120,60), c(240,120), c(480, 240))
list_size_shift
####################################################################################################
# FUNCTION TO CALCULATE RACIAL SEGREGATION/DIVERSITY CLASSIFICATION
= function(entropy, mutual_information, n) {
bivariate_classification
# max entropy is calculated as log2 from the number of race categories
= log2(n)
nent
# divide entropy values into 3 categories
= cut(entropy, breaks = c(0, 0.66, 1.33, nent), labels = c(1, 2, 3),
ent_cat include.lowest = TRUE, right = TRUE)
= as.integer(as.character(ent_cat))
ent_cat
# divide mutual information values into 3 categories
= cut(mutual_information, breaks = c(0, 0.33, 0.66, 1), labels = c(10, 20, 30),
mut_cat include.lowest = TRUE, right = TRUE)
= as.integer(as.character(mut_cat))
mut_cat
# combine categories of entropy (measure of racial diversity)
# and mutual information (measure of racial segregation)
= mut_cat + ent_cat
bivar_cls = as.factor(bivar_cls)
bivar_cls
return(bivar_cls)
}
####################################################################################################
# COLORS USED FOR VISUALIZATION
## They corresponds to 5 racial categories: ASIAN, BLACK, HISPANIC, OTHER, WHITE
= c("#F16667", "#6EBE44", "#7E69AF", "#C77213", "#F8DF1D")
race_colors
## Bivariate palette to display the racial segregation/diversity classification
= c("11" = "#e8e8e8", "12" = "#e4acac", "13" = "#c85a5a",
bivariate_class_colors "21" = "#b0d5df", "22" = "#ad9ea5", "23" = "#985356",
"31" = "#64acbe", "32" = "#627f8c", "33" = "#574249")
####################################################################################################
################################## CREATE RESULTS DIRECTORY WITH SUBDIRECTORIES ####################
# results directory will be created as subdirectory in working directory
= getwd()
pf dir.create(file.path(pf, "results"), showWarnings = FALSE)
dir.create(file.path(pf, "results", "out_data"), showWarnings = FALSE)
dir.create(file.path(pf, "results", "out_metrics"), showWarnings = FALSE)
dir.create(file.path(pf, "results", "final"), showWarnings = FALSE)
dir.create(file.path(pf, "results", "shp"), showWarnings = FALSE)
###################################################################################################
################################## PREPROCESS RACE-SPECIFIC DATA ##################################
# Read data from GeoTIFFs to a SpatRaster object
= list.files(pf_to_data, pattern = sfx, full.names = TRUE)
list_raster = rast(list_raster)
race_raster
# Rename raster layers
= sapply(strsplit(names(race_raster), "_"), tail, 1)
rnames = substr(rnames, 1, nchar(rnames) - nchar(sfx))
rnames
= dplyr::recode(
new_names
rnames,"hispanic" = "hispanic",
"nham" = "am",
"nhas" = "asian",
"nhb" = "black",
"nhother" = "other",
"nhpi" = "pi",
"nhw" = "white"
)names(race_raster) = new_names
# Reorder layers in SpatRaster
= subset(race_raster, c("asian", "am", "black", "hispanic", "other", "pi", "white"))
race_raster
# Combine race-specific categories (ASIAN=ASIAN+PI, OTHER=OTHER+AM).
# Please notice that pi category does not exist for 1990myc dataset.
if (sfx == "1990myc") {
"other"]] = race_raster[["other"]] + race_raster[["am"]]
race_raster[[= subset(race_raster, c("asian", "black", "hispanic", "other", "pi", "white"))
race_raster else {
} "other"]] = race_raster[["other"]] + race_raster[["am"]]
race_raster[["asian"]] = race_raster[["asian"]] + race_raster[["pi"]]
race_raster[[= subset(race_raster, c("asian", "black", "hispanic", "other", "white"))
race_raster
}
# race raster object contains 5 layers:
# asian, black, hispanic, other, white with subpolulation densities
race_raster
# save race_raster to a rds file
saveRDS(race_raster, file.path(pf, "results", "out_data", "race_raster.rds"))
###################################################################################################
################################## CONSTRUCTING RACIAL LANDSCAPE ##################################
= create_realizations(race_raster, n = nrealization)
real_raster
# save real_raster object
saveRDS(real_raster, file.path(pf, "results", "out_data", "real_rast.rds"))
# plot racial landscape
png(file.path("results", "final", "racial_landscape.png"))
plot_realization(x = real_raster[[1]], y = race_raster, hex = race_colors)
dev.off()
###################################################################################################
################################## CALCULATE RACE-SPECIFIC DENSTITIES #############################
= create_densities(real_raster, race_raster, window_size = 10)
dens_raster
# save dens_raster object
saveRDS(dens_raster, file.path(pf, "results", "out_data", "dens_rast.rds"))
###################################################################################################
################################## CALCULATE METRICS FOR DIFFERENT SPATIAL SCALES ################
= data.frame()
complete_smr_df for (i in list_size_shift) { #start size loop
= i[1]
size = i[2]
shift
#######################CALCULATE METRICS FOR SPECIFIED SIZE/SHIFT PARAMETER######################
= calculate_metrics(real_raster, dens_raster,
metr_df neighbourhood = 4, fun = "mean",
size = size, shift = shift, threshold = 0.5)
# Summarize metrics
## Number of motifels at given spatial scale
= metr_df[!is.na(metr_df$ent), ]
sel = mean(table(sel$realization))
nmotif
# Metrics summary
= metr_df %>%
smr group_by(row, col) %>%
summarize(
ent_mean = mean(ent, na.rm = TRUE),
ent_sd = sd(ent, na.rm = TRUE),
mutinf_mean = mean(mutinf, na.rm = TRUE),
mutinf_sd = sd(mutinf, na.rm = TRUE)
)
= as.data.frame(smr)
smr
# Calculate an ensemble average for entropy and mutual information
= c(
complete_smr size = size,
shift = shift,
n = nmotif,
ent = mean(smr$ent_mean, na.rm = TRUE),
ent_sd = mean(smr$ent_sd, na.rm = TRUE),
mutinf = mean(smr$mutinf_mean, na.rm = TRUE),
mutinf_sd = mean(smr$mutinf_sd, na.rm = TRUE)
)= rbind(complete_smr_df, complete_smr)
complete_smr_df
# Calculate racial segregation/diversity classification
$bivar_cls = bivariate_classification(entropy = smr$ent_mean,
smrmutual_information = smr$mutinf_mean,
n = nlayers(race_raster))
# Save the metrics to csv
write.csv(metr_df,
file.path("results", "out_metrics",
paste("metr_df_", size, "_", shift, ".csv", sep = "")),
row.names = FALSE)
write.csv(smr,
file.path("results", "out_metrics",
paste("smr_metr_df_", size, "_", shift, ".csv", sep = "")),
row.names = FALSE)
#######################CREATE SPATIAL OBJECT WITG METRICES######################
# Create spatial object
= create_grid(real_raster, size = size, shift = shift)
grid_sf
# Join metrics to the grid
= dplyr::left_join(grid_sf, smr, by = c("row", "col"))
attr_grid = attr_grid[!is.na(attr_grid$ent_mean),]
sel_grid
# Save the grid as shapefile
st_write(attr_grid,
file.path("results", "shp",
paste("metr_stat_", size, "_", shift, ".shp", sep = "")))
#######################VISUALIZATION#########################################
# Divide entropy values into 10 class
= c(seq(0, 2, by = 0.25), log2(nlayers(race_raster)))
ent_breaks
# Divide mutual information into 10 class
= seq(0, 1, by = 0.1)
mut_breaks
# Spatial scale in km
= (shift * res(race_raster)[1]) / 1000
scale_km
# Mapping racial diversity (save plot to .png)
png(file.path("results", "final", paste("diversity_", size, "_", shift, ".png", sep = "")))
plot(sel_grid["ent_mean"], breaks = ent_breaks, key.pos = 1,
pal = rev(hcl.colors(length(ent_breaks) - 1, palette = "RdBu")), bty = "n",
main = paste("Racial diversity (Entropy) at the scale of ",
" km", sep = ""))
scale_km, dev.off()
# Mapping racial segregation (save plot to .png)
png(file.path("results", "final", paste("segregation_", size, "_", shift, ".png", sep = "")))
plot(sel_grid["mutinf_mean"], breaks = mut_breaks, key.pos = 1,
pal = rev(hcl.colors(length(mut_breaks) - 1, palette = "RdBu")), bty = "n",
main = paste("Racial segregation (Mutual information) at the scale of ",
" km", sep = ""))
scale_km, dev.off()
# Mapping racial segregation/diversity (save plot to .png)
png(file.path("results", "final", paste("bivar_", size, "_", shift, ".png", sep = "")))
= bivariate_class_colors[names(bivariate_class_colors)%in%unique(sel_grid$bivar_cls)]
bcat plot(sel_grid["bivar_cls"],
pal = bcat,
main = paste("Racial diversity/segregation classification at the scale of ",
" km", sep = ""))
scale_km, dev.off()
#stop size loop
}
###################################################################################################
################################## CALCULATE METRICS FOR THE WHOLE RACIAL LANDSCAPE ###############
= calculate_metrics(real_raster, dens_raster,
metr neighbourhood = 4, fun = "mean",
size = NULL, threshold = 1)
= c(
complete_smr_all size = "ALL",
shift = "ALL",
n = 1,
ent = mean(metr$ent, na.rm = TRUE),
ent_sd = sd(metr$ent, na.rm = TRUE),
mutinf = mean(metr$mutinf, na.rm = TRUE),
mutinf_sd = sd(metr$mutinf, na.rm = TRUE)
)= rbind(complete_smr_df, complete_smr_all)
complete_smr_df colnames(complete_smr_df) = c("size", "shift", "n", "ent", "ent_sd", "mutinf", "mutinf_sd")
# Write table with metrices for different spatial scales and for the whole area.
write.csv(complete_smr_df,
file.path("results", "final", "complete_smr.csv"),
row.names = FALSE)
###################################################################################################