Как разбить полигоны на подмножества, используя расстояние в SPDF

Ok. Итак, я учусь и задал очень похожий вопрос, когда не узнал, что такое Фрейм данных пространственных многоугольников был около 10 дней назад: Выбрать растр в ggplot возле береговой линии.

Теперь я обнаружил магию SPDF и картограмм и, по сути, задаю тот же вопрос, но с разными типами файлов. Я все еще сижу с ума вокруг объектов S4 и не могу понять, как разбить определенные мини-полигоны MUNICIPI из моего набора данных.

К точке!

Контекст: у меня есть SPDF, который содержит эти данные: Фрейм данных внутри cataconfidence

Цель:

Я хотел бы выделить все MUNICIPI, которые находятся на определенном расстоянии от побережья. Скажем, 20 км, как указал @urbandatascientist в своем ответе на мой первый вопрос, и создадим картограмму, например, upper_trees с подмножеством MUNICIPI.

Из сообщения Выбрать растр в ggplot рядом с береговой линией у меня также есть list.of.polygon.boundaries, что мы Вычтем MUNICIPI координаты из.

Данные здесь.

Надеюсь, что после того, как я подгруппу прибрежный MUNICIPI, карта будет выглядеть что-то вроде области, заштрихованной зеленым. Я также попытался убедиться, что координаты совпадают между list.of.polygon.boundaries.

Будем очень признательны за любые подсказки или идеи!

Итак, вот моя хлороплетная карта для всего региона на примере upper_trees:

tm_shape(catasense2)+ tm_fill(col="upper_trees",n=8,style="quantile")+ tm_layout(legend.outside =TRUE)

карта для всего региона [2]


person delcast    schedule 22.03.2018    source источник
comment
С моей стороны, не совсем ясен точный вопрос: цель состоит в том, чтобы выделить из SpatialPolygonsDataFrame только те полигоны, которые находятся максимум в 20 км от береговой линии?   -  person Seymour    schedule 22.03.2018
comment
@Seymour привет! Извините, вы не поняли. Я отредактировал, чтобы быть точнее. Но да, ты прав. Подгруппа данных из этих многоугольников и нанесение только их на карту. См. Добавленную мной ссылку на то, как в идеале они должны выглядеть на карте.   -  person delcast    schedule 22.03.2018
comment
Но как определить береговую линию? Поскольку, если этот SpatialPolygonsDataFrame не является островом, некоторые внешние границы находятся на внутренних территориях, а другие - на прибрежных территориях.   -  person Seymour    schedule 22.03.2018
comment
@Seymour Отличный момент, Сеймур. Ответ на этот вопрос был дан в stackoverflow.com/questions / 49193867 /, и это то, что я называю в этом вопросе list.of.polygon.boundaries, что есть в данных.   -  person delcast    schedule 22.03.2018
comment
Отлично, тогда одно из возможных решений - это gDistance() функция пакета rGeos. Функция получит два ввода: прибрежные полигоны и весь SpatialPolygonsDataFrame. Эта функция вычисляет расстояние в метрах (поскольку мы говорим об Испании) между каждым прибрежным полигоном и каждым полигоном SPDF. На выходе получается матрица RxC, в которой каждая строка - это ID прибрежных полигонов, каждый столбец - это ID SPDF, а каждая ячейка - это расстояние в метрах между двумя пространственными объектами. Затем вы можете просто filter оставить только те, у которых distance < 20000   -  person Seymour    schedule 22.03.2018
comment
@Seymour, спасибо! Это полезная идея. Я попробую.   -  person delcast    schedule 22.03.2018
comment
Я жду, чтобы мой компьютер завершил выполнение программы, и у меня нет доступных ресурсов. Если вы обнаружите какую-либо проблему, вы можете просто спросить, или я могу опубликовать ответ через несколько часов.   -  person Seymour    schedule 22.03.2018
comment
@seymour мне нравится! Я попробую сейчас и дам знать, как это происходит.   -  person delcast    schedule 22.03.2018
comment
Единственной хитростью может быть трансформация. И для прибрежных полигонов, и для SPDF вам необходимо спроецировать их на одно и то же пространство. your_polygons ‹- spTransform (your_polygons, + proj = tmerc + lat_0 = 0 + lon_0 = 15 + k = 0.9996 + x_0 = 2520000 + y_0 = 0 + ellps = intl + units = m) в атрибуте CRS вашего SPDF.   -  person Seymour    schedule 22.03.2018
comment
@seymour ага! Я буду осторожен с CRS.   -  person delcast    schedule 22.03.2018
comment
@seymour Я могу подтвердить, что не смог этого сделать после попытки в течение последних 6 часов. Вместо этого я сделал очень ручную вещь и в основном с помощью filter и dplyr заменил нули в многоугольниках, которые находились вдали от побережья, используя их идентификаторы. Мне все равно нужно попробовать это. Так что вопрос все еще без ответа, хотите ли вы попробовать!   -  person delcast    schedule 22.03.2018
comment
Позвольте нам продолжить это обсуждение в чате.   -  person Seymour    schedule 22.03.2018


