Answers:
在最近的问题之后,您可能想利用rgeos软件包提供的功能来解决您的问题。出于可复制性的原因,我从DIVA-GIS下载了坦桑尼亚道路的形状文件,并将其放置在当前的工作目录中。对于即将执行的任务,您将需要三个软件包:
因此,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))
sapply()
到pbsapply()
和使用的集群参数cl = detectCores()-1
。现在,我可以并行运行此示例了!
以下是从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()
。
您不需要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倍)。)
rasterize()
函数包括所有触摸给定单元格的行。在某些情况下,这会导致对线段长度进行两次计数:一次是在单元格中,而一次是在线端点刚刚接触的相邻单元格中。
这是另一种方法。它与使用该spatstat
软件包已给出的内容有所不同。据我所知,该程序包具有自己的空间对象版本(例如im
vs. 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
让我向您展示具有多种功能的封装静脉,这些功能可以处理空间线并导入sf和data.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
这听起来有些天真,但是如果是道路系统,则选择道路并保存到剪贴板,然后寻找找到一个工具,该工具可让您向剪贴板添加缓冲区,将其设置为道路的合法宽度,即3米+/-请记住,缓冲区是从中心线到边缘*每边2 i,因此3米的缓冲区实际上是从一侧到另一侧的6米长的道路。
vignette('over', package = 'sp')
会有所帮助。