Вычислить выделенную область из сложенного растрового объекта

Поскольку я только недавно начал использовать R для пространственного анализа и ни в коем случае не являюсь географом или специалистом по пространственным данным, у меня есть - как я полагаю, - относительно простой вопрос. Я пытаюсь вычислить площадь части сложенного растрового объекта, которая соответствует определенным условиям. В частности, из набора данных из морских глубин в южной Атлантике я сложил два растровых объекта (глубина и наклон), которые также идентичны в системе координат (WGS84) и положении x-y (широта-долгота). Из сложенного растрового объекта я хотел бы выделить часть, которая находится на глубине (скажем) от 1000 до 4000 м с уклоном более 10 градусов. Я хотел бы знать, какова протяженность площади в квадратных километрах, и я хотел бы добавить это к ранее построенной карте. Ниже приведен воспроизводимый пример:

# Raster object containing depth values
dpt <-  raster(ncol=623, nrow=815, xmx=-31.72083, xmn=-38.50417,
ymn=-33.8875, ymx=-28.70417)
values(dpt) <- sample(-200:-5000, size=(nrow(dpt)*ncol(dpt)), replace=T)

# Raster object containing slope values
slp <- raster(ncol=623, nrow=815, xmx=-31.72083, xmn=-38.50417,
ymn=-33.8875, ymx=-28.70417)
values(slp) <- sample(0:30, size=(nrow(slp)*ncol(slp)), replace=T)

# Stack raster objects
stk <- stack(dpt,slp)


 # Colour palette
 colrs <- colorRampPalette(c("navyblue","dodgerblue3","cyan2","green2","darkgoldenrod1"))
 # Plot raster map; does not look like ocean floor because of "sample"
 plot(dpt, xlab="Longitude", ylab="Latitude", col=colrs(100), font.lab=2,
 cex.lab=1.5, las=1)


 # Create a blank copy of previous raster plot
 selectAtt <- raster(dpt)
 # Fill in cells where Attribute(s) meet(s) conditions
 selectAtt[stk$layer.1 <= -1000 & stk$layer.1 >= -4000 & stk$layer.2 >=
 10] <- 90
 # Set object projection
 projection(selectAtt) <- CRS("+proj=longlat +ellps=WGS84")
 # Plot selection in previous raster
 plot(selectAtt, col="red", add=TRUE, legend=F, proj4string=crswgs84)

Тогда у меня будет вопрос: какова площадь (в пределах общей площади) с глубиной (слой 1) и уклоном (слой 2), удовлетворяющей заданным условиям? В этом случае при высоте от -1000 до -4000 м и с углом наклона> 10 градусов.

Моя первоначальная мысль заключалась в следующем:

> area(selectAtt)

давая ответ:

class       : RasterLayer 
dimensions  : 623, 815, 507745  (nrow, ncol, ncell)
resolution  : 0.008323108, 0.008319957  (x, y)
extent      : -38.50417, -31.72083, -33.8875, -28.70417  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0 
data source : in memory
names       : layer 
values      : 0.7083593, 0.7481782  (min, max)

Это основная информация об объекте Raster ... это вызвало у меня странное ощущение, что я не получаю ответа на поставленный вопрос. Может я задавал не правильный вопрос? Во всяком случае, он мне ничего не сказал о размерах площади, соответствующей моим условиям.

Тогда я сделал:

