Je crée des cartes SIG dans R en utilisant le sf
package (et les packages associés) pour lire les fichiers de formes et ggplot2
(et les amis) pour le traçage. Cela fonctionne bien, mais je ne trouve aucun moyen de créer (automatiquement / par programme) des emplacements d'étiquettes pour des entités telles que les rivières et les routes. Ces caractéristiques sont généralement des chaînes de lignes, avec des formes irrégulières. Voir l'image jointe par exemple de wikimedia.
Le ggrepel
package fonctionne bien pour étiqueter les points de manière automatisée, mais cela n'a pas beaucoup de sens pour d'autres entités géographiques qui ne sont pas des points lat / long discrets.
Je pourrais imaginer faire cela en plaçant des étiquettes de texte individuelles sur chaque fonctionnalité individuellement, mais je cherche quelque chose de plus automatisé, si possible. Je me rends compte qu'une telle automatisation n'est pas un problème trivial, mais elle a été résolue auparavant (ArcGIS a apparemment un moyen de le faire avec une extension appelée maplex, mais je n'ai pas accès au logiciel, et j'aimerais rester dans R si possible).
Quelqu'un connaît-il une façon de procéder?
MWE ici:
#MWE Linestring labeling
library(tidyverse)
library(sf)
library(ggrepel)
set.seed(120)
#pick a county from the built-in North Carolina dataset
BuncombeCounty <- st_read(system.file("shapes/", package="maptools"), "sids") %>%
filter(NAME == "Buncombe")
#pick 4 random points in that county
pts_sf <- data.frame(
x = seq(-82.3, -82.7, by=-0.1) %>%
sample(4),
y = seq(35.5, 35.7, by=0.05) %>%
sample(4),
placenames = c("A", "B", "C", "D")
) %>%
st_as_sf(coords = c("x","y"))
#link those points into a linestring
linestring_sf <- pts_sf %>%
st_coordinates() %>%
st_linestring()
st_cast("LINESTRING")
#plot them with labels, using geom_text_repel() from the `ggrepel` package
ggplot() +
geom_sf(data = BuncombeCounty) +
geom_sf(data = linestring_sf) +
geom_label_repel(data = pts_sf,
stat = "sf_coordinates",
aes(geometry = geometry,
label = placenames),
nudge_y = 0.05,
label.r = 0, #don't round corners of label boxes
min.segment.length = 0,
segment.size = 0.4,
segment.color = "dodgerblue")
ggrepel
, essentiellement de refaire le travail que vous avez déjà fait. Cela rend beaucoup moins probable que vous obtiendrez une réponse utile.Réponses:
Je pense que j'ai quelque chose qui pourrait fonctionner pour vous. J'ai pris la liberté de changer votre exemple pour quelque chose d'un peu plus réaliste: quelques "rivières" aléatoires faites avec des marches aléatoires lissées, chacune de 100 points de long:
Nous pouvons les tracer selon votre exemple:
Ma solution consiste essentiellement à extraire des points des chaînes de lignes et à les étiqueter. Comme l'image en haut de votre question, vous voudrez peut-être plusieurs copies de chaque étiquette sur la longueur de la chaîne de lignes, donc si vous voulez n étiquettes, vous extrayez juste n points également espacés.
Bien sûr, vous voulez pouvoir étiqueter les deux rivières à la fois sans que les étiquettes ne se heurtent, vous devrez donc être en mesure de passer plusieurs caractéristiques géographiques sous forme de liste nommée.
Voici une fonction qui fait tout cela:
Donc, si nous mettons les objets que nous voulons étiqueter dans une liste nommée comme ceci:
Ensuite, nous pouvons le faire:
la source
sfheaders::sf_linestring(obj = data.frame(x = x1, y = y1))
facilitera certains dessf
code de génération.