Ich erstelle GIS-Karten in R mit dem sf
Paket (und verwandten Paketen) zum Einlesen von Shapefiles und ggplot2
(und Freunden) zum Plotten. Dies funktioniert einwandfrei, aber ich kann keine Möglichkeit finden, (automatisch / programmgesteuert) Etikettenplatzierungen für Funktionen wie Flüsse und Straßen zu erstellen. Diese Merkmale sind typischerweise Linestrings mit unregelmäßigen Formen. Siehe Bild zum Beispiel aus Wikimedia.
Das ggrepel
Paket eignet sich gut zum automatisierten Beschriften von Punkten. Dies ist jedoch für andere geografische Merkmale, die keine diskreten Lat / Long-Punkte sind, wenig sinnvoll.
Ich könnte mir vorstellen, dies zu tun, indem ich einzelne Textbeschriftungen für jedes Feature einzeln platziere, aber ich suche nach etwas Automatisierterem, wenn möglich. Mir ist klar, dass eine solche Automatisierung kein triviales Problem ist, aber sie wurde bereits zuvor gelöst (ArcGIS hat anscheinend eine Möglichkeit, dies mit einer Erweiterung namens Maplex zu tun, aber ich habe keinen Zugriff auf die Software und möchte dabei bleiben R wenn möglich).
Kennt jemand einen Weg, dies zu tun?
MWE hier:
#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
, und im Grunde die Arbeit wiederholen müssen, die Sie bereits erledigt haben. Dies macht es viel weniger wahrscheinlich, dass Sie eine nützliche Antwort erhalten.Antworten:
Ich glaube, ich habe etwas, das für Sie funktionieren könnte. Ich habe mir erlaubt, Ihr Beispiel in etwas Realistischeres zu ändern: ein paar zufällige "Flüsse", die mit geglätteten zufälligen Spaziergängen von jeweils 100 Punkten Länge erstellt wurden:
Wir können sie gemäß Ihrem Beispiel zeichnen:
Meine Lösung besteht im Wesentlichen darin, Punkte aus den Linestrings zu extrahieren und sie zu kennzeichnen. Wie das Bild oben in Ihrer Frage möchten Sie möglicherweise mehrere Kopien jedes Etiketts entlang der Länge des Linienstreifens. Wenn Sie also n Etiketten möchten, extrahieren Sie einfach n Punkte mit gleichem Abstand.
Natürlich möchten Sie in der Lage sein, beide Flüsse gleichzeitig zu kennzeichnen, ohne dass die Beschriftungen zusammenstoßen. Daher müssen Sie in der Lage sein, mehrere geografische Merkmale als benannte Liste zu übergeben.
Hier ist eine Funktion, die all das macht:
Wenn wir also die Objekte, die wir beschriften möchten, in eine benannte Liste wie folgt einfügen:
Dann können wir das tun:
quelle
sfheaders::sf_linestring(obj = data.frame(x = x1, y = y1))
erleichtert einen Teil dessf
generierenden Codes.