There is a colloquially accepted theory of gentrification in Chicago which holds that gentrification happens differently across racial and ethnic communities. Under this theory, wealthier populations are more likely to settle in predominantly Latinx communities, eventually pushing out current residents. In Black neighborhoods, however, gentrification happens after significant periods of neglect and disenfranchisement make an area unlivable, forcing residents to move elsewhere: “freeing it up” for different demographics and consequent investment catering to these new residents.

I seek to evaluate this claim by exploring the movement of racial and ethnic populations within the city, business activity as measured by business license issuances, and investment in education determined by average spend per student across different socioeconomic groups. I focus on the years immediately following the recent recession, as I am interested in the varying post-crisis resilience of neighborhoods as a factor in the theory described above.

Population Displacement in Chicago Communities

Since the Great Recession, underrepresented minority populations in Chicago have been increasingly relegated to lower income areas in the South and West of the City. Some communities have maintained a foothold in their respective neighborhoods, while others are priced out as wealthier populations move into the areas they have historically called home.

all_demos_range <- readRDS(here::here("data", "range_demos_chi_proj.Rda"))
wards.2015 <- readRDS(here::here("data", "wards2015_sf.Rda"))

ward_range <- st_intersection(wards.2015, all_demos_range)

# plot intersection of Census tracts with chicago wards
# st_intersection(wards.2015, all_demos_range) %>%
ward_range %>% filter((predominant_race == "Latinx") & (id != 2015)) %>%
ggplot() +
  # outline tracts based on predominant race based on Census, shaded by median Income for tract
  geom_sf(aes(fill=below_poverty_pct), lwd = 2, color="#6d7d53") +

  scale_fill_gradient(low = "#dae0e2", high="#2d4f5a") +
  
  # outline Chicago wards over data
  geom_sf(data = wards.2015, color="#292929", lwd = 1, fill=NA) +

  coord_sf(datum = NA) +
  theme_map_modest() + 
  theme(
        plot.title = element_text(face = "bold", hjust="0.5", family = "Ledger", size=rel(2.5)),
        plot.subtitle = element_text(margin = unit(c(0, 0, 1, 0), "lines"), size=rel(2)),
        plot.caption = element_text(hjust=1, size=rel(1.75)),
        strip.text.x = element_text(family="Ledger", size=rel(2.25)),
        legend.position = "bottom",
        legend.box = "vertical",
        legend.title = element_text(size=rel(2), family = "Ledger"),
        legend.text = element_text(size=rel(1.1)),
        legend.key.size = unit(45, "pt"),
        panel.spacing = unit(1, "lines"),
        plot.margin = unit(c(2,4,2,2),"lines")
        ) +
  facet_wrap(~ id) + 
  # guides(fill = guide_colourbar(title.position="top", title.hjust = 0.5)) + 
  labs(alpha = "Median Income", color="Predominant Race", title="Latinx Populations in Chicago Pushed to South, West Neighborhoods", caption="Data Source: U.S. Census Bureau", 
       subtitle = "Chicago racial and ethnic group movement by census tract since 2012 (5 year averages) show that Latinx communities are being\ndisplaced from the city center.", fill="Tract Percentage Below Federal Poverty Line") 

While there are myriad factors contributing to the way communities move over time, race is an undeniable component. There is a clear shift of Latinx populations from desirable neighborhoods close to the center and north of the city to more western and southern neighborhoods.

ward_range %>% filter((predominant_race == "Black") & (id != 2015)) %>%
ggplot() +
  # outline tracts based on predominant race based on Census, shaded by median Income for tract
  # geom_sf(aes(alpha=below_poverty_pct), lwd = 0, fill=get_dt_cols("ocean")) +

  geom_sf(aes(fill=below_poverty_pct), lwd = 2, color="#9d8e64") +
  # scale_alpha(range = c(0.15, 1)) +
  scale_fill_gradient(low = "#dae0e2", high="#2d4f5a") +
  # outline Chicago wards over data
  geom_sf(data = wards.2015, color="#292929", lwd = 1, fill=NA) +
  coord_sf(datum = NA) +
  theme_map_modest() + 
  theme(
        plot.title = element_text(face = "bold", hjust="0.5", family = "Ledger", size=rel(2.5)),
        plot.subtitle = element_text(margin = unit(c(0, 0, 1, 0), "lines"), size=rel(2)),
        plot.caption = element_text(hjust=1, size=rel(1.75)),
        strip.text.x = element_text(family="Ledger", size=rel(2.25)),
        legend.position = "bottom",
        legend.box = "vertical",
        legend.title = element_text(size=rel(2), family = "Ledger"),
        legend.text = element_text(size=rel(1.1)),
        legend.key.size = unit(45, "pt"),
        panel.spacing = unit(1, "lines"),
        plot.margin = unit(c(2,4,2,2),"lines")
        ) +
  facet_wrap(~ id) +
  # guides(fill = guide_colourbar(title.position="top", title.hjust = 0.5)) + 
  labs(alpha = "Median Income", color="Predominant Race", title="In Contrast, Black Communities Stay in Place in Increasingly Poor Neighborhoods ", caption="Data Source: U.S. Census Bureau", 
       subtitle = "Black communities are not pushed out of their neighborhoods, however, the percentage of residents below the federal poverty line\nin predominantly Black tracts has increased city-wide.", fill="Tract Percentage Below Federal Poverty Line") 

