ใช้ R เพื่อคำนวณพื้นที่ของรูปหลายเหลี่ยมหลายรูปบนแผนที่ที่ตัดกันกับรูปหลายเหลี่ยมที่ซ้อนทับอื่น


22

ฉันมีไฟล์รูปร่างดาวน์โหลดจากการสำรวจอาวุธยุทโธปกรณ์ที่ให้ขอบเขตการเลือกตั้งวอร์ด (แผนก) สำหรับมณฑลของสหราชอาณาจักร ฉันใช้ R เพื่อโหลด shapefile สำเร็จและวางแผนแผนที่ต่างๆโดยใช้ggplot2ตามที่อธิบายไว้ในคำถามนี้ มันทำงานได้ค่อนข้างดี

ตอนนี้ฉันต้องการสร้างรูปหลายเหลี่ยมใหม่ของรูปร่างโดยพลการเพิ่มลงในแผนที่จากนั้นคำนวณประชากรที่อาศัยอยู่ในพื้นที่ที่อยู่ภายใต้รูปร่างซึ่งอาจครอบคลุมหรือบางส่วนครอบคลุมหลายส่วน ฉันมีประชากรสำหรับแต่ละแผนกการเลือกตั้งและฉันสามารถตั้งสมมติฐานง่าย ๆ ว่าประชากรในวอร์ดแต่ละแห่งมีการกระจายอย่างเท่าเทียมกัน ที่แนะนำขั้นตอนต่อไปนี้

1) วางรูปร่างใหม่บนแผนที่ซึ่งครอบคลุมบางส่วนของหน่วยงานการเลือกตั้ง สมมติว่ามี 3 แผนกเพื่อการโต้แย้ง มันจะมีลักษณะเช่นนี้ [แก้ไข: ยกเว้นว่าในภาพด้านล่างรูปร่างคร่อม 5 ส่วนมากกว่า 3]

ป้อนคำอธิบายรูปภาพที่นี่

2) คำนวณเปอร์เซ็นต์ของพื้นที่ของแต่ละส่วนทั้ง 3 ที่ตัดกับรูปหลายเหลี่ยมที่ซ้อนทับ

3) การประมาณประชากรโดยการหาเปอร์เซ็นต์ของพื้นที่ของแต่ละส่วนที่ถูกปกคลุมด้วยรูปร่างที่ซ้อนทับและคูณด้วยประชากรของแต่ละส่วน

ฉันคิดว่าฉันสามารถหาวิธีสร้างรูปหลายเหลี่ยมและวางทับบนแผนที่เช่นเพิ่มลงใน data frame ที่มีอยู่โดยใช้คำตอบที่เป็นประโยชน์สำหรับคำถามนี้และคำถามอื่น ๆ สิ่งที่ฉันเป็นกังวลคืองานที่ต้องทำเปอร์เซ็นต์ของแต่ละส่วนที่ถูกปกคลุมด้วยรูปร่างที่ซ้อนทับ latและlongคอลัมน์ในกรอบข้อมูลที่เป็นคนแปลกตัวเลขอาวุธยุทโธปกรณ์สำรวจ OpenData (Eastings และ Northings หรือบางอย่าง)

ดังนั้นคำถามแรกของฉันคือฉันจะไปหาพื้นที่ (หรือส่วนย่อยของพื้นที่) ของรูปหลายเหลี่ยมที่กำหนดขอบเขตของการเลือกตั้งโดยใช้ข้อมูลนี้ได้อย่างไร เนื่องจากแม้แต่เซ็ตย่อยที่มีความหมายของเฟรมข้อมูลนี้ก็มีขนาดใหญ่ฉันจึงเคยdputสร้างไฟล์ขนาด 500k ( ซึ่งสามารถคัดลอกและวางหรือดาวน์โหลดได้จากที่นี่ ) แทนที่จะโพสต์ในคำถามนี้ แผนที่ที่สร้างฐานสำหรับภาพด้านบนถูกสร้างขึ้นด้วยสิ่งต่อไปนี้:

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

คำถามที่สองของฉันคือฉันใช้เครื่องมือที่เหมาะสมหรือไม่ ขณะนี้ฉันกำลังใช้readShapePolyจากmaptoolsแพ็คเกจเพื่ออ่าน shapefile จากนั้นผมก็ใช้fortifyในการสร้างกรอบข้อมูลที่เกี่ยวกับ 130K ggplotเส้นเหมาะสำหรับใช้ใน บางทีฉันควรใช้แพ็คเกจอื่นหากมีเครื่องมือที่มีประโยชน์สำหรับกระบวนการดังกล่าว

คำตอบ:


16

