Rows: 11 Columns: 5
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): metro
dbl (4): class_a, class_b, class_c, total
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 1887 Columns: 12
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Region, State, region
dbl (9): cbsa, year, population, units_total, units_1, units_5plus, n_struct...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Rows: 51924 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (3): Region, City, State
dbl (3): cbsa, SizeRank, zori
date (1): date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Problem 1: Bars and Dots
Part 1: Perceptual tasks
When making these comparisons using Figure 2 we need to break it down to 2 categories first, within a city and then across cities. Within a city the perceptual task we are using is “Position along a common (aligned) scale”. The 4 different bars sit at the same baseline and are all connected next to each other. The eye naturally goes to which bar sits the lowest by comparing where the tops of the bars end. Now across cities its a similar concept but we look at length as a the perceptual task. The length of the cars across cities dramatically decrease, so visually we can see the that change by the change in length and quickly draw the information we need.
Part 2: Two Alternative Visualizations
# keep a copy of 'total' before reshaping, just for sortingpew_long <- pew |>mutate(total_for_order = total) |>pivot_longer(cols =c(class_a, class_b, class_c, total),names_to ="class", values_to ="rent_change")
ggplot(pew_long, aes(x = rent_change, y =reorder(metro, total_for_order), color = class)) +geom_point(size =3) +labs(x ="Rent change (%)", y ="Metro",title ="2023–24 Rent Change by Building Class", color ="Class")
ggplot(pew_long, aes(x = rent_change, y =reorder(metro, total_for_order))) +geom_col() +facet_wrap(~class) +labs(x ="Rent change (%)", y ="Metro",title ="2023–24 Rent Change by Building Class")
Original Figure
Pros: Compact and Polished with Color, Easy Comparison within city because of shared baseline
Cons: Comparing high end and low end for ex. comparing Austin and Houston
Cleveland Dot Plot
Pros: Shared X-axis across cities allows for easier comparison.
Cons: With the amount of cities it is visually crowded and can be difficult for an individual to make sense of the graph. Within city comparison is not as ideal as it was within the original figure
Small Multiples
Pros: cross-city comparison in a individual class is now easier as we have 4 different graphs sepearated by class.
Cons: Cross class comparison for 1 city is substantally more work and difficult. This graph requires more effort and cannot be understood at one look.
Problem 2: Fixing a Bad Figure
Part 1: Analyze the problems with a bad figure
Skyscraper images for the bars, this is ugly and takes away from the graph itself. Regular bars are better.
There is no visual data, no way to interpet or understand the graph other than the height of the bars. Higher or lesser zori, there are no values in the x or y axis.
Both graphs are labeled differently in font and color, furthermore the use of font and color is ugly, poor selection
based on the code they are only focusing on one year, 2025 and not comparing growth.
The bar chart has a grid
Part 2: Create a Data Story
Whether or not building permits policy can help reduce rents
rent_growth <- rent_2021 |>inner_join(rent_2025, by ="cbsa") |>mutate(rent_growth_pct = (rent_2025 - rent_2021) / rent_2021 *100)story_df <-inner_join(permits, rent_growth, by ="cbsa")
ggplot(story_df, aes(x = permits_per_1000, y = rent_growth_pct)) +geom_point(alpha =0.6) +geom_smooth(method ="lm", se =FALSE, color ="darkred") +labs(x ="Permits issued per 1,000 residents (2021–2025)",y ="Rent growth (%) (2021–2025)",title ="Metros That Permit More Housing Tend to See Slower Rent Growth")
`geom_smooth()` using formula = 'y ~ x'
cities <-c("Austin-Round Rock-San Marcos, TX", "New York-Newark-Jersey City, NY-NJ","Houston-Pasadena-The Woodlands, TX", "San Francisco-Oakland-Fremont, CA")city_codes <- msa |>filter(Region %in% cities) |>distinct(cbsa) |>pull(cbsa)zori_years <- zori |>filter(cbsa %in% city_codes) |>mutate(year =year(date)) |>group_by(cbsa, Region, year) |>summarise(zori =mean(zori, na.rm =TRUE), .groups ="drop")ggplot(zori_years, aes(x = year, y = zori, color = Region)) +geom_line(linewidth =1) +labs(x ="Year", y ="Average rent (ZORI)",title ="Rent Trends: High- vs. Low-Permit Metros") +labs(subtitle ="Austin and Houston permitted far more housing per resident (2021–2025) than New York or San Francisco")
Some of the design choices i made was in first the graphs made. The first graph is a scatter plot with a linear trend line which can clearly display the downward trend of growth rate. Graph 2 adds time by showing change over years, with 2 distinct groups those that issues more permits vs those that didn’t. Rent growth versus using 1 year as previously used. Simple graphs with simple clear effective colors. Strong use of legend clearly outlining whats there along with labeled axes. 1 graph displays years and 1 displays permits issues over creating a compelling story together.