Sử dụng R để tính diện tích của nhiều đa giác trên bản đồ giao với một đa giác chồng chéo khác


22

Tôi có một shapefile được tải xuống từ Khảo sát bản đồ đưa ra ranh giới của khu vực bầu cử (phân khu) cho một quận của Vương quốc Anh. Tôi đã sử dụng R thành công để tải shapefile và vẽ các bản đồ khác nhau bằng cách sử dụng ggplot2như được mô tả trong câu hỏi này . Tất cả đều hoạt động khá tốt.

Bây giờ tôi muốn tạo một đa giác mới có hình dạng tùy ý, thêm nó vào bản đồ, sau đó tính toán dân số sống trong khu vực nằm dưới hình dạng, có thể bao phủ hoặc che phủ một phần nhiều bộ phận. Tôi có dân số cho mỗi bộ phận bầu cử và tôi có thể đưa ra giả định đơn giản hóa rằng dân số ở mỗi phường được phân bố đồng đều. Điều đó gợi ý các bước sau.

1) Xếp chồng một hình dạng mới trên bản đồ bao gồm một phần nhiều khu vực bầu cử. Giả sử có 3 bộ phận, để tranh luận. Nó sẽ trông giống như thế này. [Chỉnh sửa: ngoại trừ trong hình ảnh bên dưới hình dạng đứng 5 phân chia chứ không phải 3]

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

2) Tính tỷ lệ phần trăm diện tích của mỗi 3 phần này giao nhau với đa giác phủ.

3) Ước tính dân số bằng cách lấy tỷ lệ phần trăm diện tích của mỗi bộ phận được bao phủ bởi hình dạng phủ và nhân số này với dân số của mỗi bộ phận.

Tôi nghĩ rằng tôi có thể tìm ra cách tạo đa giác và phủ nó trên bản đồ, tức là thêm nó vào khung dữ liệu hiện có bằng cách sử dụng câu trả lời hữu ích cho câu hỏi này và các câu hỏi khác. Điều khiến tôi lo lắng là nhiệm vụ tìm ra tỷ lệ phần trăm của mỗi bộ phận được bao phủ bởi hình dạng phủ. Các cột latlongcột trong khung dữ liệu là các số liệu OpenData Khảo sát bản đồ lạ (Hướng và hướng Bắc hoặc một cái gì đó).

Vì vậy, câu hỏi đầu tiên của tôi là: Làm thế nào tôi có thể tìm kiếm khu vực (hoặc một tập hợp con của khu vực) của đa giác xác định đường viền của một bộ phận bầu cử bằng cách sử dụng dữ liệu này? Bởi vì ngay cả một tập hợp con có ý nghĩa của khung dữ liệu này là lớn, tôi đã sử dụng dputđể tạo tệp 500k ( có thể được sao chép và dán hoặc tải xuống từ đây ) thay vì đăng nó trong câu hỏi này. Bản đồ hình thành cơ sở cho hình ảnh trên được tạo ra như sau:

require(ggplot2)
ggplot(smalldf, aes(x = long, y = lat, group = group)) +
    geom_polygon(colour = "grey50", size = 1, aes(fill = smalldf$bin))

Câu hỏi thứ hai của tôi là: tôi có đang sử dụng đúng công cụ không? Hiện tại tôi đang sử dụng readShapePolytừ maptoolsgói để đọc shapefile. Sau đó tôi sử dụng fortifyđể tạo khung dữ liệu khoảng 130k dòng, phù hợp để sử dụng ggplot. Có lẽ tôi nên sử dụng một gói khác nếu có một công cụ hữu ích cho các quy trình như vậy?

Câu trả lời:


16

Câu trả lời và gợi ý của Spacesman ở trên rất hữu ích, nhưng bản thân chúng không tạo thành một câu trả lời đầy đủ. Sau một số công việc thám tử về phần tôi, tôi đã tiến gần hơn đến một câu trả lời mặc dù tôi vẫn chưa thể gIntersectionđi theo cách tôi muốn (xem câu hỏi ban đầu ở trên). Tuy nhiên, tôi đã xoay sở để đưa đa giác mới của mình vào SpatialPolygonsDataFrame.