Ответы (1)


Обзор

Подобно ответу на Выбрать растр в ggplot рядом с береговой линией, Решение включает следующие шаги:

  • Расчет координат границ Балеарских (Пиренейское море) и Западных бассейновых частей shape-файл для западной части Средиземного моря.

  • Вычисление центроидов каждого многоугольника в MUNICIPI по ссылке OP на ее папку Google Диска, которая содержит файл .zip файла формы.

  • Вычислите расстояние между первыми двумя точками и подмножеством MUNICIPI, чтобы показать многоугольники, расстояние от центра тяжести которых до Западного бассейна меньше или равно 20 километрам.

Фильтрация координат Западного бассейна

Вместо того, чтобы вычислять расстояние от каждого центроида до каждой пары координат в пределах western.basin.polygon.coordinates, я включил только координаты в пределах western.basin.polygon.coordinates, чья широтная точка находилась между (включительно) восточным побережьем Каталонии.

Для справки я использую точки широты Пенискола, Каталония и Cerbere, Франция. Сохраняя только пары координат, которые лежат вдоль восточного побережья Каталонии, вычисление расстояния между western.basin.polygon.coordinates и каждым центроидом в MUNICIPI завершается примерно за ~ 4 минуты.

СС карт Google

Затем я сохранил индексы многоугольников в MUNICIPI, центроиды которых были меньше или равны 20 километрам, в less.than.or.equal.to.max.km - логическом векторе значений ИСТИНА / ЛОЖЬ. Используя карту листовка, я показываю, как я подмножество MUNICIPI визуализирует только те многоугольники, которые содержат ИСТИННЫЕ значения внутри less.than.or.equal.to.max.km.

# load necessary packages
library( geosphere )
library( leaflet )
library( sf )

# load necessary data
unzip( zipfile = "catasense2-20180327T023956Z-001.zip" )

# transfrom zip file contents
# into a sf data frame
MUNICIPI <-
  read_sf(
    dsn = paste0( getwd(), "/catasense2" )
    , layer = "catasense2"
  )


# map data values to colors
my.color.factor <- 
  colorFactor( palette = "viridis", domain = MUNICIPI$uppr_tr )

# Visualize
leaflet( data = MUNICIPI ) %>%
  setView( lng = 1.514619
           , lat = 41.875227
           , zoom = 8 ) %>%
  addTiles() %>%
  addPolygons( color = ~my.color.factor( x = uppr_tr ) )

СС всего MUNICIPI

# unzip the western basin zip file
# unzip( zipfile = "iho.zip" )

# create sf data frame
# of the western basin
western.basin <-
  read_sf( dsn = getwd()
           , layer = "iho"
           , stringsAsFactors = FALSE )

# filter the western.basin
# to only include those bodies of water
# nearest catalonia
water.near.catalonia.condition <-
  which( 
    western.basin$name %in% 
      c( "Balearic (Iberian Sea)"
         , "Mediterranean Sea - Western Basin" )
    )