Business Activity across Chicago Areas

The neighborhoods housing these minority communities are those with distinctly lower levels of economic activity. The majority of the city’s “bouncing back” after the recession happens in the Central, North, and West sides of the city.

all_wards_all_dates <-  readRDS(here::here("data", "all_wards_all_dates.Rda"))

allDatesCount.df <- all_wards_all_dates %>% expand(SIDE_CLEAN, WARD, `APPLICATION TYPE`, count_date) %>% 
 full_join(all_wards_all_dates) %>%  arrange(SIDE_CLEAN, WARD, `APPLICATION TYPE`, count_date) %>% 
  mutate(
    activity_wk = lubridate::as_date(
      cut(count_date, breaks = "week", start.on.monday = FALSE, origin = lubridate::origin)),
   activity_month = lubridate::as_date(
      cut(count_date, breaks = "month", start.on.monday = FALSE, origin = lubridate::origin)),
   activity_qtr = lubridate::as_date(
      cut(count_date, breaks = "quarter", start.on.monday = FALSE, origin = lubridate::origin)) 
   )


library(lemon)
allDatesCount.df %>% 
  filter(`APPLICATION TYPE` %in% c("ISSUE", "RENEW")) %>% group_by(SIDE, activity_qtr, `APPLICATION TYPE`) %>% 
  summarise(active_businesses = sum(active_businesses)) %>% 
  arrange(activity_qtr, desc(active_businesses), SIDE) %>%
 mutate(SIDE_CLEAN = factor(SIDE,levels = rev(unique(SIDE))),
        SIDE_CLEAN = ifelse(SIDE_CLEAN == "Far Southwest", "Far Southwest Side", 
                     ifelse(SIDE_CLEAN == "Far Southeast", "Far Southeast Side",
                     SIDE_CLEAN))) %>%
              ggplot(aes(x=activity_qtr, y=active_businesses)) +   
  geom_bar(aes(x=activity_qtr, y=active_businesses, fill=`APPLICATION TYPE`), stat = "identity", position="dodge") +
  scale_fill_dt(labels=c("    Newly Issued Licenses    ", "    License Renewals    ")) +
  # geom_text(aes(label=active_businesses), 
  #           size = 3, position = position_stack(vjust = 0.5), color="white") +
  scale_y_continuous(labels = scales::comma) +
  scale_x_date(date_labels = "%b %y", 
                date_breaks = "1 year", limits = c(ymd("2012-01-01"), ymd("2018-12-31"))) +
  theme_modest() + 
  theme(
        legend.direction = "horizontal",
        legend.key.size = unit(25, "pt"),
        legend.title = element_blank(),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.spacing = unit(2, "lines"),
        strip.text = element_text(family="Ledger", size=rel(1.2)),
        axis.title.y = element_text(size=rel(1.5), margin=unit(c(0,0,2,2), "lines"), angle=90, family="Ledger"),
        axis.text.y = element_text(size=rel(1), margin=unit(c(0,0,2,2), "lines")),
        axis.text.x = element_text(hjust = 0, angle=-45),
        legend.position = "bottom",
        axis.title.x = element_blank(),
        plot.margin = unit(c(2,4,2,2),"lines")) + 
  facet_rep_wrap(~ SIDE_CLEAN, repeat.tick.labels=TRUE) +
      labs(y="Number of Business Licenses Issued or Renewed", 
           colour="Chicago Council Ward", 
           caption="Data Source: Chicago Open Data Portal",  
           title="New Business Never Returns to Far Southeast and Far Southwest Post-Recession", 
           subtitle = "Steady decline in new business entry post-recession in Chicago areas with lowest economic activity pre-recession", fill="Chicago Area")  

  # annotate("text", x=lubridate::ymd("2013-01-01"), y = 850000, label="Business renewals dipping in 2013, were balanced by spikes in new business due to EDGE tax credits.")