CẬP NHẬT 2012-11-11: Tôi dường như đã tìm thấy một giải pháp khả thi (xem bên dưới). Chìa khóa là bọc các đa giác trong một SpatialPolygonscuộc gọi khi sử dụng gIntersectiontừ rgeosgói. Đầu ra trông như thế này:

[1] "Haverfordwest: Portfield ED (poly 2) area = 1202564.3, intersect = 143019.3, intersect % = 11.9%"
[1] "Haverfordwest: Prendergast ED (poly 3) area = 1766933.7, intersect = 100870.4, intersect % = 5.7%"
[1] "Haverfordwest: Castle ED (poly 4) area = 683977.7, intersect = 338606.7, intersect % = 49.5%"
[1] "Haverfordwest: Garth ED (poly 5) area = 1861675.1, intersect = 417503.7, intersect % = 22.4%"

Chèn đa giác khó hơn tôi nghĩ bởi vì, đáng ngạc nhiên, dường như không có một ví dụ dễ thực hiện nào về việc chèn một hình dạng mới trong một shapefile có nguồn gốc từ Khảo sát bản đồ hiện có. Tôi đã sao chép các bước của tôi ở đây với hy vọng rằng nó sẽ hữu ích cho người khác. Kết quả là một bản đồ như thế này.

bản đồ hiển thị đa giác mới phủ

Nếu / khi tôi giải quyết vấn đề giao nhau, tôi sẽ chỉnh sửa câu trả lời này và thêm các bước cuối cùng, trừ khi, tất nhiên, trừ khi ai đó đánh bại tôi với nó và cung cấp câu trả lời đầy đủ. Trong khi đó, ý kiến ​​/ lời khuyên về giải pháp của tôi cho đến nay đều được chào đón.

Mã theo sau.

require(sp) # the classes and methods that make up spatial ops in R
require(maptools) # tools for reading and manipulating spatial objects
require(mapdata) # includes good vector maps of world political boundaries.
require(rgeos)
require(rgdal)
require(gpclib)
require(ggplot2)
require(scales)
gpclibPermit()

## Download the Ordnance Survey Boundary-Line data (large!) from this URL:
## https://www.ordnancesurvey.co.uk/opendatadownload/products.html
## then extract all the files to a local folder.
## Read the electoral division (ward) boundaries from the shapefile
shp1 <- readOGR("C:/test", layer = "unitary_electoral_division_region")
## First subset down to the electoral divisions for the county of Pembrokeshire...
shp2 <- shp1[shp1$FILE_NAME == "SIR BENFRO - PEMBROKESHIRE" | shp1$FILE_NAME == "SIR_BENFRO_-_PEMBROKESHIRE", ]
## ... then the electoral divisions for the town of Haverfordwest (this could be done in one step)
shp3 <- shp2[grep("haverford", shp2$NAME, ignore.case = TRUE),]

## Create a matrix holding the long/lat coordinates of the desired new shape;
## one coordinate pair per line makes it easier to visualise the coordinates
my.coord.pairs <- c(
                    194500,215500,
                    194500,216500,
                    195500,216500,
                    195500,215500,
                    194500,215500)

my.rows <- length(my.coord.pairs)/2
my.coords <- matrix(my.coord.pairs, nrow = my.rows, ncol = 2, byrow = TRUE)

## The Ordnance Survey-derived SpatialPolygonsDataFrame is rather complex, so
## rather than creating a new one from scratch, copy one row and use this as a
## template for the new polygon. This wouldn't be ideal for complex/multiple new
## polygons but for just one simple polygon it seems to work
newpoly <- shp3[1,]

## Replace the coords of the template polygon with our own coordinates
newpoly@polygons[[1]]@Polygons[[1]]@coords <- my.coords

## Change the name as well
newpoly@data$NAME <- "zzMyPoly" # polygons seem to be plotted in alphabetical
                                 # order so make sure it is plotted last

## The IDs must not be identical otherwise the spRbind call will not work
## so use the spCHFIDs to assign new IDs; it looks like anything sensible will do
newpoly2 <- spChFIDs(newpoly, paste("newid", 1:nrow(newpoly), sep = ""))