คำตอบและคำแนะนำของ Spacedman ข้างต้นมีประโยชน์ แต่ไม่ได้อยู่ในตัวของมันเองเป็นคำตอบแบบเต็ม หลังจากทำงานของนักสืบในส่วนของฉันฉันได้ใกล้ชิดกับคำตอบแม้ว่าฉันยังไม่ได้จัดการgIntersectionในแบบที่ฉันต้องการ (ดูคำถามเดิมข้างต้น) ยังฉันมีการจัดการเพื่อให้รูปหลายเหลี่ยมใหม่ของฉันใน SpatialPolygonsDataFrame

UPDATE 2012-11-11: ดูเหมือนว่าฉันจะพบโซลูชันที่ใช้การได้ (ดูด้านล่าง) กุญแจสำคัญคือการตัดรูปหลายเหลี่ยมในSpatialPolygonsสายเมื่อใช้gIntersectionจากrgeosแพคเกจ ผลลัพธ์มีลักษณะดังนี้:

[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%"

การแทรกรูปหลายเหลี่ยมนั้นยากกว่าที่ฉันคิดเพราะน่าแปลกใจที่ดูเหมือนจะไม่มีตัวอย่างที่ง่ายต่อการติดตามการแทรกรูปร่างใหม่ในรูปร่างไฟล์ที่ได้มาจากการสำรวจอาวุธยุทโธปกรณ์ ฉันทำซ้ำขั้นตอนของฉันที่นี่ด้วยความหวังว่ามันจะเป็นประโยชน์กับคนอื่น ผลที่ได้คือแผนที่แบบนี้

แผนที่แสดงรูปหลายเหลี่ยมใหม่ที่วางซ้อน

หาก / เมื่อฉันแก้ไขปัญหาการตัดกันฉันจะแก้ไขคำตอบนี้และเพิ่มขั้นตอนสุดท้ายเว้นแต่แน่นอนว่ามีบางคนชนะฉันและให้คำตอบเต็ม ในขณะเดียวกันความเห็น / คำแนะนำเกี่ยวกับวิธีการแก้ปัญหาของฉันจนถึงขณะนี้ยินดีต้อนรับทุกคน

รหัสดังนี้

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

คำถามนี้ (และคำตอบ) มีประโยชน์กับฉัน ตอนนี้library(scales)จะต้องมีการเพิ่มเพื่อให้การทำงานโปร่งใส
Irene

1
ขอบคุณ ฉันเชื่อว่ามีrequire(scales)สายในนั้นที่จะทำเคล็ดลับ
SlowLearner

15

อย่าใช้ readShapePoly - ละเว้นข้อกำหนดการฉาย ใช้ readOGR จากแพ็คเกจ sp

สำหรับการดำเนินงานทางภูมิศาสตร์เช่นการซ้อนทับหลายเหลี่ยมให้ตรวจสอบแพ็คเกจ rgeos

แท้จริงสิ่งสุดท้ายที่คุณควรทำคือเล่นกับ fortify และ ggplot เก็บข้อมูลของคุณในวัตถุ sp-class, พล็อตพวกเขาด้วยกราฟิกฐานและปล่อยน้ำตาล ggplot จนจบโครงการและคุณต้องการแปลงสวย


ขอบคุณสำหรับเคล็ดลับ; ฉันจะดู readOGR อีกครั้ง สำหรับ ggplot มันเป็นสิ่งที่เกิดขึ้นตามธรรมชาติในขณะที่ฉันเรียนรู้เมื่อฉันเรียน R - ไม่เคยใส่ใจกับกราฟิกพื้นฐาน
SlowLearner

1
ความคิดเห็นของคุณเกี่ยวกับวัตถุ sp-class ดูเหมือนว่าสำคัญหากฉันต้องการใช้ประโยชน์จากฟังก์ชั่น rgeosSP-ระดับนี้ดูเหมือนว่าสิ่งสำคัญถ้าผมต้องการที่จะใช้ประโยชน์จากฟังก์ชั่นใน ฉันพยายามที่จะสร้างรูปหลายเหลี่ยมโดยใช้ตัวอย่างของคุณในคำตอบที่เชื่อมโยง แต่ฉันไม่สามารถหาวิธีเพิ่มรูปหลายเหลี่ยมใหม่ไปยังกรอบข้อมูลเชิงพื้นที่ที่มีอยู่ ฉันยุ่งกับ@dataไวยากรณ์เล็กน้อย แต่ไม่ได้รับทุกที่ คุณมีเคล็ดลับหรือไม่?
SlowLearner

4
คุณสามารถเข้าร่วมกรอบข้อมูลรูปหลายเหลี่ยมเชิงพื้นที่ด้วยcbind(part1,part2)หากพวกเขามี ID รูปหลายเหลี่ยมที่ไม่ซ้ำกัน - มิฉะนั้นคุณจะได้รับคำเตือนและจำเป็นต้องใช้spChFIDsเพื่อกำหนด ID คุณลักษณะรูปหลายเหลี่ยมที่ไม่ซ้ำกัน
Spacedman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.