::p_load(sf, sfdep, magrittr, tidyverse, tmap, knitr, RColorBrewer, viridis, dplyr) pacman
Take Home Exercise 1 - Geospatial Analytics for Public Good
1 OVERVIEW
As urban transportation and infrastructure become digitized, the resulting data sets can be used as a framework for crafting patterns of movement in space and time. These large amounts of motion data collected may contain structures and patterns that provide useful information about the characteristics of the measured phenomena. The identification, analysis and comparison of these patterns will provide deeper insights into how people move and behave within cities. These understandings will potentially contribute to better urban management and provide useful information to private and public sector urban transport service providers to make informed decisions to gain a competitive advantage.
1.1 Objectives and Methods
Exploratory Spatial Data Analysis (ESDA) hold tremendous potential to address complex problems facing society. In this study, you are tasked to apply appropriate Local Indicators of Spatial Association (GLISA) and Emerging Hot Spot Analysis (EHSA) to undercover the spatial and spatio-temporal mobility patterns of public bus passengers in Singapore.
This study mainly uses three methods:
Geovisualization and Analysis
With reference to the time intervals provided in the table below, compute the passenger trips generated by origin at the hexagon level,
Peak hour period Bus tap on time Weekday morning peak 6am to 9am Weekday afternoon peak 5pm to 8pm Weekend/holiday morning peak 11am to 2pm Weekend/holiday evening peak 4pm to 7pm Display the geographical distribution of the passenger trips by using appropriate geovisualization methods,
Describe the spatial patterns revealed by the geovisualization (not more than 200 words per visual).
Local Indicators of Spatial Association (LISA) Analysis
Compute LISA of the passengers trips generate by origin at hexagon level.
Display the LISA maps of the passengers trips generate by origin at hexagon level. The maps should only display the significant (i.e. p-value < 0.05)
With reference to the analysis results, draw statistical conclusions (not more than 200 words per visual).
Emerging Hot Spot Analysis(EHSA)
With reference to the passenger trips by origin at the hexagon level for the four time intervals given above:
Perform Mann-Kendall Test by using the spatio-temporal local Gi* values,
Prepared EHSA maps of the Gi* values of the passenger trips by origin at the hexagon level. The maps should only display the significant (i.e. p-value < 0.05).
With reference to the EHSA maps and data visualization prepared, describe the spatial patterns reveled. (not more than 250 words per cluster).
1.2 Study Area
The focus of this study will be Singapore. Singapore’s public transport system is renowned for its efficient, clean, safe and timely services. The city has a comprehensive digital public transportation network that is optimized through advanced information technology and big data analytics to improve operational efficiency and passenger experience.
Singapore’s urban infrastructure, such as utilities and roads, is also highly digitalized, using sensors, the Internet of Things (IoT) and other advanced technologies to monitor and manage city operations. For example, through vehicles equipped with GPS and RFID, traffic flows and patterns can be tracked, which helps in real-time traffic management and planning.
These digitalization measures enable Singapore to make important progress in improving the efficiency of public services, promoting sustainable development and enhancing the quality of life of residents.
2 GETTING STARTED
2.1 Setting the Analytical Tools
The code chunk below installs and loads sf, sfdep, magrittr, tidyverse, tmap, knitr, RColorBrewer, viridis packages into R environment. pacman() is a R package management tool.
2.2 Importing Data
We will import the data as a first step before proceeding with data cleaning, data wrangling and data exploration for the following:
Passenger Volume
PassengerVolume is an aspatial data, we can import the data simply by using the read_csv function from tidyverse package and output it as a tibble dataframe called odbus
<- read_csv("data/aspatial/origin_destination_bus_202310.csv") odbus
Rows: 5694297 Columns: 7
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (5): YEAR_MONTH, DAY_TYPE, PT_TYPE, ORIGIN_PT_CODE, DESTINATION_PT_CODE
dbl (2): TIME_PER_HOUR, TOTAL_TRIPS
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Bus Stop Location
Bus Stop is a geospatial data in .shp file. We save it as a sf data frame called busstop using the st_read function of the sf package. The data is then geo-referenced to coordinates from the Singapore SVY21 coordinate system (EPSG: 3414)
<- st_read(dsn = "data/geospatial",
busstop layer = "BusStop") %>%
st_transform(crs=3414)
Reading layer `BusStop' from data source
`/Users/WangYuhui/Desktop/SMU/Special_Term/ISSS624-G1-Applied-Geospatial-Analytics/ISSS624/Take-Home_Exercise_1/data/geospatial'
using driver `ESRI Shapefile'
Simple feature collection with 5161 features and 3 fields
Geometry type: POINT
Dimension: XY
Bounding box: xmin: 3970.122 ymin: 26482.1 xmax: 48284.56 ymax: 52983.82
Projected CRS: SVY21
2.3 Data Wrangling
2.3.1 Passenger Volume
glimpse(odbus)
Rows: 5,694,297
Columns: 7
$ YEAR_MONTH <chr> "2023-10", "2023-10", "2023-10", "2023-10", "2023-…
$ DAY_TYPE <chr> "WEEKENDS/HOLIDAY", "WEEKDAY", "WEEKENDS/HOLIDAY",…
$ TIME_PER_HOUR <dbl> 16, 16, 14, 14, 17, 17, 17, 7, 14, 14, 10, 20, 20,…
$ PT_TYPE <chr> "BUS", "BUS", "BUS", "BUS", "BUS", "BUS", "BUS", "…
$ ORIGIN_PT_CODE <chr> "04168", "04168", "80119", "80119", "44069", "2028…
$ DESTINATION_PT_CODE <chr> "10051", "10051", "90079", "90079", "17229", "2014…
$ TOTAL_TRIPS <dbl> 3, 5, 3, 5, 4, 1, 24, 2, 1, 7, 3, 2, 5, 1, 1, 1, 1…
Since we plan to use the bus stop code as a unique identifier when joining with other datasets, change it to a factor data type.
$ORIGIN_PT_CODE <- as.factor(odbus$ORIGIN_PT_CODE)
odbus$DESTINATION_PT_CODE <- as.factor(odbus$DESTINATION_PT_CODE) odbus
Checking for Duplicates and Missing Data
<- odbus %>%
duplicate group_by_all() %>%
filter(n()>1) %>%
ungroup()
duplicate
# A tibble: 0 × 7
# ℹ 7 variables: YEAR_MONTH <chr>, DAY_TYPE <chr>, TIME_PER_HOUR <dbl>,
# PT_TYPE <chr>, ORIGIN_PT_CODE <fct>, DESTINATION_PT_CODE <fct>,
# TOTAL_TRIPS <dbl>
summary(odbus)
YEAR_MONTH DAY_TYPE TIME_PER_HOUR PT_TYPE
Length:5694297 Length:5694297 Min. : 0.00 Length:5694297
Class :character Class :character 1st Qu.:10.00 Class :character
Mode :character Mode :character Median :14.00 Mode :character
Mean :14.04
3rd Qu.:18.00
Max. :23.00
ORIGIN_PT_CODE DESTINATION_PT_CODE TOTAL_TRIPS
22009 : 17444 22009 : 17328 Min. : 1.00
84009 : 16842 84009 : 16808 1st Qu.: 2.00
52009 : 16734 52009 : 16253 Median : 4.00
75009 : 16610 75009 : 16143 Mean : 20.76
59009 : 14991 59009 : 15134 3rd Qu.: 12.00
46009 : 14642 46009 : 14167 Max. :36668.00
(Other):5597034 (Other):5598464
There is no missing data or duplicates.
2.4 Classify peak hours
According to the time interval specified in the task, calculate the passenger travel volume generated at the departure place. Passenger itineraries by origin are saved in 4 data frames according to their respective classifications, namely:
Weekday morning peak
Weekday afternoon peak
Weekend morning peak
Weekend evening peak
Save the processed data to a .rds data format file. Output files are saved in the rds subfolder. This is done to reduce load times and keep large raw files from being uploaded to GitHub.
Show the code
<- odbus %>%
weekday_morning_peak filter(DAY_TYPE == "WEEKDAY") %>%
filter(TIME_PER_HOUR >= 6 &
<= 9) %>%
TIME_PER_HOUR group_by(ORIGIN_PT_CODE) %>%
summarise(TRIPS = sum(TOTAL_TRIPS))
<- odbus %>%
weekday_afternoon_peak filter(DAY_TYPE == "WEEKDAY") %>%
filter(TIME_PER_HOUR >= 17 &
<= 20) %>%
TIME_PER_HOUR group_by(ORIGIN_PT_CODE) %>%
summarise(TRIPS = sum(TOTAL_TRIPS))
<- odbus %>%
weekend_morning_peak filter(DAY_TYPE == "WEEKENDS/HOLIDAY") %>%
filter(TIME_PER_HOUR >= 11 &
<= 14) %>%
TIME_PER_HOUR group_by(ORIGIN_PT_CODE) %>%
summarise(TRIPS = sum(TOTAL_TRIPS))
<- odbus %>%
weekend_evening_peak filter(DAY_TYPE == "WEEKENDS/HOLIDAY") %>%
filter(TIME_PER_HOUR >= 16 &
<= 19) %>%
TIME_PER_HOUR group_by(ORIGIN_PT_CODE) %>%
summarise(TRIPS = sum(TOTAL_TRIPS))
write_rds(weekday_morning_peak, "data/rds/weekday_morning_peak.rds")
<- read_rds("data/rds/weekday_morning_peak.rds")
weekday_morning_peak
write_rds(weekday_afternoon_peak, "data/rds/weekday_afternoon_peak.rds")
<- read_rds("data/rds/weekday_afternoon_peak.rds")
weekday_afternoon_peak
write_rds(weekend_morning_peak, "data/rds/weekend_morning_peak.rds")
<- read_rds("data/rds/weekend_morning_peak.rds")
weekend_morning_peak
write_rds(weekend_evening_peak, "data/rds/weekend_evening_peak.rds")
<- read_rds("data/rds/weekend_evening_peak.rds") weekend_evening_peak
2.5 Creating Hexagon Data
Create Hexagon Dataset from busstop
= st_make_grid(busstop, c(250, 250), what = "polygons", square = FALSE)
hexagon = st_sf(hexagon) %>%
hexagon_sf mutate(grid_id = 1:length(lengths(hexagon)))
Examine the Grid
$coll <- lengths(st_intersects(hexagon_sf, busstop))
hexagon_sfprint(n_distinct(hexagon_sf$grid_id))
[1] 22134
print(sum(hexagon_sf$coll == 0))
[1] 19003
summary(hexagon_sf$coll)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.0000 0.0000 0.2332 0.0000 5.0000
There are 22134 grids and 19003 grids with zero bus stops, a max of 5 bus stops per grid.
Delete hexagonal data with zero bus stops
= filter(hexagon_sf, coll > 0)
hexagon_sf write_rds(hexagon_sf, "data/rds/hexagon_sf.rds")
<- read_rds("data/rds/hexagon_sf.rds") hexagon_sf
2.6 Visualizing
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
= tm_shape(hexagon_sf) +
map_busstopcounts tm_fill(
col = "coll",
palette = c("grey",rev(viridis(6))),
breaks = c(0, 1, 2, 3, 4, 5),
title = "Number of Bus Stops",
id = "grid_id",
showNA = FALSE,
alpha = 1,
popup.vars = c(
"Number of collisions: " = "coll"
),popup.format = list(
coll = list(format = "f", digits = 0)
)+
) tm_borders(col = "black", lwd = 0.2)
map_busstopcounts
From the picture we can see:
There is no bus station in the central area, probably because there is a reservoir.
There are very few bus stops in the northwest, probably because there is a farm.
2.7 Combining the Data
Show the code
# Define a function to merge and summarize data
<- function(time_peak_data, busstop_hexagon, hexagon_sf) {
merge_and_summarize <- left_join(time_peak_data, busstop_hexagon, by = c("ORIGIN_PT_CODE" = "BUS_STOP_N")) %>%
join_list rename(ORIGIN_BS = ORIGIN_PT_CODE, ORIGIN_GRID = grid_id) %>%
group_by(ORIGIN_GRID) %>%
summarise(TOT_TRIPS = sum(TRIPS))
<- left_join(hexagon_sf, join_list, by = c("grid_id" = "ORIGIN_GRID"))
join_geometry return(join_geometry)
}
# List to store different time period data
<- list(
time_peaks
weekday_morning_peak,
weekday_afternoon_peak,
weekend_morning_peak,
weekend_evening_peak
)
# Merge bus stop and hexagonal grid
<- st_intersection(busstop, hexagon_sf) %>%
busstop_hexagon select(BUS_STOP_N, grid_id) %>%
st_drop_geometry
Warning: attribute variables are assumed to be spatially constant throughout
all geometries
Show the code
# Apply the function to each time period
<- lapply(time_peaks, function(data) merge_and_summarize(data, busstop_hexagon, hexagon_sf))
results
# Save the results in RDS format
<- c("weekday_morning_peak_join_geometry.rds",
file_names "weekday_afternoon_peak_join_geometry.rds",
"weekend_morning_peak_join_geometry.rds",
"weekend_evening_peak_join_geometry.rds")
for (i in seq_along(results)) {
write_rds(results[[i]], paste0("data/rds/", file_names[i]))
}
3. Exploratory Data Analysis (EDA)
3.1 Distribution of total trips and trips per bus stop
Show the code
<- "data/rds/"
rds_path <- readRDS(paste0(rds_path, "weekday_morning_peak_join_geometry.rds"))
weekday_morning_peak_join_geometry <- readRDS(paste0(rds_path, "weekday_afternoon_peak_join_geometry.rds"))
weekday_afternoon_peak_join_geometry <- readRDS(paste0(rds_path, "weekend_morning_peak_join_geometry.rds"))
weekend_morning_peak_join_geometry <- readRDS(paste0(rds_path, "weekend_evening_peak_join_geometry.rds"))
weekend_evening_peak_join_geometry
<- bind_rows(
combined_data %>% mutate(period = "Weekday Morning Peak"),
weekday_morning_peak_join_geometry %>% mutate(period = "Weekday Afternoon Peak"),
weekday_afternoon_peak_join_geometry %>% mutate(period = "Weekend Morning Peak"),
weekend_morning_peak_join_geometry %>% mutate(period = "Weekend Evening Peak")
weekend_evening_peak_join_geometry
)
# Plot combined data
ggplot(data = combined_data,
aes(x = as.numeric(`TOT_TRIPS`))) +
geom_histogram(bins = 20,
color = "blue",
fill = "blue") +
facet_wrap(~period, scales = "free_y") +
labs(title = "Distribution of Passenger Trips during Different Time Periods",
x = "Total Trips",
y = "Frequency")
Warning: Removed 337 rows containing non-finite values (`stat_bin()`).
Show the code
library(ggplot2)
<- combined_data %>%
combined_dsitribution mutate(`trips_per_busstop` = (`TOT_TRIPS` / coll))
ggplot(data = combined_dsitribution, aes(x = as.numeric(`trips_per_busstop`))) +
geom_histogram(bins = 20, color = "blue", fill = "blue") +
facet_wrap(~period, scales = "free_y") +
labs(title = "Distribution of Passenger Trips during Different Time Periods",
x = "Total Trips Per BusStop",
y = "Frequency") +
theme_minimal()
Warning: Removed 337 rows containing non-finite values (`stat_bin()`).
3.2 Distribution Across 4 Time Periods
Show the code
ggplot(combined_data, aes(x = factor(period), y = TOT_TRIPS)) +
geom_bar(stat = "identity", position = "dodge", fill = "blue") +
labs(title = "Distribution Across 4 Time Periods",
x = "Time Period",
y = "Total Trips") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "none")
Warning: Removed 337 rows containing missing values (`geom_bar()`).
Through the above analysis, it is found that the number of trips during the morning peak on weekdays is the largest, followed by the afternoon peak on weekdays, the morning peak on weekends, and finally the evening peak on weekends.
Public transportation authorities can use this information to better allocate personnel and public transportation resources.
4. Geovisualization and Analysis
Quantile classification proved to provide little value due to the use of hexagonal tiles and the right-skewed distribution of the data. kmeans classification effect is better.
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tmap_options(check.and.fix = TRUE)
<- function(data, title) {
create_tmap tm_shape(data) +
tm_fill("TOT_TRIPS",
style = "kmeans",
palette = c("grey", rev(viridis(6))),
title = "Passenger trips") +
tm_layout(main.title = title,
main.title.position = "center",
main.title.size = 1.2) +
tm_borders(alpha = 0.5) +
tm_scale_bar() +
tm_grid(alpha = 0.2) +
tmap_style("white")
}
<- list(
maps create_tmap(weekday_morning_peak_join_geometry, "Passenger trips during Weekday morning peak"),
create_tmap(weekday_afternoon_peak_join_geometry, "Passenger trips during Weekday afternoon peak"),
create_tmap(weekend_morning_peak_join_geometry, "Passenger trips during Weekend morning peak"),
create_tmap(weekend_evening_peak_join_geometry, "Passenger trips during Weekend evening peak")
)
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
maps
[[1]]
[[2]]
[[3]]
[[4]]
5. Local Indicators of Spatial Association (LISA) Analysis
5.1 Calculating adaptive distance weights
Because the minimum, median, mean, and 75th percentile are all 250 . Therefore we set k=1 when generating weights.
<- sf::st_geometry(hexagon_sf)
geo <- st_knn(geo, longlat = TRUE) neighbour
! Polygon provided. Using point on surface.
<- unlist(st_nb_dists(geo, neighbour)) dists
! Polygon provided. Using point on surface.
summary(dists)
Min. 1st Qu. Median Mean 3rd Qu. Max.
250.0 250.0 250.0 259.6 250.0 4250.0
Show the code
<- function(data, hexagon) {
process_data %>%
data mutate(TOT_TRIPS = replace_na(TOT_TRIPS, 0),
neighbour = st_knn(hexagon, k = 1),
wt = st_weights(neighbour, style = "W", allow_zero = TRUE),
.before = 1)
}<- process_data(weekday_morning_peak_join_geometry, hexagon) wm_q_1
! Polygon provided. Using point on surface.
Show the code
<- process_data(weekday_afternoon_peak_join_geometry, hexagon) wm_q_2
! Polygon provided. Using point on surface.
Show the code
<- process_data(weekend_morning_peak_join_geometry, hexagon) wm_q_3
! Polygon provided. Using point on surface.
Show the code
<- process_data(weekend_evening_peak_join_geometry, hexagon) wm_q_4
! Polygon provided. Using point on surface.
5.2 Calculating local Moran’s I space autocorrelation statistics
The analysis focuses on the spatial autocorrelation of the variable TOT_TRIPS in each dataset, using the local_moran function for 99 simulations.
Moran’s I spatial autocorrelation statistic is calculated to evaluate whether nearby observations exhibit similar total travel values, revealing spatial patterns and clustering.
Show the code
<- function(df) {
compute_local_moran_I %>%
df mutate(local_moran = local_moran(TOT_TRIPS, neighbour, wt, nsim = 99), .before = 1) %>%
unnest(local_moran)
}
# List of data frames
<- list(wm_q_1, wm_q_2, wm_q_3, wm_q_4)
wm_qs
# Apply the function to each data frame
<- lapply(wm_qs, compute_local_moran_I)
lisa_results
<- lisa_results[[1]]
lisa_1 <- lisa_results[[2]]
lisa_2 <- lisa_results[[3]]
lisa_3 <- lisa_results[[4]] lisa_4
5.3 visualizing
In the following code chunk, a partitioned chart is created based on local Moran’s I values. Positive Local Moran’s I values indicate a feature’s membership in a cluster, while negative values indicate that the feature is an outlier. Areas in various shades of green indicate their membership in one or more clusters.
However, relying solely on the local Moran score is not sufficient to describe spatial clustering, as it cannot provide information about whether the total number of passengers’ trips is high or low and whether the test results are statistically significant. We need to continue analyzing only areas where total passenger trips have statistically significant values.
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_fill("ii",
style = "kmeans",
palette = viridis(6)) +
tm_borders(alpha = 0.5) +
tm_layout(main.title = "local Moran I of Bus Trips in weekday morning",
main.title.size = 1.2, main.title.position = "center") +
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_2) +
tm_fill("ii",
style = "kmeans",
palette = viridis(6)) +
tm_borders(alpha = 0.5) +
tm_layout(main.title = "local Moran I of Bus Trips in weekday afternoon",
main.title.size = 1.2, main.title.position = "center") +
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_3) +
tm_fill("ii",
style = "kmeans",
palette = viridis(6)) +
tm_borders(alpha = 0.5) +
tm_layout(main.title = "local Moran I of Bus Trips in weekend morning",
main.title.size = 1.2, main.title.position = "center") +
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_4) +
tm_fill("ii",
style = "kmeans",
palette = viridis(6)) +
tm_borders(alpha = 0.5) +
tm_layout(main.title = "local Moran I of Bus Trips in weekend afternoon",
main.title.size = 1.2, main.title.position = "center") +
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
5.4 visualizing p-value of local Moran’s I
In the following code chunk below, only statistically significant local Moran’s I values (p_ii_sim < 0.05) are visualized.
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_fill("p_ii_sim",
palette = c(rev(viridis(6)), "white"),
breaks = c(0, 0.001, 0.01, 0.05, 1),
labels = c("0.001", "0.01", "0.05", "NA")) +
tm_borders(alpha = 0.2) +
tm_layout(main.title = "p-value of local Moran I in weekday morning",
main.title.size = 1.2,
main.title.position = "center" ) +
tmap_style("natural")
tmap style set to "natural"
other available styles are: "white", "gray", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_2) +
tm_fill("p_ii_sim",
palette = c(rev(viridis(6)), "white"),
breaks = c(0, 0.001, 0.01, 0.05, 1),
labels = c("0.001", "0.01", "0.05", "NA")) +
tm_borders(alpha = 0.2) +
tm_layout(main.title = "p-value of local Moran I in weekday afternoon",
main.title.size = 1.2,
main.title.position = "center") +
tmap_style("natural")
tmap style set to "natural"
other available styles are: "white", "gray", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_3) +
tm_fill("p_ii_sim",
palette = c(rev(viridis(6)), "white"),
breaks = c(0, 0.001, 0.01, 0.05, 1),
labels = c("0.001", "0.01", "0.05", "NA")) +
tm_borders(alpha = 0.2) +
tm_layout(main.title = "p-value of local Moran I in weekend morning",
main.title.size = 1.2,
main.title.position = "center") +
tmap_style("natural")
tmap style set to "natural"
other available styles are: "white", "gray", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_4) +
tm_fill("p_ii_sim",
palette = c(rev(viridis(6)), "white"),
breaks = c(0, 0.001, 0.01, 0.05, 1),
labels = c("0.001", "0.01", "0.05", "NA")) +
tm_borders(alpha = 0.2) +
tm_layout(main.title = "p-value of local Moran I in weekend afternoon",
main.title.size = 1.2,
main.title.position = "center") +
tmap_style("natural")
tmap style set to "natural"
other available styles are: "white", "gray", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
5.5 Visualizing LISA map
In the following code chunk, LISA divides each region into four groups:
High - High means that a grid with a high number of initial trips is next to other grids with a high number of initial trips.
High-Low means grids with more initial trips are next to other grids with fewer initial trips
Low - Low means that a grid with a low number of initial strokes is next to other grids with a low number of initial strokes
Low-High means that grids with fewer initial trips are located next to other grids with more initial trips.
5.5.1 Weekday morning peak
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
<- lisa_1 %>%
lisa_sig filter(p_ii_sim < 0.05)
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_polygons() +
tm_borders(alpha = 0) +
tm_shape(lisa_sig) +
tm_fill("median",
palette = c(viridis(4))) +
tm_borders(alpha = 0)+
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Warning: One tm layer group has duplicated layer types, which are omitted. To
draw multiple layers of the same type, use multiple layer groups (i.e. specify
tm_shape prior to each of them).
5.5.2 Weekday afternoon peak
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
<- lisa_2 %>%
lisa_sig filter(p_ii_sim < 0.05)
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_polygons() +
tm_borders(alpha = 0) +
tm_shape(lisa_sig) +
tm_fill("median",
palette = c(viridis(4))) +
tm_borders(alpha = 0)+
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Warning: One tm layer group has duplicated layer types, which are omitted. To
draw multiple layers of the same type, use multiple layer groups (i.e. specify
tm_shape prior to each of them).
5.5.3 Weekend morning peak
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
<- lisa_3 %>%
lisa_sig filter(p_ii_sim < 0.05)
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_polygons() +
tm_borders(alpha = 0) +
tm_shape(lisa_sig) +
tm_fill("median",
palette = c(viridis(4))) +
tm_borders(alpha = 0)+
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Warning: One tm layer group has duplicated layer types, which are omitted. To
draw multiple layers of the same type, use multiple layer groups (i.e. specify
tm_shape prior to each of them).
5.5.4 Weekend afternoon peak
Show the code
tmap_mode("plot")
tmap mode set to plotting
Show the code
<- lisa_4 %>%
lisa_sig filter(p_ii_sim < 0.05)
tmap_mode("plot")
tmap mode set to plotting
Show the code
tm_shape(lisa_1) +
tm_polygons() +
tm_borders(alpha = 0) +
tm_shape(lisa_sig) +
tm_fill("median",
palette = c(viridis(4))) +
tm_borders(alpha = 0)+
tmap_style("white")
tmap style set to "white"
other available styles are: "gray", "natural", "cobalt", "col_blind", "albatross", "beaver", "bw", "classic", "watercolor"
Warning: One tm layer group has duplicated layer types, which are omitted. To
draw multiple layers of the same type, use multiple layer groups (i.e. specify
tm_shape prior to each of them).
5.6 Conclusion
High-High: In these areas, places with high travel demand are often close to each other, forming obvious travel hotspots. These hotspots may correspond to business centers, residential areas, or other places where activity is concentrated.
Low-Low: Areas with low travel demand are relatively scattered and do not form large continuous low-demand areas. These may be more remote or inaccessible areas.
High-Low: Represents areas adjacent to high travel areas but with low travel demand. This can happen at the edges of busy areas, or in areas where travel demand has dropped for specific reasons, such as transport planning or geographical constraints.
Low-High: Indicates that although some areas have low travel demand, they are close to areas with concentrated travel demand. This may be due to superior geographical location but underdevelopment.
As can be seen from the four pictures above, the High-Low and Low-High areas are mainly located in the northeast and south-central part, indicating that there is still room for improvement in the public transportation planning of these two areas.