library(sf)
## Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1; sf_use_s2() is TRUE
library(ggplot2) # optional, nur für Visualisierung
<- read_sf("data/Punkte_A.shp")
punkte_a <- read_sf("data/Punkte_B.shp")
punkte_b
= st_read("data/Grenze.shp")
border ## Reading layer `Grenze' from data source `/home/rstudio/data/Grenze.shp' using driver `ESRI Shapefile'
## Simple feature collection with 1 feature and 2 fields
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: -558211.2 ymin: 282997.4 xmax: -557225.3 ymax: 283903.5
## Projected CRS: NAD_1983_Albers
Untitled
Benötigten libraries und daten importieren:
Daten vorbereiten:
st_crs(punkte_a) == st_crs(punkte_b)
## [1] FALSE
st_crs(punkte_a) == st_crs(border)
## [1] TRUE
st_crs(punkte_b) == st_crs(border)
## [1] FALSE
# alle datensätze müssen im gleichen CRS sein
# ich konvertiere punkte_b ins gleiche crs wie punkte_a
<- st_transform(punkte_b, st_crs(punkte_a))
punkte_b
st_crs(punkte_a) == st_crs(punkte_b)
## [1] TRUE
st_crs(punkte_b) == st_crs(border)
## [1] TRUE
Kurz schauen wie’s aussieht:
<- ggplot(data = punkte_a) +
p geom_sf(data = border) +
geom_sf(data = punkte_b, aes(col = "punkte_b"), pch = 3) +
geom_sf(aes(col = "punkte_a")) +
geom_sf_text(aes(label = Plot_Numbe), nudge_x = 15, nudge_y = 15)
p
Frage 1
Ich möchte die Distanzen zwischen den Punkten in A und B berechnen. Das Ziel am Schluss ist den nächsten Punkt aus A zu jedem einzelnen Punkt aus B zu finden.
Wenn ich dich richtig verstehe, willst du für jeden Punkt in B
den nächsten aus A
finden? Wenn das stimmt ist die Antwort ziemlich langweilig: der punkt mit der Plot_Numbe
4 ist der nächste Punkt zu allen Punkten B
. Das ergibt sich aus der obigen Visualisierung (dieser Punkt liegt in mitten aller punkte_b
.
Berechnen kannst du das folgendermassen:
st_nearest_feature(punkte_b, punkte_a)
## [1] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [39] 4
Wenn ich dich falsch verstanden habe und du das ganze umgekehrt meinst, musst du nur die Reihenfolge umdrehen.
st_nearest_feature(punkte_a, punkte_b)
## [1] 24 24 25 17 39 14 14 14 14 14 14 14 14 14 20 23 14 14 20 23 23 36 36 36 36
## [26] 23 23 23 23 39 20 14 24 36 14 14 3 36
Du kannst das ganze auch etwas “händischer” berechnen und hättest so mehr kontrolle über die Resultate. (Zum Beispiel könntest du auch die zweitnächsten Features ermitteln oder weisst auch die jeweiligen Distanzen)
<- st_distance(punkte_a, punkte_b)
dist_matrix
# Die resultierende Matrix hat soviele `rows` wie `punkte_a` features hat und so viele `columns` wie `punkte_b` features hat.
nrow(punkte_a)
## [1] 38
nrow(dist_matrix)
## [1] 38
nrow(punkte_b)
## [1] 39
ncol(dist_matrix)
## [1] 39
# Nun kannst du von der obigen matrix *pro Spalte* schauen, welche Zeile den kleinsten Wert aufweist.
apply(dist_matrix, MARGIN = 2, FUN = which.min)
## [1] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [39] 4
# ist übrigens das gleiche wie:
st_nearest_feature(punkte_b, punkte_a)
## [1] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
## [39] 4
# Margin = 1 geht durch die Zeilen von dist_matrix. Margin = 2 geht über die Spalten
# which.min gibt die *Position* des kleinsten wertes zurück. "min" würde dir lediglich den Wert zurück geben.
# Oder du schaust es pro Zeile an
apply(dist_matrix, MARGIN = 1, FUN = which.min)
## [1] 24 24 25 17 39 14 14 14 14 14 14 14 14 14 20 23 14 14 20 23 23 36 36 36 36
## [26] 23 23 23 23 39 20 14 24 36 14 14 3 36
# ist übrigens das gleiche wie:
st_nearest_feature(punkte_a, punkte_b)
## [1] 24 24 25 17 39 14 14 14 14 14 14 14 14 14 20 23 14 14 20 23 23 36 36 36 36
## [26] 23 23 23 23 39 20 14 24 36 14 14 3 36
Das ganze etwas grafischer:
# Für jeden Punkt in B, welches ist der nächste aus A?
+
p geom_sf(data = st_nearest_points(punkte_b, st_union(punkte_a)))
# Für jeden Punkt in A, welches ist der nächste aus B?
+
p geom_sf(data = st_nearest_points(st_union(punkte_b), punkte_a))
Frage 2
Ich habe basiert auf einem Shapefile A thiessenpolygone/voronoipolygone generiert. Dafür habe ich den Code aus dem ReMe Tutorial genutzt:
<- st_union(punkte_a)
punkte_a_union
<- st_voronoi(punkte_a_union)
thiessenpolygone
<- st_cast(thiessenpolygone)
thiessenpolygone
<- st_intersection(thiessenpolygone,border) thiessenpolygone_clip
<- st_sf(thiessenpolygone_clip)
thiessenpolygone_clip $id <- seq_len(nrow(thiessenpolygone_clip))
thiessenpolygone_clip
ggplot(thiessenpolygone_clip) +
geom_sf() +
geom_sf(data = punkte_b, alpha = .2) +
geom_sf_text(aes(label = id), colour = "red")
Nun möchte ich prüfen ob punkte aus B auf einem dieser Polygone liegen. Das Ziel wäre, dass ich nachher für jeden Eintrag in B die Nummer des jeweiligen Polygon steht. Dafür wollte ich folgenden Code nutzen:
= st_intersection(thiessenpolygone_clip , punkte_b)
trees_UAV_with_plot_nr ## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
st_intersection
macht eine intersection der beiden Geometrien. Was du aber brauchst ist eine Antwort auf die Frage: welches Polygon intersected mit dem jeweiligen Punkt. Das ist nicht st_intersection
sondern st_intersects
.
<- st_intersects(punkte_b, thiessenpolygone_clip) punkte_b_intersects
st_intersects
retourniert eine Sparse geometry
, also eine Liste mit der gleichen Länge wie punkte_b
. Jeder eintrag in der Liste ist ein nummerischer Wert und zeigt an, welches Feature aus thiessenpolygone_clip
mit dem entsprechend punkt_b
interesected.
In deinem Fall is dies immer 1 Feature, nicht mehr und nicht weniger (in anderen Situationen könnten es auch 0
oder ganz viele sein). Aber in deinem Fall kannst du die Liste mit unlist()
in einen Zahlenvektor konvertieren und auch gerade als neue Spalte zu punket_b
hinzufügen:
unlist(punkte_b_intersects)
## [1] 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
## [39] 7
$thiessen_pos <- unlist(punkte_b_intersects) punkte_b
Jetzt sind die Polygone jedoch eine Liste und nicht einfach ein “Geometriedatensatz”, und lässt sich nicht mit den Punkten verschneiden.
Geometrien sind in R immer als Liste abgespeichert.
is.list(punkte_a$geometry)
## [1] TRUE
is.list(punkte_b$geometry)
## [1] TRUE
is.list(border$geometry)
## [1] TRUE