## Now we should be able to insert the new polygon into the existing SpatialPolygonsDataFrame
shp4 <- spRbind(shp3, newpoly2)

## We want a visual check of the map with the new polygon but
## ggplot requires a data frame, so use the fortify() function
mydf <- fortify(shp4, region = "NAME")

## Make a distinction between the underlying shapes and the new polygon
## so that we can manually set the colours
mydf$filltype <- ifelse(mydf$id == 'zzMyPoly', "colour1", "colour2")

## Now plot
ggplot(mydf, aes(x = long, y = lat, group = group)) +
    geom_polygon(colour = "black", size = 1, aes(fill = mydf$filltype)) +
    scale_fill_manual("Test", values = c(alpha("Red", 0.4), "white"), labels = c("a", "b"))

## Visual check, successful, so back to the original problem of finding intersections
overlaid.poly <- 6 # This is the index of the polygon we added
num.of.polys <- length(shp4@polygons)
all.polys <- 1:num.of.polys
all.polys <- all.polys[-overlaid.poly] # Remove the overlaid polygon - no point in comparing to self
all.polys <- all.polys[-1] ## In this case the visual check we did shows that the
                           ## first polygon doesn't intersect overlaid poly, so remove

## Display example intersection for a visual check - note use of SpatialPolygons()
plot(gIntersection(SpatialPolygons(shp4@polygons[3]), SpatialPolygons(shp4@polygons[6])))

## Calculate and print out intersecting area as % total area for each polygon
areas.list <- sapply(all.polys, function(x) {
    my.area <- shp4@polygons[[x]]@Polygons[[1]]@area # the OS data contains area
    intersected.area <- gArea(gIntersection(SpatialPolygons(shp4@polygons[x]), SpatialPolygons(shp4@polygons[overlaid.poly])))
    print(paste(shp4@data$NAME[x], " (poly ", x, ") area = ", round(my.area, 1), ", intersect = ", round(intersected.area, 1), ", intersect % = ", sprintf("%1.1f%%", 100*intersected.area/my.area), sep = ""))
    return(intersected.area) # return the intersected area for future use
      })

Câu hỏi này (và câu trả lời) đã hữu ích cho tôi. Bây giờ library(scales)phải được thêm vào để làm cho tính minh bạch hoạt động.
Irene

1
Cảm ơn. Tôi tin rằng có một require(scales)cuộc gọi trong đó sẽ thực hiện các mẹo.
SlowLearner

15

Đừng sử dụng readShapePoly - nó bỏ qua đặc tả hình chiếu. Sử dụng readOGR từ gói sp.

Đối với các hoạt động địa lý như lớp phủ đa giác của bạn, hãy kiểm tra gói rgeos.

Theo nghĩa đen, điều cuối cùng bạn nên làm là chơi với fortify và ggplot. Giữ dữ liệu của bạn trong các đối tượng lớp sp, vẽ đồ thị với đồ họa cơ bản và để lại đường ggplot cho đến khi kết thúc dự án và bạn cần một số cốt truyện đẹp.


Cảm ơn vì những lời khuyên; Tôi sẽ xem lại readOGR. Đối với ggplot, đó là điều tự nhiên khi tôi học nó khi tôi học R - không bao giờ bận tâm với đồ họa cơ bản.
SlowLearner

1
Nhận xét của bạn về các đối tượng lớp sp, điều này có vẻ rất quan trọng nếu tôi muốn tận dụng các chức năng trong rgeos. Tôi đã quản lý để tạo ra một loại đa giác bằng ví dụ của bạn trong câu trả lời được liên kết, nhưng tôi không thể tìm ra cách thêm đa giác mới vào khung dữ liệu không gian hiện có. Tôi đã nhầm lẫn một chút với @datacú pháp nhưng không đi đến đâu. Bạn có bất cứ lời khuyên?
SlowLearner

4
Bạn có thể tham gia hai khung dữ liệu đa giác không gian cbind(part1,part2)nếu chúng có ID đa giác duy nhất - nếu không, bạn sẽ nhận được cảnh báo và cần sử dụng spChFIDsđể gán ID tính năng đa giác duy nhất.
Spainedman
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.