library(oidnChaRts)
geo_lines_map(data_geo_lines_map,
library = "leaflet")
For these examples we will use the data_geo_lines_map
data.frame from the oidnChaRts
library:
library(oidnChaRts)
head(data_geo_lines_map)
## # A tibble: 6 × 9
## sender.location sender.latitude sender.longitude receiver.location
## <chr> <dbl> <dbl> <chr>
## 1 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## 2 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## 3 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## 4 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## 5 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## 6 DEU, Mockethal 50.97178 13.96013 USA, New York (NY)
## # ... with 5 more variables: receiver.latitude <dbl>,
## # receiver.longitude <dbl>, date <date>, journey <chr>,
## # number.of.letters <int>
This dataset was generated by randomly sampling a set of letters sent between European migrants to the US during the 20th Century, and adding a random offset to the date column. In general, your data should be designed to be as similar as possible to this:
We will create interactive maps with the following data overlaid:
Maps built with leaflet
need a map to be “instantiated” and for map tiles to be set, the default map looks like this:
library(leaflet)
leaflet() %>%
addTiles()
Leaflet isn’t able to compute great circles on its own, we therefore use the great geosphere
library to compute intermediatry points along the great arcs between send and receive locations. Please note we’re using dplyr
and %>%
to handily extract the send/receive locations, you may need to refer to other tutorials to understand this.
library(geosphere)
library(dplyr)
geo_lines <- gcIntermediate(
data_geo_lines_map %>%
select(sender.longitude, sender.latitude),
data_geo_lines_map %>%
select(receiver.longitude, receiver.latitude),
sp = TRUE, # SpatialLines are what Leaflet wants
addStartEnd = TRUE, # By default this is FALSE, and would be inaccurate
n = 50 # number of intermediate points
)
## Individual geolines are SpatialLines, if you're interested in how they look uncomment the line below
## attributes(geo_lines[1])
The geo_lines
object can now be provided to addPolylines
and visualised on our map:
leaflet() %>%
addTiles() %>%
addPolylines(data = geo_lines)
The above visualisation is very unattractive because multiple lines have been placed upon one another, however it is fairly easy to fix this by modifying the data with dplyr.
unique_journies <- data_geo_lines_map %>%
group_by(sender.latitude, sender.longitude, receiver.latitude, receiver.longitude) %>%
mutate(total.letters = sum(number.of.letters)) %>%
ungroup() %>%
select(-number.of.letters, -date) %>%
unique()
library(knitr)
kable(head(iris), format = "html")
Sepal.Length | Sepal.Width | Petal.Length | Petal.Width | Species |
---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa |
4.9 | 3.0 | 1.4 | 0.2 | setosa |
4.7 | 3.2 | 1.3 | 0.2 | setosa |
4.6 | 3.1 | 1.5 | 0.2 | setosa |
5.0 | 3.6 | 1.4 | 0.2 | setosa |
5.4 | 3.9 | 1.7 | 0.4 | setosa |
There are 464 fewer lines when duplicates are removed,
To differentiate between send and receive points, a useful metaphor is as follows:
Using dplyr
, we can compute the groups of points described above:
library(tidyr) # using for separate
send_receive_points <- data_geo_lines_map %>%
mutate(send = paste(sender.latitude, sender.longitude)) %>%
mutate(receive = paste(receiver.latitude, receiver.longitude)) %>%
select(send, receive) %>%
unique()
both_s_and_r <- send_receive_points %>%
filter(send %in% receive) %>%
select(-receive) %>%
unique()
only_send <- send_receive_points %>%
filter(!send %in% receive) %>%
select(-receive) %>%
filter(!send %in% both_s_and_r$send) %>%
unique() %>%
separate(send, c('Latitude', 'Longitude'), sep=" ", convert = TRUE)
only_receive <- send_receive_points %>%
filter(!receive %in% send) %>%
select(-send) %>%
filter(!receive %in% both_s_and_r$send) %>%
unique() %>%
separate(receive, c('Latitude', 'Longitude'), sep=" ", convert = TRUE)
both_s_and_r <- both_s_and_r %>%
separate(send, c('Latitude', 'Longitude'), sep=" ", convert = TRUE)
These may then be provided to the leaflet
map as different markers:
leaflet() %>%
addTiles() %>%
addPolylines(data = geo_lines, color = "#decbe4", opacity = 0.2) %>%
addCircleMarkers(
data = only_send,
fill = FALSE,
stroke = TRUE,
# fillColor = "red",
color = "#1b9e77",
radius = 4,
weight = 2
) %>%
addCircleMarkers(
data = only_receive,
fill = TRUE,
stroke = FALSE,
fillColor = "#d95f02",
color = "#d95f02",
fillOpacity = 0.7,
opacity = 0.7,
radius = 5
) %>%
addCircleMarkers(
data = both_s_and_r,
fill = TRUE,
stroke = FALSE,
fillColor = "#7570b3",
color = "#7570b3",
fillOpacity = 0.7,
opacity = 0.7,
radius = 5
)
Plotly provides the ability to create a variety of maps, and is often a good choice of library because it provides a number of “on-screen” tools. However, due to a Null Island issue Plotly cannot be used to create effective geolines maps as of January 2017. For the interested party, the issue has been raised here - https://github.com/ropensci/plotly/issues/731.
However, it is still useful to cover the steps required to build such a chart. We first initialise a plotly-geo object with plot_geo
, and as is generally the case with plotly
objects, use layout
to modify the map projection:
library(plotly)
plot_geo() %>%
layout(geo = list(projection = list(type = "mercator")))
Geolines are added to plotly
maps via the add_segments
function, however note the additional lines to Null Island just off west coast of Africa
plot_geo() %>%
layout(geo = list(projection = list(type = "mercator"))) %>%
add_segments(data = data_geo_lines_map,
x = ~sender.longitude, xend = ~receiver.longitude,
y = ~sender.latitude, yend = ~receiver.latitude)
Highcharts provides support for mapping! The following minimal example shows how to create a world map using
# library(highcharter)
# library(dplyr)
# library(httr)
# library(jsonlite)
#
# world <- content(GET("http://code.highcharts.com/mapdata/custom/world-palestine-highres.geo.json"))
# # is text
# world <- fromJSON(world, simplifyVector = FALSE)
#
# highchart(type = "map") %>%
# hc_chart(backgroundColor = "#161C20") %>%
# hc_add_series(mapData = world, showInLegend = FALSE, nullColor = "#424242",
# borderWidth = 0)
# hcmap("countries/us/us-ca-all") %>%
# hc_title(text = "California")