western.basin <-
  western.basin[ water.near.catalonia.condition, ]

# identify the coordinates for each of the
# remaining polygons in the western.basin
# get the boundaries of each
# polygon within the western basin
# and retain only the lon (X) and lat (Y) values
western.basin.polygon.coordinates <-
  lapply( 
    X = western.basin$geometry
    , FUN = function( i )
      st_coordinates( i )[ , c( "X", "Y" ) ]
  )

# find the centroid
# of each polygon in MUNICIPI
MUNICIPI$centroids <-
  st_centroid( x = MUNICIPI$geometry )

# Warning message:
#   In st_centroid.sfc(x = MUNICIPI$geometry) :
#   st_centroid does not give correct centroids for longitude/latitude data

# store the latitude
# of the western (Peniscola, Catalonia) and eastern (Cerbere, France) 
# most parts of the eastern coast of Catalonia
east.west.lat.range <- 
  setNames( object = c( 40.3772185, 42.4469981 )
            , nm = c( "east", "west" )
  )

# set the maximum distance
# allowed between a point in df
# and the sea to 20 kilometers
max.km <- 20

# store the indices in the
# western basin polygon coordinates whose
# lat points
# fall in between (inclusive) 
# of the east.west.lat.range
satisfy.east.west.lat.max.condition <-
  lapply(
    X = western.basin.polygon.coordinates
    , FUN = function(i)
      which(
        i[, "Y"] >= east.west.lat.range["east"] &
          i[, "Y"] <= east.west.lat.range["west"]
      )
  )

# filter the western basin polygon coordinate
# by the condition
western.basin.polygon.coordinates <-
  mapply(
    FUN = function( i, j )
      i[ j, ]
    , western.basin.polygon.coordinates
    , satisfy.east.west.lat.max.condition
  )

# calculate the distance of each centroid
# in MUNICIPI
# to each point in both western.basin
# polygon boundary coordinates
# Takes ~4 minutes
distance <-
  apply(
    X = do.call( what = "rbind", args = MUNICIPI$centroids )
    , MARGIN = 1
    , FUN = function( i )
      lapply(
        X = western.basin.polygon.coordinates
        , FUN = function( j )
          distGeo(
            p1 = i
            , p2 = j
          ) / 1000 # to transform results into kilometers
      )
  )

# 1.08 GB list is returned
object.size( x = distance)
# 1088805736 bytes

# find the minimum distance value
# for each list in distance
distance.min <-
  lapply(
    X = distance
    , FUN = function( i )
      lapply(
        X = i
        , FUN = function( j )
          min( j )
      )
  )

# identify which points in df
# are less than or equal to max.km
less.than.or.equal.to.max.km <-
  sapply(
    X = distance.min
    , FUN = function( i )
      sapply(
        X = i
        , FUN = function( j )
          j <= max.km
      )
  )

# convert matrix results into
# vector of TRUE/FALSE indices
less.than.or.equal.to.max.km <-
  apply(
    X = less.than.or.equal.to.max.km
    , MARGIN = 2
    , FUN = any
  )

# now only color data that meets
# the less.than.or.equal.to.max.km condition
leaflet( data = MUNICIPI[ less.than.or.equal.to.max.km, ] ) %>%
  setView( lng = 1.514619
           , lat = 41.875227
           , zoom = 8 ) %>%
  addTiles() %>%
  addPolygons( color = ~my.color.factor( x = uppr_tr ) ) 

# end of script #

SS of Filtered MUNICIPI

Информация о сеансе

R version 3.4.4 (2018-03-15)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS High Sierra 10.13.2

Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.4/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
[1] sf_0.6-0           leaflet_1.1.0.9000 geosphere_1.5-7   

loaded via a namespace (and not attached):
 [1] mclust_5.4         Rcpp_0.12.16       mvtnorm_1.0-7     
 [4] lattice_0.20-35    class_7.3-14       rprojroot_1.3-2   
 [7] digest_0.6.15      mime_0.5           R6_2.2.2          
