Đọc tệp KML vào R?


42

Tôi đang làm việc với các tệp .kml khổng lồ (tối đa 10 Gb) và cần một cách hiệu quả để đọc chúng vào R. Cho đến bây giờ tôi đã chuyển đổi chúng thành shapefile thông qua QGIS và sau đó quay lại R với readShapePoly và readOGR (sau này , nhân tiện, nhanh hơn ~ 1000 so với trước đây). Tôi lý tưởng muốn cắt bỏ giai đoạn trung gian của QGIS vì nó cồng kềnh và chậm chạp.

Làm thế nào để đọc tập tin .kml trực tiếp?

Tôi thấy điều này cũng có thể được thực hiện với readOGR . Thật không may, tôi không thể thấy cách triển khai ví dụ đã làm việc (sau khi chuẩn bị dài tệp .kml xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities"):). Dường như "thành phố" ở đây là tên của các vật thể không gian.

Roger Bivand thừa nhận rằng "Cách một người phát hiện ra tên này là không rõ ràng, vì trình điều khiển KML trong OGR cần nó để truy cập tệp. Một khả năng là:

system(paste("ogrinfo", paste(td, "cities.kml", sep="/")), intern=TRUE)

"

Nhưng điều này cũng không làm việc cho tôi. Đây là một tập tin thử nghiệm .kml để thử nó. Với nó trong thư mục làm việc của tôi, readOGR("x.kml", "id")tạo thông báo lỗi này:

Error in ogrInfo(dsn = dsn, layer = layer, encoding = encoding, use_iconv = use_iconv) : 
  Cannot open layer . 

system(paste("ogrinfo", "x.kml"), intern=TRUE)tạo ra:

[1] "Had to open data source read-only."   "INFO: Open of `x.kml'"               
[3] "      using driver `KML' successful." "1: x (3D Polygon)"  

, điều mà tôi đơn giản là không hiểu.

Sẽ getKMLcoordinates{maptools} là một lựa chọn hợp lệ?

Tôi cũng đã thử điều này:

tkml <- getKMLcoordinates(kmlfile="x.kml", ignoreAltitude=T)
head(tkml[[1]])
tkml <- SpatialPolygons(tkml, 
                        proj4string=CRS("+init=epsg:3857"))

Các tọa độ được tạo chính xác, nhưng nỗ lực của tôi để chuyển đổi chúng trở lại thành một đối tượng đa giác không thành công với thông báo sau:

Error in SpatialPolygons(tkml, proj4string = CRS("+init=epsg:3857")) : 
  cannot get a slot ("area") from an object of type "double"

1
Bạn có thể lấy các lớp trong kml bằng hàm ogrListLayers của rgdal.
Mario Becerra

Câu trả lời:


37

Để đọc KML với trình điều khiển OGR, bạn đặt cho nó tên tệp và tên lớp.

Nhận xét của Rogers là tên lớp được ẩn trong tệp KML và trừ khi bạn biết cách tạo KML, bạn không thể suy ra tên lớp từ tên tệp KML.

Nhìn vào ví dụ KML của bạn, tôi có thể thấy:

<?xml version="1.0" encoding="utf-8" ?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document><Folder><name>x</name>
<Schema name="x" id="x">

Đó là cho tôi biết tên lớp là x, không id, và vì vậy:

> foo = readOGR("/tmp/x.kml", "x")
OGR data source with driver: KML 
Source: "/tmp/x.kml", layer: "x"
with 1 features and 2 fields
Feature type: wkbPolygon with 2 dimensions

hoạt động độc đáo.

Bây giờ, bạn có thể thử và lấy tên bằng cách phân tích KML dưới dạng XML bằng cách sử dụng trình phân tích cú pháp R XML hoặc bạn có thể thử đọc nó trong R dưới dạng tệp văn bản cho đến khi bạn tìm thấy thẻ tên.

Cách tiếp cận khác là chạy chương trình ogrinfo dòng lệnh, tạo ra các tên lớp của tệp KML:

$ ogrinfo /tmp/x.kml 
Had to open data source read-only.
INFO: Open of `/tmp/x.kml'
      using driver `KML' successful.
1: x (Polygon)

ở đây cho thấy có một lớp đa giác được gọi là x.


Cảm ơn câu trả lời của bạn Khoảng cách - giải quyết vấn đề ngay lập tức. Đó là lời giải thích rõ ràng như thế này khiến tôi thích trao đổi ngăn xếp! Một câu hỏi 'điểm thưởng': tôi có thể sử dụng cùng một lệnh để đọc trong một tập hợp con của dữ liệu (ví dụ: 1 triệu đa giác đầu tiên) không? Nếu không sẽ tìm cách chia tách các kmls lớn với một chương trình bên ngoài.
RobinLigsace

2
KML là XML không thực sự được thiết kế để truy cập ngẫu nhiên. Giải pháp thực sự là đưa dữ liệu không gian của bạn vào cơ sở dữ liệu không gian và có một số chỉ mục không gian cho tốc độ. Kiểm tra PostGIS.
Spacesman

OK kế hoạch tốt - Tôi đã nói với khách hàng rằng PostGIS là con đường phía trước cho dữ liệu lớn như vậy và tin chắc rằng đó là lựa chọn phù hợp cho loại việc anh ta muốn làm. Lý do tốt cho tôi để tìm hiểu nó đúng cách!
RobinLigsace

Ngoài ra còn có phần mở rộng không gian cho sqlite , một cơ sở dữ liệu dựa trên tệp, sẽ không yêu cầu bạn cài đặt dịch vụ và yêu cầu cấu hình ít hơn PostGIS.
Frank

lạ lùng systemtrong R cần thiết path.expandtrên ~cho ogrinfođến công việc, mặc dù nó làm việc tốt trên con đường chưa giãn nở trên dòng lệnh (MacOS; Sys.which('ogrinfo')which ogrinfotrả lại đường dẫn tương tự)
MichaelChirico

5

Nếu bạn muốn thực hiện theo cách khác bằng cách sử dụng maptool, cách này sẽ hoạt động:

tkml <- getKMLcoordinates(kmlfile="yourkml.kml", ignoreAltitude=T)
#make polygon
p1 = Polygon(tkml)
#make Polygon class
p2 = Polygons(list(p1), ID = "drivetime")
#make spatial polygons class
p3= SpatialPolygons(list(p2),proj4string=CRS("+init=epsg:4326"))

Chìa khóa ở đây là bạn cần trải qua một vài bước để tạo lớp đa giác không gian.


chào @Seen, tôi đã thử cách tiếp cận của bạn nhưng có vẻ như không hiệu quả? Tôi có một lỗi: Lỗi trong Đa giác (tkml): coords phải là ma trận hai cột> head (tkml) [[1]] [1] -87.88141 30.49800 adn Tôi có một danh sách .. bạn có nghĩ rằng nó chuyển đổi không danh sách tọa độ để ma trận? tahnks!
maycca

1

Không biết đây có phải là vấn đề với bất kỳ ai khác không, nhưng tôi đã chạy trong vòng tròn một lúc với điều này. Những gì cuối cùng làm việc cho tôi là dưới đây. Nó sử dụng XMLgói để lấy ở xmlValuenút bên phải. Tôi đã phải đặt layertham số của readOGRtên của một trong các thư mục trong tệp kml. Khi tôi đặt layertham số cho tệp kml, tôi sẽ gặp lỗi tương tự như RobinLigsace đã mô tả ở trên.

Dưới đây là rất nhiều dòng mã chỉ hiển thị cách xem các mức nút khác nhau của tài liệu kml. Tôi nghĩ rằng điều này sẽ hơi khác nhau tùy thuộc vào nguồn của kml. Nhưng bạn sẽ có thể sử dụng cùng logic để xác định giá trị tham số chính xác.

Ngoài ra, tôi đã tạo ra một danh sách các file kml vì thế nó có thể dễ dàng làm thành một chức năng có thể được đặt trong một lapply- do.callcặp. Điều này sau đó có thể lấy dữ liệu từ một danh sách dài các tệp kml. Hoặc, rất nhiều thư mục con trong một tệp kml vì dường như readOGRkhông thể xử lý nhiều thư mục con trong tệp kml.

library(rgdal); library(XML)

# SET WORKING DIRECTORY FIRST!!
dir <- getwd()

kmlfilelist <- list.files(dir, pattern =".kml$", full.names=TRUE, recursive=FALSE)

doc0 <- xmlTreeParse(kmlfilelist[2], useInternal = TRUE)
rootNode0 <- xmlRoot(doc0)
rootName0 <- xmlName(rootNode0)
element1Name0 <- names(rootNode0)

nodeNames <- names(rootNode0[1][[1]])

# entire rootNode - kml Document level
rootNode0[[1]]

# 1st element of rootNode - kml file name
rootNode0[[1]][[1]] 

# 2nd element of rootNode - kml Style Map 
rootNode0[[1]][[2]] 

# 3rd element of rootNode - Style
rootNode0[[1]][[3]]

# 4th element of rootNode - Style
rootNode0[[1]][[4]] 

# 5th element of rootNode - kml Folder with data in it.
rootNode0[[1]][[5]] 

# 5th element 1st subelement of rootNode - kml Folder name with data in it. 
#  What to set readOGR() layer parameter to.
rootNode0[[1]][[5]][[1]] 

kmlfoldername <- xmlValue(rootNode0[[1]][[5]][[1]]) # Folder name to set = layer.

readOGR(dsn=kmlfilelist[2], layer =  kmlfoldername)

0

Không biết tôi có nên sửa đổi câu trả lời trước của mình không. Có lẽ, nhưng điều đó bao gồm một số điều không có trong câu trả lời này, vì vậy tôi quyết định rời bỏ nó.

Dù sao, mã dưới đây hoạt động tốt cho tôi. Nó tìm kiếm tất cả các xmlNodes trong tệp kml được gọi là "Thư mục" và sau đó đặt layertham số của readOGRđó xmlValue. Đã thử nghiệm trên thư mục làm việc với khoảng 6 tệp kml riêng biệt. Đầu ra là một danh sách các đối tượng SpatialDataFrames đã nhập. Mỗi SpatialDataFrame có thể dễ dàng được tập hợp con từ danh sách.

Vẫn không giải quyết các tập tin kml với nhiều nút Thư mục. Nhưng tính năng đó có thể dễ dàng được thêm vào với một applychức năng lồng nhau khác .

library(rgdal); library(XML)

# SET WORKING DIRECTORY FIRST!!
dir <- getwd()

kmlfilelist <- list.files(dir, pattern =".kml$", full.names=TRUE, recursive=FALSE)

ImportKml <- function (kmlfile) {
  doc0 <- xmlTreeParse(kmlfile, useInternal = TRUE)
  rootNode0 <- xmlRoot(doc0)
  rootName0 <- xmlName(rootNode0)
  element1Name0 <- names(rootNode0)

  kmlNodeNames <- unname(names(rootNode0[1][[1]]))
  kmlFolderNodeNum <- which(kmlNodeNames == "Folder")
  kmlFolderNodeName <- xmlValue(rootNode0[[1]][[kmlFolderNodeNum]][[1]])

  kmlIn <- readOGR(dsn=kmlfile, layer = kmlFolderNodeName)
}
ImportedKmls <- lapply(kmlfilelist, ImportKml)
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.