18  Space and Scale

Some plots in this notebook require hvplot, which is not a standard geosnap dependency

Code
import pandas as pd
import geopandas as gpd
import matplotlib.pyplot as plt
import hvplot.pandas

from segregation import singlegroup, multigroup, dynamics, batch
from segregation.singlegroup import SpatialDissim, Dissim, Gini
from segregation.multigroup import MultiInfoTheory, MultiGini, MultiDiversity

from segregation.dynamics import compute_multiscalar_profile

from geosnap import DataStore
from geosnap import io as gio
from geosnap.visualize import plot_timeseries

from geosnap.analyze import segdyn
from libpysal import weights

%load_ext watermark
%watermark -iv -a "author: eli knaap"
The watermark extension is already loaded. To reload it, use:
  %reload_ext watermark
Author: author: eli knaap

matplotlib : 3.10.0
geosnap    : 0.14.1.dev14+g0443e2a.d20250103
libpysal   : 4.12.1
segregation: 2.5.1
hvplot     : 0.11.2
geopandas  : 1.0.1
pandas     : 2.2.3

18.1 Spatial Segregation Indices

Every index in the segregation package can leverage spatial relationships in its computation. Some segregation indices include a spatially-explicit formulation, e.g. the spatial dissimilarity index. Others can be generalized into spatial versions using the logic of Reardon et al, in which case we adopt the notion of ‘egohoods’

Code
datasets = DataStore()

socal = gio.get_acs(
    datasets,
    county_fips=["06037", "06025", "06059", "06071", "06073", "06065", "06111"],
    years=[2018],
)
socal = socal.to_crs(socal.estimate_utm_crs())
socal["county"] = socal.geoid.str[:5]
county_names = [
    "Imperial",
    "Los Angeles",
    "Orange",
    "Riverside",
    "San Bernadino",
    "San Diego",
    "Ventura",
]
county_fips = ["06025", "06037", "06059", "06065", "06071", "06073", "06111"]
namer = dict(zip(county_fips, county_names))
socal['county'] = socal.county.replace(to_replace=namer)

