How to use this template

You will see # TASK ///// through out this template. This indicates the beginning of a task. Right below it will be instructions for the task. Each # TASK ///// will be paired with # //TASK ///// to indicate where that specific task ends.

For example, if you see something like below…

# TASK ////////////////////////////////////////////////////////////////////////
# create a vector with element 1,2,3 and assign it to `my_vec` object
# **YOUR CODE HERE..**
# //TASK //////////////////////////////////////////////////////////////////////

What I expect you to do is to replace where it says # **YOUR CODE HERE..** with your answer, like below.

# TASK ////////////////////////////////////////////////////////////////////////
# create a vector with element 1,2,3 and assign it to `my_vec` object
my_vec <- c(1,2,3)
# //TASK //////////////////////////////////////////////////////////////////////

Some instructions may involve multiple steps, as shown below. You can use the pipe operator to chain multiple functions together to complete the task. Make sure to assign the output of your code to an object with the specified name. This ensures that your code runs smoothly—if you change the object name (e.g., subset_car in the example below), the subsequent code will not run correctly.

# TASK ////////////////////////////////////////////////////////////////////////
# 1. Using mtcars object, extract rows where cyl equals 4
# 2. Select mpg and disp columns
# 3. Create a new column 'summation' by adding mpg and disp
# 4. assign it into `subset_car` object
#subset_car <- # **YOUR CODE HERE..**
# //TASK //////////////////////////////////////////////////////////////////////

I expect you to replace where it says # **YOUR CODE HERE..** with your answer, like below.

# TASK ////////////////////////////////////////////////////////////////////////
# 1. Using mtcars object, extract rows where cyl equals 4
# 2. Select mpg and disp columns
# 3. Create a new column 'summation' by adding mpg and disp
# 4. assign it into `subset_car` object
#subset_car <- mtcars %>% 

# //TASK //////////////////////////////////////////////////////////////////////

You will need to knit it, publish it on Rpubs, and submit the link.

Task description

Park-and-Ride Simulation

In this assignment, you will simulate a journey that begins at a Census Tract centroid, drives to the nearest MARTA station, and then take the MARTA to the Midtown station. You will then compare how travel time varies by different Census Tracts. The steps and data required for this analysis are outlined below.

Step 1. Download the required GTFS data. Convert it to sf format, extract MARTA rail stations, and clean the stop names to remove duplicates. Also, extract the destination station.

Step 2. Download the required Census data. Convert Census Tract polygons into centroids and create a subset for analysis.

Step 3. Download the required OSM data. Convert it into an sfnetwork object and clean the network.

Step 4. Simulate a park-and-ride trip (from a test origin → closest station → Midtown station).

Step 5. Turn the simulation process from Step 4 into a reusable function.

Step 6. Apply the function from Step 5 iteratively to all home locations.

Step 7.Finally, create maps and plots to analyze whether there are any disparities in transit accessibility when commuting to Midtown.

Step 0. Packages

Importing the necessary packages is part of this assignment. Add any required packages to the code chunk below as you progress through the tasks.

library(tidytransit)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.2     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.1.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(leaflet)
library(tidycensus)
library(tidyverse)
library(tmap)
library(gtfsrouter)
## Warning: package 'gtfsrouter' was built under R version 4.5.2
## Registered S3 method overwritten by 'gtfsrouter':
##   method       from  
##   summary.gtfs gtfsio
library(sf)
## Linking to GEOS 3.13.1, GDAL 3.11.0, PROJ 9.6.0; sf_use_s2() is TRUE
library(osmdata)
## Warning: package 'osmdata' was built under R version 4.5.2
## Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
library(nominatimlite)
library(sfnetworks)
library(tidygraph)
## 
## Attaching package: 'tidygraph'
## 
## The following object is masked from 'package:stats':
## 
##     filter

Step 1. GTFS data

# TASK ////////////////////////////////////////////////////////////////////////
# Download MARTA GTFS data and assign it to `gtfs` object
gtfs <- read_gtfs("https://www.itsmarta.com/google_transit_feed/google_transit.zip")# **YOUR CODE HERE..**
# //TASK //////////////////////////////////////////////////////////////////////



# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Edit stop_name to append serial numbers (1, 2, etc.) to remove duplicate names
stop_dist <- stop_group_distances(gtfs$stops, by='stop_name') %>%
  filter(dist_max > 200)

gtfs$stops <- gtfs$stops %>% 
  group_by(stop_name) %>% 
  mutate(stop_name = case_when(stop_name %in% stop_dist$stop_name ~ paste0(stop_name, " (", seq(1,n()), ")"),
                               TRUE ~ stop_name))

# Create a transfer table
gtfs <- gtfsrouter::gtfs_transfer_table(gtfs, 
                                        d_limit = 200, 
                                        min_transfer_time = 120)

# NOTE: Converting to sf format uses stop_lat and stop_lon columns contained in gtfs$stops.
#       In the conversion process, stop_lat and stop_lon are converted into a geometry column, and
#       the output sf object do not have the lat lon column anymore.
#       But many other functions in tidytransit look for stop_lat and stop_lon.
#       So I re-create them using mutate().
gtfs <- gtfs %>% gtfs_as_sf(crs = 4326)

gtfs$stops <- gtfs$stops %>% 
  ungroup() %>% 
  mutate(stop_lat = st_coordinates(.)[,2],
         stop_lon = st_coordinates(.)[,1]) 

# Get stop_id for rails and buses
rail_stops <- gtfs$routes %>% 
  filter(route_type %in% c(1)) %>% 
  inner_join(gtfs$trips, by = "route_id") %>% 
  inner_join(gtfs$stop_times, by = "trip_id") %>% 
  inner_join(gtfs$stops, by = "stop_id") %>% 
  group_by(stop_id) %>% 
  slice(1) %>% 
  pull(stop_id)

# Extract MARTA rail stations
station <- gtfs$stops %>% filter(stop_id %in% rail_stops)

# Extract Midtown Station
midtown <- gtfs$stops %>% filter(stop_id == "134")

# Create a bounding box to which we limit our analysis
bbox <- st_bbox(c(xmin = -84.45241, ymin = 33.72109, xmax = -84.35009, ymax = 33.80101), 
                 crs = st_crs(4326)) %>% 
  st_as_sfc()

# =========== NO MODIFY ZONE ENDS HERE ========================================

Step 2. Census data

# TASK ////////////////////////////////////////////////////////////////////////
# Specify Census API key whichever you prefer using census_api_key() function
key <- readLines('senses.txt')
census_api_key(key, install = TRUE, overwrite = TRUE)
## Your original .Renviron will be backed up and stored in your R HOME directory if needed.
## Your API key has been stored in your .Renviron and can be accessed by Sys.getenv("CENSUS_API_KEY"). 
## To use now, restart R or run `readRenviron("~/.Renviron")`
## [1] "03c592a77e2372047f441537ce6b9cb6a12b6712"
# //TASK //////////////////////////////////////////////////////////////////////



# TASK ////////////////////////////////////////////////////////////////////////
# Using get_acs() function, download Census Tract level data for 2022 for Fulton, DeKalb, and Clayton in GA.
# and assign it to `census` object.
# Make sure you set geometry = TRUE.

# Required data from the Census ACS:
#  1) Median Household Income (name the column `hhinc`)
#  2) Minority Population (%) (name the column `pct_minority`)
# Note: You may need to download two or more Census ACS variables to calculate minority population (%). "Minority" here can refer to either racial minorities or racial+ethnic minorities -- it's your choice.

census <- get_acs(geography = 'tract', variables = c('B19013_001','B02001_001','B02001_002'),
                  year = 2022, state = 'GA', 
                  county = c('DeKalb','Clayton', "Fulton"), 
                  geometry = TRUE) 
