Hey folks,
I was recently asked how to visualize flight connections with R, so I decided to make a blog post with a short tutorial on this topic: The aim is to map all possible flight connections from the NYC JFK Airport to other major airports in the US. For this we will be using the following packages:
nycflights13:
Dataset with flights departing from NYC in 2013.dplyr:
package for manipulating datasets.maps:
package for mapping.geosphere:
package for spherical trigonometry.
Make sure to install and load these beforehand using the install.packages()
and library()
functions.
Data:
Lets get a quick overview on the dataset first. Once you loaded the package nycflights13
you have access to the dataset airports
:
library(nycflights13) airports Source: local data frame [1,397 x 7] faa name lat lon alt tz dst 1 04G Lansdowne Airport 41.13047 -80.61958 1044 -5 A 2 06A Moton Field Municipal Airport 32.46057 -85.68003 264 -5 A 3 06C Schaumburg Regional 41.98934 -88.10124 801 -6 A 4 06N Randall Airport 41.43191 -74.39156 523 -5 A 5 09J Jekyll Island Airport 31.07447 -81.42778 11 -4 A 6 0A9 Elizabethton Municipal Airport 36.37122 -82.17342 1593 -4 A 7 0G6 Williams County Airport 41.46731 -84.50678 730 -5 A 8 0G7 Finger Lakes Regional Airport 42.88356 -76.78123 492 -5 A 9 0P2 Shoestring Aviation Airfield 39.79482 -76.64719 1000 -5 U 10 0S9 Jefferson County Intl 48.05381 -122.81064 108 -8 A .. ... ... ... ... ... .. ...
The dataset contains useful metadata on airports. For our map however we only want airports that are located in the US. Therefore we will make a couple of data filtering steps using the dplyr
package. We will select only those airports which have a latitude < 48.5 and a longitude > -130. Then we will exclude the JFK airport from this dataset and create a new dataframe just containing the JFK airport:
usairports <- filter(airports, lat < 48.5) usairports <- filter(usairports, lon > -130) usairports <- filter(usairports, faa!="JFK") #filter out jfk jfk <- filter(airports, faa=="JFK") #separate df for jfk
Create flight connection map:
The data is now prepared for our final flight connection map. The first step will be to create a basemap for the US using the maps
package:
#create basemap map("world", regions=c("usa"), fill=T, col="grey8", bg="grey15", ylim=c(21.0,50.0), xlim=c(-130.0,-65.0)) #overlay airports points(usairports$lon,usairports$lat, pch=3, cex=0.1, col="chocolate1")
The map should now look like this:
The next and final step is to add the flight connectins from NYC to all other airports using the gesophere
package and the gcIntermediate()
function.
for (i in (1:dim(usairports)[1])) { inter <- gcIntermediate(c(jfk$lon[1], jfk$lat[1]), c(usairports$lon[i], usairports$lat[i]), n=200) lines(inter, lwd=0.1, col="turquoise2") }
The gcIntermediate()
function takes two points and creates a circular connection between them. With the lines()
function you add this circle to the plot. In this example this is done for all airports in the dataframe with a for loop. The final map can be seen below:
Enjoy the final result! If you have any questions related to dplyr or the gesophere package, feel free to ask.
Cheers
Martin
17 Comments
You can post comments in this post.
Wow, that’s a pretty nice visual result with just a couple lines of code. Can you also load rasters using one of those modules?
Kuba Konczyk 9 years ago
You can plot raster images with the package called “raster”. First you have to load your raster into R and then you can plot it with the
plot()
function. If you want to overlay points or lines, you have to be carful that both coordinate systems match. You can find a basic introduction into the raster package here: R {raster}: Introduction and basic plottingMartin 9 years ago
Thanks Martin, I’ll check it out 🙂
Kuba Konczyk 9 years ago
Thanks for such a great and succinct post on this! I came across your blog from the question in stackoverflow. Love the colors in your visualization as well.
Nistara Randhawa 8 years ago
Thanks for the positive feedback.
Martin 8 years ago
Hey Martin!
Great job on the visualization, it looks awesome!
How did you manage to create such thin lines, and make the lines look sort of transparant ?
Enzo 7 years ago
Hey Martin!
Great job on the visualization, it looks awesome!
How did you manage to create such thin lines, and make the lines look sort of transparant?
Enzo 7 years ago
Hey Enzo! Actually the lines only appear to be transparent but its an illusion because they are really thin. So when two lines overlap and intersect they create a broader line which appears to be darker.
Its all done by setting the lwd paramater of the lines() function to 0.1 and by selecting a bright color compared to the background:
lines(inter, lwd=0.1, col=”turquoise2″)
Martin 7 years ago
Hi Martin,
Thanks for your post. I have another question on how you get such thin line. I duplicate your code in R studio, but I cannot get that thin line as the ones showed on your example.
And no matter how I change the value of Lwd, it does not work.
Could u please help me on this?
Rex Cao 4 years ago
Dear Rex,
sorry for the late reply. Did you manage to make it work?
Martin 4 years ago
The visualization looks great, thank you for sharing Martin! I would like to do a somewhat similar map but for Eurasia (including EU, Russia and countries in between), do you know if it is possible with the steps you have described?
Anastasia 6 years ago
It’s definitely possible but you need a comparable datasets on flights in Eurasia or atleast airport coordinates so you can simualte such a dataset. The vizualisation steps are then the same.
Martin 6 years ago
Martin,
Thanks for the great visualization. I started using the code to plot livestock movements in the US and looks awesome. I am trying to weight my movements based on the # of shipments from county-to-county or # of animals shipped in each shipment. In simple words, those county-to-county movements with more # of shipments every year will be represented in my flow map with thicker lines. Do you think is that possible within your code?
Thanks!!
Aurelio 6 years ago
Hey Aurelio,
happy to hear! yes! you need to change the lwd (linewidth) paramater for each shipment individually.
Now it looks like this – with a fixed width of 0.1:
lines(inter, lwd=0.1, col=”turquoise2″)
Hope this helps!
Martin 6 years ago
Hi Martin,
Thanks for the post.
I have a question on this code:
for (i in (1:dim(usairports)[1])) {
inter <- gcIntermediate(c(jfk$lon[1], jfk$lat[1]), c(usairports$lon[i], usairports$lat[i]), n=200)
lines(inter, lwd=0.1, col="turquoise2")
}
What does n=200 stand for here?
Thanks
Rex 4 years ago
Hi Martin,
Thanks for your post. I have another question on how you get such thin line. I duplicate your code in R studio, but I cannot get that thin line as the ones showed on your example.
And no matter how I change the value of Lwd, it does not work.
Could u please help me on this?
Thanks.
Rex Cao 4 years ago
Hola Martín,
Estoy un trabajo de clase sobre mapas en R y no consigo corregir la trayectoria de gcIntermediate para que la conexión que estoy haciendo entre Melbourne y Buenos Aires no pase por una línea recta al final del mapa. Lo he intentado todo, pero nada funciona. Si pudieras ayudarme.
Un saludo!
Myriam Cobos Fernandez 4 years ago
Post A Reply