coastal = socal[socal.county.isin(["Los Angeles", "Orange", "San Diego", "Ventura"])]
inland = socal[socal.county.isin(['Riverside', "San Bernadino", "Imperial"])]
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/constructors.py:215: UserWarning: Currency columns unavailable at this resolution; not adjusting for inflation
  warn(
Code
w_queen = weights.Queen.from_dataframe(socal)
w_dist = weights.DistanceBand.from_dataframe(socal, 2500)
/var/folders/j8/5bgcw6hs7cqcbbz48d6bsftw0000gp/T/ipykernel_63228/243544763.py:1: FutureWarning: `use_index` defaults to False but will default to True in future. Set True/False directly to control this behavior and silence this warning
  w_queen = weights.Queen.from_dataframe(socal)
/Users/knaaptime/miniforge3/envs/urban_analysis/lib/python3.12/site-packages/libpysal/weights/contiguity.py:347: UserWarning: The weights matrix is not fully connected: 
 There are 3 disconnected components.
 There is 1 island with id: 2933.
  W.__init__(self, neighbors, ids=ids, **kw)
/Users/knaaptime/miniforge3/envs/urban_analysis/lib/python3.12/site-packages/libpysal/weights/util.py:826: UserWarning: The weights matrix is not fully connected: 
 There are 488 disconnected components.
 There are 418 islands with ids: 1157, 1158, 1162, 1163, 1164, 1274, 1275, 1289, 1296, 1297, 1321, 1322, 1323, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 2933, 2934, 3370, 3380, 3381, 3789, 5235, 5236, 5249, 5250, 5259, 5268, 5270, 5274, 5275, 5276, 5361, 5463, 5465, 5469, 5470, 5471, 5472, 5473, 5523, 5524, 5551, 5552, 5553, 5554, 5555, 5744, 5747, 5752, 5753, 5799, 5812, 5813, 5814, 5817, 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, 5827, 5828, 5829, 6124, 6168, 6169, 6170, 6171, 6172, 6191, 6205, 6511, 6512, 6513, 6514, 6515, 6516, 6519, 6520, 6542, 6544, 6791, 6792, 7051, 7114, 7150, 7227, 7243, 7334, 7335, 7336, 7396, 7417, 7562, 7563, 7605, 7606, 7607, 7625, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7643, 7644, 7645, 7647, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7667, 7669, 7670, 7671, 7672, 7673, 7675, 7677, 7754, 7781, 7893, 7901, 7904, 7906, 7907, 7908, 7909, 7919, 7920, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7948, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7968, 7970, 7971, 7972, 7973, 7974, 7976, 8002, 8230, 8368, 8496, 8570, 8572, 8603, 8604, 8605, 8606, 8607, 8608, 8612, 8613, 8614, 8615, 8617, 8625, 8626, 8630, 8631, 8632, 8633, 8635, 9105, 9106, 9107, 9108, 9109, 9122, 9123, 9124, 9125, 9166, 9416, 9422, 9444, 9445, 9446, 9447, 9448, 9450, 9455, 9456, 9462, 9659, 9660, 9661, 9667, 9669, 9686, 9687, 9721, 9722, 9723, 9733, 9743, 9751, 9953, 9954, 9970, 9971, 9997, 10029, 10220, 10238, 10240, 10241, 10242, 10243, 10248, 10261, 10266, 10267, 10268, 10269, 10270, 10271, 10272, 10273, 10274, 10275, 10286, 10289, 10290, 10291, 10301, 10308, 10384, 10387, 10514, 10565, 10777, 10794, 10796, 10797, 10798, 10799, 10800, 10805, 10806, 10807, 10817, 10818, 10826, 10850, 10851, 10852, 10853, 10854, 10886, 10894, 11149, 11180, 11181, 11187, 11188, 11191, 11192, 11215, 11217, 11360, 11545, 11553, 11554, 11555, 11570, 11571, 11572, 11573, 11574, 11575, 11576, 11577, 11578, 11579, 11580, 11583, 11584, 11585, 11586, 11587, 11588, 11602, 11727, 11776, 11778, 11816, 11820, 11821, 11822, 11823, 11829, 11833, 11835, 11836, 11837, 11838, 11839, 11840, 11841, 11842, 11843, 11844, 11845, 11846, 11847, 11848, 11849, 11850, 11851, 11852, 11853, 11854, 11855, 11856, 11857, 11859, 11863, 11864, 11865, 11866, 11867, 11869, 11877, 11888, 11900, 11970, 11979, 11995, 11996, 12023, 12063, 12075, 12076, 12077, 12078, 12079, 12083, 12084, 12087, 12103, 12104, 12107, 12110, 12111, 12128, 12165, 12186, 12187, 12188, 12254, 12258, 12263, 12276, 12279, 12286, 12287, 12288, 12364, 12377, 12378, 12511, 12513, 12514, 12597, 12617, 12667, 12673, 12689, 12690.
  w = W(neighbors, weights, ids, **kwargs)
/Users/knaaptime/miniforge3/envs/urban_analysis/lib/python3.12/site-packages/libpysal/weights/distance.py:844: UserWarning: The weights matrix is not fully connected: 
 There are 488 disconnected components.
 There are 418 islands with ids: 1157, 1158, 1162, 1163, 1164, 1274, 1275, 1289, 1296, 1297, 1321, 1322, 1323, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 2933, 2934, 3370, 3380, 3381, 3789, 5235, 5236, 5249, 5250, 5259, 5268, 5270, 5274, 5275, 5276, 5361, 5463, 5465, 5469, 5470, 5471, 5472, 5473, 5523, 5524, 5551, 5552, 5553, 5554, 5555, 5744, 5747, 5752, 5753, 5799, 5812, 5813, 5814, 5817, 5819, 5820, 5821, 5822, 5823, 5824, 5825, 5826, 5827, 5828, 5829, 6124, 6168, 6169, 6170, 6171, 6172, 6191, 6205, 6511, 6512, 6513, 6514, 6515, 6516, 6519, 6520, 6542, 6544, 6791, 6792, 7051, 7114, 7150, 7227, 7243, 7334, 7335, 7336, 7396, 7417, 7562, 7563, 7605, 7606, 7607, 7625, 7630, 7631, 7632, 7633, 7634, 7635, 7636, 7637, 7638, 7639, 7640, 7643, 7644, 7645, 7647, 7653, 7654, 7655, 7656, 7657, 7658, 7659, 7660, 7661, 7662, 7663, 7664, 7667, 7669, 7670, 7671, 7672, 7673, 7675, 7677, 7754, 7781, 7893, 7901, 7904, 7906, 7907, 7908, 7909, 7919, 7920, 7929, 7930, 7931, 7932, 7933, 7934, 7935, 7936, 7937, 7938, 7939, 7940, 7941, 7942, 7943, 7944, 7948, 7952, 7953, 7954, 7955, 7956, 7957, 7958, 7968, 7970, 7971, 7972, 7973, 7974, 7976, 8002, 8230, 8368, 8496, 8570, 8572, 8603, 8604, 8605, 8606, 8607, 8608, 8612, 8613, 8614, 8615, 8617, 8625, 8626, 8630, 8631, 8632, 8633, 8635, 9105, 9106, 9107, 9108, 9109, 9122, 9123, 9124, 9125, 9166, 9416, 9422, 9444, 9445, 9446, 9447, 9448, 9450, 9455, 9456, 9462, 9659, 9660, 9661, 9667, 9669, 9686, 9687, 9721, 9722, 9723, 9733, 9743, 9751, 9953, 9954, 9970, 9971, 9997, 10029, 10220, 10238, 10240, 10241, 10242, 10243, 10248, 10261, 10266, 10267, 10268, 10269, 10270, 10271, 10272, 10273, 10274, 10275, 10286, 10289, 10290, 10291, 10301, 10308, 10384, 10387, 10514, 10565, 10777, 10794, 10796, 10797, 10798, 10799, 10800, 10805, 10806, 10807, 10817, 10818, 10826, 10850, 10851, 10852, 10853, 10854, 10886, 10894, 11149, 11180, 11181, 11187, 11188, 11191, 11192, 11215, 11217, 11360, 11545, 11553, 11554, 11555, 11570, 11571, 11572, 11573, 11574, 11575, 11576, 11577, 11578, 11579, 11580, 11583, 11584, 11585, 11586, 11587, 11588, 11602, 11727, 11776, 11778, 11816, 11820, 11821, 11822, 11823, 11829, 11833, 11835, 11836, 11837, 11838, 11839, 11840, 11841, 11842, 11843, 11844, 11845, 11846, 11847, 11848, 11849, 11850, 11851, 11852, 11853, 11854, 11855, 11856, 11857, 11859, 11863, 11864, 11865, 11866, 11867, 11869, 11877, 11888, 11900, 11970, 11979, 11995, 11996, 12023, 12063, 12075, 12076, 12077, 12078, 12079, 12083, 12084, 12087, 12103, 12104, 12107, 12110, 12111, 12128, 12165, 12186, 12187, 12188, 12254, 12258, 12263, 12276, 12279, 12286, 12287, 12288, 12364, 12377, 12378, 12511, 12513, 12514, 12597, 12617, 12667, 12673, 12689, 12690.
  W.__init__(

18.1.1 Single Group

Code
dissim = SpatialDissim(socal, 'n_hispanic_persons', 'n_total_pop')
dissim.statistic
/Users/knaaptime/miniforge3/envs/urban_analysis/lib/python3.12/site-packages/segregation/singlegroup/spatial_dissim.py:48: FutureWarning: `use_index` defaults to False but will default to True in future. Set True/False directly to control this behavior and silence this warning
  w_object = Queen.from_dataframe(data)
/Users/knaaptime/miniforge3/envs/urban_analysis/lib/python3.12/site-packages/libpysal/weights/contiguity.py:347: UserWarning: The weights matrix is not fully connected: 
 There are 3 disconnected components.
 There is 1 island with id: 2933.
  W.__init__(self, neighbors, ids=ids, **kw)
0.3593155593679396
Code
dissim_queen = SpatialDissim(socal, 'n_hispanic_persons', 'n_total_pop', w=w_queen)
dissim_queen.statistic
0.3593155593679396
Code
# spatially-explicit index using distance-based neighborhoods of 2500m)
# exeryone inside the distance-band has the same interaction potential

dissim_dist = SpatialDissim(socal, 'n_hispanic_persons', 'n_total_pop', w=w_dist)
dissim_dist.statistic
0.32598268562202015
Code
# spatially-implicit Dissimilarity index
# the interaction potential among people inside the distance-band is weighted by proximity

dissim_implicit_linear = Dissim(socal, 'n_hispanic_persons', 'n_total_pop', distance=2500)
dissim_implicit_linear.statistic
0.42280908328763056
Code
dissim_implicit_gaussian = Dissim(socal, 'n_hispanic_persons', 'n_total_pop', distance=2500, function='gaussian')
dissim_implicit_gaussian.statistic
0.4083023733143102
Code
# spatially-implicit Dissimilarity index
dissim_implicit = Dissim(socal, 'n_hispanic_persons', 'n_total_pop', distance=3000)
dissim_implicit.statistic
0.40953375558943683

18.1.2 Multi Group

Code
pop_groups = [
    "n_asian_persons",
    "n_hispanic_persons",
    "n_nonhisp_black_persons",
    "n_nonhisp_white_persons",
]

spatial_info_queen = MultiInfoTheory(socal, pop_groups, w=w_queen)
spatial_info_dist = MultiInfoTheory(socal, pop_groups, w=w_dist)
info_spatial = MultiInfoTheory(socal, groups=pop_groups, distance=2000)
Code
spatial_info_queen.statistic
0.22563772225109704
Code
spatial_info_dist.statistic
0.21547125965781244
Code
info_spatial.statistic
0.24148247566253597

18.2 Network Distance

18.3 The Scale of Metropolitan Segregation

The multiscalar segregation profile is a way of measuring how global versus local the segregation patterns are in a region. As stylized examples, consider a city where one population groups lives on the eastern half and another group lives on the western half (large-scale/macro segregation) versus a city full of dense apartment buildings, but each building is occupied exclusively by members of a single population group

Code
distances = [1500., 2500., 3500., 4500., 5500.]
prof = compute_multiscalar_profile(socal,segregation_index=MultiInfoTheory, groups=pop_groups, distances=distances)
prof.plot()

We can also look at how the segregation profiles differ by region. If we plot them all on the same graph, we can compare the slopes of the lines to see how the shape of segregation differs between places in the southern cal region

Code
coastal_prof = compute_multiscalar_profile(coastal, segregation_index=MultiInfoTheory, groups=pop_groups, distances=distances)
inland_prof = compute_multiscalar_profile(inland, segregation_index=MultiInfoTheory, groups=pop_groups, distances=distances)

pd.Series(prof, name='socal').plot(legend=True)
pd.Series(coastal_prof, name='coastal').plot(legend=True)
pd.Series(inland_prof, name='inland').plot(legend=True)

Code
datasets = DataStore()

dc = gio.get_acs(datasets, msa_fips='47900', years=[2012, 2016,])
dc21 =  gio.get_acs(datasets, msa_fips='47900', years=[2021])
dc21=dc21.set_crs(dc.crs)
dc = gpd.GeoDataFrame(pd.concat([dc,dc21]))
dc = dc.to_crs(dc.estimate_utm_crs())
dc.head()
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/constructors.py:188: UserWarning: `constant_dollars` is True, but no `currency_year` was specified. Resorting to max value of 2016
  warn(
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/util.py:275: UserWarning: Unable to find local adjustment year for 2021. Attempting from online data
  warn(
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/io/constructors.py:215: UserWarning: Currency columns unavailable at this resolution; not adjusting for inflation
  warn(
geoid n_total_housing_units n_vacant_housing_units n_occupied_housing_units n_owner_occupied_housing_units n_renter_occupied_housing_units n_housing_units_multiunit_structures_denom n_housing_units_multiunit_structures n_total_housing_units_sample median_home_value ... p_hispanic_persons p_native_persons p_asian_persons p_hawaiian_persons p_asian_indian_persons p_edu_hs_less p_edu_college_greater p_veterans geometry year
0 110010001001 776.0 120.0 656.0 245.0 411.0 776.0 375.0 776.0 1.014441e+06 ... 12.808642 0.000000 3.395062 0.0 3.395062 0.0 87.141444 4.938272 MULTIPOLYGON (((320658.461 4309603.54, 320718.... 2012
1 110010001002 907.0 110.0 797.0 369.0 428.0 907.0 546.0 907.0 7.830297e+05 ... 1.210287 0.000000 3.479576 0.0 3.479576 0.0 86.875612 5.975794 MULTIPOLYGON (((321636.641 4308861.303, 321646... 2012
2 110010001003 589.0 39.0 550.0 391.0 159.0 589.0 221.0 589.0 1.047112e+06 ... 4.755245 5.664336 7.552448 0.0 7.552448 0.0 97.289448 8.181818 MULTIPOLYGON (((320967.686 4308858.767, 320969... 2012
3 110010001004 552.0 102.0 450.0 256.0 194.0 552.0 166.0 552.0 1.047112e+06 ... 1.612903 0.000000 6.854839 0.0 6.854839 0.0 85.314685 4.334677 MULTIPOLYGON (((320608.256 4307826.451, 321099... 2012
4 110010002011 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 NaN ... 4.442808 0.000000 12.272950 0.0 12.272950 0.0 49.382716 0.000000 MULTIPOLYGON (((319785.287 4309141.585, 319879... 2012

5 rows × 58 columns

Code
from IPython.display import IFrame

18.4 Temporal Segregation Dynamics: Change over Time

Code
plot_timeseries(dc, 'p_nonhisp_white_persons', nrows=1, ncols=3, figsize=(18,10), cmap='Blues', alpha=0.8)
plt.tight_layout()
/Users/knaaptime/Dropbox/projects/geosnap/geosnap/visualize/mapping.py:170: UserWarning: `proplot` is not installed.  Falling back to matplotlib
  warn("`proplot` is not installed.  Falling back to matplotlib")

18.4.1 Temporal Dynamics

18.4.1.1 Multi-Group Indices

Code
groups = [
    "n_nonhisp_white_persons",
    "n_nonhisp_black_persons",
    "n_hispanic_persons",
    "n_asian_persons",
]

multi_by_time = segdyn.multigroup_tempdyn(dc, groups)
multi_by_time
year 2012 2016 2021
Name
GlobalDistortion 191.2887 179.0859 195.9176
MultiDissim 0.5263 0.5138 0.5151
MultiDivergence 0.3845 0.3727 0.3900
MultiDiversity 1.1958 1.2200 1.2499
MultiGini 0.6952 0.6788 0.6816
MultiInfoTheory 0.3215 0.3055 0.3120
MultiNormExposure 0.3315 0.3169 0.3150
MultiRelativeDiversity 0.3196 0.3061 0.3066
MultiSquaredCoefVar 0.2640 0.2579 0.2700
SimpsonsConcentration 0.3503 0.3375 0.3212
SimpsonsInteraction 0.6497 0.6625 0.6788
Code
multi_by_time.T.plot()

Code
multi_by_time.iloc[1:].T.plot()

Most indices are changing little over time, but most have followed the same trend with a mild drop in 2016 prior to a slight increase in the latest available data

Code
fig, axs = plt.subplots(1,2, figsize=(10,4))

multi_by_time.loc['MultiDissim'].plot(ax=axs[0])
multi_by_time.loc['MultiDissim'].plot(kind='bar', ax=axs[1])

fig.suptitle("Multigroup Dissimilarity")
Text(0.5, 0.98, 'Multigroup Dissimilarity')

One that isn’t, is SimpsonsConcentration, which is increasing over time. Another index that bucks the trend is SimpsonsInteraction, which is decreasing over time (corresponding with an increse in segregation). The divergence between indices tells us that segregation may be changing in different ways across its different dimensions.

Code
fig, axs = plt.subplots(1,2, figsize=(10,4))

multi_by_time.loc['SimpsonsConcentration'].plot(ax=axs[0])
multi_by_time.loc['SimpsonsConcentration'].plot(kind='bar', ax=axs[1])

fig.suptitle("Simpson's Concentration")
Text(0.5, 0.98, "Simpson's Concentration")

18.4.1.2 Single-Group Indices

Code
from geosnap.analyze.segdyn import singlegroup_tempdyn
Code
singlegroup_tempdyn?
Code
dc['blackwhite'] = dc.n_nonhisp_black_persons + dc.n_nonhisp_white_persons
Code
segs_single = segdyn.singlegroup_tempdyn(dc, group_pop_var='n_nonhisp_black_persons', total_pop_var='blackwhite' )
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
  0%|          | 0/27 [00:00<?, ?it/s]AbsoluteCentralization:   0%|          | 0/27 [00:00<?, ?it/s]AbsoluteClustering:   4%|▎         | 1/27 [00:00<00:00, 67.28it/s]  0%|          | 0/27 [00:00<?, ?it/s]AbsoluteCentralization:   0%|          | 0/27 [00:00<?, ?it/s]AbsoluteClustering:   4%|▎         | 1/27 [00:00<00:00, 67.73it/s]  0%|          | 0/27 [00:00<?, ?it/s]AbsoluteCentralization:   0%|          | 0/27 [00:00<?, ?it/s]AbsoluteClustering:   4%|▎         | 1/27 [00:00<00:00, 59.71it/s]AbsoluteClustering:   7%|▋         | 2/27 [00:00<00:01, 13.05it/s]AbsoluteConcentration:   7%|▋         | 2/27 [00:00<00:01, 13.05it/s]Atkinson:  11%|█         | 3/27 [00:00<00:01, 13.05it/s]             BiasCorrectedDissim:  15%|█▍        | 4/27 [00:00<00:01, 13.05it/s]AbsoluteClustering:   7%|▋         | 2/27 [00:00<00:01, 12.91it/s]AbsoluteConcentration:   7%|▋         | 2/27 [00:00<00:01, 12.91it/s]Atkinson:  11%|█         | 3/27 [00:00<00:01, 12.91it/s]             BiasCorrectedDissim:  15%|█▍        | 4/27 [00:00<00:01, 12.91it/s]AbsoluteClustering:   7%|▋         | 2/27 [00:00<00:02,  8.52it/s]AbsoluteConcentration:   7%|▋         | 2/27 [00:00<00:02,  8.52it/s]Atkinson:  11%|█         | 3/27 [00:00<00:02,  8.52it/s]             BiasCorrectedDissim:  15%|█▍        | 4/27 [00:00<00:02,  8.52it/s]BiasCorrectedDissim:  19%|█▊        | 5/27 [00:00<00:03,  5.80it/s]BoundarySpatialDissim:  19%|█▊        | 5/27 [00:00<00:03,  5.80it/s]BiasCorrectedDissim:  19%|█▊        | 5/27 [00:00<00:03,  5.79it/s]BoundarySpatialDissim:  19%|█▊        | 5/27 [00:00<00:03,  5.79it/s]BiasCorrectedDissim:  19%|█▊        | 5/27 [00:00<00:04,  4.93it/s]BoundarySpatialDissim:  19%|█▊        | 5/27 [00:00<00:04,  4.93it/s]BoundarySpatialDissim:  22%|██▏       | 6/27 [00:04<00:22,  1.09s/it]ConProf:  22%|██▏       | 6/27 [00:04<00:22,  1.09s/it]              CorrelationR:  26%|██▌       | 7/27 [00:04<00:21,  1.09s/it]Delta:  30%|██▉       | 8/27 [00:04<00:20,  1.09s/it]       DensityCorrectedDissim:  33%|███▎      | 9/27 [00:04<00:19,  1.09s/it]BoundarySpatialDissim:  22%|██▏       | 6/27 [00:04<00:23,  1.10s/it]ConProf:  22%|██▏       | 6/27 [00:04<00:23,  1.10s/it]              CorrelationR:  26%|██▌       | 7/27 [00:04<00:21,  1.10s/it]Delta:  30%|██▉       | 8/27 [00:04<00:20,  1.10s/it]       DensityCorrectedDissim:  33%|███▎      | 9/27 [00:04<00:19,  1.10s/it]BoundarySpatialDissim:  22%|██▏       | 6/27 [00:05<00:25,  1.20s/it]ConProf:  22%|██▏       | 6/27 [00:05<00:25,  1.20s/it]              CorrelationR:  26%|██▌       | 7/27 [00:05<00:23,  1.20s/it]Delta:  30%|██▉       | 8/27 [00:05<00:22,  1.20s/it]       DensityCorrectedDissim:  33%|███▎      | 9/27 [00:05<00:21,  1.20s/it]DensityCorrectedDissim:  37%|███▋      | 10/27 [00:16<00:36,  2.16s/it]Dissim:  37%|███▋      | 10/27 [00:16<00:36,  2.16s/it]                DistanceDecayInteraction:  41%|████      | 11/27 [00:16<00:34,  2.16s/it]DensityCorrectedDissim:  37%|███▋      | 10/27 [00:16<00:36,  2.16s/it]Dissim:  37%|███▋      | 10/27 [00:16<00:36,  2.16s/it]                DistanceDecayInteraction:  41%|████      | 11/27 [00:16<00:34,  2.16s/it]DistanceDecayInteraction:  44%|████▍     | 12/27 [00:16<00:23,  1.54s/it]DistanceDecayIsolation:  44%|████▍     | 12/27 [00:16<00:23,  1.54s/it]  DistanceDecayInteraction:  44%|████▍     | 12/27 [00:16<00:23,  1.55s/it]DistanceDecayIsolation:  44%|████▍     | 12/27 [00:16<00:23,  1.55s/it]  DistanceDecayIsolation:  48%|████▊     | 13/27 [00:16<00:18,  1.31s/it]Entropy:  48%|████▊     | 13/27 [00:16<00:18,  1.31s/it]               Gini:  52%|█████▏    | 14/27 [00:16<00:17,  1.31s/it]   DistanceDecayIsolation:  48%|████▊     | 13/27 [00:16<00:18,  1.31s/it]Entropy:  48%|████▊     | 13/27 [00:16<00:18,  1.31s/it]               Gini:  52%|█████▏    | 14/27 [00:16<00:17,  1.31s/it]   Gini:  56%|█████▌    | 15/27 [00:18<00:13,  1.14s/it]Interaction:  56%|█████▌    | 15/27 [00:18<00:13,  1.14s/it]Isolation:  59%|█████▉    | 16/27 [00:18<00:12,  1.14s/it]  MinMax:  63%|██████▎   | 17/27 [00:18<00:11,  1.14s/it]   ModifiedDissim:  67%|██████▋   | 18/27 [00:18<00:10,  1.14s/it]Gini:  56%|█████▌    | 15/27 [00:18<00:13,  1.14s/it]Interaction:  56%|█████▌    | 15/27 [00:18<00:13,  1.14s/it]Isolation:  59%|█████▉    | 16/27 [00:18<00:12,  1.14s/it]  MinMax:  63%|██████▎   | 17/27 [00:18<00:11,  1.14s/it]   ModifiedDissim:  67%|██████▋   | 18/27 [00:18<00:10,  1.14s/it]ModifiedDissim:  70%|███████   | 19/27 [00:18<00:04,  1.62it/s]ModifiedGini:  70%|███████   | 19/27 [00:18<00:04,  1.62it/s]  ModifiedDissim:  70%|███████   | 19/27 [00:18<00:04,  1.62it/s]ModifiedGini:  70%|███████   | 19/27 [00:18<00:04,  1.62it/s]  DensityCorrectedDissim:  37%|███▋      | 10/27 [00:18<00:41,  2.45s/it]Dissim:  37%|███▋      | 10/27 [00:18<00:41,  2.45s/it]                DistanceDecayInteraction:  41%|████      | 11/27 [00:18<00:39,  2.45s/it]DistanceDecayInteraction:  44%|████▍     | 12/27 [00:18<00:26,  1.77s/it]DistanceDecayIsolation:  44%|████▍     | 12/27 [00:18<00:26,  1.77s/it]  DistanceDecayIsolation:  48%|████▊     | 13/27 [00:19<00:21,  1.50s/it]Entropy:  48%|████▊     | 13/27 [00:19<00:21,  1.50s/it]               Gini:  52%|█████▏    | 14/27 [00:19<00:19,  1.50s/it]   ModifiedGini:  74%|███████▍  | 20/27 [00:20<00:05,  1.20it/s]PARDissim:  74%|███████▍  | 20/27 [00:20<00:05,  1.20it/s]   Gini:  56%|█████▌    | 15/27 [00:20<00:15,  1.26s/it]Interaction:  56%|█████▌    | 15/27 [00:20<00:15,  1.26s/it]Isolation:  59%|█████▉    | 16/27 [00:20<00:13,  1.26s/it]  MinMax:  63%|██████▎   | 17/27 [00:20<00:12,  1.26s/it]   ModifiedDissim:  67%|██████▋   | 18/27 [00:20<00:11,  1.26s/it]ModifiedGini:  74%|███████▍  | 20/27 [00:20<00:05,  1.20it/s]PARDissim:  74%|███████▍  | 20/27 [00:20<00:05,  1.20it/s]   ModifiedDissim:  70%|███████   | 19/27 [00:20<00:05,  1.47it/s]ModifiedGini:  70%|███████   | 19/27 [00:20<00:05,  1.47it/s]  ModifiedGini:  74%|███████▍  | 20/27 [00:23<00:06,  1.07it/s]PARDissim:  74%|███████▍  | 20/27 [00:23<00:06,  1.07it/s]   PARDissim:  78%|███████▊  | 21/27 [00:24<00:08,  1.39s/it]RelativeCentralization:  78%|███████▊  | 21/27 [00:24<00:08,  1.39s/it]RelativeClustering:  81%|████████▏ | 22/27 [00:24<00:06,  1.39s/it]    PARDissim:  78%|███████▊  | 21/27 [00:24<00:08,  1.40s/it]RelativeCentralization:  78%|███████▊  | 21/27 [00:24<00:08,  1.40s/it]RelativeClustering:  81%|████████▏ | 22/27 [00:24<00:06,  1.40s/it]    RelativeClustering:  85%|████████▌ | 23/27 [00:24<00:03,  1.04it/s]RelativeConcentration:  85%|████████▌ | 23/27 [00:24<00:03,  1.04it/s]SpatialDissim:  89%|████████▉ | 24/27 [00:24<00:02,  1.04it/s]        RelativeClustering:  85%|████████▌ | 23/27 [00:24<00:03,  1.04it/s]RelativeConcentration:  85%|████████▌ | 23/27 [00:24<00:03,  1.04it/s]SpatialDissim:  89%|████████▉ | 24/27 [00:24<00:02,  1.04it/s]        SpatialDissim:  93%|█████████▎| 25/27 [00:26<00:01,  1.14it/s]SpatialProxProf:  93%|█████████▎| 25/27 [00:26<00:01,  1.14it/s]SpatialDissim:  93%|█████████▎| 25/27 [00:26<00:01,  1.15it/s]SpatialProxProf:  93%|█████████▎| 25/27 [00:26<00:01,  1.15it/s]PARDissim:  78%|███████▊  | 21/27 [00:27<00:09,  1.53s/it]RelativeCentralization:  78%|███████▊  | 21/27 [00:27<00:09,  1.53s/it]RelativeClustering:  81%|████████▏ | 22/27 [00:27<00:07,  1.53s/it]    RelativeClustering:  85%|████████▌ | 23/27 [00:27<00:04,  1.06s/it]RelativeConcentration:  85%|████████▌ | 23/27 [00:27<00:04,  1.06s/it]SpatialDissim:  89%|████████▉ | 24/27 [00:27<00:03,  1.06s/it]        SpatialDissim:  93%|█████████▎| 25/27 [00:29<00:01,  1.01it/s]SpatialProxProf:  93%|█████████▎| 25/27 [00:29<00:01,  1.01it/s]SpatialProxProf:  96%|█████████▋| 26/27 [00:43<00:03,  3.85s/it]SpatialProximity:  96%|█████████▋| 26/27 [00:43<00:03,  3.85s/it]SpatialProxProf:  96%|█████████▋| 26/27 [00:43<00:03,  3.85s/it]SpatialProximity:  96%|█████████▋| 26/27 [00:43<00:03,  3.85s/it]SpatialProximity: 100%|██████████| 27/27 [00:43<00:00,  3.09s/it]SpatialProximity: 100%|██████████| 27/27 [00:43<00:00,  1.60s/it]
SpatialProximity: 100%|██████████| 27/27 [00:43<00:00,  3.08s/it]SpatialProximity: 100%|██████████| 27/27 [00:43<00:00,  1.61s/it]
SpatialProxProf:  96%|█████████▋| 26/27 [00:48<00:04,  4.42s/it]SpatialProximity:  96%|█████████▋| 26/27 [00:48<00:04,  4.42s/it]SpatialProximity: 100%|██████████| 27/27 [00:49<00:00,  3.54s/it]SpatialProximity: 100%|██████████| 27/27 [00:49<00:00,  1.82s/it]
Code
segs_single
year 2012 2016 2021
Name
AbsoluteCentralization 0.6945 0.6938 0.6804
AbsoluteClustering 0.3263 0.3326 0.3613
AbsoluteConcentration 0.8278 0.8284 0.8270
Atkinson 0.6294 0.6069 0.6106
BiasCorrectedDissim 0.6523 0.6443 0.6463
BoundarySpatialDissim 0.5239 0.5191 0.4999
ConProf 0.6069 0.6020 0.6068
CorrelationR 0.5192 0.5065 0.5097
Delta 0.7937 0.7921 0.7920
DensityCorrectedDissim 0.5064 0.4942 0.5153
Dissim 0.6526 0.6446 0.6466
DistanceDecayInteraction 0.4776 0.4797 0.4707
DistanceDecayIsolation 0.5349 0.5366 0.5523
Entropy 0.4665 0.4511 0.4538
Gini 0.8248 0.8137 0.8164
Interaction 0.3174 0.3227 0.3144
Isolation 0.6826 0.6773 0.6856
MinMax 0.7898 0.7839 0.7854
ModifiedDissim 0.6442 0.6361 0.6377
ModifiedGini 0.8187 0.8074 0.8097
PARDissim 0.6379 0.6303 0.6327
RelativeCentralization -0.0193 -0.0258 -0.0424
RelativeClustering 0.7093 0.7241 0.7556
RelativeConcentration 0.6029 0.6142 0.6299
SpatialDissim 0.5171 0.5121 0.4943
SpatialProxProf 0.5772 0.5896 0.6116
SpatialProximity 1.2668 1.2650 1.2801
Code
segs_single.T.hvplot(height=600)

https://www.jstor.org/stable/2579183

Code
IFrame('https://www.jstor.org/stable/2579183', height=600, width=800)
Code
(segs_single.T[['Gini', 'Entropy', 'Dissim', 'Atkinson']].hvplot(title='Evenness Dimension', width=380, height=400).opts(legend_position='bottom', show_grid=True) +
segs_single.T[['AbsoluteConcentration', 'RelativeConcentration' , 'Delta']].hvplot(title='Concentration Dimension', width=380, height=400).opts(legend_position='bottom', show_grid=True) +
segs_single.T[['AbsoluteClustering', 'Isolation', 'CorrelationR', 'Interaction', 'SpatialProxProf']].hvplot(title='Exposure/Clustering Dimension', width=380, height=400).opts(legend_position='bottom', show_grid=True))
Code
segs_single.T[['AbsoluteClustering', 'Isolation', 'SpatialProxProf', 'Interaction']].pct_change(periods=5) # we should only compare non-overlapping intervals
Name AbsoluteClustering Isolation SpatialProxProf Interaction
year
2012 NaN NaN NaN NaN
2016 NaN NaN NaN NaN
2021 NaN NaN NaN NaN

Between the sampling periods 2008-2012 and 2013-2017: - the isolation index increased by 5.2% - the absolute clustering index increased by 12.4%.
- the spatial proximity profile increased by 17.6%

Between the sampling periods 2009-2013 and 2014-2018: - the isolation index increased by 7.9% - the absolute clustering index increased by 18.2% - the spatial proximity profile increased by 21.9%

18.5 Space-Time Dynamics

Code
from segregation.singlegroup import Entropy
Code
d = segdyn.spacetime_dyn(dc, singlegroup.Entropy, group_pop_var='n_nonhisp_black_persons', total_pop_var='blackwhite', distances=list(range(500,5500,500)))
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
Code
d.plot(cmap='Reds')

Entropy is falling the fastest at large scales (the gap is wider on the right-hand side of the graph than the left-hand side)

Code
iso = segdyn.spacetime_dyn(dc, singlegroup.Isolation, group_pop_var='n_nonhisp_black_persons', total_pop_var='blackwhite', distances=list(range(500,5500,500)))
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
OMP: Info #276: omp_set_nested routine deprecated, please use omp_set_max_active_levels instead.
Code
iso.plot(cmap='Reds')

Isolation is growing the fastest at large scales (the gap is wider with larger distances on the right). Isolation is actually growing at the smallest scale

Code
from geosnap.visualize import animate_timeseries
Code
animate_timeseries(dc, 'p_nonhisp_black_persons', filename='dc_black_pop_change.gif', fps=1.5)
<Figure size 1920x1920 with 0 Axes>
<Figure size 1920x1920 with 0 Axes>
<Figure size 1920x1920 with 0 Axes>
<Figure size 960x960 with 0 Axes>
Code
from IPython.display import Image
Code
Image('dc_black_pop_change.gif',width=800)
<IPython.core.display.Image object>

18.6 Using geosnap as a Dashboard Engine

The Python dashboarding ecosystem is evolving quickly, so we won’t opine on which platform or toolset is best. But if you have a personal favorite, geosnap is performant to power an urban analytics dashboard on-the-fly. The example below wraps a simple streamlit interface around the workflow above that lets us explore every metro region quickly

example: https://github.com/knaaptime/incseg_app

18.7 Demo