【问题标题】:Calculate selected area from stacked raster object从堆叠的栅格对象计算选定区域
【发布时间】:2017-07-14 12:16:51
【问题描述】:

因为我最近才开始使用 R 进行空间分析,所以我是 无论如何,我都不是地理学家或空间数据专家,我有一个-什么 我认为这是一个相对简单的问题。我正在尝试计算 堆叠的光栅对象中满足特定条件的部分区域 状况。 更具体地说,来自深海的数据集 南大西洋,我堆叠了两个栅格对象(深度和坡度) 在坐标系 (WGS84) 和 x-y (Lat-Long) 中进一步相同 位置。从堆叠的栅格对象中,我想 提取位于(例如)1000 到 4000 m 深度之间的部分,使用 坡度超过 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)

那么,我的问题是:深度(layer.1)和坡度(layer.2)都满足给定条件的面积(在总面积内)是多少?在这种情况下,海拔在 -1000 和 -4000 m 之间,坡度角 >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 功能之间的不匹配,即使我不完全知道它们是什么。

无论如何,我以为我在对空间数据提出一个相对简单的查询,即基于栅格堆栈中多个图层的信息的选择对应的区域是多少?我在这里想念什么?任何帮助是极大的赞赏 !

【问题讨论】:

    标签: r raster r-raster map-projections


    【解决方案1】:

    有几种方法可以访问栅格堆栈的图层和值。我更喜欢以下内容:

    #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 
    

    【讨论】:

    • 嗨,马丁,感谢您的回复和清晰的解释,这有助于理解这一切的泛型。但是,我有一个反问题:我从另一个论坛/列表中获得了替代答案,该人建议我只需执行以下操作即可获得与给定条件相对应的区域:area_raster &lt;- area(selectAtt, na.rm = TRUE); cellStats(area_raster, 'sum') 但是,这给了我一个不同的结果。方法有什么区别,哪种方法最好用?
    • 正如区域功能帮助页面所述: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 区域可能不是最好的方法,因为您的感兴趣区域非常大)。
    • 我不知道这是否是(唯一的)问题,在这里。如果我没有做错任何事,结果会完全不同maRtin approach: 258898897920 - cellStats approach: 156745.9。即使是“测量单位”不同,也无法解释差异。此外,该区域距离两极不是很近,无法解释cellStats 方法的“误差”如此之大,也没有那么“大”(约 600 公里)来证明由于“单 UTM 区域”问题导致的巨大偏差是合理的。我更同意@maRtin 的观点,即重投影方法似乎更好,但也许我们仍然缺少一些东西。
    【解决方案2】:

    好的,这是一种可能的不同方法,基于将栅格单元转换为多边形,然后利用包 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 answer 的不同结果。

    顺便说一句,对于 OP:你为什么要使用如此“奇怪”的参考系统(纬度/经度,不同的 x/y 分辨率)设置一个示例?

    【讨论】:

    • 我可以问下投票的原因吗?这种方法错了吗?
    • 这没有回答从栅格计算面积的问题。
    • 我不同意。我们要计算的是对应于栅格单元在它们用于表示的表面上的区域。地理投影中栅格(或其子集)的像元表示由像元边界界定的地球表面的特定部分,该区域是可计算的。但是,由于单元格不是方形的,并且单位不是公制的,因此需要一些技巧来计算面积(转换投影,或使用矢量表示和球面几何)。因此,答案可能是错误的,但它确实正确地回答了问题。
    • 问题具体是“从堆叠的光栅对象计算选定区域”。如果人们关心光栅对象与表面的关系,那是一个完全独立的问题。显然,提出这个问题的人所面临的问题不仅仅是能够计算一个面积。这里的问题是特定于栅格的,您不需要坐标系来计算给定类像素所占据的栅格面积。
    • 我不得不说@LoBu 更接近这里的标记。我的问题确实是,正如他所说的那样:“地理投影中栅格(或其子集)的单元代表地球表面的特定部分,由单元边界分隔,该区域是可计算的。”。 IMO,一旦你想用单位系统(法尔,米,海里)来表达它,投影就会开始发挥作用。我将回到我的数据并尝试这里提到的方法。非常感谢!
    【解决方案3】:

    所以首先进行一些健全性检查...

    我们在这里处理的实际区域是什么? 我们将基于您的堆栈,我们将使用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]
    

    所以现在我们有了一个层,我们在其中对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%。这在我看来是合理的。

    关于其他答案 cmets 中的投影和坐标系问题,是的这是一个问题。但是你要确保你的预测不会有问题,并且对你想要做的事情有意义。还要记住,简单地重新分配投影系统与重新投影不同。我看到在 R 中使用栅格时最常见的错误之一可能是简单地重新分配 CRS 而不是重新投影栅格。您需要知道您的数据是以什么形式进入的,以及您需要用它做什么才能对它进行您想要做的那种数学运算。

    【讨论】:

    • 也许我遗漏了一些东西,但如果我们处理公制投影,这个length(stk)*res(stk)[1]*res(stk)[2] = 70.32058 是正确的,因此“res”的结果以米(或倍数)为单位。不是纬度/经度,其中单元格的“宽度”(以米为单位)随纬度而变化。此外,该计算得出的面积测量单位是什么。 ?十进制度数的平方?
    • 是的,你是对的。但是这个问题不会随着任何从栅格计算面积的方式而消失。数据的用户知道他在适当的投影中工作,在栅格上进行任何类型的基于区域的数学是明智的。我在开幕式和闭幕式中提到了这一点。如果用户想通过计算栅格面积获得合理的结果,他们需要确保他们的数据已针对该工作进行了适当的投影。这里的问题是关于从栅格计算面积,而不是投影。
    • 我不同意。如果我正确地跟随你,从这个陈述中可以看出,不能从地理投影中的栅格开始进行任何区域计算/分析,这在 IMO 中是不正确的(见我下面的评论)。
    • 我认为你没有关注 LoBu。我的观点是并且仍然是,无论它具有什么坐标系或投影,或者即使它根本没有,都可以从栅格计算面积。用户需要了解他们所处的坐标/投影系统,以及推断“现实世界”(米、英尺、弗隆、两周等)单位是否有意义。我认为您提出的问题特定于这里的人为示例,因为他在设置坐标系/投影的方式上犯了一个错误。
    • 好吧,这个例子并没有那么“人为”:在纬度/经度投影中有大量数据集用于各种分析。而且,除非有人出于某种原因事先将“度量”地图重新投影到纬度/经度,否则他想要计算一个区域 IMO 并没有做错任何事情。 (另外,你不需要知道参考系统来计算一个区域并不是真的。如果在地理坐标中工作,想象一下如果你想计算火星上的一个区域?即使改变地球上的参考基准也会给你(有点,我承认)不同的结果。)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 2016-04-30
    • 2020-11-12
    • 2018-03-06
    • 1970-01-01
    相关资源
    最近更新 更多