Prepare the data
Your data should look like this:
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.2.1 ✔ readr 2.2.0
## ✔ forcats 1.0.1 ✔ stringr 1.6.0
## ✔ ggplot2 4.0.3 ✔ tibble 3.3.1
## ✔ lubridate 1.9.5 ✔ tidyr 1.3.2
## ✔ purrr 1.2.2
## ── 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
od <- tribble(
~Origin, ~Destination, ~Volume,
"Olopi", "Kilgoris", 1320,
"Olopi", "Kehancha", 2845,
"Kilgoris", "Olopi", 1180,
"Kilgoris", "Kehancha", 2010,
"Kehancha", "Olopi", 2560,
"Kehancha", "Kilgoris", 1715
)
od_matrix <- od %>%
pivot_wider(
names_from = Destination,
values_from = Volume,
values_fill = 0
)
od_matrix
## # A tibble: 3 × 4
## Origin Kilgoris Kehancha Olopi
## <chr> <dbl> <dbl> <dbl>
## 1 Olopi 1320 2845 0
## 2 Kilgoris 0 2010 1180
## 3 Kehancha 1715 0 2560
origin_summary <- od %>%
group_by(Origin) %>%
summarise(
Total_Outbound = sum(Volume)
)
origin_summary
## # A tibble: 3 × 2
## Origin Total_Outbound
## <chr> <dbl>
## 1 Kehancha 4275
## 2 Kilgoris 3190
## 3 Olopi 4165
destination_summary <- od %>%
group_by(Destination) %>%
summarise(
Total_Inbound = sum(Volume)
)
destination_summary
## # A tibble: 3 × 2
## Destination Total_Inbound
## <chr> <dbl>
## 1 Kehancha 4855
## 2 Kilgoris 3035
## 3 Olopi 3740
od_summary <- od %>%
summarise(
Total_Trips = sum(Volume),
Mean_Flow = mean(Volume),
Maximum_Flow = max(Volume),
Minimum_Flow = min(Volume)
)
od_summary
## # A tibble: 1 × 4
## Total_Trips Mean_Flow Maximum_Flow Minimum_Flow
## <dbl> <dbl> <dbl> <dbl>
## 1 11630 1938. 2845 1180
balance <- full_join(
origin_summary,
destination_summary,
by = c("Origin" = "Destination")
) %>%
mutate(
Net_Flow = Total_Outbound - Total_Inbound
)
balance
## # A tibble: 3 × 4
## Origin Total_Outbound Total_Inbound Net_Flow
## <chr> <dbl> <dbl> <dbl>
## 1 Kehancha 4275 4855 -580
## 2 Kilgoris 3190 3035 155
## 3 Olopi 4165 3740 425
Positive values indicate a net producer of trips, while negative values indicate a net attractor.
pairs <- od %>%
mutate(
Pair = map2_chr(
Origin,
Destination,
~paste(sort(c(.x, .y)), collapse = " - ")
)
) %>%
group_by(Pair) %>%
summarise(
Direction1 = first(Volume),
Direction2 = last(Volume),
Difference = abs(Direction1 - Direction2),
Ratio = round(min(Direction1, Direction2) /
max(Direction1, Direction2), 2),
.groups = "drop"
)
pairs
## # A tibble: 3 × 5
## Pair Direction1 Direction2 Difference Ratio
## <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Kehancha - Kilgoris 2010 1715 295 0.85
## 2 Kehancha - Olopi 2845 2560 285 0.9
## 3 Kilgoris - Olopi 1320 1180 140 0.89
A ratio close to 1.00 indicates well-balanced traffic between the two directions
ggplot(od,
aes(Destination,
Origin,
fill = Volume)) +
geom_tile(color = "white") +
geom_text(aes(label = Volume),
color = "black",
size = 5) +
scale_fill_gradient(low = "white",
high = "steelblue") +
labs(title = "Origin-Destination Matrix") +
theme_minimal()
library(openxlsx)
write.xlsx(
list(
"OD Matrix" = od_matrix,
"Origin Totals" = origin_summary,
"Destination Totals" = destination_summary,
"Overall Summary" = od_summary,
"Balance" = balance,
"Opposite Directions" = pairs
),
"OD_Analysis.xlsx",
overwrite = TRUE
)