## Getting data from the 2018-2022 5-year ACS
## Downloading feature geometry from the Census website.  To cache shapefiles for use in future sessions, set `options(tigris_use_cache = TRUE)`.
##   |                                                                              |                                                                      |   0%  |                                                                              |=                                                                     |   1%  |                                                                              |=                                                                     |   2%  |                                                                              |==                                                                    |   2%  |                                                                              |==                                                                    |   3%  |                                                                              |===                                                                   |   4%  |                                                                              |===                                                                   |   5%  |                                                                              |====                                                                  |   5%  |                                                                              |====                                                                  |   6%  |                                                                              |=====                                                                 |   7%  |                                                                              |=====                                                                 |   8%  |                                                                              |======                                                                |   8%  |                                                                              |======                                                                |   9%  |                                                                              |=======                                                               |   9%  |                                                                              |=======                                                               |  10%  |                                                                              |========                                                              |  11%  |                                                                              |=========                                                             |  12%  |                                                                              |=========                                                             |  13%  |                                                                              |==========                                                            |  14%  |                                                                              |===========                                                           |  15%  |                                                                              |===========                                                           |  16%  |                                                                              |============                                                          |  17%  |                                                                              |=============                                                         |  18%  |                                                                              |=============                                                         |  19%  |                                                                              |==============                                                        |  20%  |                                                                              |===============                                                       |  21%  |                                                                              |===============                                                       |  22%  |                                                                              |================                                                      |  23%  |                                                                              |=================                                                     |  24%  |                                                                              |=================                                                     |  25%  |                                                                              |==================                                                    |  25%  |                                                                              |==================                                                    |  26%  |                                                                              |===================                                                   |  27%  |                                                                              |===================                                                   |  28%  |                                                                              |====================                                                  |  28%  |                                                                              |====================                                                  |  29%  |                                                                              |=====================                                                 |  30%  |                                                                              |=====================                                                 |  31%  |                                                                              |======================                                                |  31%  |                                                                              |======================                                                |  32%  |                                                                              |=======================                                               |  33%  |                                                                              |=======================                                               |  34%  |                                                                              |========================                                              |  34%  |                                                                              |=========================                                             |  35%  |                                                                              |=========================                                             |  36%  |                                                                              |==========================                                            |  37%  |                                                                              |===========================                                           |  38%  |                                                                              |===========================                                           |  39%  |                                                                              |============================                                          |  39%  |                                                                              |============================                                          |  40%  |                                                                              |=============================                                         |  41%  |                                                                              |=============================                                         |  42%  |                                                                              |==============================                                        |  42%  |                                                                              |==============================                                        |  43%  |                                                                              |===============================                                       |  44%  |                                                                              |===============================                                       |  45%  |                                                                              |================================                                      |  45%  |                                                                              |================================                                      |  46%  |                                                                              |=================================                                     |  47%  |                                                                              |=================================                                     |  48%  |                                                                              |==================================                                    |  48%  |                                                                              |==================================                                    |  49%  |                                                                              |===================================                                   |  50%  |                                                                              |===================================                                   |  51%  |                                                                              |====================================                                  |  51%  |                                                                              |====================================                                  |  52%  |                                                                              |=====================================                                 |  53%  |                                                                              |======================================                                |  54%  |                                                                              |======================================                                |  55%  |                                                                              |=======================================                               |  56%  |                                                                              |========================================                              |  57%  |                                                                              |=========================================                             |  58%  |                                                                              |=========================================                             |  59%  |                                                                              |==========================================                            |  59%  |                                                                              |==========================================                            |  60%  |                                                                              |===========================================                           |  61%  |                                                                              |===========================================                           |  62%  |                                                                              |============================================                          |  62%  |                                                                              |============================================                          |  63%  |                                                                              |=============================================                         |  64%  |                                                                              |=============================================                         |  65%  |                                                                              |==============================================                        |  65%  |                                                                              |==============================================                        |  66%  |                                                                              |===============================================                       |  67%  |                                                                              |================================================                      |  68%  |                                                                              |================================================                      |  69%  |                                                                              |=================================================                     |  70%  |                                                                              |==================================================                    |  71%  |                                                                              |==================================================                    |  72%  |                                                                              |===================================================                   |  73%  |                                                                              |====================================================                  |  74%  |                                                                              |====================================================                  |  75%  |                                                                              |=====================================================                 |  76%  |                                                                              |======================================================                |  77%  |                                                                              |======================================================                |  78%  |                                                                              |=======================================================               |  79%  |                                                                              |========================================================              |  80%  |                                                                              |=========================================================             |  81%  |                                                                              |==========================================================            |  82%  |                                                                              |==========================================================            |  83%  |                                                                              |===========================================================           |  84%  |                                                                              |============================================================          |  85%  |                                                                              |============================================================          |  86%  |                                                                              |=============================================================         |  87%  |                                                                              |==============================================================        |  88%  |                                                                              |==============================================================        |  89%  |                                                                              |===============================================================       |  90%  |                                                                              |================================================================      |  91%  |                                                                              |================================================================      |  92%  |                                                                              |=================================================================     |  93%  |                                                                              |==================================================================    |  94%  |                                                                              |==================================================================    |  95%  |                                                                              |===================================================================   |  95%  |                                                                              |===================================================================   |  96%  |                                                                              |====================================================================  |  97%  |                                                                              |====================================================================  |  98%  |                                                                              |===================================================================== |  98%  |                                                                              |===================================================================== |  99%  |                                                                              |======================================================================| 100%
census <- census %>%
  pivot_wider(names_from = variable, values_from = estimate) %>%
  group_by(NAME) %>%
  summarise(across(starts_with("B"), mean, na.rm = TRUE), .groups = "drop")
