This is a description and use of all the functions in the package.
The API returns everything in Dutch and therefore I have kept the responses in Dutch as well. The NS website does have a English translation which I will link to here: https://www.ns.nl/en/travel-information/ns-api.
First a description of how to set up your username and password and than a breakdown of all the functions.
Before you can use any of the functions you need a username and password To get that go to: https://www.ns.nl/ews-aanvraagformulier/
You will receive a confirmation email, and finally a username and password (that can’t be changed for some reason).
You need to add the username and password to your rsession for the nsapi package to work. Why? Good question! It is not smart to type your passwords in a R session, they will end up in your history file and will be available for everyone who searches your computer. You might think that this password and account is not that important and you might be right, but let’s do the right thing anyway.
A temporary way is to add them to your session with :
Sys.setenv(NSAPIACCOUNT = "probablyyouremail@email.com")
Sys.setenv(NSAPIPW = "yourpasswordgiveninplaintextoveremailwhydopeopledothisohgod")
At the end of your session (if you go to a new project, if you restart R or if you crash) the keys are removed from memory. Keep in mind that this DOES put your password in the history file and is therefore NOT recommended.
Go to your global .Renviron file (or make one) and add the keys
The file will open and you can add two entries:
NSAPIPW = yourpasswordgiveninplaintextoveremailwhydopeopledothisohgod
NSAPIACCOUNT = probablyyouremail@email.com
How do you know if you succeeded?
If you’d like to know when your train from Amsterdam to Groningen goes, use the travel_advise function with departure and arrival station.
library(nsapi)
ams_to_ut <- get_travel_advise(
fromStation = "Amsterdam Centraal",
toStation = "Utrecht Centraal",
#dateTime = , # I don't use it because I want to leave now!
departure = TRUE # I want to depart now
)
ams_to_ut[,1:5]
#> Melding AantalOverstappen GeplandeReisTijd ActueleReisTijd
#> 1 NA 0 0:27 0:27
#> 2 NA 0 0:26 0:26
#> 3 NA 0 0:27 0:27
#> 4 NA 0 0:26 0:26
#> 5 NA 0 0:27 0:27
#> 6 NA 0 0:26 0:26
#> 7 NA 0 0:27 0:27
#> 8 NA 0 0:26 0:26
#> 9 NA 0 0:27 0:27
#> VertrekVertraging
#> 1 <NA>
#> 2 <NA>
#> 3 <NA>
#> 4 <NA>
#> 5 <NA>
#> 6 <NA>
#> 7 <NA>
#> 8 <NA>
#> 9 <NA>
The function returns a data.frame with 4 advises before and 4 after the time you selected.
ams_to_ut[,6:8]
#> AankomstVertraging Optimaal GeplandeVertrekTijd
#> 1 <NA> FALSE 2018-08-10 20:55:00
#> 2 <NA> FALSE 2018-08-10 21:11:00
#> 3 <NA> FALSE 2018-08-10 21:25:00
#> 4 <NA> FALSE 2018-08-10 21:41:00
#> 5 <NA> TRUE 2018-08-10 21:55:00
#> 6 <NA> FALSE 2018-08-10 22:11:00
#> 7 <NA> FALSE 2018-08-10 22:25:00
#> 8 <NA> FALSE 2018-08-10 22:41:00
#> 9 <NA> FALSE 2018-08-10 22:55:00
The column Reisdeel is a nested data frame with a nested data frame called stops within.
str(ams_to_ut[1,13])
#> List of 1
#> $ :'data.frame': 1 obs. of 5 variables:
#> ..$ Vervoerder : chr "NS"
#> ..$ VervoerType: chr "Intercity"
#> ..$ RitNummer : chr "3077"
#> ..$ Status : chr "VOLGENS-PLAN"
#> ..$ Stops :List of 1
#> .. ..$ :'data.frame': 3 obs. of 4 variables:
#> .. .. ..$ Naam : chr [1:3] "Amsterdam Centraal" "Amsterdam Amstel" "Utrecht Centraal"
#> .. .. ..$ Tijd : POSIXct[1:3], format: "2018-08-10 20:55:00" ...
#> .. .. ..$ Spoor : chr [1:3] "5b" NA "19"
#> .. .. ..$ SpoorWijziging: chr [1:3] NA NA NA
#> - attr(*, "class")= chr "AsIs"
The API returns a lot of nested information, and as a consequence the data.frame is nested too.
Every row is thus an advise with arrival and departure times and travelparts, if you have to switch trains there will be more than 1 row in the ReisDeel column. For instance in the first row:
ams_to_ut$ReisDeel[[1]]
#> Vervoerder VervoerType RitNummer Status
#> 1 NS Intercity 3077 VOLGENS-PLAN
#> Stops
#> 1 Amsterdam Centraal, Amsterdam Amstel, Utrecht Centraal, 1533927300, 1533927780, 1533928920, 5b, NA, 19, NA, NA, NA
And every part of the trip has stops where the train stops:
Another endpoint of the API is a list of stations.
stations <- get_stationlist()
head(stations)
#> Code Type Namen Land UICCode Lat
#> 1 HT knooppuntIntercitystation list("De.... NL 8400319 51.69048
#> 2 HTO stoptreinstation list("Dn.... NL 8400320 51.70055
#> 3 HDE stoptreinstation list("'t.... NL 8400388 52.40917
#> 4 AHBF knooppuntIntercitystation list("Aa.... D 8015345 50.76780
#> 5 ATN stoptreinstation list("Aa.... NL 8400045 51.92133
#> 6 AC stoptreinstation list("Ab.... NL 8400047 52.27850
#> Lon Synoniemen
#> 1 5.293620 list("He....
#> 2 5.318333 list("He....
#> 3 5.893611 list("Ha....
#> 4 6.091499 NA
#> 5 6.578627 NA
#> 6 4.977000 NA
names(stations)
#> [1] "Code" "Type" "Namen" "Land" "UICCode"
#> [6] "Lat" "Lon" "Synoniemen"
This will return a data frame with all the stations in the NS API. There are not only Dutch stations, but also multiple Belgian, German, English, Austrian, French,Polish and other country stations. Every station has an international code, name, synonyms, geolocation (Lat, Lon), and type of station.
# code is not executed, I don't want to add these dependencies to the package
library(tidyverse)
library(ggrepel)
stations <-
get_stations() %>%
mutate(Naam = map_chr(Namen, ~.[["Kort"]][[1]]),
Label = ifelse(Type == "knooppuntIntercitystation", Naam,NA) ) %>%
as.tibble()
stations %>%
filter(Land == "NL") %>%
ggplot(aes(Lon, Lat, label = Label))+
geom_point(alpha = 1/3)+
geom_text_repel()+
coord_map()+
labs(
title = "Only Dutch Stations",
subtitle = "Major stations named",
caption = "Data: NS 2018 (Dutch National Railways)"
)
You can see the departure times of any station at this time by calling the departures()
function.
leiden_trains <- get_departures(station = "Leiden Lammenschans")
head(leiden_trains)
#> RitNummer VertrekTijd EindBestemming TreinSoort
#> 1 2018-08-10 21:57:00 Utrecht Centraal Intercity
#> 2 2018-08-10 22:02:00 Leiden Centraal Intercity
#> 3 2018-08-10 22:27:00 Utrecht Centraal Intercity
#> 4 2018-08-10 22:32:00 Leiden Centraal Intercity
#> 5 2018-08-10 22:57:00 Utrecht Centraal Intercity
#> 6 2018-08-10 23:02:00 Leiden Centraal Intercity
#> RouteTekst Vervoerder VertrekSpoor Spoorwijziging
#> 1 Alphen a/d Rijn 1
#> 2 <NA> 1
#> 3 Alphen a/d Rijn 1
#> 4 <NA> 1
#> 5 Alphen a/d Rijn 1
#> 6 <NA> 1
These 3 functions call out to find out about disruptions and engineering on the tracks for the current time, for the next 2 weeks or a specific station. Every call returns a dataframe with “id”, “Traject”, “Periode”, “Reden”, “Bericht”, “Advies”, and “Datum”.
Bericht is often a complete message with html markup:
<p>\n<b>Wanneer: vanaf zaterdag 26 mei </b><br/>\n<b>Oorzaak: aangepaste dienstregeling</b><br/>\n<b>Advies: U kunt gebruikmaken van de gewijzigde dienstregeling</b>\n<br/>Stoptreinen tussen Roosendaal en Antwerpen Centraal/Puurs rijden in een aangepaste dienstregeling; reizigers dienen in Essen (B) over te stappen op een andere trein\n<br/> plan uw reis in de Internationale Reisplanner\n<br/> <br/>\n <b>Extra reistijd: een kwartier tot een half uur</b><br/>\n</p>
Showing only columns Traject and Periode:
This call returns scheduled engineering work for the next 2 weeks.
example:
sched <- get_scheduled_engineering_work()
sched[2:4,c("Traject","Periode", "Advies")]
#> Traject
#> 2 Zwolle-Amersfoort
#> 3 Heerlen-Herzogenrath
#> 4 Oss-Wijchen
#> Periode
#> 2 vrijdag 10 tot en met zondag 12 augustus
#> 3 vrijdag 10 augustus vanaf 22.50 uur
#> 4 in de nacht van vrijdag 10 op zaterdag 11 augustus vanaf 00.20 uur
#> Advies
#> 2 Raadpleeg Internet
#> 3 Raadpleeg Internet
#> 4 Raadpleeg Internet
Showing only first 2 messages:
get_disruptions_station(station = "Rotterdam Centraal")$Bericht[1:2]
#> [1] "<p>\n<b>Wanneer: vanaf zaterdag 26 mei </b><br/>\n<b>Oorzaak: aangepaste dienstregeling</b><br/>\n<b>Advies: U kunt gebruikmaken van de gewijzigde dienstregeling</b>\n<br/>Stoptreinen tussen Roosendaal en Antwerpen Centraal/Puurs rijden in een aangepaste dienstregeling; reizigers dienen in Essen (B) over te stappen op een andere trein\n<br/> plan uw reis in de Internationale Reisplanner\n<br/> <br/>\n <b>Extra reistijd: een kwartier tot een half uur</b><br/>\n</p>"
#> [2] "<p>\n<b>Wanneer: vrijdag 10 tot en met zondag 12 augustus</b><br/>\n<b>Oorzaak: werkzaamheden</b><br/>\n<b>Advies: U kunt gebruikmaken van de omreisroute of de bussen</b>\n<br/>reis tussen Zwolle en Amersfoort via Deventer \n<br/> reis tussen Zwolle en Utrecht Centraal via Amsterdam Zuid of via Deventer\n<br/> reis tussen Zwolle en Rotterdam Centraal via Leiden Centraal of via Schiphol Airport met Intercity direct\n<br/> er rijden bussen tussen 't Harde en Amersfoort\n<br/> tussen Amersfoort Vathorst en Amersfoort is de dienstregeling aangepast\n<br/> <br/>\n <b>Extra reistijd: een kwartier tot drie kwartier</b><br/>\n</p>"