Tutorial: Build an interactive map with regional data
We’ll need a map, some data - and
echarty to bring them together.
Map is France by regions, from here.
Data is France population by region, from here.
Let start by initializing the chart, load the map as a plugin and make
sure it shows correctly.
library(echarty); library(dplyr)
url <- 'https://raw.githubusercontent.com/echarts-maps/echarts-countries-js/master/echarts-countries-js/France.js'
ec.init(
load= url,
series.param= list(type= 'map', map= 'France', roam= TRUE)
)
We use ec.init() to load the map plugin. We set also
‘series.param’ for series’ parameters type, map and
roam documented here.
No error, but also …no map ??!
The problem is in the map name. In docs
we see that for file ‘china.js’ they use map=‘china’. So by
analogy, it’s easy to set map=‘France’ for ‘France.js’ ?
Actually map name and file name may have nothing in common. We’ll need
to dig inside the JS file to find the exact name.
Open France.js in a text editor and look for
‘registerMap(’. It turns out the name right after is ‘法国’ -
Chinese for ‘France’. Let’s update the code. The map has been already
installed, so we just load it by name (‘file://France.js’). We also add a title.
ec.init( load= 'file://France.js',
title = list(text= 'France'),
series.param = list(type= 'map', map= '法国', roam= TRUE)
)
The map is indeed of France, it’s zoomable and we see the regions
highlighted on hover.
Ok, map part done ✔. Data is next (with some surprises).
Our data
page shows a blue table. Source code inspection reveals a data table
and we’ll use library rvest to extract it.
library(rvest)
furl <- 'https://www.ined.fr/en/everything_about_population/data/france/population-structure/regions/'
wp <- read_html(furl)
wt <- wp %>% html_node('#para_nb_1 > div > div > div > table') %>% html_table(header=TRUE)
wt
## # A tibble: 14 × 5
## `` `Census 1990` `Census 1999` `January 1st 2008` `January 1st 2024 (p)`
## <chr> <chr> <chr> <chr> <chr>
## 1 Auverg… 6 668 168 6 949 608 8 235 923 8 197 325
## 2 Bourgo… 2 705 826 2 728 086 2 791 719 2 786 296
## 3 Bretag… 2 794 317 2 904 075 3 453 023 3 429 882
## 4 Centre… 2 369 808 2 440 295 2 573 295 2 572 278
## 5 Corse 249 645 260 152 355 528 351 255
## 6 Grand … 5 274 064 5 387 509 5 568 711 5 562 262
## 7 Hauts-… 5 770 671 5 855 448 5 983 823 5 980 697
## 8 Île-de… 10 644 665 10 946 012 12 419 961 12 358 932
## 9 Norman… 3 126 859 3 202 449 3 327 077 3 317 023
## 10 Nouvel… 5 114 287 5 257 954 6 154 772 6 110 365
## 11 Occita… 4 546 249 4 842 680 6 154 729 6 101 005
## 12 Pays d… 3 055 197 3 219 960 3 926 389 3 907 426
## 13 Proven… 4 257 244 4 502 385 5 198 011 5 160 091
## 14 France… 56 577 000 58 496 613 66 142 961 65 834 837
We’ll have to do some cleanup, like rename columns, remove all spaces
and the summary row. Then try adding the data to the series.
As you can see, we are using ec.data() for data conversion from
data.frame to a list. Each row becomes a sublist with name and
value. Name is the region name, and value is the number of
people (ppl).
Added also a visualMap which will color the regions depending
on their values (population).
library(rvest)
wp <- read_html(furl)
wt <- wp %>% html_node('#para_nb_1 > div > div > div > table') %>% html_table(header=TRUE)
names(wt) <- c('region','v1','v2','v3','ppl') # rename columns
wt <- wt[-nrow(wt),] # delete summary row, contaminates color values
wt$ppl <- as.numeric(gsub('[^\x01-\x7f]', '', wt$ppl)) # remove weird spaces
ec.init(load='file://France.js',
title= list(text= 'France'),
series.param= list(type='map', map='法国', roam=TRUE,
data= lapply(ec.data(wt, 'names'),
function(x) list(name= x$region, value= x$ppl))
),
visualMap= list(type= 'continuous', calculable= TRUE, max= max(wt$ppl))
)
Ok, there is some color, but why most of the regions are blank?
It’s again a data problem. The region names from the map and those from
the web page do not match completely. It’s more difficult to change the
map, so we’ll update the wt data.frame instead. To replace
region names, lets use conditional mutate from
dplyr.
The visualMap is enhanced with a formatter.
It shows the visualMap values as formatted integers. Sometimes,
like in our case, formatters are JS code that needs to be wrapped in
htmlwidgets::JS() so it can be sent to ECharts for execution.
Other template
formatters are just strings like “{a}: {c}”.
Note also how the max parameter is set. Without it the color
range would be out of sync.
wp <- read_html(furl)
wt <- wp %>% html_node('#para_nb_1 > div > div > div > table') %>% html_table(header=T)
names(wt) <- c('region','v1','v2','v3','ppl') # rename columns
wt$ppl <- as.numeric(gsub(' ','', wt$ppl)) # remove weird(binary) spaces
wt <- wt[-nrow(wt),] # delete summary row, contaminates color values
wt <- wt %>% mutate(region = case_when(
region=='Grand Est' ~'Alsace–Champagne-Ardenne–Lorraine',
region=='Nouvelle Aquitaine' ~'Aquitaine-Limousin-Poitou-Charentes',
region=='Bretagne' ~'Brittany',
region=='Île-de-France' ~'Ile-de-France',
region=='Occitanie' ~'Languedoc-Roussillon-Midi-Pyrénées',
region=='Hauts-de-France' ~'Nord-Pas-de-Calais and Picardy',
region=='Normandie' ~'Normandy',
region=='Centre - Val de Loire' ~'Centre-Val de Loire',
region=='Corse' ~'Corsica',
region=='Provence-Alpes-Côte d’Azur' ~"Provence-Alpes-Côte d'Azur",
region=='Bourgogne- Franche-Comté' ~'Bourgogne-Franche-Comté',
TRUE ~ region))
url <- 'https://raw.githubusercontent.com/echarts-maps/echarts-countries-js/master/echarts-countries-js/France.js'
ec.init( load= url,
title= list(text='France Population (current)'),
backgroundColor= 'whitesmoke', tooltip= list(show=T),
series.param= list(type='map', map='法国', roam=TRUE,
data= lapply(ec.data(wt, 'names'), function(x) list(name= x$region, value= x$ppl))
),
visualMap= list(type= 'continuous', calculable= TRUE,
max= max(wt$ppl), min= min(wt$ppl), formatter= ec.clmn('%L@', -1))
)
So here is the final result - a nice map with pan/zoom and value coloring.