a <- stk[stk$layer.1 <= -1000 & stk$layer.1 >= -4000 & stk$layer.2 >= 10]
 area(a, na.rm=T)

 # This gives me the error message:
 Error in (function (classes, fdef, mtable)  :
         unable to find an inherited method for function ‘area’ for signature ‘"matrix"’

Я попытался найти, что это на самом деле означает, и похоже, что это несоответствие между функциями S3 и S4, хотя я точно не знаю, что это такое.

Во всяком случае, я думал, что задаю относительно простой запрос к пространственным данным, а именно, какая область соответствует выделению на основе информации из нескольких слоев из растрового стека? Что мне здесь не хватает? Любая помощь приветствуется!


person Francesc Montserrat    schedule 23.02.2017    source источник


Ответы (3)


Есть несколько методов доступа к слоям и значениям стека растра. Я предпочитаю следующее:

#select first layer of raster stack 
stk[[1]]

#get values of second layer
stk[[2]][]

Теперь вернемся к вашему вопросу:

Когда я хочу рассчитать площадь пикселей, соответствующих определенным критериям, я делаю следующее (при работе с небольшими растрами):

numberOfPixels <- sum(stk[[1]][] <= -1000 & stk[[1]][] >= -4000 & stk[[2]][] >= 10, na.rm=T)

Это дает вам количество пикселей, соответствующих определенным критериям. Если вы будете работать в системе координат проекции (вы работаете в WGS 84 и, следовательно, вы не можете рассчитать точные площади из этого), вы просто умножите numberOfPixels на разрешение вашего растра:

area <- numberOfPixels * (res(stk)[1] * res(stk)[2])

Если вы хотите получить площадь в квадратных метрах, перепроецируйте свой растр в систему координат проекции. Например, в UTM. В вашем случае этот вариант может подойти (обратите внимание, что ваш экстент охватывает несколько зон): http://www.spatialreference.org/ref/epsg/wgs-84-utm-zone-24s/

stk <- projectRaster(from=stk, crs="+proj=utm +zone=24 +south +ellps=WGS84 +datum=WGS84 +units=m +no_defs")

Затем еще раз:

numberOfPixels <- sum(stk[[1]][] <= -1000 & stk[[1]][] >= -4000 & stk[[2]][] >= 10, na.rm=T)
area <- numberOfPixels * (res(stk)[1] * res(stk)[2])
area
[1] 258898897920 
person maRtin    schedule 24.02.2017
comment
Привет, Мартин, спасибо за ваш ответ и четкое объяснение, которое очень помогает в понимании общей сути всего этого. Однако у меня есть встречный вопрос: я получил альтернативный ответ с другого форума / списка, где человек посоветовал мне просто сделать следующее, чтобы получить область, соответствующую заданным условиям: area_raster <- area(selectAtt, na.rm = TRUE); cellStats(area_raster, 'sum') Однако это дает мне другой результат. В чем разница в подходах и какой из них лучше всего использовать? - person Francesc Montserrat; 24.02.2017
comment
Как указано на странице справки по функциям области: Compute the approximate surface area of cells in an unprojected (longitude/latitude) Raster object. ... This variation is greatest near the poles and the values are thus not very precise for very high latitudes. Очевидно, оба метода дают существенно разные результаты. Однако я бы сказал, что вам будет безопаснее, если вы сначала перепроецируете растр в систему координат проекции, а затем вычислите площадь. (Еще раз обратите внимание: одна зона UTM может быть не лучшим подходом, поскольку ваша область интересов довольно велика). - person maRtin; 25.02.2017
comment
Я не знаю, является ли это (единственной) проблемой здесь. Если я не сделал ничего плохого, результаты будут совершенно другими: maRtin approach: 258898897920 - cellStats approach: 156745.9. Даже если бы единицы измерения были разными, это не объяснило бы разницу. Кроме того, область не так близка к полюсам, чтобы объяснить такую ​​большую ошибку для подхода cellStats, и не настолько велика (около 600 км), чтобы оправдать огромные отклонения из-за проблемы с одной зоной UTM. Я скорее согласен с @maRtin в том, что подход репроецирования кажется лучше, но, возможно, мы все еще что-то упускаем. - person lbusett; 25.02.2017

Хорошо, вот возможный другой подход, основанный на преобразовании ячеек растра в полигоны и последующем вычислении площади полигонов с использованием пакета geosphere:

require(geosphere)
polys = rasterToPolygons(stk)
polys_sub = subset(polys, (layer.1 <= -1000 & layer.1 >= -4000 & layer.2 >= 10))
> sum(areaPolygon(polys_sub))/1E6  #in km2

[1] 157035.2

Это очень похоже на то, что OP получил от метода cellStats (скидка около 2%), и все же полностью отличается от метода reprojection. Насколько я понимаю из areaPolygon, это должен быть численно правильный подход. Однако я до сих пор не понимаю различных результатов в отношении ответа @maRtin.

Кстати, для OP: зачем вы настраиваете пример с такой "странной" системой отсчета (широта / долгота, другое разрешение x / y)?

person lbusett    schedule 25.02.2017
comment
Могу я узнать причину отрицательного голоса? Это неправильный подход? - person lbusett; 08.03.2017
comment
Это не отвечает на вопрос о вычислении площади из растра. - person SeldomSeenSlim; 08.03.2017
comment
Я не согласен. Мы хотим вычислить площадь, соответствующую ячейкам растра на поверхности, которую они используются для представления. Ячейки растра (или его подмножества) в геопроекции представляют собой определенную часть земной поверхности, ограниченную границами ячеек, площадь которых является вычислимой. Однако, поскольку ячейки не квадратные, а единицы измерения неметрические, необходимы некоторые уловки для вычисления площади (преобразование проекции или использование векторного представления и сферической геометрии). Таким образом, возможно, что ответ неверен, но он отвечает на вопрос правильно. - person lbusett; 09.03.2017
comment
Вопрос конкретно в том, чтобы вычислить выделенную область из сложенного растрового объекта. Если вас беспокоит, как растровый объект соотносится с поверхностью, это совершенно отдельный вопрос. Очевидно, что у человека, задающего этот вопрос, есть проблема больше, чем просто возможность вычислить площадь. Вопрос здесь специфичен для растров, и вам не нужна система координат для вычисления площади растра, занятой заданным классом пикселей. - person SeldomSeenSlim; 09.03.2017
comment
Я бы сказал, что @LoBu здесь ближе к цели. Моя проблема действительно заключалась в том, как он это сформулировал: Ячейки растра (или его подмножества) в геопроекции представляют собой определенную часть земной поверхности, ограниченную границами ячеек, которые являются вычислимыми .. ИМО, проекция начинает играть роль, когда вы хотите выразить его в системе единиц (фартинги, м, морские мили). Я вернусь к своим данным и опробую упомянутые здесь подходы. Большое спасибо ! - person Francesc Montserrat; 10.03.2017
comment
@LoBu, я не уверен, что вы имеете в виду, отвечая на свой предыдущий вопрос о том, почему вы настраиваете пример с такой странной системой отсчета (широта / долгота, другое разрешение x / y)? Я пытался предоставить работоспособный пример, поэтому я скопировал большую часть своего скрипта, но попытался создать случайный набор данных. Конечно, реальные данные показывают красивую карту морского дна на глубине от 200 до 5000 метров. Или ты не об этом? - person Francesc Montserrat; 10.03.2017
comment
Просто ваш пример сгенерировал растр с переменным разрешением в широте и долготе (0,01088819 и 0,006359914), что необычно для карты. Этот dpt <- raster( xmx=-31.72083, xmn=-38.50417, ymn=-33.8875, ymx=-28.70417, res = c(0.01,0.01)), например, даст вам такое же разрешение 0,01. - person lbusett; 11.03.2017

Итак, сначала пара проверок на вменяемость ...

В какой области мы имеем дело? Мы основываем это на вашем стеке и будем использовать res() для получения разрешений. Достаточно просто взять их вручную, но я предпочитаю называть их.

 length(stk)*res(stk)[1]*res(stk)[2]

 70.32058

Таким образом, я получаю ~ 70,3 как фактическую площадь стека. Я получаю это только из того, что вы предоставили для данных, поэтому, если CRS или прогнозы ненадежны, это на вас. Если мы проведем работу по поиску области для нашего подмножества и обнаружим, что она сильно отличается от этой, мы сбились с пути.

Теперь я начну с вашего 4-го блока кода, в котором вы это сделали:

 a <- stk[stk$layer.1 <= -1000 & stk$layer.1 >= -4000 & stk$layer.2 >= 10]

Итак, теперь у нас есть слой a, на котором мы разделили stk, так что теперь это список значений, соответствующих критериям. Нам не нужен этот список, мы просто хотим знать, сколько элементов он содержит.

Заменить:

 a<-length(stk[stk$layer.1 <= -1000 & stk$layer.1 >= -4000 & stk$layer.2 >= 10])

поскольку мы только хотим знать, сколько элементов находится в списке ...

теперь, используя res() для получения разрешений x и y:

 a*res(stk)[1]*res(stk)[2]

Результаты в:

 29.80777

Судя по площади растра, которую мы вычислили ранее, это кажется разумным, ~ 42% от общей площади. Мне это кажется разумным.

Что касается проблем с проекциями и системами координат в других комментариях к ответам, ДА, это проблема. Но вы должны убедиться, что ваши прогнозы не ошибочны и имеют смысл для того, что вы пытаетесь сделать. Также помните, что простое переназначение системы проецирования - это не то же самое, что повторное проецирование. Вероятно, одна из самых распространенных ошибок, которые я вижу при работе с растрами в R, - это просто переназначение CRS вместо перепроецирования растра. Вы должны знать, в какой форме поступают ваши данные и что вам нужно с ними делать, чтобы делать с ними математические расчеты.

person SeldomSeenSlim    schedule 08.03.2017
comment
Возможно, я что-то упускаю, но это length(stk)*res(stk)[1]*res(stk)[2] = 70.32058 было бы правильным, если бы мы имели дело с метрической проекцией, так что результат res выражается в метрах (или кратных). Только не с широтой и долготой, когда ширина ячейки (в метрах) зависит от широты. Кроме того, какими будут единицы измерения площади, полученной в результате этого вычисления. ? десятичные градусы в квадрате? - person lbusett; 08.03.2017
comment
Да вы правы. Но эта проблема не решается никаким способом вычисления площади из растра. Пользователь данных должен знать, что он работает в соответствующей проекции, где разумно выполнять любые вычисления на основе площади на растре. Я упомянул об этом в начале и в конце. ЕСЛИ пользователь хочет получить разумные результаты от вычисления площади на растре, он должен убедиться, что его данные спроектированы соответствующим образом для этой работы. Речь идет о расчете площади по растру, а не по проекциям. - person SeldomSeenSlim; 08.03.2017
comment
Я скорее не согласен. Если я правильно следую за вами, из этого утверждения следует, что НИКАКОЕ вычисление / анализ площади не может быть выполнено, начиная с растра в географической проекции, что ИМО неверно (см. Мой комментарий ниже). - person lbusett; 09.03.2017
comment
Не думаю, что вы следите за Лобу. Моя точка зрения заключается в том, что можно вычислить площадь из растра независимо от того, какая система координат или проекция у него есть, или даже если она вообще есть. Пользователь должен знать, в какой системе координат / проекции они находятся, и имеет смысл экстраполировать на единицы реального мира (метры, футы, фарлонги, две недели и т. Д.). Я думаю, что проблема, которую вы поднимаете, относится к надуманному примеру здесь, потому что он ошибся в том, как он установил свою систему координат / проекцию. - person SeldomSeenSlim; 09.03.2017
comment
Что ж, пример не так уж и надуман: существует множество наборов данных в проекции широты и долготы, используемых для различных анализов. И, если кто-то заранее не перепроецирует метрическую карту в широту / долготу по какой-либо причине, он не делает ничего плохого, желая вычислить площадь, ИМО. (Кроме того, это не совсем правда, что вам не нужно знать систему отсчета для вычисления площади. Если вы работаете в географических координатах, представьте, хотите ли вы вычислить площадь на Марсе? Даже изменение опорной точки на Земле даст вам (Допускаю, что) разные результаты.) - person lbusett; 09.03.2017
comment
Чтобы вычислить площадь из растра: определите разрешение по осям x и y; умножьте это значение на количество пикселей. Вот и все. Период. CRS не имеет отношения к этому. По сути, в растре нет ничего геопространственного. То, что у вас может быть растр с проекцией, ничего не меняет в том, как вы выполняете основную математику в растре. Если его данные неверно спроектированы, а единицы бессмысленны, то это совершенно отдельный вопрос. Думаю, я сказал это 6 раз в этом вопросе. Здесь меня совершенно не волнует, какие у него подразделения. Это его проблема. - person SeldomSeenSlim; 09.03.2017
comment
Возможно, вы сказали это 6 раз, но я все равно не согласен. Итак, согласимся, что мы не согласны, и все ;-). - person lbusett; 09.03.2017
comment
Позвольте нам продолжить это обсуждение в чате. - person SeldomSeenSlim; 09.03.2017
comment
Нет. Это вопрос с очень конкретным, ясным и простым ответом, на который любой, кто занимается базовой работой с растром, должен иметь возможность ответить и имеет отношение к этому вопросу. Оставить вид, что на него не ответят, окажет медвежью услугу любому, у кого есть такая же проблема. - person SeldomSeenSlim; 09.03.2017