[10] plyr_1.8.4         backports_1.1.2    stats4_3.4.4      
[13] evaluate_0.10.1    e1071_1.6-8        ggplot2_2.2.1     
[16] pillar_1.2.1       rlang_0.2.0        lazyeval_0.2.1    
[19] diptest_0.75-7     whisker_0.3-2      kernlab_0.9-25    
[22] R.utils_2.6.0      R.oo_1.21.0        rmarkdown_1.9     
[25] udunits2_0.13      stringr_1.3.0      htmlwidgets_1.0   
[28] munsell_0.4.3      shiny_1.0.5        compiler_3.4.4    
[31] httpuv_1.3.6.2     htmltools_0.3.6    nnet_7.3-12       
[34] tibble_1.4.2       gridExtra_2.3      dendextend_1.7.0  
[37] viridisLite_0.3.0  MASS_7.3-49        R.methodsS3_1.7.1 
[40] grid_3.4.4         jsonlite_1.5       xtable_1.8-2      
[43] gtable_0.2.0       DBI_0.8            magrittr_1.5      
[46] units_0.5-1        scales_0.5.0       stringi_1.1.7     
[49] reshape2_1.4.3     viridis_0.5.0      flexmix_2.3-14    
[52] sp_1.2-7           robustbase_0.92-8  squash_1.0.8      
[55] RColorBrewer_1.1-2 tools_3.4.4        fpc_2.1-11        
[58] trimcluster_0.1-2  DEoptimR_1.0-8     crosstalk_1.0.0   
[61] yaml_2.1.18        colorspace_1.3-2   cluster_2.0.6     
[64] prabclus_2.2-6     classInt_0.1-24    knitr_1.20        
[67] modeltools_0.2-21 
person Cristian E. Nuno    schedule 31.03.2018
comment
Уважаемый @aspiringurbandatascientist, я очень внимательно изучил это и смог запустить его! Спасибо, что все подробно объяснили. У меня есть несколько вопросов, но они не срочны: execute.east.west.lat.max.condition ‹- lapply (X = western.basin.polygon.coordinates, FUN = function (i) which (i [, Y]› = east.west.lat.range [восток] & i [, Y] ‹= east.west.lat.range [запад])) # Вопрос: если мы говорим о самых западных и восточных координатах, почему мы фильтруем Y вместо X (также определено). - person delcast; 04.04.2018
comment
Также: western.basin.polygon.coordinates ‹- mapply (FUN = function (i, j) i [j,], western.basin.polygon.coordinates, execute.east.west.lat.max.condition) # Вопрос: почему мы используем mapply, а не sapply? - person delcast; 04.04.2018
comment
@delcast без проблем. К вашему первому комментарию я делю подмножество western.basin.polygon.coordinates, чтобы вернуть только индексы широты - посредством i[, "Y" ] - которые удовлетворяют неравенству. Мы не используем X, потому что он представляет долготу. Что касается вашего второго комментария, мы используем недавно созданный satisfy.east.west.lat.max.condition внутри mapply() для фильтрации каждого списка в western.basin.polygon.coordinates по нему, сохраняя список; тогда как sapply() возвращает вектор или матрицу. - person Cristian E. Nuno; 04.04.2018
comment
Я удалил свой предыдущий комментарий в свете вашего анализа. Для меня я увидел два ввода и, естественно, подумал, что mapply(), поскольку это многовариантная версия sapply(). Теперь мне любопытно узнать об альтернативных методах определения того, какие полигоны в пределах MUNICIPI расположены на расстоянии не более 20 километров от береговой линии. - person Cristian E. Nuno; 04.04.2018
comment
и я удалил свой, потому что на самом деле ошибка была: Ошибка в i [j,]: недопустимый индекс типа 'list'. - person delcast; 04.04.2018
comment
Этот комментарий, вероятно, будет отмечен и удален модератором, но я думаю, что это здорово, что подмножество выглядит как морской конек. - person Cristian E. Nuno; 04.04.2018
comment
То же самое и с модератором, но да! Это так классно!! - person delcast; 04.04.2018