Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

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 &amp;amp;lt;- "https://en.wikipedia.org/wiki/List_of_countries_by_level_of_military_equipment#List"
r &amp;amp;lt;- GET(url)
airforces &amp;amp;lt;- readHTMLTable(doc = content(r, "text"))[[2]]

# Clean required columns
airforces &amp;amp;lt;- airforces[-1, c("Country[note 1]", "Military aircraft[note 3]")]
colnames(airforces) &amp;amp;lt;- c("Country", "MilitaryAircraft")
remove.bracket.content &amp;amp;lt;- function(s) {
return(gsub("\$.+\$", "", s))
}
airforces &amp;amp;lt;- data.frame(apply(airforces, 2, remove.bracket.content))
airforces$MilitaryAircraft &amp;amp;lt;- 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)&amp;amp;lt;/pre&amp;amp;gt;
url &amp;amp;lt;- paste0(url, "fMilQ=TRUE")

positions &amp;amp;lt;- fromJSON(url)$acList if (length(positions) != 0) { positions &amp;amp;lt;- positions[positions$Type != "TEST", ]
positions &amp;amp;lt;- 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 &amp;amp;lt;- 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 &amp;amp;lt;- plot_geo(airforces) %&amp;amp;gt;% 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)) %&amp;amp;gt;% config(displayModeBar = F) %&amp;amp;gt;% 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 &amp;amp;lt; 200 &amp;amp;amp; positions$Alt &amp;amp;lt; 2000] &amp;amp;lt;- "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!

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.

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.