spanishoddata is an R package that provides functions for downloading and formatting Spanish open mobility data released by the Ministry of Transport and Sustainable Mobility of Spain (Secretaría de Estado de Transportes y Movilidad Sostenible 2024).
It supports the two versions of the Spanish mobility data that consists of origin-destination matrices and some additional data sets. The first version covers data from 2020 and 2021, including the period of the COVID-19 pandemic. The second version contains data from January 2022 onwards and is updated monthly on the fifteenth of each month. Both versions of the data primarily consist of mobile phone positioning data, and include matrices for overnight stays, individual movements, and trips of Spanish residents at different geographical levels. See the package website and vignettes for v1 and v2 data for more details.
spanishoddata is designed to save people time by providing the data in analysis-ready formats. Automating the process of downloading, cleaning, and importing the data can also reduce the risk of errors in the laborious process of data preparation. It also reduces computational resources by using computationally efficient packages behind the scenes. To effectively work with multiple data files, it’s recommended you set up a data directory where the package can search for the data and download only the files that are not already present.
To create static maps like that see our vignette here.
Figure 3: Example of the data available through the package: interactive daily flows in Barcelona with time filter
To create interactive maps see our vignette here.
The package is not yet available on CRAN.
You can install the latest version of the package from rOpenSpain R universe:
install.packages("spanishoddata",
repos = c("https://ropenspain.r-universe.dev",
"https://cloud.r-project.org"))
Alternative installation and developemnt
Alternative way to install the package from GitHub:
if (!require("remotes")) install.packages("remotes")
remotes::install_github("rOpenSpain/spanishoddata",
force = TRUE, dependencies = TRUE)
For Developers
To load the package locally, clone it and navigate to the root of the package in the terminal, e.g. with the following:
gh repo clone rOpenSpain/spanishoddata
code spanishoddata
# with rstudio:
rstudio spanishoddata/spanishoddata.Rproj
Then run the following command from the R console:
devtools::load_all()
Load it as follows:
library(spanishoddata)
Choose where {spanishoddata}
should download (and convert) the data by
setting the data directory following command:
spod_set_data_dir(data_dir = "~/spanish_od_data")
The function above will also ensure that the directory is created and that you have sufficient permissions to write to it.
Setting data directory for advanced users
You can also set the data directory with an environment variable:
Sys.setenv(SPANISH_OD_DATA_DIR = "~/spanish_od_data")
The package will create this directory if it does not exist on the first run of any function that downloads the data.
To permanently set the directory for all projects, you can specify the
data directory globally by setting the SPANISH_OD_DATA_DIR
environment
variable, e.g. with the following command:
usethis::edit_r_environ()
# Then set the data directory globally, by typing this line in the file:
SPANISH_OD_DATA_DIR = "~/spanish_od_data"
You can also set the data directory locally, just for the current
project. Set the ‘envar’ in the working directory by editing .Renviron
file in the root of the project:
file.edit(".Renviron")
If you only want to analyse the data for a few days, you can use the
spod_get()
function. It will download the raw data in CSV format and
let you analyse it in-memory. This is what we cover in the steps on this
page.
If you need longer periods (several months or years), you should use the
spod_convert()
and spod_connect()
functions, which will convert the
data into special format which is much faster for analysis, for this see
the Download and convert OD datasets vignette.
spod_get_zones()
will give you spatial data with zones that can be
matched with the origin-destination flows from the functions above using
zones ’id’s. Please see a simple example below, and also consult the
vignettes with detailed data description and instructions in the package
vignettes with spod_codebook(ver = 1)
and spod_codebook(ver = 2)
, or
simply visit the package website at
https://ropenspain.github.io/spanishoddata/. The
Figure 4 presents
the overall approach to accessing the data in the spanishoddata
package.
To run the code in this README we will use the following setup:
library(tidyverse)
theme_set(theme_minimal())
sf::sf_use_s2(FALSE)
Get metadata for the datasets as follows (we are using version 2 data covering years 2022 and onwards):
metadata <- spod_available_data(ver = 2) # for version 2 of the data
metadata
# A tibble: 9,442 × 6
target_url pub_ts file_extension data_ym data_ymd
<chr> <dttm> <chr> <date> <date>
1 https://movilidad-o… 2024-07-30 10:54:08 gz NA 2022-10-23
2 https://movilidad-o… 2024-07-30 10:51:07 gz NA 2022-10-22
3 https://movilidad-o… 2024-07-30 10:47:52 gz NA 2022-10-20
4 https://movilidad-o… 2024-07-30 10:14:55 gz NA 2022-10-18
5 https://movilidad-o… 2024-07-30 10:11:58 gz NA 2022-10-17
6 https://movilidad-o… 2024-07-30 10:09:03 gz NA 2022-10-12
7 https://movilidad-o… 2024-07-30 10:05:57 gz NA 2022-10-07
8 https://movilidad-o… 2024-07-30 10:02:12 gz NA 2022-08-07
9 https://movilidad-o… 2024-07-30 09:58:34 gz NA 2022-08-06
10 https://movilidad-o… 2024-07-30 09:54:30 gz NA 2022-08-05
# ℹ 9,432 more rows
# ℹ 1 more variable: local_path <chr>
Zones can be downloaded as follows:
distritos <- spod_get_zones("distritos", ver = 2)
distritos_wgs84 <- distritos |>
sf::st_simplify(dTolerance = 200) |>
sf::st_transform(4326)
plot(sf::st_geometry(distritos_wgs84))
od_db <- spod_get(
type = "origin-destination",
zones = "districts",
dates = c(start = "2024-03-01", end = "2024-03-07")
)
class(od_db)
[1] "tbl_duckdb_connection" "tbl_dbi" "tbl_sql"
[4] "tbl_lazy" "tbl"
colnames(od_db)
[1] "full_date" "time_slot"
[3] "id_origin" "id_destination"
[5] "distance" "activity_origin"
[7] "activity_destination" "study_possible_origin"
[9] "study_possible_destination" "residence_province_ine_code"
[11] "residence_province" "income"
[13] "age" "sex"
[15] "n_trips" "trips_total_length_km"
[17] "year" "month"
[19] "day"
The result is an R database interface object (tbl_dbi
) that can be
used with dplyr functions and SQL queries ‘lazily’, meaning that the
data is not loaded into memory until it is needed. Let’s do an
aggregation to find the total number trips per hour over the 7 days:
n_per_hour <- od_db |>
group_by(date, time_slot) |>
summarise(n = n(), Trips = sum(n_trips)) |>
collect() |>
mutate(Time = lubridate::ymd_h(paste0(date, time_slot, sep = " "))) |>
mutate(Day = lubridate::wday(Time, label = TRUE))
n_per_hour |>
ggplot(aes(x = Time, y = Trips)) +
geom_line(aes(colour = Day)) +
labs(title = "Number of trips per hour over 7 days")
The figure above summarises 925,874,012 trips over the 7 days associated with 135,866,524 records.
As we demonstrated above, you can perform very quick analysis using just a few lines of code.
To highlight the benefits of the package, here is how you would do this manually:
-
download the xml file with the download links
-
parse this xml to extract the download links
-
write a script to download the files and locate them on disk in a logical manner
-
figure out the data structure of the downloaded files, read the codebook
-
translate the data (columns and values) into English, if you are not familiar with Spanish
-
write a script to load the data into the database or figure out a way to claculate summaries on multiple files
-
and much more…
We did all of that for you and present you with a few simple functions that get you straight to the data in one line of code, and you are ready to run any analysis on it.
We’ll use the same input data to pick-out the most important flows in Spain, with a focus on longer trips for visualisation:
od_national_aggregated <- od_db |>
group_by(id_origin, id_destination) |>
summarise(Trips = sum(n_trips), .groups = "drop") |>
filter(Trips > 500) |>
collect() |>
arrange(desc(Trips))
od_national_aggregated
# A tibble: 96,404 × 3
id_origin id_destination Trips
<fct> <fct> <dbl>
1 2807908 2807908 2441404.
2 0801910 0801910 2112188.
3 0801902 0801902 2013618.
4 2807916 2807916 1821504.
5 2807911 2807911 1785981.
6 04902 04902 1690606.
7 2807913 2807913 1504484.
8 2807910 2807910 1299586.
9 0704004 0704004 1287122.
10 28106 28106 1286058.
# ℹ 96,394 more rows
The results show that the largest flows are intra-zonal. Let’s keep only the inter-zonal flows:
od_national_interzonal <- od_national_aggregated |>
filter(id_origin != id_destination)
We can convert these to geographic data with the {od} package (Lovelace and Morgan 2024):
od_national_sf <- od::od_to_sf(
od_national_interzonal,
z = distritos_wgs84
)
distritos_wgs84 |>
ggplot() +
geom_sf(aes(fill = population)) +
geom_sf(data = spData::world, fill = NA, colour = "black") +
geom_sf(aes(size = Trips), colour = "blue", data = od_national_sf) +
coord_sf(xlim = c(-10, 5), ylim = c(35, 45)) +
theme_void()
Let’s focus on trips in and around a particular area (Salamanca):
salamanca_zones <- zonebuilder::zb_zone("Salamanca")
distritos_salamanca <- distritos_wgs84[salamanca_zones, ]
plot(distritos_salamanca)
We will use this information to subset the rows, to capture all movement within the study area:
ids_salamanca <- distritos_salamanca$id
od_salamanca <- od_national_sf |>
filter(id_origin %in% ids_salamanca) |>
filter(id_destination %in% ids_salamanca) |>
arrange(Trips)
Let’s plot the results:
od_salamanca_sf <- od::od_to_sf(
od_salamanca,
z = distritos_salamanca
)
ggplot() +
geom_sf(fill = "grey", data = distritos_salamanca) +
geom_sf(aes(colour = Trips), size = 1, data = od_salamanca_sf) +
scale_colour_viridis_c() +
theme_void()
For more information on the package, see:
- The pkgdown site
- Information on the functions
- v1 data (2020-2021) codebook
- v2 data (2022 onwards) codebook (work in progress)
- Download and convert data
- The OD disaggregation vignette showcases flows disaggregation
- Making static
flowmaps
vignette shows how to create flowmaps using the data acquired with
{spanishoddata}
- Making interactive
flowmaps
shows how to create an interactive flowmap using the data acquired
with
{spanishoddata}
Lovelace, Robin, and Malcolm Morgan. 2024. “Od: Manipulate and Map Origin-Destination Data,” August. https://cran.r-project.org/web/packages/od/od.pdf.
Secretaría de Estado de Transportes y Movilidad Sostenible. 2024. “Estudio de movilidad de viajeros de ámbito nacional aplicando la tecnología Big Data. Informe metodológico (Study of National Traveler mobility Using Big Data Technology. Methodological Report).” https://www.transportes.gob.es/ministerio/proyectos-singulares/estudio-de-movilidad-con-big-data.