将线shapefile转换为栅格,值=像元中线的总长度


14

我有一个代表道路网络的shapefile文件。我希望对该数据进行栅格化,栅格中的结果值显示了落入栅格像元内的线的总长度。

数据在英国国家网格投影中,因此单位将是米。

理想情况下,我想使用来执行此操作R,并且我猜测程序包中的rasterize功能raster将在实现此功能中起作用,我只是无法弄清楚应应用的功能。


也许vignette('over', package = 'sp')会有所帮助。

Answers:


12

最近的问题之后,您可能想利用rgeos软件包提供的功能来解决您的问题。出于可复制性的原因,我从DIVA-GIS下载了坦桑尼亚道路的形状文件,并将其放置在当前的工作目录中。对于即将执行的任务,您将需要三个软件包:

  • rgdal用于一般空间数据处理
  • 用于shapefile数据栅格化的栅格
  • rgeos使用栅格模板检查道路交叉点并计算道路长度

因此,can的第一行应如下所示:

library(rgdal)
library(raster)
library(rgeos)

之后,您需要导入shapefile数据。请注意,DIVA-GIS形状文件分布在EPSG:4326中,因此我将形状文件投影到EPSG:21037(UTM 37S)以处理米而非度。

roads <- readOGR(dsn = ".", layer = "TZA_roads")
roads_utm <- spTransform(roads, CRS("+init=epsg:21037"))

对于后续的栅格化,您将需要一个覆盖shapefile空间范围的栅格模板。栅格模板默认情况下由10行和10列组成,因此避免了过多的计算时间。

roads_utm_rst <- raster(extent(roads_utm), crs = projection(roads_utm))

现在已经设置好模板,循环遍历栅格的所有像元(当前仅由NA值组成)。通过将值“ 1”分配给当前单元格并随后执行rasterToPolygons,生成的shapefile“ tmp_shp”将自动保存当前处理的像素的范围。gIntersects检测此范围是否与道路重叠。如果不是,该函数将返回值“ 0”。否则,道路shapefile将由当前单元格裁剪,并使用来计算该单元格内“ SpatialLines”的总长度gLength

lengths <- sapply(1:ncell(roads_utm_rst), function(i) {
  tmp_rst <- roads_utm_rst
  tmp_rst[i] <- 1
  tmp_shp <- rasterToPolygons(tmp_rst)

  if (gIntersects(roads_utm, tmp_shp)) {
    roads_utm_crp <- crop(roads_utm, tmp_shp)
    roads_utm_crp_length <- gLength(roads_utm_crp)
    return(roads_utm_crp_length)
  } else {
    return(0)
  }
})

最后,您可以将计算出的长度(转换为公里)插入栅格模板,并直观地验证结果。

roads_utm_rst[] <- lengths / 1000

library(RColorBrewer)
spplot(roads_utm_rst, scales = list(draw = TRUE), xlab = "x", ylab = "y", 
       col.regions = colorRampPalette(brewer.pal(9, "YlOrRd")), 
       sp.layout = list("sp.lines", roads_utm), 
       par.settings = list(fontsize = list(text = 15)), at = seq(0, 1800, 200))

lines2raster


这太棒了!我改sapply()pbsapply()和使用的集群参数cl = detectCores()-1。现在,我可以并行运行此示例了!
philiporlando

11

以下是从Jeffrey Evans的解决方案中修改的。该解决方案不使用栅格化,因此速度更快

library(raster)
library(rgdal)
library(rgeos)

roads <- shapefile("TZA_roads.shp")
roads <- spTransform(roads, CRS("+proj=utm +zone=37 +south +datum=WGS84"))
rs <- raster(extent(roads), crs=projection(roads))
rs[] <- 1:ncell(rs)

# Intersect lines with raster "polygons" and add length to new lines segments
rsp <- rasterToPolygons(rs)
rp <- intersect(roads, rsp)
rp$length <- gLength(rp, byid=TRUE) / 1000
x <- tapply(rp$length, rp$layer, sum)
r <- raster(rs)
r[as.integer(names(x))] <- x

似乎是列出的那些方法中最有效,最优雅的方法。另外,与raster::intersect() 以前不同,我喜欢它结合了相交特征的属性rgeos::gIntersection()
马特SM

+1总是很高兴看到更有效的解决方案!
杰弗里·埃文斯

@RobertH,我尝试将这个解决方案用于另一个问题,我想按照此线程中的要求执行相同的操作,但是具有非常大的道路shapefile(适用于整个大陆)。它似乎有效,但是当我尝试执行@ fdetsch所做的图形时,我没有得到连续的网格,而在图片中只有几个彩色正方形(请参见tinypic.com/r/20hu87k/9)。
Doon_Bogan '16

最有效的...我的样本数据集:此解决方案的运行时间为0.6秒,而最赞成的解决方案的运行时间为8.25秒。
user3386170 '18

1

您不需要for循环。只需一次相交所有内容,然后使用sp中的“ SpatialLinesLengths”功能将线长添加到新的线段中。然后,将栅格数据包栅格化功能与fun = sum参数一起使用,您可以创建一个栅格,该栅格的线长之和与每个像元相交。使用上面的答案和相关数据,这里的代码将产生相同的结果。

require(rgdal)
require(raster)
require(sp)
require(rgeos)

setwd("D:/TEST/RDSUM")
roads <- readOGR(getwd(), "TZA_roads")
  roads <- spTransform(roads, CRS("+init=epsg:21037"))
    rrst <- raster(extent(roads), crs=projection(roads))

