Використовуючи R для обчислення площі декількох багатокутників на карті, які перетинаються з іншим накладеним багатокутником


22

У мене є файл завантаженого формату з опитування щодо розпорядження, яке дає межі виборчої палати (поділу) для графства Сполученого Королівства. Я успішно використовував R для завантаження файлу форм і побудував різні карти за допомогою ggplot2описаного в цьому запитанні . Це все працює досить добре.

Тепер я хотів би створити новий багатокутник довільної форми, додати його до карти, а потім обчислити населення, яке проживає в районі, що лежить під формою, який може охоплювати або частково охоплювати декілька поділів. У мене є кількість населення для кожного виборчого поділу, і я можу зробити спрощене припущення про те, що чисельність населення в кожній палаті розподілена рівномірно. Це говорить про наступні кроки.

1) Накладіть на карту нову форму, яка частково охоплює декілька виборчих поділів. Скажімо, для аргументації є 3 відділи. Це виглядало б приблизно так. [Редагувати: за винятком того, що на зображенні внизу форми намальовано 5 поділів, а не 3]

введіть тут опис зображення

2) Обчисліть відсоток площі кожного з цих 3 поділів, що перетинається з накладеним багатокутником.

3) Оцініть чисельність населення, отримавши відсоток площі кожного поділу, охопленого накладеною формою, і помноживши це на чисельність населення кожного поділу.

Я думаю, що, напевно, я можу розробити, як створити багатокутник і накласти його на карту, тобто додати його до існуючого кадру даних, використовуючи корисну відповідь на це та інші питання. Біт, який мене хвилює, - це завдання опрацювати відсоток кожного поділу, який охоплюється накладеною формою. 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пакету, щоб прочитати файл форми. Потім я використовую fortifyдля створення фрейму даних розміром близько 130 тис. Рядків, придатного для використання в ggplot. Можливо, я повинен використовувати інший пакет, якщо є такий, у якому є корисні інструменти для таких процесів?

Відповіді:


16

Відповідь і підказки Spacedman були корисними, але самі по собі не є повною відповіддю. Після деякої детективної роботи з мого боку я наблизився до відповіді, хоча ще не встиг дійти gIntersectionтак, як мені хочеться (див. Оригінальне запитання вище). Тим НЕ менше, я вже встиг отримати свій новий полігон в SpatialPolygonsDataFrame.

ОНОВЛЕННЯ 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%"

Вставити полігон було складніше, ніж я думав, тому що, на диво, здається, що не є легким для наслідування прикладом вставки нової форми в існуючий файл даних, отриманий з опитування Ordnance. Я відтворив свої кроки тут у надії, що це буде корисно комусь іншому. Результат - така карта.

карта, на якій зображений новий багатокутник

Якщо / коли я вирішу питання перехрестя, я відредагую цю відповідь і додаю останні кроки, якщо, звичайно, хтось не переверне мене на це і не дасть повну відповідь. Тим часом коментарі / поради щодо мого рішення поки що вітаються.

Кодекс наступний.

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)потрібно додати, щоб прозорість працювала.
Ірен

1
Спасибі. Я вірю, що там є require(scales)дзвінок, який зробить трюк.
SlowLearner

15

Не використовуйте readShapePoly - він ігнорує специфікацію проекції. Використовуйте readOGR з пакету sp.

Для географічних операцій, таких як накладання багатокутника, перегляньте пакет rgeos.

Буквально останнє, що вам слід зробити, це грати з фортифікацією та ggplot. Зберігайте свої дані в об'єктах sp-класу, побудуйте їх на основі базової графіки та залиште цукор ggplot до кінця проекту, і вам знадобляться декілька гарних сюжетів.


Дякую за поради; Я ще раз перегляну readOGR. Що стосується ggplot, то це те, що відбувається природно, як я дізнався його, як я вивчив R - ніколи не заважав базовій графіці.
SlowLearner

1
Перегляньте свій коментар до об'єктів sp-класу, це здається вирішальним, якщо я хочу скористатися функціями в rgeos. Мені вдалося скласти асортимент багатокутників, використовуючи ваш приклад у пов'язаній відповіді, але я не можу розробити, як додати новий багатокутник до існуючого просторового кадру даних. Я трохи заплутався з @dataсинтаксисом, але нікуди не потрапив. У вас є поради?
SlowLearner

4
Ви можете приєднати два просторових кадри даних багатокутника, cbind(part1,part2)якщо вони мають унікальні ідентифікатори багатокутника - інакше ви отримуватимете попередження та потрібно використовувати spChFIDsдля призначення унікальних ідентифікаторів функції багатокутника.
Спайдермен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.