Comment remplir un polygone avec des trous par une zone hachurée dans leaflet

Remplir un “SpatialPolygons” avec des trous par une zone hachurée

Dessiner des polygones remplis avec une zone hachurée est assez simple sur un graphique classique dans R. Cela nécessite simplement de définir les paramètres density et angle de la fonction polygon. La fonction SpatialPolygons de la librairie sp utilise aussi cette function polygon. Cependant, créer un polygone hachuré lorsqu’il y a des trous n’est pas idéal car le trou est rempli avec la couleur d’arrière-plan du graphique pour masquer les hachures des polygones qui l’entoure. Ainsi, si vous dessinez des polygones comprenant des trous par dessus une image d’arrière-plan par exemple, vous ne verrez pas l’image au travers des trous, ce qui est dommage puisque ça peut être une des raisons de créer un trou dans un fichier spatialisé de polygones. Pour créer des zones hachurées dans un polygone spatialisé comprenant des trous, je me suis dit que je pourrais utiliser des SpatialLines. Par ailleurs, à ma connaissance, il n’est pas possible de créer un polygone avec une zone hachurée avec leaflet. Une fonction permettant de créer des SpatialLines pour remplir le fond d’un polygone est donc utile pour les utilisateurs de leaflet souhaitant dessiner des polygones hachurés plutôt qu’une couleur avec de la transparence.

Une librairie sur github

J’ai créé un package R, disponible sur mon github statnmap, pour proposer la fonction hatched.SpatialPolygons. Cette fonction a été créée à partir de la fonction de base pour dessiner les SpatialPolygons de la librairie sp. J’ai retiré de la fonction tout ce qui permettait de dessiner directement. La fonction produit donc simplement un objet de classe SpatialLinesDataFrame qui peut ensuite être ajouté à n’importe quel figure, avec ou sans les polygones originaux. Une vignette est proposée avec la librairie et vous pouvez récupérer le code Rmarkdown complet de cet article ici.

devtools::install_github("statnmap/HatchedPolygons", build_vignettes = TRUE)
library(HatchedPolygons)
vignette("leaflet_shading_polygon", package = "HatchedPolygons")

Dessiner une zone hachurée dans un polygone

J’ai créé deux polygones, l’un étant un trou dans l’autre.

library(dplyr)
library(sp)
library(sf)
library(raster)
library(HatchedPolygons)

# Create two polygons: second would be a hole inside the first
xy = cbind(
  x = c(13.4, 13.4, 13.6, 13.6, 13.4),
  y = c(48.9, 49, 49, 48.9, 48.9)
    )
hole.xy <- cbind(
  x = c(13.5, 13.5, 13.45, 13.45, 13.5),
  y = c(48.98, 48.92, 48.92, 48.98, 48.98)
  )

plot(xy)
polygon(xy, density = 20)
polygon(hole.xy, density = 20, angle = -45, col = "blue")

Dessiner une zone hachurée dans un objet “SpatialPolygons”

Dupliquons les polygones à différentes positions et transformons ces polygones en SpatialPolygons avec des trous. Avec les options graphiques par défaut, les polygones peuvent dessinés avec des hachures et les trous sont visibles. La fonction permettant de dessiner les polygones utilise la couleur d’arrière-plan pour remplir les trous pour qu’ils apparaissent comme tels. Cependant, si vous superposez une couche de polygones par-dessus une autre couche, les trous cacheront ce qu’il y a derrière.

# Transform as SpatialPolygon to plot
xy.sp <- SpatialPolygons(list(
  Polygons(list(Polygon(xy), 
                Polygon(hole.xy, hole = TRUE)), "1"),
  Polygons(list(Polygon(xy + 0.2),
                Polygon(xy + 0.35),
                Polygon(hole.xy + 0.2, hole = TRUE)), "2")
  ))

par(bg = "lightblue") # default
plot(xy.sp, density = 20, col = 2:3)

# Let's define a raster to be used as background
r <- raster(nrows = 50, ncols = 50)
extent(r) <- extent(xy.sp)
r <- setValues(r, 1:ncell(r))

