How to Build a Geographic Dashboard with Real-Time Data

November 20, 2017
By

(This article was first published on R – Displayr, and kindly contributed to R-bloggers)

In this post, I show how to build an interactive geographic dashboard using Displayr, Plotly and R. It is particularly fascinating in that it tracks the real-time position of military aircraft. To do so, I am first going to bring in some data from two separate sources (regions based on the size of military air-force, and then the real-time tracking of aircraft positions). The dashboard displays the dynamic data in two ways: region shading (to indicate the size of the military force per country) and point markers (for the aircraft positions). I then build a map to neatly and attractively display all this data.


Reading tabular data from the web

I am going to shade each country of the map according to the size of its military air-force. To do this I need a list of aircraft per country. Fortunately, the ever useful Wikipedia has just what I need (here). The following code reads in the data and cleans it to produce a neat table.

library(httr)
library(XML)

# Extract table via URL
url <- "https://en.wikipedia.org/wiki/List_of_countries_by_level_of_military_equipment#List"
r <- GET(url)
airforces <- readHTMLTable(doc = content(r, "text"))[[2]]

# Clean required columns
airforces <- airforces[-1, c("Country[note 1]", "Military aircraft[note 3]")]
colnames(airforces) <- c("Country", "MilitaryAircraft")
remove.bracket.content <- function(s) {
return(gsub("\\[.+\\]", "", s))
}
airforces <- data.frame(apply(airforces, 2, remove.bracket.content))
airforces$MilitaryAircraft <- as.numeric(gsub(",", "", airforces$MilitaryAircraft))
airforces

Pooling real-time data from across the globe

Compared to the above, the second source of data is more dynamic. I am using ADS-B, which pools real-time flight tracking information from across the globe. Not all military operations are top secret. Apparently, some aircraft operated by the armed forces broadcast their positions publicly.

To collate this information, I construct a URL to retrieve a JSON object with information about military aircraft (JSON is flexible text format used for data exchange). Then I parse the JSON to create a data.frame.

library(jsonlite)</pre>
url <- "http://public-api.adsbexchange.com/VirtualRadar/AircraftList.json?"
url <- paste0(url, "fMilQ=TRUE")

positions <- fromJSON(url)$acList

if (length(positions) != 0) {
positions <- positions[positions$Type != "TEST", ]
positions <- positions[!is.na(positions$Lat), ]
}
positions

Shading countries of a map

The following code produces a plotly map of the world. The countries are shaded according to the size of the air-force, with the scale shown on a legend. In plotly terminology, each layer of the map is known as a trace. 

library(plotly)
library(flipFormat)

# specify map area and projection
g <- list(scope = "world",
showframe = FALSE, showcoastlines = TRUE,
projection = list(type = 'mercator'),
lonaxis = list(range = c(-140, 179)),
lataxis = list(range = c(-55, 70)),
resolution = 50) # higher resolution

# shade countries by airforce size
p <- plot_geo(airforces) %>%

add_trace(data = airforces, name = "Airforce",
z = ~MilitaryAircraft, color = ~MilitaryAircraft,
colors = 'Blues', locations = ~Country,
marker = list(line = list(color = toRGB("grey"), width = 0.5)),
showscale = TRUE, locationmode = "country names",
colorbar = list(title = 'Airforce', separatethousands = TRUE)) %>%
config(displayModeBar = F) %>%

layout(geo = g,
margin = list(l=0, r=0, t=0, b=0, pad=0),
paper_bgcolor = 'transparent')

Adding markers for the aircraft

Finally, I add markers showing the airplane locations as another trace. I use a different color for those with speed less than 200 knots and altitude less than 2000 feet. The hover text contains more detail about the aircraft.

aircolors = rep("airborne", nrow(positions))  # create a vector with the status of each aeroplane
aircolors[positions$Spd < 200 & positions$Alt < 2000] <- "ground/approach"
hovertext = paste0("Operator:", positions$Op, "\nModel:", positions$Mdl, 
"\nAltitide(ft):", sapply(positions$Alt, FormatAsReal))
hoverinfo = rep("all", nrow(positions))

p = add_trace(p, data = positions, x = positions$Long, y = positions$Lat, 
 color = aircolors, hovertext = hovertext, showlegend = FALSE)

The final result is shown below. Since broadcasting of position is purely voluntary, I suspect that the Top Gun flights are not shown!


Adding some finishing touches

While the map above shows the required information, it can easily be made more useful and appealing. Displayr allows me to add a control to switch between regions, text and image annotations, and a background. Here is a link to the finished dashboard, with a screenshot shown below.

Militiary aircraft still of the map

Thinking about it again, if you can’t see any military aircraft at all on the radar, then you should really worry!


Try it yourself

You can explore the dashboards used in this post within Displayr. All the code is embedded within the pages (look on the right-hand panel after you click on an object). Click here to see the copy of the working document (without background and finishing touches). Click here open a copy of the finished document that includes the background, control box, and other finishing touches.

To leave a comment for the author, please follow the link and comment on their blog: R – Displayr.

R-bloggers.com offers daily e-mail updates about R news and tutorials on topics such as: Data science, Big Data, R jobs, visualization (ggplot2, Boxplots, maps, animation), programming (RStudio, Sweave, LaTeX, SQL, Eclipse, git, hadoop, Web Scraping) statistics (regression, PCA, time series, trading) and more...



If you got this far, why not subscribe for updates from the site? Choose your flavor: e-mail, twitter, RSS, or facebook...

Comments are closed.

Search R-bloggers

Sponsors

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)