## Warning: There was 1 warning in `summarise()`.
## ℹ In argument: `across(starts_with("B"), mean, na.rm = TRUE)`.
## ℹ In group 1: `NAME = "Census Tract 10.01; Fulton County; Georgia"`.
## Caused by warning:
## ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
## Supply arguments directly to `.fns` through an anonymous function instead.
## 
##   # Previously
##   across(a:b, mean, na.rm = TRUE)
## 
##   # Now
##   across(a:b, \(x) mean(x, na.rm = TRUE))
census <- census %>%
  rename('tot' = 'B02001_001',
           'whtpop' = 'B02001_002',
           'hhinc' = 'B19013_001') 

census <- census %>%
  mutate(pct_min = (((tot-whtpop)/tot) *100))

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Convert the CRS of `census` to GCS

census <- census %>% st_transform(crs = 4326)


  # **YOUR CODE HERE..**
# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# and assign it to `home` object.
# get centroids of `census` polygons, 
c_centroid <- census %>%
  st_centroid()
## Warning: st_centroid assumes attributes are constant over geometries
#checking work
tmap_mode('plot') +
  tm_shape(c_centroid) +
  tm_dots(col = "hhinc", size = 0.1, popup.vars = c("NAME","hhinc")) +
  tm_shape(bbox) +
  tm_polygons(col = NA, border.col = "red", lwd = 2, alpha = .07)
## ℹ tmap modes "plot" - "view"
## ℹ toggle with `tmap::ttm()`
## 
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## 
## [v3->v4] `tm_polygons()`: use 'fill' for the fill color of polygons/symbols
## (instead of 'col'), and 'col' for the outlines (instead of 'border.col').
## [v3->v4] `tm_polygons()`: use `fill_alpha` instead of `alpha`.
## This message is displayed once per session.

# extract centroids that fall inside the `bbox`, 
census_intersect <- st_intersection(c_centroid, bbox)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
tmap_mode('plot') +
  tm_shape(census_intersect) +
  tm_dots(col = 'hhinc', size = .1) +
  tm_shape(bbox) +
  tm_polygons(col = NA, border.col = "red", lwd = 2, alpha = .07)
## ℹ tmap modes "plot" - "view"
## 
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## 
## [v3->v4] `tm_polygons()`: use `fill_alpha` instead of `alpha`.

home <- census_intersect

# //TASK //////////////////////////////////////////////////////////////////////

Step 3. OSM data

