Track Hurricane Danny (Interactively) with R + leaflet
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
Danny became the first hurricane of the 2015 Season, so it’s a good time to revisit how one might be able to track them with R.
We’ll pull track data from Unisys and just look at Danny, but it should be easy to extrapolate from the code.
For this visualization, we’ll use leaflet since it’s all the rage and makes the plots interactive without any real work (thanks to the very real work by the HTML Widgets folks and the Leaflet.JS folks).
Let’s get the library calls out of the way:
library(leaflet) library(stringi) library(htmltools) library(RColorBrewer) |
Now, we’ll get the tracks:
danny <- readLines("http://weather.unisys.com/hurricane/atlantic/2015/DANNY/track.dat") |
Why aren’t we using read.csv
or read.table
directly, you ask? Well, the data is in a really ugly format thanks to the spaces in the STATUS
column and two prefix lines:
Date: 18-20 AUG 2015 Hurricane-1 DANNY ADV LAT LON TIME WIND PR STAT 1 10.60 -36.50 08/18/15Z 30 1009 TROPICAL DEPRESSION 2 10.90 -37.50 08/18/21Z - - TROPICAL DEPRESSION 3 11.20 -38.80 08/19/03Z - - TROPICAL DEPRESSION 4 11.30 -40.20 08/19/09Z - - TROPICAL DEPRESSION 5 11.20 -41.10 08/19/15Z - - TROPICAL DEPRESSION 6 11.50 -42.00 08/19/21Z - - TROPICAL DEPRESSION 7 12.10 -42.70 08/20/03Z - - TROPICAL DEPRESSION 8 12.20 -43.70 08/20/09Z - - TROPICAL DEPRESSION 9 12.50 -44.80 08/20/15Z - - TROPICAL DEPRESSION +12 13.10 -46.00 08/21/00Z 70 - HURRICANE-1 +24 14.00 -47.60 08/21/12Z 75 - HURRICANE-1 +36 14.70 -49.40 08/22/00Z 75 - HURRICANE-1 +48 15.20 -51.50 08/22/12Z 70 - HURRICANE-1 +72 16.00 -56.40 08/23/12Z 65 - HURRICANE-1 +96 16.90 -61.70 08/24/12Z 65 - HURRICANE-1 +120 18.00 -66.60 08/25/12Z 55 - TROPICAL STORM |
But, we can put that into shape pretty easily, using gsub
to make it easier to read everything with read.table
and we just skip over the first two lines (we’d use them if we were doing other things with more of the data).
danny_dat <- read.table(textConnection(gsub("TROPICAL ", "TROPICAL_", danny[3:length(danny)])), header=TRUE, stringsAsFactors=FALSE) |
Now, let’s make the data a bit prettier to work with:
# make storm type names prettier danny_dat$STAT <- stri_trans_totitle(gsub("_", " ", danny_dat$STAT)) # make column names prettier colnames(danny_dat) <- c("advisory", "lat", "lon", "time", "wind_speed", "pressure", "status") |
Those steps weren’t absolutely necessary, but why do something half-baked (unless it’s chocolate chip cookies)?
Let’s pick better colors than Unisys did. We’ll use a color-blind safe palette from Color Brewer:
danny_dat$color <- as.character(factor(danny_dat$status, levels=c("Tropical Depression", "Tropical Storm", "Hurricane-1", "Hurricane-2", "Hurricane-3", "Hurricane-4", "Hurricane-5"), labels=rev(brewer.pal(7, "YlOrBr")))) |
And, now for the map! We’ll make lines for the path that was already traced by Danny, then make interactive points for the forecast locations from the advisory data:
leaflet() %>% addTiles() %>% addPolylines(data=danny_dat[danny_dat$advisory<=9,], ~lon, ~lat, color=~color) %>% addCircles(data=danny_dat[danny_dat$advisory>9,], ~lon, ~lat, color=~color, fill=~color, radius=25000, popup=~sprintf("<b>Advisory forecast for +%dh (%s)</b><hr noshade size='1'/> Position: %3.2f, %3.2f<br/> Expected strength: <span style='color:%s'><strong>%s</strong></span><br/> Forecast wind: %s (knots)<br/>Forecast pressure: %s", htmlEscape(advisory), htmlEscape(time), htmlEscape(lon), htmlEscape(lat), htmlEscape(color), htmlEscape(status), htmlEscape(wind_speed), htmlEscape(pressure))) |
Click on one of the circles to see the popup.
The entire source code is in this gist and, provided you have the proper packages installed, you can run this at any time with:
devtools::source_gist("e3253ddd353f1a489bb4", sha1="b3e1f13e368d178804405ab6d0bf98a185126a9a") |
The use of the sha1
hash parameter will help ensure you aren’t being asked to run a potentially modified & harmful gist, but you should visit the gist first to make sure I’m not messing with you (which, I’m not).
If you riff off of this or have suggestions for improvement, drop a note here or in the gist comments.
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.