Immediately post-recession in 2013, the amount of Economic Development for a Growing Economy (EDGE) tax credits granted by Illinois nearly doubled from the prior year, causing a brief spike in new business license Issuances for every area of the city beyond Central (Loop area), which has experienced fairly constant new business entry since the recession. Thus far, only the West Side of Chicago is approaching 2012 levels of new business, with most other areas of the city remaining fairly constant after EDGE excitement tapered off.

In the Far Southeast and Far Southwest Sides, economic activity (in terms of number of active businesses) was about half that of the next lowest areas, even before EDGE-induced business dropped off. One must wonder how much growth a neighborhood can experience with a monthly rate of new business entry that has hovered around 500 businesses for years. For context, the mean number of quarterly new licenses issued in the Central area of the city is just under 700,000, and the mean number of quarterly licenses issued in the Northwest Side is just over 85,000.

Mapping Chicago’s Forgotten Economies

There is unquestionable variation in the level of economic activity within each Side. However, positive variance from the norm for areas that are predominantly Black and Latinx actually appear to be in parts of these communities that border areas with larger Asian, White, and Other racial/ ethnic populations.

# filter for business license issuances and renewals, and create a monthly count
bus_licenses %>% filter(!is.na(WARD), active==1,  activity_date >= mdy("1/1/2012")) %>%
  group_by(activity_month, activity_yr, WARD, SIDE) %>% 
  summarise(business_count = n()) %>% group_by(WARD, SIDE) %>% arrange(desc(business_count)) %>% 
  
  # plot boxplot of median monthly issuances and renewals for each ward
  ggplot(aes(x=reorder(reorder(reorder(SIDE, business_count, FUN = median),WARD),business_count, FUN=median), y=business_count)) + 
  # add comparison line for lowest levels of montly ward business activity
  geom_hline(yintercept=25, linetype = "dotted") +
  # draw boxplots with color and order determined by Chicago Side area
  geom_boxplot(aes(group=reorder(as.factor(WARD), SIDE), fill=as.factor(SIDE)), show.legend = FALSE) + 
  scale_fill_dt() +
  
  # limit scale to 750, (one Loop ward's outliers extend ~1000 above other wards)
  # still very clearly the highest even without all outliers visible
  scale_y_continuous(breaks = sort(c(seq(0, 750, 150), 25)), limits = c(0, 750), 
                     minor_breaks = seq(0 , 750, 75)) +
  scale_x_discrete(breaks=unique(bus_licenses$SIDE), 
    labels=addline_format(as.factor(unique(bus_licenses$SIDE))) ) +
  labs(x="Chicago Council Ward", y="Average Monthly Business Count", caption="Data Source: Chicago Open Data Portal", title="Least New & Surviving Businesses in Far South, Southwest Wards for 5+ Years", subtitle="Since 2012, Far South wards average 26 or less monthly business license issuances and renewals",fill="Chicago Area") + 
  theme_modest() +
  theme(
        panel.grid.major.x = element_blank(),
        axis.ticks =  element_blank(),
        axis.title.x = element_blank(),
        axis.text.x = element_text( family="Ledger", size=rel(1)),
        axis.text.y = element_text( margin=unit(c(0,2,2,2), "lines"), size=rel(1)),
        axis.title.y = element_text(margin=unit(c(0,0,2,2), "lines"), size=rel(1.2), angle = 90, family = "Ledger"),
        plot.caption = element_text(hjust=1)
        ) +
  annotate("text", x = 7 , y= 390, label="Most West Side business\noccurs in Wards 2 and 27,\nwhich border the Loop.", size=rel(4)) +
  annotate("text", x = 8.9 , y= 745, label="The Central area is comprised\nof Ward 42, the Loop area.", size=rel(4)) +
  annotate("text", x = 5 , y= 335, label="South Side business activity\nis concentrated in Kenwood,\n Fuller Park areas bordering\nthe University of Chicago.", size=rel(4)) +
  annotate("text", x = 3 , y= 305, label="Ward 12 on the Southwest\nSide, which neighbors Chinatown, is\ncharacterized by higher rates\nof business activity than\nits neighbors.", size=rel(4)) 

Exploring Voter Activation in Deinvested Wards

In light of fairly clear de-investment in certain parts of Chicago, I hypothesized that voters in affected wards would be encouraged to vote in aldermen who would help improve their interests. I was interested to see that the Far Southwest Side, arguably the area most impacted by de-investment, had the highest voter turnout in both of the two most recent elections.