# Draw again polygons with holes
par(bg = "lightblue")
plot(r, legend = FALSE)
plot(xy.sp, density = 20, col = 2:3, add = TRUE)

Créer un objet SpatialLines pour dessiner la zone hachurée en dehors des trous.

Pour éviter de remplir les trous avec les hachures du polygone qui l’entoure, j’ai décidé d’utiliser les SpatialLines et de ne sélectionner que l’intersection des SpatialLines avec le SpatialPolygons avec la librairie rgeos. Pour que la fonction puisse fonctionner avec les polygones multiples, le SpatialLines est accompagné d’une table attributaire enregistrant l’identifiant unique des polygones d’origine. Ainsi, le nombre d’entités dans le SpatialLines peut être plus grand que celui dans le SpatialPolygons lorsqu’il y a des polygones multiples, mais le lien entre les deux, pour les colorer par exemple, peut se faire grâce à la table attributaire.

# Allows for density different for each polygon
xy.sp.hatch <- hatched.SpatialPolygons(xy.sp, density = c(60, 90), angle = c(45, 135))

# Draw again polygons with holes
par(bg = "lightblue")
plot(r, legend = FALSE)
plot(xy.sp, col = c("blue", "red"), add = TRUE)
plot(xy.sp.hatch, col = c("cyan", "grey40")[as.numeric(xy.sp.hatch$ID)], lwd = 2, add = TRUE)

Dessiner une zone hachurée dans un SpatialPolygons avec leaflet

Un point intéressant de cette fonction, c’est qu’elle permet aussi de créer des polygones hachurés avec leaflet, ce qui, à ma connaissance, n’est pas possible par défaut. Attention si vous choisissez des noms pour les couleurs, elles doivent exister en css/html, sinon, utilisez les codes hexa.

library(leaflet)

m <- leaflet() %>%
  addTiles(
    urlTemplate = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png") %>%
          addPolygons(data = xy.sp, 
                    fillColor = c("transparent", "red"),
                    color = "#000000", 
                    opacity = 1, 
                    fillOpacity = 0.6, 
                    stroke = TRUE,
                    weight = 1.5
        ) %>%
  addPolylines(data = xy.sp.hatch,
               color = c("blue", "#545454")[as.numeric(xy.sp.hatch$ID)])

Dessiner une zone hachurée dans un SpatialPolygons avec trous avec ggplot2

Évidemment, les SpatialLines pouvant être dessinés avec ggplot2, la fonction peut aussi permettre de créer des polygones hachurés sur les figures réalisées avec ggplot2. Dans le cas présent, il vaut mieux utliser la librairie sf pour les polygones avec des trous (cf. question stackoverflow)).

library(ggplot2)

xy.sp.hatch.sf <- sf::st_as_sf(xy.sp.hatch)
xy.sp.sf <- sf::st_as_sf(xy.sp) %>%
  mutate(ID = factor(1:2))

ggplot() +
  geom_sf(data = xy.sp.sf, aes(fill = ID)) +
  geom_sf(data = xy.sp.hatch.sf, aes(colour = ID)) +
  scale_colour_manual(values = c("#6BA5F7", "#545454"))

La fonction hatched.SpatialPolygons se trouve dans le package R HatchedPolygons sur mon github statnmap. Ce package R a été créé uniquement pour cette fonction



Citation :

Merci de citer ce travail avec :
Rochette Sébastien. (2017, May. 23). "Comment remplir un polygone avec des trous par une zone hachurée dans leaflet". Retrieved from https://statnmap.com/fr/2017-05-23-comment-remplir-un-polygone-avec-des-trous-par-une-zone-hachuree-dans-leaflet/.


Citation BibTex :
@misc{Roche2017Comme,
    author = {Rochette Sébastien},
    title = {Comment remplir un polygone avec des trous par une zone hachurée dans leaflet},
    url = {https://statnmap.com/fr/2017-05-23-comment-remplir-un-polygone-avec-des-trous-par-une-zone-hachuree-dans-leaflet/},
    year = {2017}
  }