# TASK ////////////////////////////////////////////////////////////////////////
# 1. Get OSM road data for all road types for the `bbox` area.
osm_road <- opq(bbox = bbox) %>%
  add_osm_feature(key = 'highway', 
                  value = c("motorway", "motorway_link",
                            "trunk", "trunk_link", 
                            "primary", "primary_link",
                            "secondary", "secondary_link",
                            "tertiary", "residential")) %>%
  # 3. Convert the OSM data into an sf object
  osmdata_sf() %>% 
  # 4. Convert osmdata polygons into lines
  osm_poly2line()

tmap_mode('plot')
## ℹ tmap modes "plot" - "view"
tm_shape(osm_road$osm_lines) + tm_lines(col = "highway") +
  tm_shape(bbox) +
  tm_polygons(col = NA, border.col = "red", lwd = 2, alpha = .07)
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_polygons()`: use `fill_alpha` instead of `alpha`.

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# 1. Convert osm_road$osm_line into sfnetwork
net <- sfnetworks::as_sfnetwork(osm_road$osm_line, directed = FALSE)
# 2. Activate edges
net %>% activate("edges") %>% st_as_sf()
## Simple feature collection with 5591 features and 203 fields
## Geometry type: LINESTRING
## Dimension:     XY
## Bounding box:  xmin: -84.47054 ymin: 33.71401 xmax: -84.33904 ymax: 33.80595
## Geodetic CRS:  WGS 84
## # A tibble: 5,591 × 204
##     from    to osm_id  name            `abandoned:railway` access `access:lanes`
##    <int> <int> <chr>   <chr>           <chr>               <chr>  <chr>         
##  1     1     2 9164335 <NA>            <NA>                <NA>   <NA>          
##  2     3     4 9165104 <NA>            <NA>                <NA>   <NA>          
##  3     5     6 9186247 Ralph David Ab… <NA>                <NA>   <NA>          
##  4     7     8 9234642 Akridge Place … <NA>                <NA>   <NA>          
##  5     9    10 9234648 Mills Street N… <NA>                <NA>   <NA>          
##  6    11    12 9234652 Travis Street … <NA>                <NA>   <NA>          
##  7    13    14 9234658 Arthur Street … <NA>                <NA>   <NA>          
##  8    15    16 9234725 <NA>            <NA>                <NA>   <NA>          
##  9    17    18 9234734 <NA>            <NA>                <NA>   <NA>          
## 10    19    20 9234751 <NA>            <NA>                <NA>   <NA>          
## # ℹ 5,581 more rows
## # ℹ 197 more variables: `addr:street` <chr>, alt_name <chr>, alt_name_1 <chr>,
## #   attribution <chr>, bicycle <chr>, bridge <chr>, `bridge:name` <chr>,
## #   `bus:lanes` <chr>, change <chr>, `change:backward` <chr>,
## #   `change:forward` <chr>, `change:lanes` <chr>,
## #   `change:lanes:backward` <chr>, `change:lanes:forward` <chr>,
## #   `check_date:surface` <chr>, covered <chr>, created_by <chr>, …
# 3. Clean the network using the methods we learned
simple_net <- net %>%
  activate("edges") %>%
  filter(!edge_is_multiple()) %>% # remove multiple edges
  filter(!edge_is_loop()) # remove loops
# 4. Assign the cleaned network to an object named 'osm'
osm <- simple_net 
  # **YOUR CODE HERE..**
  # ...
# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Add a new column named 'length' to the edges part of the object `osm`.
osm <- osm %>% 
  activate('edges') %>%
  mutate('length' = edge_length())
  # **YOUR CODE HERE..**
  # ...
# //TASK //////////////////////////////////////////////////////////////////////

Step 4. Simulate a park-and-ride trip

# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Extract the first row from `home` object and store it `home_1`
home_1 <- home[1,]
# =========== NO MODIFY ZONE ENDS HERE ========================================

tmap_mode('view')
## ℹ tmap modes "plot" - "view"
# TASK ////////////////////////////////////////////////////////////////////////
# Find the shortest paths from `home_1` to all other stations

#gather rail data
transit <- tidytransit::read_gtfs("https://www.itsmarta.com/google_transit_feed/google_transit.zip") %>% 
  tidytransit::gtfs_as_sf()

rail_stops_id <- transit$routes %>% 
  filter(route_type %in% c(0,1,2)) %>% 
  inner_join(transit$trips, by = "route_id") %>% 
  inner_join(transit$stop_times, by = "trip_id") %>% 
  inner_join(transit$stops, by = "stop_id") %>% 
  group_by(stop_id) %>% 
  slice(1) %>% 
  pull(stop_id)

rail_stops <- transit$stops %>% 
  filter(stop_id %in% rail_stops_id) %>% 
  distinct(stop_desc, .keep_all = T)

rail_stops_geom <- rail_stops %>% st_geometry()

#shortest path from home_1 to all other stations
osm_1 <- osm %>% st_transform(4326)
start_p <- st_geometry(home_1$geometry)
end_p <- st_geometry(rail_stops)
paths <- st_network_paths(osm_1, from = start_p, to = end_p, type = 'shortest')
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
# //TASK //////////////////////////////////////////////////////////////////////

  
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Get shortest network distances from `home_1` to all other stations.
dist_all <- map_dbl(1:nrow(paths), function(x){
  osm %>%
    activate("nodes") %>% 
    slice(paths$node_paths[[x]]) %>% 
    st_as_sf("edges") %>% 
    pull(length) %>% 
    sum()
}) %>% unlist()

# Replace zeros with a large value.
if (any(dist_all == 0)){
  dist_all[dist_all == 0] <- max(dist_all)
}

# TASK ////////////////////////////////////////////////////////////////////////
# Find the closest station and assign the value to `closest_station`
closest_index <- which.min(dist_all)
closest_station <- rail_stops$stop_id[closest_index]     # only the stop_id
closest_dist <- as.numeric(dist_all[closest_index])     # convert units to numeric
# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Calculate travel time based on the `closest_dist` assuming we drive at 20 miles/hour speed.
# Assign the value to `trvt_osm_m` object.

speed_mps <- 20 * 1609.34 / 3600
trvt_osm_m <- closest_dist / speed_mps / 60

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Create a subset of stop_times data table for date = 2025-11-10, 
# minimum departure time of 7AM, maximum departure time of 10AM.
# Assign the output to `am_stop_time` object

am_stop_time <- filter_stop_times(
  gtfs = gtfs,
  extract_date = "2025-11-10",
  min_departure_time = 7*3600,
  max_arrival_time = 10*3600
)

# TASK ////////////////////////////////////////////////////////////////////////
# 1. Calculate travel times from the `closest_station` to all other stations 
#    during time specified in `am_stop_time`. Allow ONE transfer.
# 2. Filter the row where the destination is Midtown station. 
# 3. Assign it to `trvt` object.

trvt <- travel_times(
  filtered_stop_times = am_stop_time,  
  stop_name = "MIDTOWN STATION",       
  time_range = 3600,                   
  arrival = FALSE,                     
  max_transfers = 1,
  return_coords = TRUE
)

# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Divide the calculated travel time by 60 to convert the unit from seconds to minutes.
trvt_gtfs_m <- trvt$travel_time/60

# Add the travel time from home to the nearest station and
# the travel time from the nearest station to Midtown station
total_trvt <- trvt_osm_m + trvt_gtfs_m
# =========== NO MODIFY ZONE ENDS HERE ========================================

Step 5. Convert Step 4 into a function

# Function definition (do not modify other parts of the code in this code chunk except for those inside the TASK section)

get_trvt <- function(home, osm, station, midtown){
home_1 <- home[1,]
# =========== NO MODIFY ZONE ENDS HERE ========================================

# TASK ////////////////////////////////////////////////////////////////////////
# Find the shortest paths from `home_1` to all other stations

#gather rail data we don't need to redo this part each time

#shortest path from home_1 to all other stations
osm_1 <- osm %>% st_transform(4326)
start_p <- st_geometry(home_1$geometry)
end_p <- st_geometry(rail_stops)
paths <- st_network_paths(osm_1, from = start_p, to = end_p, type = 'shortest')
 
# //TASK //////////////////////////////////////////////////////////////////////

  
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Get shortest network distances from `home_1` to all other stations.
dist_all <- map_dbl(1:nrow(paths), function(x){
  osm %>%
    activate("nodes") %>% 
    slice(paths$node_paths[[x]]) %>% 
    st_as_sf("edges") %>% 
    pull(length) %>% 
    sum()
}) %>% unlist()

# Replace zeros with a large value.
if (any(dist_all == 0)){
  dist_all[dist_all == 0] <- max(dist_all)
}

# TASK ////////////////////////////////////////////////////////////////////////
# Find the closest station and assign the value to `closest_station`
closest_index <- which.min(dist_all)
closest_station <- rail_stops$stop_id[closest_index]     # only the stop_id
closest_dist <- as.numeric(dist_all[closest_index])     # convert units to numeric
# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Calculate travel time based on the `closest_dist` assuming we drive at 20 miles/hour speed.
# Assign the value to `trvt_osm_m` object.

speed_mps <- 20 * 1609.34 / 3600
trvt_osm_m <- closest_dist / speed_mps / 60

# //TASK //////////////////////////////////////////////////////////////////////


# TASK ////////////////////////////////////////////////////////////////////////
# Create a subset of stop_times data table for date = 2025-11-10, 
# minimum departure time of 7AM, maximum departure time of 10AM.
# Assign the output to `am_stop_time` object

am_stop_time <- filter_stop_times(
  gtfs = gtfs,
  extract_date = "2025-11-10",
  min_departure_time = 7*3600,
  max_arrival_time = 10*3600
)

# TASK ////////////////////////////////////////////////////////////////////////
# 1. Calculate travel times from the `closest_station` to all other stations 
#    during time specified in `am_stop_time`. Allow ONE transfer.
# 2. Filter the row where the destination is Midtown station. 
# 3. Assign it to `trvt` object.

trvt <- travel_times(
  filtered_stop_times = am_stop_time,  
  stop_name = "MIDTOWN STATION",       
  time_range = 3600,                   
  arrival = FALSE,                     
  max_transfers = 1,
  return_coords = TRUE
)
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Divide the calculated travel time by 60 to convert the unit from seconds to minutes.
trvt_gtfs_m <- trvt$travel_time/60

# Add the travel time from home to the nearest station and
# the travel time from the nearest station to Midtown station
total_trvt <- trvt_osm_m + trvt_gtfs_m
# =========== NO MODIFY ZONE ENDS HERE ========================================
}

Step 6. Apply the function to all home locations.

# Prepare an empty vector
total_trvt <- vector("numeric", nrow(home))

# Apply the function to all Census Tracts
# Fill `total_trvt` object with the calculated time
for (i in 1:nrow(home)){
  total_trvt[i] <- get_trvt(home[i,], osm, station, midtown)
}
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
## Warning in shortest_paths(x, from, to, weights = weights, output = "both", : At
## vendor/cigraph/src/paths/dijkstra.c:534 : Couldn't reach some vertices.
## Warning in total_trvt[i] <- get_trvt(home[i, ], osm, station, midtown): number
## of items to replace is not a multiple of replacement length
# cbind the calculated travel time to `home`
home <- home %>% 
  mutate(trvt = total_trvt)

Step 7. Create maps and plots

Create two maps and two plots by following the instructions in the code chunk below. Write a brief (maximum 200 words) description summarizing your observations from the maps and plots

# TASK ////////////////////////////////////////
# Create an interactive map displaying `census` (polygons) and `home` (points), effectively visualizing household income and travel time to Midtown Station, respectively.

# 
tm_shape(census) +
  tm_polygons(col = "hhinc", palette = "Blues", title = "Median Household Income") +
  tm_shape(home) +
  tm_dots(col = "trvt", palette = "Reds", colorNA = 'black', size = 0.6, title = "Travel Time (min)") +
  tm_view(view.legend.position = c("left","top"))
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the visual variable `fill` namely 'palette' (rename to 'values') to fill.scale
## = tm_scale(<HERE>).
## [v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'
## [tm_dots()] Argument `title` unknown.
## [v3->v4] `tm_view()`: use legend.position instead of view.legend.position
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Blues" is named
## "brewer.blues"
## Multiple palettes called "blues" found: "brewer.blues", "matplotlib.blues". The first one, "brewer.blues", is returned.
## 
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Reds" is named
## "brewer.reds"
# Create an interactive map displaying `census` (polygons) and `home` (points) effectively visualizing the percentage of minority population and travel time to Midtown Station, respectively.

#
tm_shape(census) +
  tm_polygons(
    col = "pct_min",
    palette = "Blues",
    title = "% Minority Population"
  ) +
  tm_shape(home) +
  tm_dots(
    col = "trvt",
    palette = "Oranges",
    size = 0.6,
    title = "Travel Time (min)",
    colorNA = "black"
  ) +
  tm_view(legend.position = c("left", "top"))
## 
## ── tmap v3 code detected ───────────────────────────────────────────────────────
## [v3->v4] `tm_tm_polygons()`: migrate the argument(s) related to the scale of
## the visual variable `fill` namely 'palette' (rename to 'values') to fill.scale
## = tm_scale(<HERE>).[v3->v4] `tm_polygons()`: migrate the argument(s) related to the legend of the
## visual variable `fill` namely 'title' to 'fill.legend = tm_legend(<HERE>)'[tm_dots()] Argument `title` unknown.[cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Blues" is named
## "brewer.blues"Multiple palettes called "blues" found: "brewer.blues", "matplotlib.blues". The first one, "brewer.blues", is returned.
## [cols4all] color palettes: use palettes from the R package cols4all. Run
## `cols4all::c4a_gui()` to explore them. The old palette name "Oranges" is named
## "brewer.oranges"
# Create a scatter plot with a trend line showing the relationship between household income (x-axis) and travel time to Midtown Station (y-axis).
home <- home %>%
  mutate(hhinc = case_when(
    is.na(hhinc) ~ 0,   
    TRUE ~ hhinc         
  ))

home <- home %>% 
  mutate(
    trvt = total_trvt,                     
    hhinc = ifelse(is.na(hhinc), 0, hhinc) 
  )

# Scatter plot: Household Income vs Travel Time
ggplot(home, aes(x = hhinc, y = trvt)) +
  geom_point(color = "blue", alpha = 0.6) +
  geom_smooth(method = "lm", color = "red") +
  labs(
    x = "Median Household Income ($)",
    y = "Travel Time to Midtown (min)",
    title = "Income vs Travel Time to Midtown"
  ) +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# Scatter plot: % Minority Population vs Travel Time
ggplot(home, aes(x = pct_min, y = trvt)) +
  geom_point(color = "purple", alpha = 0.6) +
  geom_smooth(method = "lm", color = "red") +
  labs(
    x = "% Minority Population",
    y = "Travel Time to Midtown (min)",
    title = "Minority Population vs Travel Time to Midtown"
  ) +
  theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# //TASK //////////////////////////////////////

so i had a lot of trouble with this assignment. As you can see from my maps, I thought i ended up getting a lot missing data, but I shifted it to black and saw a lot of 0 - .9. I’m very suspicious of this because they appear all over the map even in places where there isn’t a MARTA rail station, so maybe it is taking into account bus routes? However, I did get a couple of points to interact with, and what I got is that most travel times were in the 3 - 6 area. My thought is that since the function calls for only allowing one transfer, and there aren’t marta stops in many of these census tracts, it wasn’t able to find a shortest path to the midtown station with one transfer by metro. For household income, we see that for where data is present it is pretty low income 0 - 50k in majority minority areas. If we ignore the 0 values in the scatterplots, we some relationships. Income is largely flat, but a little bit positive. Makes sense since income disparaty is widely spread across north atlanta. For minorities, there appears to be a negative association where more minority populations census tracts live closer to midtown.