Le défi #30DayMapChallenge a été lancé par Topi Tjukanov sur Twitter. Il est ouvert à tous ceux qui souhaitent afficher une carte, quel que soit le logiciel. Dans ce billet de blog, je vais montrer des cartes réalisées avec R. Je m’ajoute des contraintes pour le plaisir. Cette semaine, j’utiliserai {tmap} pour créer les cartes.
Cet article suis celui de la semaine dernière : #30DayMapChallenge: 30 jours de création de cartes (1) - ggplot2
Packages
library(dplyr)
library(sf)
library(raster)
library(readr)
library(tmap)
library(xml2)
library(purrr)
# remotes::install_github("tylermorganwall/rayshader")
library(rayshader)
## Customize
my_blue <- "#1e73be"
# Test for font family
# extrafont::font_import(prompt = FALSE)
font <- extrafont::choose_font(c("Nanum Pen", "Lato", "sans"))
Données : Transformer la France en une grille régulière d’hexagones
- Récupérer les données du monde dans le package {tmap}
- Récupérer la couche spatiale de la France
- Transformer la France en une grille régulière d’hexagones
# extraWD <- "." # Uncomment for the script to work
data(World)
# Read shapefile "Departement.shp"
France_L93 <- st_read(file.path(extraWD, "DEPARTEMENT.shp"), quiet = TRUE)
# Transform as hex polygon grid
#' @param x a sf object
transform_to_hex <- function(x) {
x %>%
st_make_grid(what = "polygons", square = FALSE,
n = c(40, 20)) %>%
st_sf() %>%
mutate(id_hex = 1:n()) %>%
dplyr::select(id_hex, geometry)
}
France_hex <- transform_to_hex(France_L93)
tm_shape(France_hex) +
tm_fill(col = my_blue) +
tm_borders(col = "grey80") +
tm_legend(
title = "France map transformed as hexagonal grid"
)
Vert : Dessiner une grille régulière d’hexagones avec {tmap}
Maintenant que j’ai accès aux jeux de données OpenDataSoft, je vais tricher un peu sur le défi et l’utiliser pour mes cartes suivantes. Qu’est-ce qui pourrait être vert ? La pharmacie est un bon candidat.
Comme je vais utiliser à nouveau le code pour transformer les données OSM en fichiers spatialisés pour le prochain défi, je peux transformer ce code en fonction.
#' @param amenity Character. An amenity.
#' @param file_amenity path to where to save downloaded data
#' @param hex Hexagonal polygon grid
get_and_sf <- function(amenity, file_amenity, hex) {
if (!file.exists(file_amenity)) {
# devtools::install_github("tutuchan/fodr")
# portal <- fodr::fodr_portal("ods")
poi <- fodr::fodr_dataset("ods", "points-dinterets-openstreetmap-en-france")
# Get amenity
amenity <- poi$get_records(refine = list(amenity = amenity))
amenity_chr <- amenity %>%
dplyr::select(-geo_shape, -other_tags)
write_csv(amenity_chr, file_amenity)
} else {
amenity_chr <- read_csv(file_amenity)
}
amenity_sf_l93 <- amenity_chr %>%
st_as_sf(coords = c("lng", "lat"), crs = 4326) %>%
st_transform(crs = 2154)
# Join amenity wth hex and count
amenity_hex_l93 <- st_join(amenity_sf_l93, hex)
amenity_hex_count <- amenity_hex_l93 %>%
st_drop_geometry() %>%
count(id_hex)
# Join hex with bars count
France_hex_amenity <- hex %>%
left_join(amenity_hex_count)
}
C’est une nouvelle semaine, alors ajoutons nous un défi supplémentaire. Cette semaine, je crée des cartes avec {tmap} au lieu de {ggplot2}.
France_hex_pharmacy <- get_and_sf(
amenity = "pharmacy",
file_amenity = file.path(extraWD, "pharmacy.csv"),
hex = France_hex)
tm_shape(France_hex_pharmacy, is.master = TRUE) +
tm_fill(col = "n", palette = "Greens",
style = "quantile",
title = "Number") +
tm_borders(col = "grey80", lwd = 0.5) +
tm_shape(World) +
tm_borders() +
tm_credits("OpenStreetMap - @statnmap",
position = c("RIGHT", "BOTTOM"),
size = 2) +
tm_legend(
main.title = "Number of pharmacy in France",
main.title.color = my_blue
# main.title.size = 1
)
Jaune : Dessiner une grille de points répartis dans une grille hexagonale
La carte précédente n’est pas la plus belle carte que j’aie jamais réalisée… J’utiliserai cette semaine pour aller un peu plus loin dans l’utilisation de {tmap}. Je continue à utiliser les données OpenDataSoft, cette fois avec les données postales, car c’est le défi jaune.
- Les nuances de couleurs ne sont pas la meilleure façon de visualiser les différences. J’utiliserai des centroïdes des hexagones pour créer une carte de points.
- Dans la carte précédente, je ne pouvais pas faire le remplissage des polygones des autres pays européens. C’était parce que la couche utilisée comme master est la carte de France et elle n’a pas la même projection que celle du Monde. La projection à la volée de la carte du monde par {tmap} n’a pas vraiment fonctionné. En cartographie, c’est très souvent un problème de projection ! Retournez lire Initiation à la cartographie avec {sf} & Co. pour en savoir plus. Pour éviter ce problème, j’ai filtré uniquement les pays européens à partir du jeu de données “Monde” et je les ai projetés sur le système de projection de la France. Comme on va zoomer proche de la France, je me le permet…
France_hex_post <- get_and_sf(
amenity = "post_office",
file_amenity = file.path(extraWD, "post_office.csv"),
hex = France_hex)
# Transform as points
France_hexcenter_post <- France_hex_post %>%
st_centroid()
lim.n <- range(France_hexcenter_post$n, na.rm = TRUE)
# Transform to projection of the master map for correct colour fill
Europe <- World %>%
filter(continent == "Europe") %>%
st_transform(crs = st_crs(France_hex_post))
# tmap
tm <- tm_shape(Europe) +
tm_fill(col = "#38424f") +
tm_borders(col = "grey80") +
tm_shape(France_hexcenter_post, is.master = TRUE) +
tm_bubbles(size = "n", col = "#ffff33", alpha = 0.75,
border.col = NA, shape = 20, scale = 3,
title.size = "Number",
legend.size.is.portrait = TRUE) +
tm_credits("OpenStreetMap - {tmap} - @statnmap",
position = c(0.38, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey90") +
tm_layout(
main.title = "Number of recorded post offices in France",
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
# Margin to allow legend
inner.margins = c(0, 0.2, 0, 0),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = "grey60",
legend.title.fontfamily = "Nanum Pen",
legend.title.size = 1.5,
legend.bg.color = "grey80",
legend.bg.alpha = 0.5
)
tmap_save(tm, filename = file.path(extraWD, "yellow.jpg"),
width = 1024, height = 512, units = "px",
dpi = 100)
tm
Noir et Blanc : Ajouter des icônes personnalisées à une carte {tmap}
Cartographions la répartition des administrations fiscales françaises. Les données sont disponibles auprès de Service-public.fr - Annuaire de l’administration - Base de données locales. Ces jeux de données sont stockés sous forme de fichiers XML dans des répertoires différents pour chaque département et des fichiers différents pour chaque bureau.
- Extraction de coordonnées à partir de fichiers XML, à l’aide de {xml2}.
- Extraction de tous les bureaux de tous les départements
- Utilisation d’une carte du monde plus précise de {rnaturalearth} pour remplacer la carte d’Europe utilisée précédemment
# Get data if not already dowloaded ----
data_untared <- file.path(extraWD, "all_20191107")
if (!dir.exists(data_untared)) {
databz2 <- file.path(extraWD, "all_latest.tar.bz2")
download.file(
"http://lecomarquage.service-public.fr/donnees_locales_v2/all_latest.tar.bz2", destfile = databz2)
utils::untar(databz2, exdir = extraWD)
}
# Get data from xml ----
#' Get infos from one xml
#' @param xml_path Path to one xml
#' @return a tibble
get_infos <- function(xml_path) {
# which_tresor <- 1
# xml_path <- tresor[which_tresor]
xml_content <- read_xml(xml_path)
lat <- xml_content %>%
xml_find_first(xpath = ".//Latitude") %>%
xml_double()
long <- xml_content %>%
xml_find_first(xpath = ".//Longitude") %>%
xml_double()
codepostal <- xml_content %>%
xml_find_first(xpath = ".//CodePostal") %>%
xml_text()
nomcommune <- xml_content %>%
xml_find_first(xpath = ".//NomCommune") %>%
xml_text()
tibble(
x = long,
y = lat,
code_postal = codepostal,
nom_commune = nomcommune,
file = basename(xml_path)
)
}
# Get all data from all interesting xml
directory <- file.path(data_untared, "organismes")
all_dpt <- list.dirs(directory, full.names = TRUE, recursive = FALSE)
all_positions <- map_dfr(all_dpt, function(one_dpt) {
interest <- list.files(one_dpt,
pattern = "^tresorerie.*\\.xml$",
full.names = TRUE)
if (length(interest) != 0) {
map_dfr(interest, get_infos)
} else {NULL}
})
# Transform as spatial data
all_positions_sf <- all_positions %>%
filter(!is.na(x) & !is.na(y)) %>%
st_as_sf(coords = c("x", "y"), crs = 4326)
# Transform to projection of the master map for correct colour fill
world_ne <- rnaturalearth::ne_countries(scale = 10 , returnclass = "sf")
tm1 <- tm_shape(world_ne, projection = "wintri") +
tm_fill() +
tm_shape(all_positions_sf) +
tm_symbols(
shape = leaflet::icons(
file.path(extraWD, "Logo_Tresor_public_50x50.png")),
size = 0.1
)
tm1
# Metropolitan France only
all_france_metro <- all_positions_sf %>%
st_transform(st_crs(France_L93)) %>%
st_crop(France_L93)
europe_ne <- world_ne %>%
filter(continent == "Europe")
# Point with the big logo
logo <- st_point(c(100000, 6500000)) %>%
st_sfc(crs = st_crs(France_L93))
# Map
tm2 <- tm_shape(europe_ne) +
tm_borders(col = "grey90") +
tm_shape(France_L93, is.master = TRUE) +
tm_fill(col = "white") +
tm_shape(logo) +
tm_symbols(
shape = tmap_icons(
file.path(extraWD, "Logo_Tresor_public_50x50.png")),
size = 3) +
tm_shape(all_france_metro) +
tm_symbols(
shape = tmap_icons(
file.path(extraWD, "Logo_Tresor_public_50x50.png")),
size = 0.05,
border.col = NA, border.lwd = 0,
alpha = 1
) +
tmap_icons(
file.path(extraWD, "Logo_Tresor_public_50x50.png"),
iconAnchorX = -4, iconAnchorY = 50) +
tm_credits("service-public.fr - {tmap} - @statnmap",
position = c(0.38, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey90") +
tm_layout(
main.title = "Tax offices in France",
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
# Margin to allow legend
inner.margins = c(0, 0.2, 0, 0),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = my_blue #"grey60"
)
tmap_save(tm2, filename = file.path(extraWD, "black_white.jpg"),
width = 1024, height = 512, units = "px",
dpi = 100)
tm2
Elevation : Superposer plusieurs rasters sur une carte avec {tmap}
{tmap} est également très bon pour tracer des jeux de données de type raster. La combinaison de plusieurs fichiers raster est également très simple. Ici, je montre les données d’élévation du département Loire-atlantique par-dessus une carte d’ombrage pour donner une impression 3D.
- Lire le raster d’altitude
- Reprojeter le raster d’altitude. Soyez prudent lorsque vous reprojetez des jeux de données raster, vous recalculez un tout nouveau raster, avec la position des cellules qui a changé par rapport au jeu de données original.
- Calculez la position du soleil pour un point et une date à l’aide de {cartomisc}
remotes::install_github("statnmap/cartomisc")
- Calculer l’ombrage avec {raster}
- Choisir des couleurs de telle sorte qu’on simule une élévation de la mer jusqu’à 10m.
# Reproject
Alti_44_wgs84 <- raster(file.path(extraWD, "Alti_44_L93.tif")) %>%
projectRaster(crs = "+init=epsg:4326")
# Calculate sun position in the center with {cartomisc}
Sun <- cartomisc::sun_position(year = 2019, month = 5, day = 3,
hour = 16, min = 30, sec = 0,
long = mean(bbox(Alti_44_wgs84)[1,]),
lat = mean(bbox(Alti_44_wgs84)[2,])
)
# Calculate hillShade
slope_44_wgs84 <- terrain(Alti_44_wgs84, opt = "slope")
aspect_44_wgs84 <- terrain(Alti_44_wgs84, opt = "aspect")
hillShade_44_wgs84 <- hillShade(
slope = slope_44_wgs84 * 40, aspect = aspect_44_wgs84,
angle = Sun$elevation, direction = Sun$azimuth,
overwrite = TRUE)
# Graph
tm <- tm_shape(France_L93) +
tm_fill("grey90") +
tm_borders(col = "grey20") +
tm_shape(hillShade_44_wgs84, is.master = TRUE) +
tm_raster(
style = "pretty",
palette = "-Greys",
legend.show = FALSE
) +
tm_shape(Alti_44_wgs84) +
tm_raster(
style = "fixed",
palette = c(my_blue, terrain.colors(5)[2:5]),
breaks = c(-120, 10, 25, 40, 55, 120),
alpha = 0.70,
title = "Altitude (m)"
) +
tm_credits("ign.fr - {raster} + {tmap} - @statnmap",
position = c(0.48, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey40") +
tm_layout(
main.title = "Elevation of Loire-atlantique with exagerated 3D",
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
title = " The colorscale chosen fakes\n a sea rise up to 10m...",
title.fontfamily = "Nanum Pen",
# Margin to allow legend
inner.margins = c(0, 0.2, 0.05, 0),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = my_blue, #"grey60",
# Legend
legend.title.color = "grey80",
legend.text.color = "grey80",
legend.position = c("left","bottom")
)
tmap_save(tm, filename = file.path(extraWD, "elevation.jpg"),
width = 1024, height = 512, units = "px",
dpi = 100)
tm
Mouvements : Transformer des points en lignes et animer une carte avec {tmap}
Essayons de me suivre du 1er janvier au 31 décembre 2019. Devinez où j’habite…
- Joindre les couches de trajets avec les positions des villes
- Créez des lignes avec chaque couple de points “début-fin”.
- Dupliquer les points et les lignes pour créer une animation où les lignes précédentes restent à l’écran.
- Créez une carte animée avec {tmap} et
tmap_animation()
. Notez que l’animation doit être définie avec `tm_facets()’ pour chaque couche si nécessaire.
world_ne <- rnaturalearth::ne_countries(scale = 10 , returnclass = "sf")
# Transform to projection of the master map for correct colour fill
europe_ne <- world_ne %>%
filter(continent == "Europe") %>%
st_transform(crs = 2154)
my_move <- readr::read_delim(file.path(extraWD, "movements_train_sr.txt"), delim = ";")
city_position <- readr::read_delim(file.path(extraWD, "city_positions.txt"), delim = ";")
# Transform as spatial data
my_move_sf <- my_move %>%
left_join(city_position, by = "city") %>%
st_as_sf(coords = c("lon", "lat"), crs = 4326) %>%
st_transform(crs = 2154)
# mapview::mapview(my_move_sf)
# Create lines with two points
# _Start
my_move_sf_head <- my_move_sf %>%
head(-1) %>%
mutate(id = 1:n())
# _End
my_move_sf_tail <- my_move_sf %>%
tail(-1) %>%
mutate(id = 1:n())
# Combine head and tail points into lines
my_move_sf_lines <- my_move_sf_head %>%
st_union(my_move_sf_tail, by_feature = TRUE) %>%
filter(id == id.1) %>%
st_cast("LINESTRING")
# Duplicate lines for animation
max.frames <- nrow(my_move_sf) - 1
my_move_sf_lines_dup <- my_move_sf_lines %>%
mutate(
frames = map2(id, max.frames, ~(.x:.y))
) %>%
tidyr::unnest(frames) %>%
dplyr::select(id, frames, everything())
# Cities duplicated for animation
my_move_sf_dup <- my_move_sf %>%
mutate(
id = c(1, 1:(n()-1)), #same id for first two
frames = map2(id, max.frames, ~(.x:.y))
) %>%
tidyr::unnest(frames) %>%
dplyr::select(id, frames, everything())
# Plot
tm <- tm_shape(europe_ne) +
tm_fill() +
tm_borders(col = "grey10") +
tm_shape(my_move_sf_dup, is.master = TRUE) +
tm_dots(alpha = 0.25, size = 2) +
# facets for animation for this shpae
tm_facets(along = "frames", free.coords = FALSE,
free.scales = FALSE) +
tm_shape(my_move_sf_lines_dup) +
tm_lines(#lwd = "size",
alpha = 0.75,
scale = 4,
col = "id",
palette = "-viridis",
title.col = "Trip number") +
# facets for animation for this shpae
tm_facets(along = "frames", free.coords = FALSE,
free.scales = FALSE) +
tm_credits("ign.fr - {raster} + {tmap} - @statnmap",
position = c(0.48, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey40") +
tm_layout(
main.title = paste("My", nrow(my_move_sf), "movements in 2019"),
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
title.fontfamily = "Nanum Pen",
# Margin to allow legend
inner.margins = c(0.15, 0.15, 0.15, 0.15),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = my_blue, #"grey60",
# Legend
legend.title.color = "grey80",
legend.text.color = "grey80",
legend.position = c("left", "center")
)
# Animation
tmap_animation(tm,
filename = file.path(extraWD, "movements.gif"),
width = 512, height = 512,# units = "px",
dpi = 100, delay = 40)
system(paste('mogrify -fuzz 10% -layers Optimize', file.path(extraWD, "movements.gif")))
#
# tmap_save(tm, filename = file.path(extraWD, "movements.jpg"),
# width = 512, height = 512, units = "px",
# dpi = 100)
Routes : Changer l’épaisseur des lignes avec {tmap}
Une autre façon d’explorer mes mouvements est de mettre en évidence les voies ferrées les plus utilisées.
- Créez un ID unique pour chaque chemin, quelle que soit la direction du trajet.
- Comptez le nombre de fois où chaque voie a été utilisée.
- Créez une carte avec des lignes spatiales dont la largeur dépend de l’utilisation de la voie.
- Ajouter des points avec une couleur en fonction du nombre d’arrêts
# count tracks
my_tracks_count <- my_move_sf_lines %>%
mutate(
unique_id = map2_chr(
city, city.1,
~paste(range(.x, .y), collapse = "-"))
) %>%
count(unique_id, sort = TRUE)
# count cities
my_cities_count <- my_move_sf %>%
count(city, sort = TRUE)
# Plot
tm <- tm_shape(europe_ne) +
tm_fill() +
tm_borders(col = "grey10") +
tm_shape(my_cities_count, is.master = TRUE) +
tm_symbols(col = "n", size = 2,
style = "pretty", n = 5,
title.col = "Stop count") +
tm_shape(my_tracks_count) +
tm_lines(lwd = "n",
scale = 8,
title.lwd = "Trip Count") +
tm_credits("ign.fr - {raster} + {tmap} - @statnmap",
position = c(0.48, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey40") +
tm_layout(
main.title = paste("The", nrow(my_tracks_count), "different tracks I used in 2019"),
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
title.fontfamily = "Nanum Pen",
# Margin to allow legend
inner.margins = c(0.15, 0.15, 0.15, 0.15),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = my_blue, #"grey60",
# Legend
legend.title.color = "grey80",
legend.text.color = "grey80",
legend.position = c("left", "top")
)
tmap_save(tm, filename = file.path(extraWD, "tracks.jpg"),
width = 1024, height = 512, units = "px",
dpi = 100)
tm
Frontières : Transformer des polygones en raster et utiliser {rayshader}
Essayons de jouer avec {rayshader}. J’utilise les frontières des départements français comme des murs.
- Transformer les polygones en lignes
- Union de toutes les lignes en une seule
- Créer une zone tampon autour des lignes
- Rastériser les zones tampons
- Passer dans {rayshader} !
- Retransformer en raster géographique
- Tracez avec {tmap} parce que c’est la semaine {tmap} !
France_L93_linespolygons <- France_L93 %>%
st_simplify(preserveTopology = TRUE, dTolerance = 1000) %>%
st_cast("MULTILINESTRING") %>%
st_union() %>%
st_simplify(preserveTopology = TRUE, dTolerance = 9000) %>%
st_buffer(dist = units::set_units(5, "km")) %>%
st_sf() %>%
mutate(id = 1)
# Transform lines as raster
r <- raster(extent(France_L93), nrow = 500, ncol = 400,
crs = st_crs(France_L93)$proj4string,
vals = 0)
France_L93_lines_r <- rasterize(France_L93_linespolygons, r,
background = 0) %>%
mask(France_L93)
# mapview::mapview(France_L93_lines_r)
# Let's rayshade this while exagerate walls height
elmat <- raster_to_matrix(France_L93_lines_r * 30000)
elmat_rayed <- elmat %>%
ray_shade(zscale = res(r)[1])
# Transform back as a raster
r_shade <- raster::flip(raster(t(elmat_rayed)), direction = "y")
extent(r_shade) <- extent(France_L93_lines_r)
projection(r_shade) <- projection(France_L93_lines_r)
# mapview::mapview(r_shade)
# Plot
palette <- mapview::mapviewGetOption("raster.palette")(20)[1:19]
tm <- tm_shape(r_shade) +
tm_raster(palette = palette,
n = 20, style = "quantile",
legend.show = FALSE) +
tm_shape(France_L93_linespolygons) +
tm_fill(col = my_blue, alpha = 0.5) +
tm_credits("ign.fr - {rayshader} + {raster} + {tmap} - @statnmap",
position = c(0.05, -0.01),
size = 1.3, fontfamily = "Nanum Pen",
col = "grey90") +
tm_layout(
main.title = paste("Internal boundaries?"),
main.title.color = my_blue,
main.title.fontfamily = "Nanum Pen",
main.title.size = 1.75,
title.fontfamily = "Nanum Pen",
# Margin to allow legend
# inner.margins = c(0.15, 0.15, 0.15, 0.15),
# Colours
outer.bg.color = c("#E6EFFA"),
bg.color = my_blue, #"grey60",
# Legend
legend.title.color = "grey80",
legend.text.color = "grey80",
legend.position = c("left", "top")
)
tmap_save(tm, filename = file.path(extraWD, "boundaries.jpg"),
width = 1024, height = 512, units = "px",
dpi = 100)
tm
Maintenant que vous avez vu les possibilités de {tmap} pour créer des cartes avec R, vous pouvez lire les articles des autres semaines du challenge :
- Créer des cartes dans R avec {ggplot2}
- Créer des cartes dans R avec une vue sphérique à l’échelle du globe
Comme toujours, le code et les données sont disponibles sur https://github.com/statnmap/blog_tips
# Biblio with {chameleon}
tmp_biblio <- tempdir()
attachment::att_from_rmd("2019-11-15-30daymapchallenge-building-maps-2-tmap.Rmd",
inside_rmd = TRUE) %>%
chameleon::create_biblio_file(
out.dir = tmp_biblio, to = "html", edit = FALSE,
output = "packages")
htmltools::includeMarkdown(file.path(tmp_biblio, "bibliography.html"))
List of dependencies
- dplyr (Wickham et al. (2020))
- sf (Pebesma (2020))
- raster (Hijmans (2020))
- readr (Wickham, Hester, and Francois (2018))
- tmap (Tennekes (2020))
- xml2 (Wickham, Hester, and Ooms (2020))
- purrr (Henry and Wickham (2020))
- rayshader (Morgan-Wall (2020))
- extrafont (Winston Chang (2014))
- fodr (Formont and Roussel (2018))
- attachment (Guyader and Rochette (2020))
- chameleon (Rochette (2020))
- htmltools (RStudio and Inc. (2019))
Citation :
Merci de citer ce travail avec :
Rochette Sébastien. (2019, nov.. 15). "#30DayMapChallenge: 30 jours de création de cartes (2) - tmap". Retrieved from https://statnmap.com/fr/2019-11-15-30daymapchallenge-creer-cartes-2-tmap/.
Citation BibTex :
@misc{Roche2019#30Da,
author = {Rochette Sébastien},
title = {#30DayMapChallenge: 30 jours de création de cartes (2) - tmap},
url = {https://statnmap.com/fr/2019-11-15-30daymapchallenge-creer-cartes-2-tmap/},
year = {2019}
}