As it turns out, the highest voter activation in this area occurred in Ward 19, the Beverly and Mt. Greenwood area, of which over 70% of the population is white, in comparison to the rest of the area, which has a white population of less than 1%, and had turnout of 35-40%. It is perhaps interesting that in a community that is largely black, another population group has the loudest voices in terms of voter input.

# read in turnout and change in turnout by Chicago ward and Chciago Side
  turnoutSides <-  readRDS(here::here("data", "sides_turnout.Rda"))
  turnoutDiff <-  readRDS(here::here("data", "wards_turnout.Rda"))
  
  # turnoutDiff %>% group_by(SIDE, WARD) %>% summarise(z = max(TURNOUT)) %>% filter(SIDE == "Far Southwest")
  
  # plot average turnout in 2011 and 2015 for each Chicago Side
  ggplot(turnoutSides, aes(x=as.factor(YEAR), y=TURNOUT, group=as.factor(SIDE))) + 
  geom_line(aes(colour=SIDE), size=1.5, show.legend = FALSE) +
  # geom_line(data = filter(turnoutSides, (DIFFERENCE > -0)||(is.na(DIFFERENCE))), aes(colour=SIDE), size=1.5, show.legend=FALSE) +
  scale_color_dt() + 
    
  # add lines for distribution within each Side at Ward level
  geom_line(data = turnoutDiff, aes(group=as.factor(WARD), color=SIDE), size=0.5, alpha=0.35, show.legend = FALSE) +
  
  # label each Side's values in line graphs for both 2011 and 2015
  geom_label_repel(data = turnoutSides %>% filter(YEAR == 2011), 
            aes(label = paste0(SIDE, " - ", TURNOUT, "%"), color = SIDE),
            fill=NA,
            hjust = "left",
            nudge_x = -.15,
            force=6,
            direction = "y",
            xlim= c(-0.5,.965),
            fontface = "bold",
            label.size = 0,
            point.padding   = 0.75,
            size = rel(5),
            show.legend = FALSE,
            family="Ledger") +
  geom_label_repel(data = turnoutSides %>% filter(YEAR == 2015),
            aes(label = paste0(SIDE, " - ", TURNOUT, "%"), color = SIDE),
            fill=NA,
            hjust = "right",
            nudge_x = .25,
            force = 5,
            direction = "y",
            fontface = "bold",
            point.padding   = 0.75,
            xlim=c(2.05,3),
            label.size = 0,
            size = rel(5),
            show.legend = FALSE,
            family="Ledger") +
  # move x-axis text to top of graph
  scale_x_discrete(position = "top") +
   # coord_cartesian(ylim=c(23.5, 60)) +
  theme_modest() + 
  theme(axis.text.x.top = element_text(size=rel(1.25), vjust = -8, face="bold", family="Ledger"),
          axis.title.y = element_blank(),
          axis.title.x = element_blank(),
          axis.text.y = element_blank(),
          panel.grid.minor=element_blank(),
          panel.grid.major=element_blank()
          # plot.title = element_text(size=rel(1.5)),
          # plot.subtitle = element_text(hjust=0.35)
        ) +
       
  labs(title="Amid City-Wide Turnout Dropoff, Significantly Higher Voter Activation in Far Southwest Side", 
         subtitle="Voters in the Far Southwest, which has faced de-investment as determined by a number of factors, far exceeded other areas'\nparticipation in the last two City Council elections.", 
         caption="Source: Chicago Board of Election Commissioners", color="Chicago Area") +
  annotate("text",  x = 1, y = 25, label = "*Underlying ward trends visualized\nbehind Side trendlines", size=rel(4)) + 
    annotate("text", x = 0.7, y = 70, label="Ward 19 on the Far Southwest\nSide, which contains the Beverly\nand Morgan Park neighborhoods,\nhad voter turnout of nearly 75%\n in the 2011 City Council Election.", size=rel(4), hjust=0, color=get_dt_cols("mauve"))

The disparities explored above give all Chicagoans good reason to utilize their right to choose leaders who will work to build a more equitable Chicago.

Chicago City Council Election Day is Tuesday, February 26, 2019!

Find your ward’s early voting site to vote before Monday, February 25, 2019.

Not registered for the upcoming Chicago Elections? Register here, or double-check your registration status.

Want to learn about the candidates? Visit the City Council election page on Ballotpedia.

Resources:

Illinois State Board of Education, Report Card Data Library 2013-2019

Chicago Public Schools, Find Your School Budget 2013-2019

Chicago Public Schools, School Demographic Data 2013-2019

Chicago Department of Business Affairs and Consumer Protection, Business Licenses Dataset 2012-2018

U.S. Census Bureau, ACS 5-Year Tables 2012-2017