Chuyển đổi shapefile dòng thành raster, value = tổng chiều dài của các dòng trong ô


14

Tôi có một shapefile dòng đại diện cho một mạng lưới đường. Tôi muốn rasterize dữ liệu này, với các giá trị kết quả trong raster hiển thị tổng chiều dài của các dòng nằm trong ô raster.

Dữ liệu nằm trong phép chiếu Lưới Quốc gia Anh nên các đơn vị sẽ là mét.

Lý tưởng nhất là tôi muốn thực hiện thao tác này bằng cách sử dụng Rvà tôi đoán rằng rasterizechức năng từ rastergói sẽ đóng góp một phần trong việc đạt được điều này, tôi chỉ không thể tìm ra chức năng được áp dụng là gì.


Có lẽ vignette('over', package = 'sp')có thể giúp đỡ.

Câu trả lời:


12

Sau một câu hỏi gần đây , bạn có thể muốn sử dụng các chức năng được cung cấp bởi gói rgeos để giải quyết vấn đề của bạn. Vì lý do tái sản xuất, tôi đã tải xuống một shapefile của đường Tanzania từ DIVA-GIS và đưa nó vào thư mục làm việc hiện tại của tôi. Đối với các tác vụ sắp tới, bạn sẽ cần ba gói:

  • rgdal để xử lý dữ liệu không gian chung
  • raster cho rasterization dữ liệu shapefile
  • rgeos để kiểm tra giao lộ của đường với mẫu raster và tính chiều dài đường

Do đó, các dòng đầu tiên của bạn có thể trông như thế này:

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

Sau đó, bạn cần nhập dữ liệu shapefile. Lưu ý rằng các shapefile DIVA-GIS được phân phối trong EPSG: 4326, vì vậy tôi sẽ chiếu shapefile thành EPSG: 21037 (UTM 37S) để xử lý các mét thay vì độ.

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

Đối với rasterization tiếp theo, bạn sẽ cần một mẫu raster bao gồm phạm vi không gian của shapefile của bạn. Mẫu raster bao gồm 10 hàng và 10 cột theo mặc định, do đó tránh thời gian tính toán quá rộng.

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

Bây giờ mẫu đã được thiết lập, lặp qua tất cả các ô của raster (hiện chỉ bao gồm các giá trị NA). Bằng cách chỉ định giá trị '1' cho ô hiện tại và sau đó thực thi rasterToPolygons, shapefile 'tmp_shp' kết quả sẽ tự động giữ phạm vi của pixel hiện đang được xử lý. gIntersectsphát hiện xem mức độ này trùng với đường. Nếu không, hàm sẽ trả về giá trị '0'. Mặt khác, shapefile đường bị cắt bởi ô hiện tại và tổng chiều dài của 'SpatialLines' trong ô đó đang được tính bằng cách sử dụng 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)
  }
})

Cuối cùng, bạn có thể chèn độ dài tính toán (được chuyển đổi thành km) vào mẫu raster và xác minh trực quan kết quả của bạn.

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))

dòng2raster


Điều này thật tuyệt! tôi đã thay đổisapply() đến pbsapply()và sử dụng đối số cụm cl = detectCores()-1. Bây giờ tôi có thể chạy ví dụ này song song!
philiporlando

11

Dưới đây được sửa đổi từ giải pháp của Jeffrey Evans. Giải pháp này nhanh hơn nhiều vì nó không sử dụng rasterize

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

Có vẻ là phương pháp hiệu quả và thanh lịch nhất của những người được liệt kê. Ngoài ra, chưa từng thấy raster::intersect() trước đây, tôi thích rằng nó kết hợp các thuộc tính của các tính năng giao nhau, không giống như rgeos::gIntersection().
Matt SM

+1 luôn luôn tốt đẹp khi thấy các giải pháp hiệu quả hơn!
Jeffrey Evans

@RobertH, tôi đã thử sử dụng giải pháp này cho một vấn đề khác, nơi tôi muốn làm tương tự như được hỏi trong chủ đề này, nhưng với một đường shapefile rất lớn (cho toàn bộ một lục địa). Nó dường như đã hoạt động, nhưng khi tôi cố gắng thực hiện con số như được thực hiện bởi @ fdetsch, tôi không nhận được một lưới liền kề mà chỉ có một vài ô vuông màu trong hình (xem trong tinypic.com/r/20hu87k/9 ).
Doon_Bogan

