#Import necessary packages
library(tidycensus)
library(dplyr)
library(tmap)
library(tidyverse)
library(sf)
library(osmdata)
library(sfnetworks)
library(tidygraph)
library(units)
library(leaflet)
library(leafsync)
library(ggplot2)
# TASK ////////////////////////////////////////////////////////////////////////
# Set up your api key here
census_api_key(Sys.getenv("CENSUS_API"))
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Download Census Tract polygon for Fulton and DeKalb
tract <- get_acs("tract",
variables = c('pop' = 'B01001_001'),
year = 2023,
state = "GA",
county = c("Fulton", "DeKalb"),
geometry = TRUE)
## | | | 0% | |= | 1% | |= | 2% | |== | 2% | |== | 3% | |== | 4% | |=== | 4% | |=== | 5% | |==== | 5% | |==== | 6% | |===== | 7% | |===== | 8% | |====== | 8% | |====== | 9% | |======= | 9% | |======= | 10% | |======= | 11% | |======== | 11% | |======== | 12% | |========= | 13% | |========== | 14% | |========== | 15% | |=========== | 16% | |============ | 17% | |============= | 18% | |============= | 19% | |============== | 19% | |============== | 20% | |=============== | 21% | |=============== | 22% | |================ | 22% | |================ | 23% | |================= | 24% | |================== | 25% | |================== | 26% | |=================== | 27% | |==================== | 28% | |==================== | 29% | |===================== | 30% | |====================== | 31% | |====================== | 32% | |======================= | 33% | |======================== | 34% | |======================== | 35% | |========================= | 35% | |========================= | 36% | |========================== | 37% | |========================== | 38% | |=========================== | 38% | |=========================== | 39% | |============================ | 40% | |============================ | 41% | |============================= | 41% | |============================= | 42% | |============================== | 43% | |=============================== | 44% | |================================ | 45% | |================================ | 46% | |================================= | 47% | |================================== | 48% | |================================== | 49% | |=================================== | 49% | |=================================== | 50% | |==================================== | 51% | |==================================== | 52% | |===================================== | 52% | |===================================== | 53% | |====================================== | 54% | |====================================== | 55% | |======================================= | 55% | |======================================= | 56% | |======================================== | 57% | |======================================== | 58% | |========================================= | 58% | |========================================= | 59% | |========================================== | 60% | |=========================================== | 61% | |=========================================== | 62% | |============================================ | 63% | |============================================= | 64% | |============================================= | 65% | |============================================== | 66% | |=============================================== | 67% | |=============================================== | 68% | |================================================ | 69% | |================================================= | 69% | |================================================= | 70% | |================================================== | 71% | |================================================== | 72% | |=================================================== | 72% | |=================================================== | 73% | |==================================================== | 74% | |===================================================== | 75% | |===================================================== | 76% | |====================================================== | 77% | |======================================================= | 78% | |======================================================= | 79% | |======================================================== | 80% | |========================================================= | 81% | |========================================================= | 82% | |========================================================== | 83% | |=========================================================== | 84% | |=========================================================== | 85% | |============================================================ | 85% | |============================================================ | 86% | |============================================================= | 87% | |============================================================= | 88% | |============================================================== | 88% | |============================================================== | 89% | |=============================================================== | 90% | |=============================================================== | 91% | |================================================================ | 91% | |================================================================ | 92% | |================================================================= | 93% | |================================================================= | 94% | |================================================================== | 94% | |=================================================================== | 95% | |=================================================================== | 96% | |==================================================================== | 97% | |===================================================================== | 98% | |===================================================================== | 99% | |======================================================================| 99% | |======================================================================| 100%
tmap_mode("view")
tm_basemap("OpenStreetMap") +
tm_shape(tract) +
tm_polygons(fill_alpha = 0.2)
# =========== NO MODIFY ZONE ENDS HERE ========================================
# TASK ////////////////////////////////////////////////////////////////////////
# 1. Specify the GEOIDs of your walkable and unwalkable Census Tracts.
# e.g., tr_id_walkable <- c("13121001205", "13121001206")
# 2. Extract the selected Census Tracts using `tr_id_walkable` and `tr_id_unwalkable`
# For the walkable Census Tract(s)
tr_id_walkable <- c("13121001001")
tract_walkable <- tract %>%
filter(GEOID == tr_id_walkable)
# For the unwalkable Census Tract(s)
tr_id_unwalkable <- c("13121009601")
tract_unwalkable <- tract %>%
filter(GEOID == tr_id_unwalkable)
# //TASK //////////////////////////////////////////////////////////////////////
# TASK ////////////////////////////////////////////////////////////////////////
# Create an interactive map showing `tract_walkable` and `tract_unwalkable`
tmap_mode("view")
tm_basemap("OpenStreetMap") +
tm_shape(tract) +
tm_polygons(alpha = 0.2, col = "#adadad") +
tm_shape(tract_walkable) +
tm_borders(col = "#38b6f5", lwd = 5) +
tm_fill(col = "#38b6f5", alpha = 0.6, title = "Most Walkable Tract") +
tm_shape(tract_unwalkable) +
tm_borders(col = "#db9d32", lwd = 5) +
tm_fill(col = "#db9d32", alpha = 0.6, title = "Least Walkable Tract") +
tm_layout(
main.title = "Selected Walkable vs Unwalkable Census Tracts",
main.title.size = 1.2,
)
# //TASK //////////////////////////////////////////////////////////////////////
The census tract I selected as most walkable is Census Tract 10.01, which is located in Midtown. It is most walkable considering its proximity to the Midtown and North Avenue MARTA stations. It is also more walkability because its block size is smaller and there are more crosswalks. The pedestrian sidewalks are also well-maintained.
The census tract I selected as least walkable is Census Tract 96.01, which is located in Buckhead. It is less walkable because it is so difficult to reach the nearest Buckhead MARTA station. It is very not pedestrian-friendly due to its large block size and poorly maintained sidewalks. The cars that drive by are at dangerous speed that I always feel like I’ll get hit if I’m not being careful.
# TASK ////////////////////////////////////////////////////////////////////////
# Create one bounding box (`tract_walkable_bb`) for your walkable Census Tract(s) and another (`tract_unwalkable_bb`) for your unwalkable Census Tract(s).
# For the walkable Census Tract(s)
tract_walkable_bb <- st_bbox(tract_walkable)
# For the unwalkable Census Tract(s)
tract_unwalkable_bb <- st_bbox(tract_unwalkable)
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Get OSM data for the two bounding boxes
osm_walkable <- opq(bbox = tract_walkable_bb) %>%
add_osm_feature(key = 'highway',
value = c("primary", "secondary", "tertiary", "residential")) %>%
osmdata_sf() %>%
osm_poly2line()
osm_unwalkable <- opq(bbox = tract_unwalkable_bb) %>%
add_osm_feature(key = 'highway',
value = c("primary", "secondary", "tertiary", "residential")) %>%
osmdata_sf() %>%
osm_poly2line()
# =========== NO MODIFY ZONE ENDS HERE ========================================
# TASK ////////////////////////////////////////////////////////////////////////
# 1. Convert `osm_walkable` and `osm_unwalkable` into sfnetwork objects (as undirected networks),
# 2. Clean the network by (1) deleting parallel lines and loops, (2) creating missing nodes, and (3) removing pseudo nodes (make sure the `summarise_attributes` argument is set to 'first' when doing so).
net_walkable <- osm_walkable$osm_lines %>%
# Drop redundant columns
select(osm_id, highway) %>%
sfnetworks::as_sfnetwork(directed = FALSE) %>%
activate("edges") %>%
filter(!edge_is_multiple()) %>% # remove duplicated edges
filter(!edge_is_loop()) %>% # remove loops
convert(., sfnetworks::to_spatial_subdivision) %>% # subdivide edges
convert(., sfnetworks::to_spatial_smooth, summarise_attributes = "first") # delete pseudo nodes
net_unwalkable <- osm_unwalkable$osm_lines %>%
# Drop redundant columns
select(osm_id, highway) %>%
sfnetworks::as_sfnetwork(directed = FALSE) %>%
activate("edges") %>%
filter(!edge_is_multiple()) %>% # remove duplicated edges
filter(!edge_is_loop()) %>% # remove loops
convert(., sfnetworks::to_spatial_subdivision) %>% # subdivide edges
convert(., sfnetworks::to_spatial_smooth, summarise_attributes = "first") # delete pseudo nodes
# //TASK //////////////////////////////////////////////////////////////////////
# TASK //////////////////////////////////////////////////////////////////////
# Using `net_walkable` and`net_unwalkable`,
# 1. Activate the edge component of each network.
# 2. Create a `length` column.
# 3. Filter out short (<300 feet) segments.
# 4. Randomly Sample 100 rows per road type.
# 5. Assign the results to `edges_walkable` and `edges_unwalkable`, respectively.
# OSM for the walkable part
edges_walkable <- net_walkable %>%
# Extract 'edges'
st_as_sf("edges") %>%
# Drop redundant columns
select(osm_id, highway) %>%
# Add a length column
mutate(length = st_length(.) %>% unclass()) %>%
# Drop short segments (< 300 feet)
filter(length >= 91) %>%
# Sample 10 rows per road type
group_by(highway) %>%
slice_sample(n = 100) %>%
# Assign a unique ID for each edge
ungroup() %>%
mutate(edge_id = seq(1,nrow(.)))
# OSM for the unwalkable part
edges_unwalkable <- net_unwalkable %>%
# Extract 'edges'
st_as_sf("edges") %>%
# Drop redundant columns
select(osm_id, highway) %>%
# Add a length column
mutate(length = st_length(.) %>% unclass()) %>%
# Drop short segments (< 300 feet)
filter(length >= 91) %>%
# Sample 10 rows per road type
group_by(highway) %>%
slice_sample(n = 100) %>%
# Assign a unique ID for each edge
ungroup() %>%
mutate(edge_id = seq(1,nrow(.)))
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Merge the two
edges <- bind_rows(edges_walkable %>% mutate(is_walkable = TRUE),
edges_unwalkable %>% mutate(is_walkable = FALSE)) %>%
mutate(edge_id = seq(1,nrow(.)))
# =========== NO MODIFY ZONE ENDS HERE ========================================
getAzimuth <- function(line){
# TASK ////////////////////////////////////////////////////////////////////////
# 1. Use the `st_line_sample()` function to sample three points at locations 0.48, 0.5, and 0.52 along the line. These points will be used to calculate the azimuth.
# 2. Use `st_cast()` function to convert the 'MULTIPOINT' object into a 'POINT' object.
# 3. Extract coordinates using `st_coordinates()`.
# 4. Assign the coordinates of the midpoint to `mid_p`.
# 5. Calculate the azimuths from the midpoint in both directions and save them as `mid_azi_1` and `mid_azi_2`, respectively.
# 1-3
mid_p3 <- line %>%
st_line_sample(sample = c(0.48, 0.5, 0.52)) %>%
st_cast("POINT") %>%
st_coordinates()
# 4
mid_p <- mid_p3[2,]
# 5
mid_azi_1 <- atan2(mid_p3[1,"X"] - mid_p3[2, "X"],
mid_p3[1,"Y"] - mid_p3[2, "Y"])*180/pi
mid_azi_2 <- atan2(mid_p3[3,"X"] - mid_p3[2, "X"],
mid_p3[3,"Y"] - mid_p3[2, "Y"])*180/pi
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
return(tribble(
~type, ~X, ~Y, ~azi,
"mid1", mid_p["X"], mid_p["Y"], mid_azi_1,
"mid2", mid_p["X"], mid_p["Y"], mid_azi_2))
# =========== NO MODIFY ZONE ENDS HERE ========================================
}
# TASK ////////////////////////////////////////////////////////////////////////
# Apply getAzimuth() function to all edges.
# Remember that you need to pass edges object to st_geometry() before you apply getAzimuth()
edges_azi <- edges %>%
st_geometry() %>%
map_df(getAzimuth, .progress = T)
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
edges_azi <- edges_azi %>%
bind_cols(edges %>%
st_drop_geometry() %>%
slice(rep(1:nrow(edges),each=2))) %>%
st_as_sf(coords = c("X", "Y"), crs = 4326, remove=FALSE) %>%
mutate(img_id = seq(1, nrow(.)))
# =========== NO MODIFY ZONE ENDS HERE ========================================
getImage <- function(iterrow){
# This function takes one row of `edges_azi` and downloads GSV image using the information from the row.
# TASK ////////////////////////////////////////////////////////////////////////
# 1. Extract required information from the row of `edges_azi`
# 2. Format the full URL and store it in `request`. Refer to this page: https://developers.google.com/maps/documentation/streetview/request-streetview
# 3. Format the full path (including the file name) of the image being downloaded and store it in `fpath`
type <- iterrow$type
location <- paste0(iterrow$Y %>% round(5), ",", iterrow$X %>% round(5))
heading <- iterrow$azi %>% round(1)
edge_id <- iterrow$edge_id
img_id <- iterrow$img_id
key <- Sys.getenv("GOOGLE_API") # your Google API key
endpoint <- "https://maps.googleapis.com/maps/api/streetview"
request <- glue::glue("{endpoint}?size=640x640&location={location}&heading={heading}&fov=90&pitch=0&key={key}")
fname <- glue::glue("GSV-nid_{img_id}-eid_{edge_id}-type_{type}-Location_{location}-heading_{heading}.jpg") # Don't change this code for fname
fpath <- file.path("M:/CP8883_UA/Assignments/Major/Major2/GSVImages", fname)
# //TASK //////////////////////////////////////////////////////////////////////
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
# Download images
if (!file.exists(fpath)){
download.file(request, fpath, mode = 'wb')
}
# =========== NO MODIFY ZONE ENDS HERE ========================================
}
# =========== NO MODIFICATION ZONE STARTS HERE ===============================
for (i in seq(1,nrow(edges_azi))){
getImage(edges_azi[i,])
}
#ZIP THE DOWNLOADED IMAGES AND NAME IT 'gsv_images.zip' FOR STEP 6.
# =========== NO MODIFY ZONE ENDS HERE ========================================
# TASK ////////////////////////////////////////////////////////////////////////
# Read the downloaded CSV file containing the semantic segmentation results.
seg_output <- read.csv("seg_output.csv")
# //TASK ////////////////////////////////////////////////////////////////////////
# TASK ////////////////////////////////////////////////////////////////////////
# 1. Join the `seg_output` data to `edges_azi`.
# 2. Calculate the proportion of predicted pixels for the following categories: `building`, `sky`, `road`, and `sidewalk`. If there are other categories you are interested in, feel free to include their proportions as well.
# 3. Calculate the proportion of greenness using the `vegetation` and `terrain` categories.
# 4. Calculate the building-to-street ratio. For the street, use `road` and `sidewalk` pixels; including `car` pixels is optional.
edges_seg_output <- edges_azi %>%
inner_join(seg_output, by=c("img_id"="img_id")) %>%
mutate(p_building = building/(768*768),
p_sky = sky/(768*768),
p_road = road/(768*768),
p_sidewalk = sidewalk/(768*768),
p_greenness = (vegetation + terrain)/(768*768),
b2s_ratio = building / (road + sidewalk + car)) %>%
mutate(b2s_ratio = case_when(
b2s_ratio >= 1 ~ 1, # Set the upper limit as 1.
TRUE ~ b2s_ratio))
# //TASK ////////////////////////////////////////////////////////////////////////
# TASK ////////////////////////////////////////////////////////////////////////
# Plot interactive map(s)
# As long as you can deliver the message clearly, you can use any format/package you want.
walkable_edges <- edges_seg_output %>% filter(is_walkable == TRUE)
unwalkable_edges <- edges_seg_output %>% filter(is_walkable == FALSE)
# 3 Walkable maps
m1_walk <- leaflet(walkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("Blues", p_sidewalk)(p_sidewalk),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Sidewalk Proportion: ", round(p_sidewalk, 2))
) %>%
addLegend(pal = colorNumeric("Blues", walkable_edges$p_sidewalk),
values = ~p_sidewalk, title = "Sidewalk Proportion")
m2_walk <- leaflet(walkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("YlGn", p_greenness)(p_greenness),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Greenness Proportion: ", round(p_greenness, 2))
) %>%
addLegend(pal = colorNumeric("YlGn", walkable_edges$p_greenness),
values = ~p_greenness, title = "Greenness Proportion")
m3_walk <- leaflet(walkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("YlOrBr", b2s_ratio)(b2s_ratio),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Building-to-Street Ratio: ", round(b2s_ratio, 2))
) %>%
addLegend(pal = colorNumeric("YlOrBr", walkable_edges$b2s_ratio),
values = ~b2s_ratio, title = "Building–to-Street Ratio")
# 3 Unwalkable maps
m1_unwalk <- leaflet(unwalkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("Blues", p_sidewalk)(p_sidewalk),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Sidewalk Proportion: ", round(p_sidewalk, 2))
) %>%
addLegend(pal = colorNumeric("Blues", unwalkable_edges$p_sidewalk),
values = ~p_sidewalk, title = "Sidewalk Proportion")
m2_unwalk <- leaflet(unwalkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("YlGn", p_greenness)(p_greenness),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Greenness Proportion: ", round(p_greenness, 2))
) %>%
addLegend(pal = colorNumeric("YlGn", unwalkable_edges$p_greenness),
values = ~p_greenness, title = "Greenness Proportion")
m3_unwalk <- leaflet(unwalkable_edges) %>%
addProviderTiles("CartoDB.Positron") %>%
addCircleMarkers(
color = ~colorNumeric("YlOrBr", b2s_ratio)(b2s_ratio),
radius = 3,
opacity = 0.9,
fillOpacity = 0.8,
label = ~paste0("Building-to-Street Ratio: ", round(b2s_ratio, 2))
) %>%
addLegend(pal = colorNumeric("YlOrBr", unwalkable_edges$b2s_ratio),
values = ~b2s_ratio, title = "Building–to-Street Ratio")
# //TASK //////////////////////////////////////////////////////////////////////
leafsync::sync(m1_walk, m1_unwalk)
From the interactive map comparing sidewalk proportion between Midtown and Buckhead, we can see that there are way more points due to more road segments within Midtown than Buckhead. Generally speaking, the points in Midtown have more darker colors, indicating more segments have higher sidewalk proportions.
leafsync::sync(m2_walk, m2_unwalk)
From the interactive map comparing greenness proportion between Midtown and Buckhead, we can see that majority of points in Buckhead have higher greenness, compared to Midtown.
leafsync::sync(m3_walk, m3_unwalk)
From the interactive map comparing building-to-street ratio between Midtown and Buckhead, we can see significantly higher ratio in Midtown compared to Buckhead, indicating that there is a denser environment in Midtown.
# TASK ////////////////////////////////////////////////////////////////////////
# Create boxplot(s) using ggplot2 package.
edges_seg_output$walkable <- if_else(edges_seg_output$is_walkable == TRUE, "walkable", "unwalkable")
# //TASK //////////////////////////////////////////////////////////////////////
ggplot(edges_seg_output, aes(x = walkable, y = p_building)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Building Proportion by Walkability",
x = NULL,
y = "Proportion of Building Pixels"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of building proportion, we can see that walkable tracts have higher proportions of building pixels, indicating that there are denser developments in Midtown.
ggplot(edges_seg_output, aes(x = walkable, y = p_sky)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Sky Proportion by Walkability",
x = NULL,
y = "Proportion of Sky Pixels"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of sky proportion, we can see that unwalkable tracts have higher proportions of sky pixels, indicating that there are less buildings and more open skies in Buckhead.
ggplot(edges_seg_output, aes(x = walkable, y = p_road)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Road Proportion by Walkability",
x = NULL,
y = "Proportion of Road Pixels"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of road proportion, we can see that walkable and unwalkable tracts have similar proportions of road pixels.
ggplot(edges_seg_output, aes(x = walkable, y = p_sidewalk)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Sidewalk Proportion by Walkability",
x = NULL,
y = "Proportion of Sidewalk Pixels"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of sidewalk proportion, we can see that walkable tracts have higher proportions of sidewalk pixels, indicating that there are more sidewalks in Midtown thus more pedestrian-friendly.
ggplot(edges_seg_output, aes(x = walkable, y = p_greenness)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Greenness Proportion by Walkability",
x = NULL,
y = "Proportion of Greenness Pixels"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of greenness proportion, we can see that unwalkable tracts have higher proportions of greenness, indicating that there are more vegetation along roads in Buckhead.
ggplot(edges_seg_output, aes(x = walkable, y = b2s_ratio)) +
geom_boxplot(outlier.shape = 21, alpha = 0.8, fill = "#b8b8b8") +
labs(
title = "Building-to-Street Ratio by Walkability",
x = NULL,
y = "Building-to-Street Ratio"
) +
theme_minimal(base_size = 12) +
theme(
legend.position = "none",
plot.title = element_text(face = "bold", hjust = 0.5)
)
From the boxplot of building-to-street ratio, we can see that walkable tracts have higher ratios, indicating that there are more buildings compared to streets and cars thus more pedestrian-oriented streets in Midtown.
# TASK ////////////////////////////////////////////////////////////////////////
# Perform t-tests and report both the differences in means and their statistical significance.
# As long as you can deliver the message clearly, you can use any format/package you want.
# Create df to store results
t_results <- data.frame(
variable = character(),
mean_walkable = numeric(),
mean_unwalkable = numeric(),
p_value = numeric(),
stringsAsFactors = FALSE
)
variables <- vars <- c("p_building", "p_sky", "p_road", "p_sidewalk", "p_greenness", "b2s_ratio")
# For loop to run t-tests for each variable
for (v in variables) {
# Run t-test for walkable vs unwalkable
ttest <- t.test(
edges_seg_output[[v]] ~ edges_seg_output$walkable
)
# Store results
t_results <- rbind(
t_results,
data.frame(
variable = v,
mean_walkable = round(mean(edges_seg_output[[v]][edges_seg_output$walkable == "walkable"], na.rm = TRUE),2),
mean_unwalkable = round(mean(edges_seg_output[[v]][edges_seg_output$walkable == "unwalkable"], na.rm = TRUE),2),
p_value = round(ttest$p.value,2)
)
)
}
t_results
## variable mean_walkable mean_unwalkable p_value
## 1 p_building 0.15 0.09 0.00
## 2 p_sky 0.16 0.18 0.03
## 3 p_road 0.36 0.37 0.36
## 4 p_sidewalk 0.04 0.03 0.04
## 5 p_greenness 0.24 0.30 0.01
## 6 b2s_ratio 0.36 0.21 0.00
# //TASK //////////////////////////////////////////////////////////////////////
T-test shows that there are statistically significant (p < 0.05) differences for proportion of building, sky, sidewalk, and greenness, and building-to-street ratio between walkable and unwalkable tracts.