The highcharter package include highmaps libraries from highchartsJS to chart maps, choropleths and geojson.
Basics
The easiest way to chart a map with highcharter is using
hcmap()
function. Select a map (a url) from the highmaps
collection https://code.highcharts.com/mapdata/. and use the url as
a map in hcmap()
function. This will download the map and
create a highchart
object using the info as a
mapData
argument.
Let’s try some maps:
library(highcharter)
hcmap("countries/nz/nz-all")
hcmap("custom/usa-and-canada", showInLegend = FALSE)
hcmap("countries/us/us-ca-all") |>
hc_title(text = "California") |>
hc_subtitle(text = "You can use the same functions to modify your map!")
Note: The copyright information is added to the chart credits by default, but please be aware that you will have to display this information somewhere else if you choose to disable chart credits. Copyright information for each map can be found as properties in the GeoJSON and Javascript files.
Choropleths
What about add data to get a choropleth? Every map downloaded from the highchartsJS maps collection have keys to join data. There are 2 functions to help to know what are the regions coded to know how to join the map and data:
-
download_map_data()
: Download the geojson data from the highchartsJS collection. -
get_data_from_map()
: Get the properties for each region in the map, as the keys from the map data.
require(dplyr)
mapdata <- get_data_from_map(download_map_data("custom/usa-and-canada"))
glimpse(mapdata)
## Rows: 64
## Columns: 21
## $ `hc-group` <chr> "admin1", "admin1", "admin1", "admin1", "admin1", "admin…
## $ `hc-middle-x` <dbl> 0.40, 0.50, 0.52, 0.59, 0.48, 0.50, 0.47, 0.48, 0.51, 0.…
## $ `hc-middle-y` <dbl> 0.53, 0.51, 0.50, 0.50, 0.55, 0.49, 0.35, 0.50, 0.54, 0.…
## $ `hc-key` <chr> "us-ca", "us-or", "us-nd", "ca-sk", "us-mt", "us-az", "u…
## $ `hc-a2` <chr> "CA", "OR", "ND", "SK", "MT", "AZ", "NV", "AL", "NM", "C…
## $ labelrank <chr> "0", "0", "0", "2", "0", "0", "0", "0", "0", "0", "0", "…
## $ hasc <chr> "US.CA", "US.OR", "US.ND", "CA.SK", "US.MT", "US.AZ", "U…
## $ `alt-name` <chr> "CA|Calif.", "OR|Ore.", "ND|N.D.", NA, "MT|Mont.", "AZ|A…
## $ `woe-id` <chr> "2347563", "2347596", "2347593", "2344925", "2347585", "…
## $ subregion <chr> "Pacific", "Pacific", "West North Central", "Prairies", …
## $ fips <chr> "US06", "US41", "US38", "CA11", "US30", "US04", "US32", …
## $ `postal-code` <chr> "CA", "OR", "ND", "SK", "MT", "AZ", "NV", "AL", "NM", "C…
## $ name <chr> "California", "Oregon", "North Dakota", "Saskatchewan", …
## $ country <chr> "United States of America", "United States of America", …
## $ `type-en` <chr> "State", "State", "State", "Province", "State", "State",…
## $ region <chr> "West", "West", "Midwest", "Western Canada", "West", "We…
## $ longitude <chr> "-119.591", "-120.386", "-100.302", "-105.682", "-110.04…
## $ `woe-name` <chr> "California", "Oregon", "North Dakota", "Saskatchewan", …
## $ latitude <chr> "36.7496", "43.8333", "47.4675", "54.4965", "46.9965", "…
## $ `woe-label` <chr> "California, US, United States", "Oregon, US, United Sta…
## $ type <chr> "State", "State", "State", "Province", "State", "State",…
data_fake <- mapdata |>
select(code = `hc-a2`) |>
mutate(value = 1e5 * abs(rt(nrow(mapdata), df = 10)))
glimpse(data_fake)
## Rows: 64
## Columns: 2
## $ code <chr> "CA", "OR", "ND", "SK", "MT", "AZ", "NV", "AL", "NM", "CO", "WY"…
## $ value <dbl> 191420.8669, 57744.4399, 143880.8061, 14665.4241, 82072.0653, 35…
If we compare this 2 data frames the hc-key
is same code
that code
. So we’ll use these columns as keys:
Categorized areas
data <- tibble(
country =
c("PT", "IE", "GB", "IS",
"NO", "SE", "DK", "DE", "NL", "BE", "LU", "ES", "FR", "PL", "CZ", "AT",
"CH", "LI", "SK", "HU", "SI", "IT", "SM", "HR", "BA", "YF", "ME", "AL", "MK",
"FI", "EE", "LV", "LT", "BY", "UA", "MD", "RO", "BG", "GR", "TR", "CY",
"RU"),
tz = c(rep("UTC", 4), rep("UTC + 1",25), rep("UCT + 2",12), "UTC + 3")
)
# auxiliar variable
data <- data |>
mutate(value = cumsum(!duplicated(tz)))
# now we'll create the dataClasses
dta_clss <- data |>
mutate(value = cumsum(!duplicated(tz))) |>
group_by(tz) |>
summarise(value = unique(value)) |>
arrange(value) |>
rename(name = tz, from = value) |>
mutate(to = from + 1) |>
list_parse()
hcmap(
map = "custom/europe",
data = data,
joinBy = c("iso-a2","country"),
name = "Time zone",
value = "value",
tooltip = list(pointFormat = "{point.name} {point.tz}"),
dataLabels = list(enabled = TRUE, format = "{point.country}")
) |>
hc_colorAxis(
dataClassColor = "category",
dataClasses = dta_clss
) |>
hc_title(text = "Europe Time Zones")
Example from https://www.highcharts.com/demo/maps/category-map.
Adding Points
With highcharter is possible add data as points or bubbles. For this
it is necessary a data frame with lat
, lon
columns, and name
, z
are optional:
cities <- data.frame(
name = c("London", "Birmingham", "Glasgow", "Liverpool"),
lat = c(51.507222, 52.483056, 55.858, 53.4),
lon = c(-0.1275, -1.893611, -4.259, -3),
z = c(1, 2, 3, 2)
)
hcmap("countries/gb/gb-all", showInLegend = FALSE) |>
hc_add_series(
data = cities,
type = "mappoint",
name = "Cities",
minSize = "1%",
maxSize = "5%"
) |>
hc_mapNavigation(enabled = TRUE)
hcmap("countries/gb/gb-all", showInLegend = FALSE) |>
hc_add_series(
data = cities,
type = "mapbubble",
name = "Cities",
minSize = "1%",
maxSize = "5%"
) |>
hc_mapNavigation(enabled = TRUE)
Another example:
library(dplyr)
airports <- read.csv(
"https://raw.githubusercontent.com/ajdapretnar/datasets/master/data/global_airports.csv",
stringsAsFactors = FALSE
)
south_america_countries <- c(
"Brazil", "Ecuador", "Venezuela",
"Chile", "Argentina", "Peru",
"Uruguay", "Paraguay", "Bolivia",
"Suriname", "Guyana", "Colombia"
)
airports <- airports |>
filter(country %in% south_america_countries) |>
rename(lat = latitude, lon = longitude) |>
filter(lon < -30)
hcmap(
"custom/south-america",
name = "South America",
showInLegend = FALSE
) |>
hc_add_series(
data = airports,
type = "mappoint",
name = "Airports",
color = hex_to_rgba("darkred", alpha = 0.3),
maxSize = "10",
tooltip = list(
pointFormat = "{point.name}: {point.altitude:,.0f} feets <br>
({point.lat:,.2f}, {point.lon:,.2f})"
)
) |>
hc_chart(zoomType = "xy")
geojsonio
Package
highchartsJS support geo_json
classes from the
geojsonio
package. So you can use
hc_add_series
as usual without use
geojson = TRUE
parameter/argument.
library(httr)
library(jsonlite)
library(geojsonio)
ausgeojson <- GET("https://raw.githubusercontent.com/johan/world.geo.json/master/countries/AUS.geo.json") |>
content() |>
fromJSON(simplifyVector = FALSE) |>
as.json()
ausmap <- highchart(type = "map") |>
hc_add_series(mapData = ausgeojson, showInLegend = FALSE)
ausmap
We can still adding data:
airports <- read.csv("https://raw.githubusercontent.com/ajdapretnar/datasets/master/data/global_airports.csv")
airports <- filter(airports, country == "Australia", name != "Roma Street Railway Station")
airp_geojson <- geojson_json(airports, lat = "latitude", lon = "longitude")
class(airp_geojson)
## [1] "geofeaturecollection" "geojson" "geo_json"
## [4] "json"
ausmap |>
hc_add_series(
data = airp_geojson,
type = "mappoint",
dataLabels = list(enabled = FALSE),
name = "Airports",
tooltip = list(pointFormat = "{point.name}")
)
Advanced Example
Let’s download some geojson files and make a map.
getContent <- function(url) {
library(httr)
content(GET(url))
}
world <- getContent("https://raw.githubusercontent.com/johan/world.geo.json/master/countries.geo.json")
# is text
world <- jsonlite::fromJSON(world, simplifyVector = FALSE)
# http://cedeusdata.geosteiniger.cl/layers/geonode:mundo_corrientes_maritimas
marine <- getContent("http://cedeusdata.geosteiniger.cl/geoserver/wfs?srsName=EPSG%3A4326&typename=geonode%3Amundo_corrientes_maritimas&outputFormat=json&version=1.0.0&service=WFS&request=GetFeature")
# marine <- geojsonio::as.json(marine)
# http://cedeusdata.geosteiniger.cl/layers/geonode:mundo_limites_placas
plates <- getContent("http://cedeusdata.geosteiniger.cl/geoserver/wfs?srsName=EPSG%3A4326&typename=geonode%3Amundo_limites_placas&outputFormat=json&version=1.0.0&service=WFS&request=GetFeature")
# plates <- geojsonio::as.json(plates)
# http://cedeusdata.geosteiniger.cl/layers/geonode:mundo_volcanes
volcano <- getContent("http://cedeusdata.geosteiniger.cl/geoserver/wfs?srsName=EPSG%3A4326&typename=geonode%3Amundo_volcanes&outputFormat=json&version=1.0.0&service=WFS&request=GetFeature")
# volcano <- geojsonio::as.json(volcano)
The data is ready. Remember you can keep using the rest of the API to customize your map.
highchart(type = "map") |>
hc_chart(backgroundColor = "#161C20") |>
hc_add_series(
mapData = world,
showInLegend = FALSE,
nullColor = "#424242",
borderWidth = 0
) |>
hc_add_series(
data = marine,
type = "mapline",
geojson = TRUE,
color = "#2980b9",
name = "Marine currents",
tooltip = list(pointFormat = "{point.properties.NOMBRE}")
) |>
hc_add_series(
data = plates,
type = "mapline",
lineWidth = 2,
zIndex = -1,
geojson = TRUE,
color = "#d35400",
name = "Plates",
tooltip = list(pointFormat = "{point.properties.TIPO}")
) |>
hc_add_series(
data = volcano,
type = "mappoint",
color = hex_to_rgba("#f1c40f", 0.4),
geojson = TRUE,
name = "Volcanos",
tooltip = list(pointFormat = "{point.properties.NOMBRE}"),
marker = list(lineWidth = 0, radius = 2)
)