Và bằng cách hiệu quả nhất ... với tập dữ liệu mẫu của tôi: thời gian chạy 0,6 giây cho giải pháp này so với 8,25 giây cho giải pháp nâng cao nhất.
dùng3386170

1

Bạn không cần một vòng lặp for. Chỉ cần cắt mọi thứ cùng một lúc và sau đó thêm độ dài dòng vào các phân đoạn dòng mới bằng cách sử dụng chức năng "SpatialLinesL wavels" trong sp. Sau đó, bằng cách sử dụng hàm rasterize gói rasterize với đối số fun = sum, bạn có thể tạo một raster với tổng độ dài (s) giao nhau của mỗi ô. Sử dụng câu trả lời ở trên và dữ liệu liên quan ở đây là mã sẽ tạo ra kết quả tương tự.

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))

Lần đầu tiên tôi thấy SpatialLinesLengths. Đoán không bao giờ là quá muộn để học, cảm ơn bạn (: rasterizemất khá nhiều thời gian, mặc dù (dài hơn 7 lần so với cách tiếp cận trên máy của tôi).
fdetsch

Tôi đã nhận thấy rằng rasterize đang bị chậm. Tuy nhiên, đối với các vấn đề lớn, vòng lặp for sẽ thực sự làm mọi thứ chậm lại và tôi nghĩ rằng bạn sẽ thấy một giải pháp tối ưu hơn nhiều với rasterize. Bên cạnh đó, nhà phát triển gói raster đang cố gắng làm cho mọi bản phát hành được tối ưu hóa và nhanh hơn.
Jeffrey Evans

Một vấn đề tiềm năng tôi tìm thấy với kỹ thuật này là rasterize()hàm bao gồm tất cả các dòng chạm vào một ô đã cho. Điều này dẫn đến độ dài phân đoạn dòng được tính hai lần trong một số trường hợp: một lần trong ô mà chúng được cho là và một lần trong ô liền kề mà điểm cuối của đường chỉ chạm vào.
Matt SM

Đúng, nhưng "rp" là đối tượng đang được rasterized mà nó là giao điểm của đa giác và điểm.
Jeffrey Evans

1

Đây là một cách tiếp cận khác. Nó đi chệch khỏi những cái đã được đưa ra bằng cách sử dụng spatstatgói. Theo như tôi có thể nói, gói này có phiên bản riêng của các đối tượng không gian (ví dụ:im so với rastercác đối tượng), nhưng maptoolsgói cho phép chuyển đổi qua lại giữa spatstatcác đối tượng và các đối tượng không gian tiêu chuẩn.

Cách tiếp cận này được lấy từ bài R-sig-Geo này .

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))

Imgur

Bit chậm nhất là chuyển đổi các đường từ SpatialLinesthành Mẫu phân đoạn dòng (nghĩa là spatstat::psp). Khi đã xong, các phần tính toán độ dài thực tế khá nhanh, thậm chí cho độ phân giải cao hơn nhiều. Ví dụ, trên MacBook 2009 cũ của tôi:

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 

Hmmmm ... Tôi chắc chắn mong muốn những cái rìu đó không có trong ký hiệu khoa học. Bất cứ ai có bất kỳ ý tưởng làm thế nào để khắc phục điều đó?
Matt SM

Bạn có thể sửa đổi cài đặt R toàn cầu và tắt ký hiệu bằng cách sử dụng: tùy chọn (scipen = 999)) tuy nhiên, tôi không biết liệu mạng có tôn trọng cài đặt môi trường toàn cầu hay không.
Jeffrey Evans

0

Hãy để tôi giới thiệu cho bạn tĩnh mạch gói với một số chức năng để làm việc các dòng không gian và nhập 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

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


-1

Điều này nghe có vẻ hơi ngây thơ nhưng nếu đó là hệ thống đường thì hãy chọn đường và lưu vào bảng clip sau đó tìm một công cụ cho phép bạn thêm bộ đệm vào bảng tạm đặt thành chiều rộng hợp pháp của đường tức là 3 mét +/- hãy nhớ rằng bộ đệm nằm từ đường trung tâm đến cạnh * 2 i cho mỗi bên nên bộ đệm 3 mét thực sự là đường 6 mét từ bên này sang bên kia.


Chiều rộng đường phải làm gì với chiều dài đường. Câu trả lời này không giải quyết câu hỏi.
alphabetasoup
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.