# Intersect lines with raster "polygons" and add length to new lines segments
rrst.poly <- rasterToPolygons(rrst)
  rp <- gIntersection(roads, rrst.poly, byid=TRUE)
    rp <- SpatialLinesDataFrame(rp, data.frame(row.names=sapply(slot(rp, "lines"), 
                               function(x) slot(x, "ID")), ID=1:length(rp), 
                               length=SpatialLinesLengths(rp)/1000) ) 

# Rasterize using sum of intersected lines                            
rd.rst <- rasterize(rp, rrst, field="length", fun="sum")

# Plot results
require(RColorBrewer)
spplot(rd.rst, scales = list(draw=TRUE), xlab="x", ylab="y", 
       col.regions=colorRampPalette(brewer.pal(9, "YlOrRd")), 
       sp.layout=list("sp.lines", rp), 
       par.settings=list(fontsize=list(text=15)), at=seq(0, 1800, 200))

第一次见SpatialLinesLengths。猜猜学习永远不会太晚了,谢谢(rasterize虽然花了很长时间(比我的机器上层方法要长7倍)。)
fdetsch 2014年

我确实注意到栅格化很慢。但是,对于大问题,for循环确实会减慢速度,我认为您会看到使用光栅化的更优化的解决方案。除此以外,raster软件包的开发人员正在努力使每个发行版都更加优化和更快。
Jeffrey Evans

我发现这种技术的一个潜在问题是该rasterize()函数包括所有触摸给定单元格的行。在某些情况下,这会导致对线段长度进行两次计数:一次是在单元格中,而一次是在线端点刚刚接触的相邻单元格中。
Matt SM

是的,但是“ rp”是栅格化的对象,它是多边形和点的交集。
Jeffrey Evans

1

这是另一种方法。它与使用该spatstat软件包已给出的内容有所不同。据我所知,该程序包具有自己的空间对象版本(例如imvs. raster对象),但是该maptools程序包允许在spatstat对象和标准空间对象之间来回转换。

这种方法取材于R-sig-Geo帖子

require(sp)
require(raster)
require(rgdal)
require(spatstat)
require(maptools)
require(RColorBrewer)

# Load data and transform to UTM
roads <- shapefile('data/TZA_roads.shp')
roadsUTM <- spTransform(roads, CRS("+init=epsg:21037"))

# Need to convert to a line segment pattern object with maptools
roadsPSP <- as.psp(as(roadsUTM, 'SpatialLines'))

# Calculate lengths per cell
roadLengthIM <- pixellate.psp(roadsUTM, dimyx=10)

# Convert pixel image to raster in km
roadLength <- raster(dtanz / 1000, crs=projection(roadsUTM))

# Plot
spplot(rtanz, scales = list(draw=TRUE), xlab="x", ylab="y", 
       col.regions=colorRampPalette(brewer.pal(9, "YlOrRd")), 
       sp.layout=list("sp.lines", roadsUTM), 
       par.settings=list(fontsize=list(text=15)), at=seq(0, 1800, 200))

伊姆古尔

最慢的位是将道路从转换为SpatialLines线段模式(即spatstat::psp)。一旦完成,即使对于更高的分辨率,实际的长度计算部分也很快。例如,在我的旧版2009 MacBook上:

system.time(pixellate(tanzpsp, dimyx=10))
#    user  system elapsed 
#   0.007   0.001   0.007

system.time(pixellate(tanzpsp, dimyx=1000))
#    user  system elapsed 
#   0.146   0.032   0.178 

嗯...我当然希望那些轴不是科学计数法。有人知道如何解决吗?
Matt SM

您可以使用:options(scipen = 999))修改全局R设置并关闭符号,但是,我不知道点阵是否会支持全局环境设置。
杰弗里·埃文斯

0

让我向您展示具有多种功能的封装静脉,这些功能可以处理空间线并导入sfdata.table

library(vein)
library(sf)
library(cptcity)
data(net)
netsf <- st_as_sf(net) #Convert Spatial to sf
netsf <- st_transform(netsf, 31983) # Project data
netsf$length_m  <- st_length(netsf)
netsf <- netsf[, "length_m"]
g <- make_grid(netsf, width = 1000) #Creat grid of 1000m spacing with columns id for each feature
# Number of lon points: 12
# Number of lat points: 11

gnet <- emis_grid(netsf, g)
plot(gnet["length_m"])

sf_to_raster <- function(x, column, ncol, nrow){
  x <- sf::as_Spatial(x)
  r <- raster::raster(ncol = ncol, nrow = nrow)
  raster::extent(r) <- raster::extent(x)
  r <- raster::rasterize(x, r, column)
  return(r)
}

rr <- sf_to_raster(gnet, "length_m", 12, 11)
spplot(rr, sp.layout = list("sp.lines", as_Spatial(netsf)),
       col.regions = cpt(), scales = list(draw = T))
spplot(rr, sp.layout = list("sp.lines", as_Spatial(netsf)),
       col.regions = cpt(pal = 5176), scales = list(draw = T))
spplot(rr, sp.layout = list("sp.lines", as_Spatial(netsf)),
       col.regions = lucky(), scales = list(draw = T))
# Colour gradient: neota_flor_apple_green, number: 6165

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明


-1

这听起来有些天真,但是如果是道路系统,则选择道路并保存到剪贴板,然后寻找找到一个工具,该工具可让您向剪贴板添加缓冲区,将其设置为道路的合法宽度,即3米+/-请记住,缓冲区是从中心线到边缘*每边2 i,因此3米的缓冲区实际上是从一侧到另一侧的6米长的道路。


道路宽度与道路长度有什么关系。这个答案没有解决这个问题。
alphabetasoup
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.