I'm trying to create a world map in R using the Highcharter package. The goal is to plot connections (lines) between São Paulo and the top 10 export destinations, with each connection represented by a line (mapline type) on the map. However, the lines are not displaying.
I've tried formatting the data in several ways, but the lines still don’t show up on the map. Below is the code I'm using, along with a description of the dataset structure and my intended output.
# df
top_destinations <- tibble(
Cidade = rep("São Paulo - SP", 10),
Nome_Pais = c("China", "Canadá", "Estados Unidos", "Itália", "Bélgica",
"Emirados Árabes Unidos", "Suíça", "Argentina", "Índia", "Argélia"),
Lat_Municipio = rep(-23.6, 10),
Long_Municipio = rep(-46.6, 10),
Lat_PAIS = c(33.4, 59.1, 39.6, 42.7, 50.6, 23.5, 46.9, -35.4, 21.0, 28.2),
Long_PAIS = c(107.0, -109.0, -98.6, 12.8, 4.66, 54.2, 7.91, -65.2, 78.5, 2.63),
US_FOB = c(1e9, 3.46e8, 3.08e8, 2.26e8, 2.04e8, 1.63e8, 1.14e8, 1.08e8, 9.3e7, 8.12e7)
)
# Packages
library(highcharter)
library(dplyr)
# Load world map data
worldgeojson <- get_data_from_map(download_map_data("https://code.highcharts.com/mapdata/custom/world.geo.json"))
# Prepare data for destination points
dest_points <- data.frame(
lat = top_destinations$Lat_PAIS,
lon = top_destinations$Long_PAIS,
name = top_destinations$Nome_Pais,
US_FOB = top_destinations$US_FOB
)
# Prepare data for connections (maplines)
connections <- lapply(1:nrow(top_destinations), function(i) {
list(
from = list(lat = top_destinations$Lat_Municipio[i], lon = top_destinations$Long_Municipio[i]),
to = list(lat = top_destinations$Lat_PAIS[i], lon = top_destinations$Long_PAIS[i])
)
})
# Create the map with Highcharts
highchart(type = "map") %>%
# Add base map
hc_add_series(
mapData = worldgeojson,
showInLegend = FALSE,
nullColor = "#E0E0E0",
borderWidth = 0
) %>%
hc_mapNavigation(enabled = TRUE) %>%
# Add São Paulo as the origin point
hc_add_series(
type = "mappoint",
data = data.frame(
lat = top_destinations$Lat_Municipio[1],
lon = top_destinations$Long_Municipio[1],
name = "São Paulo",
color = "#3d9970",
US_FOB = sum(top_destinations$US_FOB)
),
marker = list(symbol = "circle", radius = 4),
tooltip = list(pointFormat = "City: {point.name}<br>Export Value: {point.US_FOB}")
) %>%
# Add destination points
hc_add_series(
type = "mappoint",
name = "Destinations",
data = dest_points,
color = "#d35400",
marker = list(symbol = "circle", radius = 3),
tooltip = list(pointFormat = "Country: {point.name}<br>Export Value: {point.US_FOB}")
) %>%
# Add connections between São Paulo and destinations
hc_add_series(
type = "mapline",
data = connections,
lineWidth = 1.5,
opacity = 0.8,
showInLegend = FALSE,
enableMouseTracking = FALSE
) %>%
# Title and tooltip settings
hc_title(text = "Main Export Destinations from São Paulo") %>%
hc_tooltip(useHTML = TRUE)
I believe you can only use mapline
type with geo_json
or geo_list
objects of {geojsonio}
(ref: hc_add_series
for geo_json
& geo_list
objects ).
I'm using sf
to build a set of linestrings which will be converted for highcharter
with geojson_list()
. And as I need source & destination points to be sf
/ sfc
objects anyway, I switched to sf
's spatial data frames and GeoJSON for all data objects, this also caused a couple of small changes on tooltips.
For whatever reason highcharts.com is not severing world.geo.json for me, so using base map from {giscoR}
instead.
library(highcharter)
library(geojsonio)
library(dplyr)
library(sf)
#> Linking to GEOS 3.12.1, GDAL 3.8.4, PROJ 9.3.1; sf_use_s2() is TRUE
worldgeojson <-
giscoR::gisco_countries %>%
geojsonio::geojson_json()
# sf object with a source point
src_point_sf <-
top_destinations %>%
summarise(
name = "São Paulo",
US_FOB = sum(US_FOB),
lat = first(Lat_Municipio),
lon = first(Long_Municipio)
) |>
st_as_sf(coords = c("lon", "lat"), crs = "WGS84")
# Prepare data for destination points
dest_points_sf <-
top_destinations %>%
st_as_sf(coords = c("Long_PAIS", "Lat_PAIS"), crs = "WGS84") %>%
select(name = Nome_Pais, US_FOB)
# sf object with connection lines (generate point pair, union, cast to line)
connections_sf <-
lapply(
st_geometry(dest_points_sf),
\(to) st_union(c(st_geometry(src_point_sf)[[1]], to)) %>% st_cast("LINESTRING") ) %>%
st_as_sfc(crs = st_crs(dest_points_sf)) %>%
st_sf(geometry = _) %>%
# with just 2 endpoints we'd get straight lines,
# adding a vertex at every 1000km introduces curves once linestrings are projected
st_segmentize(dfMaxLength = 1000*1000)
# Create the map with Highcharts
highchart(type = "map") %>%
# Add base map
hc_add_series(
mapData = worldgeojson,
showInLegend = FALSE,
nullColor = "#E0E0E0",
borderWidth = 0
) %>%
hc_mapNavigation(enabled = TRUE) %>%
# Add São Paulo as the origin point
hc_add_series(
data = geojson_list(src_point_sf),
type = "mappoint",
marker = list(symbol = "circle", radius = 4),
color = "#3d9970" ,
tooltip = list(pointFormat = "City: {point.properties.name}<br>Export Value: {point.properties.US_FOB}")
) %>%
# Add destination points
hc_add_series(
data = geojson_list(dest_points_sf),
type = "mappoint",
name = "Destinations",
color = "#d35400",
marker = list(symbol = "circle", radius = 3),
tooltip = list(pointFormat = "Country: {point.properties.name}<br>Export Value: {point.properties.US_FOB}")
) %>%
# Add connections between São Paulo and destinations
hc_add_series(
data = geojson_list(connections_sf),
type = "mapline",
lineWidth = 1.5,
opacity = 0.8,
showInLegend = FALSE,
enableMouseTracking = FALSE
) %>%
# Title and tooltip settings
hc_title(text = "Main Export Destinations from São Paulo") %>%
hc_tooltip(useHTML = TRUE)
Example data:
# df
top_destinations <- tibble(
Cidade = rep("São Paulo - SP", 10),
Nome_Pais = c("China", "Canadá", "Estados Unidos", "Itália", "Bélgica",
"Emirados Árabes Unidos", "Suíça", "Argentina", "Índia", "Argélia"),
Lat_Municipio = rep(-23.6, 10),
Long_Municipio = rep(-46.6, 10),
Lat_PAIS = c(33.4, 59.1, 39.6, 42.7, 50.6, 23.5, 46.9, -35.4, 21.0, 28.2),
Long_PAIS = c(107.0, -109.0, -98.6, 12.8, 4.66, 54.2, 7.91, -65.2, 78.5, 2.63),
US_FOB = c(1e9, 3.46e8, 3.08e8, 2.26e8, 2.04e8, 1.63e8, 1.14e8, 1.08e8, 9.3e7, 8.12e7)
)