library(readxl)
library(sf)
library(packcircles)
library(magick)
Le cartogramme par points – The Dot Cartogram
Ce document technique accompagne l’article intitulé “Le cartogramme par points – The Dot cartogram” de Françoise Bahoken et Nicolas Lambert. Il propose une collection de “cartogrammes par points” réalisés en langage R à partir de données de population et de richesse à l’échelle mondiale. Pour assurer la traçabilité et la reproductibilité, les codes sources (R) sont détaillés tout au long du document.
Les données
Toutes les cartes construites dans cette publication sont basées sur les données de la base de données du projet Maddison 2018. Cette base de données réalisée pa Jutta Bolt, Robert Inklaar, Herman de Jong et Jan Luiten van Zanden est sous licence Creative Commons Attribution 4.0 International License. Toute la documentation est disponible sur le site web. Les géométries utilisées proviennnet du projet Magrit et de la base de données Natural Earth.
Packages
Import et mise en forme
Import de données
= data.frame(read_excel("data/mpd2020.xlsx", sheet = "Full data"))
maddison <- maddison[maddison$year>=1950,]
maddison $gdp <- maddison$gdppc * maddison$pop / 1000000 maddison
Import des géométries
<- st_read("data/world_countries_data.shp", quiet = TRUE )
countries <- countries[,c("ISO3", "NAMEen", "NAMEfr","geometry")]
countries colnames(countries) <- c("id", "NAMEen", "NAMEfr","geometry")
Graticule & sphère
<- st_read("data/ne_110m_wgs84_bounding_box.shp", quiet = TRUE )
sphere <- st_read("data/ne_110m_graticules_20.shp", quiet = TRUE ) graticule
Projection
<- "+proj=robin +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"
crs <- st_transform(countries, crs)
countries <- st_transform(graticule, crs)
graticule <- st_transform(sphere, crs) sphere
Le cas du Soudan
<- c("SSD", "SDN")
l <- data.frame(id = "SDN", NAMEen = "Sudan (former)", NAMEfr = "Soudan")
df <- st_union(st_geometry(countries[countries$id %in% l,]))
geom <- st_as_sf(geometry = geom, df)
SDN <- countries[!countries$id %in% l,]
countries <- rbind(countries,SDN) countries
Le cas de la Tchécoslovaquie
<- c("SVK","CZE")
l <- data.frame(id = "CSK", NAMEen = "Czechoslovakia", NAMEfr = "Tchécoslovaquie")
df <- st_union(st_geometry(countries[countries$id %in% l,]))
geom <- st_as_sf(geometry = geom, df)
CSK <- rbind(countries,CSK) countries
Le cas de la Yougolslavie
<- c("SVN","HRV","BIH","SRB", "MNE","MKD","KOS")
l <- data.frame(id = "YUG", NAMEen = "Former Yugoslavia", NAMEfr = "Ex-Yougoslavie")
df <- st_union(st_geometry(countries[countries$id %in% l,]))
geom <- st_as_sf(geometry = geom, df)
YUG <- rbind(countries,YUG) countries
L’union soviétique
<- c("RUS","UKR","BLR","MDA","UZB","KAZ","KGZ","TJK",
l "TKM","GEO","AZE","ARM","LTU","LVA","EST")
<- data.frame(id = "SUN", NAMEen = "Former USSR", NAMEfr = "URSS")
df <- st_union(st_geometry(countries[countries$id %in% l,]))
geom <- st_as_sf(geometry = geom, df)
SUN <- rbind(countries,SUN) countries
Le monde de 1950 à 1991.
= c("SVK", "CZE", "RUS", "UKR", "BLR", "MDA", "UZB","KAZ",
l1 "KGZ", "TJK", "TKM", "GEO", "AZE", "ARM", "LTU", "LVA",
"EST","SVN","HRV", "BIH", "SRB","MNE", "MKD", "KOS")
<- countries[!countries$id %in% l1,] world1
Le monde en 1992.
= c("CSK", "YUG","RUS", "UKR", "BLR", "MDA","UZB", "KAZ",
l2 "KGZ", "TJK", "TKM", "GEO", "AZE", "ARM", "LTU", "LVA",
"EST")
<- countries[!countries$id %in% l2,] world2
Le monde de 1993 à 2018.
= c("CSK", "SUN", "YUG")
l3 <- countries[!countries$id %in% l3,] world3
Données manquantes
= c("ATA","AND", "ATG", "BHS", "BLZ", "BRN", "BTN", "ERI", "FJI", "FLK", "FRO",
l "FSM", "GGY", "GRD", "GRL", "GUY", "IMN", "JEY", "KIR", "KNA", "LIE", "MAC",
"MCO", "MDV", "MHL", "NCL", "NRU", "PLW", "PNG", "SAH", "SLB", "SMR", "SOM",
"SSD", "SUR", "TLS", "TON", "TUV", "VAT", "VCT", "VUT", "WSM")
<- countries[countries$id %in% l,] missing
Dossiers
Création de dossiers pour enregistrer les cartes.
if (!file.exists("maps")){
dir.create("maps")
}
if (!file.exists("tmp")){
dir.create("tmp")
dir.create("tmp/gdp")
dir.create("tmp/pop")
}
Fonctions utiles
Charte graphique (couleurs)
<- "#ebeced"
background <- "#b1cbe6"
water <- "#e0d98b"
land <- "#de4e37"
red <- "#406dc7" blue
Fonction pour créer un template cartographique
<- function(year, title){
template
if (year <= 1991){basemap <- world1}
if (year == 1992){basemap <- world2}
if (year >= 1993){basemap <- world3}
<- 1000000
d <- 500000
dd = c(st_bbox(sphere)[1] +d , st_bbox(sphere)[3] - d)
xlim = c(st_bbox(sphere)[2] + dd, st_bbox(sphere)[4] + dd)
ylim par(mar = c(0,0,0,0), bg = background)
plot(st_geometry(sphere), col = water, border = NA, xlim = xlim, ylim = ylim)
plot(st_geometry(graticule), col = "white", lwd = 0.5, lty = 3, add = T)
plot(st_geometry(basemap) + c(25000, -25000), col ="#00000010", border = NA, add = T)
plot(st_geometry(basemap) + c(50000, -50000), col ="#00000010", border = NA, add = T)
plot(st_geometry(basemap) + c(75000, -75000), col ="#00000010", border = NA, add = T)
plot(st_geometry(basemap) + c(100000, -100000), col ="#00000010", border = NA, add = T)
plot(st_geometry(basemap), col = land, border = "white", lwd = 0.3, add= T)
plot(st_geometry(missing), col = "#FFFFFF80", border = NA, add= T)
plot(st_geometry(sphere), col = NA, border = "#42495c", lwd = 1, add = T)
text(x= 0, y = st_bbox(sphere)[4] + 300000, title , cex = 1.8, pos = 3, font = 2,
col = "#283445")
text(x= 0, y = st_bbox(sphere)[2] - 300000,
paste0("Source: Maddison Project Database, version 2020. ",
"Map designed by N. Lambert & F. Bahoken, 2021."),
cex = 0.6, col = "#283445")
}
Function pour récupérer les centroides et des informations utiles.
<- function(var,year){
getcentroids if (year <= 1991){x <- world1}
if (year == 1992){x <- world2}
if (year >= 1993){x <- world3}
<- merge(x, maddison[maddison$year == year,], by.x = "id", by.y = "countrycode")
x st_geometry(x) <- st_centroid(sf::st_geometry(x),of_largest_polygon = TRUE)
<- data.frame(x$id, x[var], st_coordinates(x))
x <- x[,c("x.id","X","Y",var)]
x colnames(x) <- c("id","x","y","v")
<- x[!is.na(x$v),]
x
# move the USSR centroid to RUS centroid
if (year < 1993){
$id =="SUN",]$x <- 7278988.16
x[x$id =="SUN",]$y <- 6402700.62
x[x
}
return(x)
}
Calibration de la taille.
<- 1400000
rmax <- getcentroids("pop", 2018)
x <- rmax * rmax /max(x$v)
kpop <- getcentroids("gdp", 2018)
x <- rmax * rmax /max(x$v) kgdp
Légende
<- function(x, var, pos = NULL, col = "#FFFFFF00",
legend border = "#283445",lwd = 1, values.cex = 0.6,
values.round = 0, lty = 3, nb.circles = 4,
title.txt = "Title of the legend",
title.cex = 0.8,
title.font = 2) {
# Radii & Values
<- x
v st_geometry(v) <- NULL
<- v[,var]
v <- sqrt(as.numeric(st_area(x))/pi)
r <- seq(from = max(r), to = min(r), length.out = nb.circles)
radii <- radii * radii * pi
sle <- sle * max(v) / sle[1]
values
# Positions
par()$usr
<- (par()$usr[2] - par()$usr[1]) / 50
delta if(length(pos) != 2){
<- c(par()$usr[1] + radii[1] + delta,par()$usr[3] + delta)
pos
}
# Circles
for(i in 1:nb.circles){
# circles
<- pos[1]
posx <- pos[2] + radii[i]
posy <- st_sfc(st_point(c(posx,posy)))
p <- st_buffer(st_as_sf(p), dist = radii[i])
circle plot(circle, col = col, border = border, lwd=lwd, add=T)
# lines
segments(posx, posy + radii[i], posx + radii[1] + radii[1]/10,
col = border, lwd=lwd, lty = lty)
# texts
text(x = posx + radii[1] + radii[1]/5, y = posy + radii[i],
labels = formatC(round(values[i],values.round),
big.mark = " ", format = "fg", digits = values.round),
adj = c(0,0.5), cex = values.cex)
}
# Title
text(x = posx - radii[1] ,
y = posy + radii[1]*2 + radii[1]/3, title.txt,
adj = c(0,0), cex = title.cex,
font = title.font, col ="#283445")
}
Template cartographique
<- "maps/maptemplate.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
template(year = 2018, title = "Template cartographique")
dev.off()
}
png
2
Centroïdes
<- function(var = "pop", year = 2018, col = red, r = 10,
drawcentroids title = "Map Title"){
<- getcentroids(var, year)
x <- st_buffer(sf::st_as_sf(x, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = r)
template(year = year, title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
}
<- "maps/centroids.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
drawcentroids(var = "pop",year = 2018, r = 75000, col = "black",
title = "Centroïdes des pays dont les données sont disponibles, 2018")
dev.off()
}
png
2
Symboles proportionnels
NB : Même si cela aurait été plus facile, le choix a été fait ici de ne pas utiliser le [package cartography] (https://cran.r-project.org/web/packages/cartography/index.html) afin d’exploiter au mieux les fonctionnalités de base de R. L’objectif est d’avoir une très grande comparabilité entre les cartes.
<- function(var = "pop", year = 2018, k = 1, col = red,
propsymbols title = "Map Title", leg.title = "Legend"){
<- getcentroids(var, year)
x <- x[order(x$v, decreasing = TRUE),]
x $r <- sqrt(x$v * k)
x<- st_buffer(sf::st_as_sf(x, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = x$r)
template(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
legend(x = circles, var = "v", pos =c(-12000000,-5000000), title.txt = leg.title)
}
<- "maps/propsymbolspop2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
propsymbols(var = "pop",year = 2018, k = kpop, col = blue,
title = "Population mondiale par symboles proportionnels en 2018",
leg.title = "Population (en hab.)")
dev.off()
}
png
2
<- "maps/propsymbolsgdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
propsymbols(var = "gdp",year = 2018, k = kgdp, col = red,
title = "PIB mondial par symboles proportionnels en 2018",
leg.title = "PIB en milliards (US$ 2011)")
dev.off()
}
png
2
Carte par points
<- function(var = "pop", year = 2018, onedot = 1, radius = 1,
dotdensitymap col = red, title = "Map Title", unit =""){
if (year <= 1991){x <- world1}
if (year == 1992){x <- world2}
if (year >= 1993){x <- world3}
<- merge(x, maddison[maddison$year == year,], by.x = "id",
x by.y = "countrycode")
<- x[,c("id",var,"geometry")]
x "v"] <- round(x[,var] %>% st_drop_geometry() /onedot,0)
x[,<- st_sample(x, x$v, type = "random", exact = TRUE)
dots <- st_buffer(dots, dist = radius)
circles
template(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add = T)
text(x= 0, y = -6000000, paste0("1 point = ",onedot, " ",unit),
cex = 1.1, pos = 3, font = 2, col = col)
}
<- "maps/dotdensitypop2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotdensitymap(var = "pop", year = 2018, onedot = 10000, radius = 100000,
col = blue, title = "Population mondiale, 2018", unit ="hab.")
dev.off()
}
png
2
<- "maps/dotdensitygdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotdensitymap(var = "gdp", year = 2018, onedot = 100, radius = 100000,
col = red, title = "PIB mondial, 2018", unit ="milliards $")
dev.off()
}
png
2
Cartogramme de Dorling
<- function(var = "pop", year = 2018, k = 1, itermax = 10,
dorling col = red, title = "Map Title", leg.title ="Legend"){
<- getcentroids(var, year)
x
<- x[,c("x","y","v")]
dat.init $v <- sqrt(dat.init$v * k)
dat.init<- circleRepelLayout(x = dat.init, xysizecols = 1:3,
simulation wrap = FALSE, sizetype = "radius",
maxiter = itermax, weights =1)$layout
<- st_buffer(sf::st_as_sf(simulation, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = simulation$radius)
$v = x$v
circlestemplate(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
legend(x = circles, var = "v", pos =c(-12000000,-5000000), title.txt = leg.title)
}
<- "maps/drolingpop2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dorling(var = "pop",year = 2018, k = kpop, itermax = 10, col = blue,
title = "Population mondiale par cartogrammes de Dorling, 2018",
leg.title = "Population (en hab.)")
dev.off()
}
png
2
<- "maps/drolinggdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dorling(var = "gdp",year = 2018, k = kgdp, itermax = 10, col = red,
title = "Richesse mondiale par cartogrammes de Dorling Cartogram, 2018",
leg.title = "PIB en milliards (2011 US$)")
dev.off()
}
png
2
Cartogramme par points
<- function(var = "pop", year = 2018, itermax = 10,
dotcartogram onedot = 1, radius = 1, col = red,
title = "Map Title", unit = ""){
<- getcentroids(var, year)
x $v <- round(x$v/onedot,0)
x<- x[x$v > 0,]
x
<- x[x$v == 1,c("x","y","v")]
dots <- x[x$v > 1,c("x","y","v")]
rest
<- nrow(rest)
nb for (i in 1:nb){
<- rest[i,]
new $v <- 1
newfor (j in 1:rest$v[i]){ dots <- rbind(dots,new)}
}
$x <- jitter(dots$x)
dots$y <- jitter(dots$y)
dots$v <- radius
dots
<- circleRepelLayout(x = dots, xysizecols = 1:3,
simulation wrap = FALSE, sizetype = "radius",
maxiter = itermax, weights =1)$layout
<- st_buffer(sf::st_as_sf(simulation, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = radius)
template(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
text(x= 0, y = -6000000, paste0("1 point = ",onedot, " ",unit), cex = 1.1, pos = 3, font = 2,
col = col)
}
<- "maps/dotcartogrampop2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram(var = "pop",year = 2018, itermax = 70, onedot = 10000,
radius = 100000, col = blue,
title = "Cartogramme par points de la population mondiale en 2018", unit = "hab.")
dev.off()
}
png
2
<- "maps/dotcartogramgdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram(var = "gdp",year = 2018, itermax = 70, onedot = 100,
radius = 100000, col = red,
title = "Dodge Dotmap du PIB mondial en 2018", unit = "milliards $")
dev.off()
}
png
2
Bien sûr, nous pouvons modifier la taille et la valeur de chaque point.
<- "maps/dotcartogramgdp2018_v2.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram(var = "gdp",year = 2018, itermax = 100, onedot = 20,
radius = 60000, col = red,
title = "Cartogramme par points du PIB mondial, 2018", unit = "milliards de $")
dev.off()
}
png
2
Cartogramme par points (amélioration)
Ici, nous ajoutons le paramètre “position” à la fonction dotcartogram afin que les points puissent être disposés de manière régulière ou aléatoire à l’intérieur des pays, et non plus seulement répartis à partir du centroïde. Les trois cartes suivantes vous permettent de visualiser l’effet de ce paramètre.
<- function(var = "pop", year = 2018, itermax = 10,
dotcartogram2 onedot = 1, position = "center", radius = 1, col = red,
title = "Map Title", unit = ""){
if (position %in% c("regular","random")){
if (year <= 1991){x <- world1}
if (year == 1992){x <- world2}
if (year >= 1993){x <- world3}
<- merge(x, maddison[maddison$year == year,], by.x = "id",
x by.y = "countrycode")
<- x[,c("id",var,"geometry")]
x "v"] <- round(x[,var] %>% st_drop_geometry() /onedot,0)
x[,= x[x$v > 0,]
x <- st_sample(x, x$v, type = position, exact = TRUE)
dots <- data.frame(st_coordinates(dots),radius)
dots colnames(dots) <- c("x","y","v")
}
if (position == "center"){
<- getcentroids(var, year)
x $v <- round(x$v/onedot,0)
x<- x[x$v > 0,]
x
<- x[x$v == 1,c("x","y","v")]
dots <- x[x$v > 1,c("x","y","v")]
rest
<- nrow(rest)
nb for (i in 1:nb){
<- rest[i,]
new $v <- 1
newfor (j in 1:rest$v[i]){ dots <- rbind(dots,new)}
}
$x <- jitter(dots$x)
dots$y <- jitter(dots$y)
dots$v <- radius
dots
}
<- circleRepelLayout(x = dots, xysizecols = 1:3,
simulation wrap = FALSE, sizetype = "radius",
maxiter = itermax, weights =1)$layout
<- st_buffer(sf::st_as_sf(simulation, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = radius)
template(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
text(x= 0, y = -6000000, paste0("1 point = ",onedot, " ",unit), cex = 1.1, pos = 3, font = 2,
col = col)
}
Position = “center”
<- "maps/center_dotcartogramgdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram2(var = "gdp",year = 2018, itermax = 100, onedot = 60,
radius = 80000, col = red,
position = "center",
title = "Cartogramme par points du PIB (centre)",
unit = "milliards de $")
dev.off()
}
png
2
Carte avec position = “random”
<- "maps/random_dotcartogramgdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram2(var = "gdp",year = 2018, itermax = 100, onedot = 60,
radius = 80000, col = red,
position = "random",
title = "Cartogramme par points du PIB (aléatoire)",
unit = "milliards de $")
dev.off()
}
png
2
Position = “regular”
<- "maps/regular_dotcartogramgdp2018.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram2(var = "gdp",year = 2018, itermax = 100, onedot = 60,
radius = 80000, col = red,
position = "regular",
title = "Cartogramme par points du PIB (régulier)",
unit = "milliards de $")
dev.off()
}
png
2
Variation 1
Dans cette variante, nous proposons de colorer les points en fonction d’une donnée quantitative relative : le pib par habitant. Pour faire simple, et parce que ce point particulier n’est pas central ici, nous utilisons dans ce cas le package mapsf.
library(mapsf)
= "gdp"
var = 2018
year = 100
itermax = 50
onedot = 90000
radius <- c("#ffffb2","#fed976","#feb24c","#fd8d3c","#f03b20","#bd0026")
cols = "La richesse dans le monde en 2018"
title = "milliards de $"
unit <- "maps/dodgeratio.png"
file
if (!file.exists(file)){
<- getcentroids(var, year)
x $v <- round(x$v/onedot,0)
x<- x[x$v > 0,]
x
<- merge(x, maddison[maddison$year == year,], by.x = "id", by.y = "countrycode")
x <- x[,c("x","y","v","gdppc")]
x colnames(x) <- c("x","y","v","s")
<- x[x$v == 1,c("x","y","v","s")]
dots <- x[x$v > 1,c("x","y","v","s")]
rest <- nrow(rest)
nb for (i in 1:nb){
<- rest[i,]
new $v <- 1
newfor (j in 1:rest$v[i]){ dots <- rbind(dots,new)}
}
$x <- jitter(dots$x)
dots$y <- jitter(dots$y)
dots$v <- radius
dots
<- circleRepelLayout(x = dots, xysizecols = 1:3,
simulation wrap = FALSE, sizetype = "radius",
maxiter = itermax, weights =1)$layout
$s <- dots$s
simulation
<- st_buffer(sf::st_as_sf(simulation, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = radius)
png(file, width = 2000, height = 1120, res = 150)
template(year = year, title = title)
mf_map(x = circles, var = "s", type = "choro", pal = cols,
breaks = "quantile", nbreaks = 6, leg_val_rnd = 0,
leg_pos = c(-13000000, -1000000), leg_title = "PIB par habitant (en $)",
add = TRUE)
text(x= 0, y = -6000000, paste0("1 point = ",onedot, " ",unit), cex = 1.1, pos = 3, font = 2,
col = red)
dev.off()
}
png
2
Variation 2
Ici, nous proposons une autre alternative où le nombre de points dans chaque pays est le même. C’est le paramètre qui est fixé. Par conséquent, la surface des cercles à l’intérieur des pays est modifiée pour refléter les quantités. Ci-dessous, nous décidons d’avoir 50 points par pays.
<- function(var = "pop", year = 2018, itermax = 10,
dotcartogram4 divide = 4, k = 1, col = red,
title = "Map Title", legtitle = "Legend"){
<- getcentroids(var, year)
x <- x[x$v > 0,c("x","y","v")]
x
<- x
dots for (i in 1:(round(divide) - 1)){
<- rbind(dots,x)
dots
}
$x <- jitter(dots$x)
dots$y <- jitter(dots$y)
dots$v <- sqrt(dots$v/divide * k)
dots
<- circleRepelLayout(x = dots, xysizecols = 1:3,
simulation wrap = FALSE, sizetype = "radius",
maxiter = itermax, weights =1)$layout
<- st_buffer(sf::st_as_sf(simulation, coords =c('x', 'y'),
circles crs = sf::st_crs(sphere)), dist = simulation$radius)
#legend(x = circles, var = "v", pos =c(-12000000,-5000000), title.txt = legtitle)
template(year = year, title = title)
plot(st_geometry(circles), col = col, border= "#283445", lwd = 0.5, add= T)
}
<- "maps/dotcartogrampop2018_alter.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram4(var = "pop",year = 2018, k = kpop, itermax = 20, divide = 50, col = blue,
title = "Population mondiale, en 2018 (divide = 50)", legtitle = "Nombre d'habitants")
dev.off()
}
png
2
<- "maps/dotcartogramgdp2018_alter.png"
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram4(var = "gdp",year = 2018, k = kgdp, itermax = 20, divide = 50, col = red,
title = "PIB mondial en 2018 (divide = 50)", legtitle = "PIB (en $)")
dev.off()
}
png
2
Timelines
PIB de 1950 à 2018.
for (year in 1950:2018){
<- paste0("tmp/gdp/gdp_",year,".png" )
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram(var = "gdp",year = year, itermax = 100, onedot = 40,
radius = 75000, col = red,
title = paste0("Richesse mondiale en ", year), unit = "milliards de $")
dev.off()
}
}
png -> gif
<- "maps/gdp.gif"
file if (!file.exists(file)){
<- paste0("tmp/gdp/",list.files("tmp/gdp"))
frames <- image_read(frames)
m <- image_animate(m)
m image_write(m, file)
}
Population de 1950 à 2018.
for (year in 1950:2018){
<- paste0("tmp/pop/pop_",year,".png" )
file
if (!file.exists(file)){
png(file, width = 2000, height = 1120, res = 150)
dotcartogram(var = "pop",year = year, itermax = 100, onedot = 4000,
radius = 75000, col = blue,
title = paste0("Population mondiale en ", year), unit = "hab.")
dev.off()
}
}
png -> gif
<- "maps/pop.gif"
file if (!file.exists(file)){
<- paste0("tmp/pop/",list.files("tmp/pop"))
frames <- image_read(frames)
m <- image_animate(m)
m image_write(m, file)
}
Comparaison Dorling / Cartogramme par points
<- "maps/pop_transform.gif"
file if (!file.exists(file)){
<- c("maps/drolingpop2018.png", "maps/dotcartogrampop2018.png")
frames <- image_read(frames)
m <- image_animate(m, fps = 2)
m image_write(m, file)
}
<- "maps/gdp_transform.gif"
file if (!file.exists(file)){
<- c("maps/drolinggdp2018.png","maps/dotcartogramgdp2018.png")
frames <- image_read(frames)
m <- image_animate(m, fps = 2)
m image_write(m, file)
}
Addendum
La méthode est également disponible en javascript avec la bibliothèque D3.js. Le code est disponible ici et le résultat est affiché ci-dessous.
La méthode est également implémentée dans la bibliothèque JavaScript bertin
. Voir : @neocartocnrs/bertin-js-dots-cartograms