Başka bir kaplanmış çokgenle kesişen bir haritadaki birden çok çokgen alanını hesaplamak için R kullanma


22

İngiltere’nin bir ilçesi için seçim koğuşu (bölüm) sınırları sağlayan Mühimmat Anketi’nden indirilen bir şekil dosyam var. Şekil dosyasını yüklemek için R'yi başarılı bir şekilde kullandım ve bu sorudaggplot2 açıklanan şekilde çeşitli haritaları çizdim . Her şey çok iyi çalışıyor.

Şimdi yeni bir rasgele şekil poligonu oluşturmak, haritaya eklemek, sonra da formun altında kalan bölgede yaşayan nüfusu hesaplamak istiyorum, bu da birden fazla bölümü kapsayabilir veya kısmen kapsayabilir. Her seçim bölümü için nüfusa sahibim ve basitleştirici her bir koğuştaki nüfusun eşit dağıldığı varsayımını yapabilirim. Bu, aşağıdaki adımları önerir.

1) Haritada çok sayıda seçim bölümünü kısmen kapsayan yeni bir şekil çizin. Diyelim ki tartışma uğruna 3 bölüm var. Böyle bir şey olurdu. [Düzenleme: şeklin altındaki resimde, 3 yerine 5 bölme

görüntü tanımını buraya girin

2) Üst üste yerleştirilmiş çokgenle kesişen bu 3 bölümün her birinin alanının yüzdesini hesaplayın.

3) Üst üste binen şeklin kapsadığı her bir bölümün alanının yüzdesini alarak ve bu durumu her bölümün popülasyonu ile çarparak nüfusu tahmin edin.

Sanırım poligonun nasıl oluşturulacağı ve harita üzerinde yer alacağı konusunda çalışabilirim, yani bu ve diğer sorulara verilen cevapları kullanarak mevcut veri çerçevesine ekleyin . Beni endişelendiren bit, üst üste binen şekil tarafından kapsanan her birimin yüzdesini çalışma görevidir. latVe longveri çerçevesindeki sütunları bu garip Ordnance Survey OpenData rakamlar (Easting'ler ve Northings veya şey) vardır.

Öyleyse ilk sorum şu: Bu verileri kullanarak seçim bölümünün sınırlarını belirleyen poligon alanını (veya alanın alt kümesini) bulma konusunda nasıl gidebilirim?Bu veri çerçevesinin anlamlı bir alt kümesi bile büyük olduğundan, bu soruya göndermekten çok dput500k dosya ( buradan kopyalanıp yapıştırılabilir veya indirilebilir ) oluşturmak için kullandım . Yukarıdaki görüntünün temelini oluşturan harita aşağıdakilerle oluşturuldu:

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

İkinci sorum şudur: doğru araçları mı kullanıyorum? Şu anda kullanıyorum readShapePolygelen maptoolsşekil dosyası okumak için paketin. Sonra kullanırımfortify için uygun yaklaşık 130k satırlık bir veri çerçevesi oluşturmak için kullanıyorum ggplot. Belki de böyle işlemler için faydalı araçlara sahipseniz farklı bir paket kullanmalıyım?

Yanıtlar:


16

Spacedman'ın cevabı ve yukarıdaki ipuçları faydalıydı, fakat kendi başlarına tam bir cevap oluşturmuyorlar. Benim tarafımdaki bazı dedektiflik çalışmalarından sonra, henüz istediğim gibi yapmayı başaramadığım halde bir cevaba daha yakın gIntersectionoldum (yukarıdaki orijinal soruya bakınız). Yine de, var SpatialPolygonsDataFrame içine benim yeni çokgen başardı.

GÜNCELLEME 2012-11-11: Uygulanabilir bir çözüm bulmuş gibiyim (aşağıya bakınız). Anahtar içinde poligonları sarmak için oldu SpatialPolygonskullanırken çağrı gIntersectiongelen rgeospaketin. Çıktı şöyle görünür:

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

Çokgenin yerleştirilmesi düşündüğümden daha zordu, çünkü şaşırtıcı bir şekilde mevcut bir Müdahale Anketi türetilmiş şekil dosyasına yeni bir şekil eklemek için izlemesi kolay bir örnek yok gibi görünüyor. Buradaki adımlarımı, başkası için faydalı olacağı umuduyla çoğalttım. Sonuç, böyle bir harita.

kaplanmış yeni çokgen gösteren harita

Kesişim sorununu çözdüğümde, bu cevabı düzenleyeceğim ve elbette, birileri beni geçmediği ve tam bir cevap vermediği sürece son adımları ekleyeceğim. Bu arada, şu ana kadar çözümümle ilgili yorum / öneriye açığız.

Kod takip ediyor.

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

Bu soru (ve cevap) benim için faydalı oldu. Şimdi library(scales)şeffaflık çalışması için ilave edilmelidir.
Irene

1
Teşekkürler. require(scales)Hile yapacak bir telefon olduğuna inanıyorum .
SlowLearner

15

ReadShapePoly kullanmayın - projeksiyon özelliğini dikkate almaz. Sp paketinden readOGR kullanın.

Poligon kaplamanız gibi coğrafi işlemler için, rgeos paketine bakın.

Kelimenin tam anlamıyla yapmanız gereken en son şey takviye ve ggplot ile oynamak. Verilerinizi sp-class nesnelerde saklayın, temel grafiklerle çizin ve ggplot şekerini bir projenin sonuna kadar bırakın.


İpuçları için teşekkürler; ReadOGR'a tekrar bakacağım. Ggplot'a gelince, öğrendiğim gibi doğal olarak gelen şey, R'yi öğrendiğim gibi - asla temel grafikleri rahatsız etmedi.
SlowLearner

1
Sp sınıfı nesneler hakkındaki yorumunuzu yeniden yazın, bu işlevlerden yararlanmak istersem çok önemli görünüyor rgeos. Bağlantılı cevaptaki örneğinizi kullanarak çokgen çeşitleri oluşturmayı başardım, ancak varolan bir uzamsal veri çerçevesine nasıl yeni bir çokgen ekleyeceğimi çözemiyorum. Biraz @datasözdizimi ile uğraşmıştım ama hiçbir yere ulaşamadım. Herhangi bir ipucun var mı?
SlowLearner

4
İki uzamsal çokgen veri çerçevesine cbind(part1,part2)benzersiz çokgen kimlikleri varsa katılabilirsiniz - aksi takdirde bir uyarı alırsınız ve spChFIDsbenzersiz çokgen özellikli kimlikleri atamak için kullanmanız gerekir .
Spacedman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.