У меня есть файлы форм за несколько лет (всего восемь лет), представляющие обработку инсектицидами определенной площади. Я могу легко найти общую обработанную площадь и сравнить перекрытие за два отдельных года. Однако я застрял в разработке краткого кода для определения общей площади, обработанной два раза, три раза, за раз и т. д.
Упрощенное изображение прикреплено в качестве примера: каждый год имеет разный цвет. Некоторые области обрабатываются только один раз (один цвет), некоторые обрабатываются дважды (перекрывающиеся цвета), а некоторые обрабатываются более 2 раз.
Как мне найти общую площадь, обработанную 1, 2, 3, 4 и т. д. раз?
Я не могу создать пример кода, например изображения карты (или поделиться своими файлами форм). Однако вот очень упрощенный пример площади, обработанной за год, с некоторым перекрытием между годами (по запросу):
library(tidyverse)
library(sf)
polygon1 <- st_polygon(list(
matrix(c(0, 0, 1, 0, 1, 1, 0, 1, 0, 0), ncol = 2, byrow = TRUE)
))
polygon2 <- st_polygon(list(
matrix(c(2, 2, 3, 2, 3, 3, 2, 3, 2, 2), ncol = 2, byrow = TRUE)
))
polygon3 <- st_polygon(list(
matrix(c(0.5, 0.5, 1.5, 0.5, 1.5, 1.3, 0.5, 1.3, 0.5, 0.5), ncol = 2, byrow = TRUE)
))
polygon4 <- st_polygon(list(
matrix(c(2, 0.5, 2.5, 0.5, 2.5, 2.5, 2, 2.5, 2, 0.5), ncol = 2, byrow = TRUE)
))
polygon5 <- st_polygon(list(
matrix(c(1.2, 1.5, 1.8, 1.5, 1.8, 1.8, 1.2, 1.8, 1.2, 1.5), ncol = 2, byrow = TRUE)
))
polygon6 <- st_polygon(list(
matrix(c(0.8, 0.8, 2.2, 0.8, 2.2, 1.2, 0.8, 1.2, 0.8, 0.8), ncol = 2, byrow = TRUE)
))
polygon7 <- st_polygon(list(
matrix(c(1.3, 2.2, 2.1, 2.2, 2.1, 2.8, 1.3, 2.8, 1.3, 2.2), ncol = 2, byrow = TRUE)
))
year1 <- st_multipolygon(list(polygon1, polygon2)) |>
st_sfc()
year2 <- st_multipolygon(list(polygon3, polygon4, polygon5))|>
st_sfc()
year3 <- st_multipolygon(list(polygon6, polygon7))|>
st_sfc()
ggplot() +
geom_sf(data = year1, fill = "#009E73", color = 'black', alpha = 0.5) +
geom_sf(data = year2, fill = "#E69F00", color = 'black', alpha = 0.5) +
geom_sf(data = year3, fill = "#0072B2", color = 'black', alpha = 0.5) +
theme_classic()
Как бы я мог определить общую площадь, покрытую трижды, общую площадь, покрытую только дважды, а общую площадь, покрытую только один раз?
используя растровый подход и данные вашего примера:
library(sf)
the_polygons <-
do.call(rbind,
lapply(list('year1', 'year2', 'year3'),
FUN = \(o_name) data.frame(year = o_name,
geometry = get(o_name)
)
)
) |>
st_sf()
## > the_polygons
## Simple feature collection with 3 features and 1 field
## Geometry type: MULTIPOLYGON
## Dimension: XY
## Bounding box: xmin: 0 ymin: 0 xmax: 3 ymax: 3
## CRS: NA
## year geometry
## 1 year1 MULTIPOLYGON (((0 0, 1 0, 1...
## 2 year2 MULTIPOLYGON (((0.5 0.5, 1....
## 3 year3 MULTIPOLYGON (((0.8 0.8, 2....
st_bbox
и желаемым разрешением. Этот пустой базовый растр позже заполняется значениями полигонов. library(terra) ## the workhorse for raster, as {sf} is for features
raster_base <- the_polygons |> st_bbox() |> ext() |> rast(resolution = .1)
rasterize
включив полигоны в базовый растр, sum
подсчитав количество непустых значений (по одному на полигон, охватывающий конкретную ячейку):
raster_output <- rasterize(the_polygons, raster_base, fun = sum)
table(values(raster_output))
## 1 2 3
## 325 78 7
(multiply cell count by cell size to obtain area at your resolution)
визуальный контроль:
plot(raster_output)
Для векторного метода я бы подошел к этому, объединив данные за все годы в один слой с переменной, идентифицирующей год, а затем выполнил самопересечение. В результате будет создан индекс, который можно будет использовать для обратной ссылки на объединенный годичный слой, чтобы получить подробную информацию о каждом перекрытии, которую вы можете объединить в новое поле, в котором перечислены годы. Затем это можно объединить, суммируя полученный слой научной фантастики по интересующим вас переменным. В случае действительно больших слоев этап пересечения может занять некоторое время.
#assign a value to each year
year1 <- st_multipolygon(list(polygon1, polygon2)) %>%
st_sfc() %>%
st_union() %>%
st_as_sf() %>%
mutate(Year=2024)%>%
st_set_geometry("geometry")
year2 <- st_multipolygon(list(polygon3, polygon4, polygon5))%>%
st_sfc() %>%
st_union() %>%
st_as_sf() %>%
mutate(Year=2023)%>%
st_set_geometry("geometry")
year3 <- st_multipolygon(list(polygon6, polygon7))%>%
st_sfc() %>%
st_union() %>%
st_as_sf() %>%
mutate(Year=2022) %>%
st_set_geometry("geometry")
###combine into a single layer
combo_years <- bind_rows(list(year1, year2, year3))
#self intersect, give an index of overlaps "origins"
combo_years_intersect <- st_intersection(combo_years)
#use the index nubers to the get the year values from the original data set and concantenate into a list using purr functions, could alos use an apply or loop to do the same
combo_years_intersect_list <- combo_years_intersect %>%
st_collection_extract("POLYGON") %>% #this not necessary in simplified example but in messy shapes sometimes linestrings an points created
mutate(Year_List=map_chr(origins, \(x) paste0(combo_years$Year[x], collapse = "; ") ))
#group and summarise by the nuber of overlaps and the the overalpping years
combo_years_intersect_summarised <- combo_years_intersect_list %>%group_by(n.overlaps, Year_List) %>%
summarise() %>%
ungroup() %>%
mutate(area=st_area(.))
mapview::mapview(combo_years_intersect_summarised, zcol = "n.overlaps")
mapview::mapview(combo_years_intersect_summarised, zcol = "Year_List")
##can be piped together
combo_years_summary_piped <- combo_years %>%
st_intersection() %>%
mutate(Year_List=map_chr(origins, \(x) paste0(combo_years$Year[x], collapse = "; ") ))%>%
group_by(n.overlaps, Year_List) %>%
summarise()%>%
ungroup() %>%
mutate(area=st_area(.))
##can calc other values at same time
combo_years_summary_many <- combo_years %>%
st_intersection() %>%
mutate(Year_List=map_chr(origins, \(x) paste0(combo_years$Year[x], collapse = "; ") ),
Year_Min=map_dbl(origins, \(x) min(combo_years$Year[x], na.rm=T) ),
Year_Max=map_dbl(origins, \(x) min(combo_years$Year[x], na.rm=T) ))%>%
group_by(n.overlaps, Year_List,Year_Min, Year_Max) %>%
summarise()%>%
ungroup() %>%
mutate(area=st_area(.))
mapview::mapview(combo_years_summary_many, zcol = "n.overlaps")
mapview::mapview(combo_years_summary_many, zcol = "Year_Min")
##can now summarise total area by overlapping treatments
OVERLAP_SUMMARY_AREAS <- combo_years_summary_many %>%
st_drop_geometry() %>%
group_by(n.overlaps) %>%
summarise(total_area=sum(area))
#or
OVERLAP_SUMMARY_AREAS <- combo_years_summary_many %>%
st_drop_geometry() %>%
group_by(Year_List) %>%
summarise(total_area=sum(area))