กำลังอ่านไฟล์ KML เป็น R หรือไม่


41

ฉันทำงานกับไฟล์. kml ขนาดใหญ่ (มากถึง 10 Gb) และต้องการวิธีที่มีประสิทธิภาพในการอ่านไฟล์ให้เป็นไฟล์ R จนกระทั่งตอนนี้ฉันได้แปลงไฟล์เหล่านี้ให้เป็นไฟล์รูปร่างผ่าน QGIS แล้วกลับไปเป็น R ด้วย readShapePoly และ readOGR โดยวิธีการคือ 1,000 เร็วกว่าเดิม) ฉันชอบที่จะลดขั้นตอนการเป็นตัวกลาง QGIS เนื่องจากยุ่งยากและช้าลง

จะอ่านไฟล์. kml โดยตรงได้อย่างไร

ฉันเห็นนี้ยังสามารถทำได้ด้วย readOGR น่าเสียดายที่ผมไม่สามารถดูวิธีการใช้ตัวอย่างที่ทำงาน (หลังจากการเตรียมความยาวของไฟล์ .kml: xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities")) ดูเหมือนว่า "เมือง" ที่นี่เป็นชื่อของวัตถุเชิงพื้นที่

Roger Bivand ยอมรับว่า "วิธีค้นพบชื่อนี้ไม่ชัดเจนเนื่องจากไดรเวอร์ KML ใน OGR ต้องการให้เข้าถึงไฟล์ได้สิ่งหนึ่งที่เป็นไปได้คือ:

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

"

แต่นี่ไม่ได้ผลสำหรับฉันเช่นกัน นี่คือไฟล์ทดสอบ. kml ที่จะลองใช้ ด้วยในไดเรกทอรีทำงานของฉันreadOGR("x.kml", "id")สร้างข้อความแสดงข้อผิดพลาดนี้:

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

และsystem(paste("ogrinfo", "x.kml"), intern=TRUE)สร้าง:

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

ซึ่งฉันก็ไม่เข้าใจ

จะgetKMLcoordinates{} maptools เป็นทางเลือกที่ถูกต้อง?

ฉันเคยลองแล้ว:

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

พิกัดถูกสร้างขึ้นอย่างถูกต้อง แต่ความพยายามในการแปลงกลับเป็นวัตถุรูปหลายเหลี่ยมล้มเหลวด้วยข้อความต่อไปนี้:

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

1
คุณสามารถรับเลเยอร์ใน kml โดยใช้ฟังก์ชั่นของ rgdal ogrListLayers
Mario Becerra

คำตอบ:


36

หากต้องการอ่าน KML พร้อมกับไดรเวอร์ OGR คุณต้องตั้งชื่อไฟล์และชื่อเลเยอร์

ความคิดเห็นของโรเจอร์คือชื่อเลเยอร์ถูกซ่อนอยู่ในไฟล์ KML และถ้าคุณไม่ทราบว่าสร้าง KML อย่างไรคุณไม่สามารถอนุมานชื่อเลเยอร์จากชื่อไฟล์ KML ได้

เมื่อดูตัวอย่าง KML ของคุณฉันสามารถดู:

<?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">

สิ่งที่บอกชื่อเลเยอร์คือxไม่ใช่idและอื่น ๆ :

> 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

ทำงานได้ดี

ตอนนี้คุณสามารถลองและรับชื่อโดยการวิเคราะห์ KML เป็น XML โดยใช้ตัวแยกวิเคราะห์ R XML หรือคุณอาจลองอ่านใน R เป็นไฟล์ข้อความจนกว่าคุณจะพบแท็กชื่อ

วิธีอื่นคือการเรียกใช้โปรแกรม ogrinfo บรรทัดคำสั่งซึ่งแยกชื่อเลเยอร์ของไฟล์ 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)

xที่นี่มีการแสดงเป็นชั้นรูปหลายเหลี่ยมที่เรียกว่า


ขอบคุณสำหรับคำตอบของคุณ Spaced - แก้ไขปัญหาได้ทันที คำอธิบายที่ชัดเจนเช่นนี้ทำให้ฉันรักการแลกเปลี่ยนสแต็ค! หนึ่งคำถาม 'คะแนนโบนัส': ฉันสามารถใช้คำสั่งเดียวกันเพื่ออ่านในส่วนย่อยของข้อมูล (เช่น 1 ล้านรูปหลายเหลี่ยมแรก) ได้หรือไม่ มิฉะนั้นจะมีลักษณะที่จะแยก kmls ขนาดใหญ่ด้วยโปรแกรมภายนอก
RobinLovelace

2
KML เป็น XML ไม่ได้รับการออกแบบมาเพื่อการเข้าถึงแบบสุ่ม ทางออกที่แท้จริงคือการใส่ข้อมูลเชิงพื้นที่ของคุณลงในฐานข้อมูลเชิงพื้นที่และมีดัชนีเชิงพื้นที่สำหรับความเร็ว ตรวจสอบ PostGIS
Spacedman

ตกลงแผนดี - ฉันได้บอกลูกค้าว่า PostGIS เป็นหนทางข้างหน้าสำหรับข้อมูลขนาดใหญ่ดังกล่าวและฉันเชื่อว่ามันเป็นตัวเลือกที่เหมาะสมสำหรับสิ่งที่เขาต้องการทำ ข้อแก้ตัวที่ดีสำหรับฉันที่จะเรียนรู้มันอย่างถูกต้อง!
RobinLovelace

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

แปลกsystemใน R จำเป็นpath.expandบน~สำหรับogrinfoการทำงานแม้ว่ามันจะทำงานได้ดีบนเส้นทางที่ไม่ได้ขยายในบรรทัดคำสั่ง (MacOS; Sys.which('ogrinfo')และwhich ogrinfoกลับเส้นทางเดียวกัน)
MichaelChirico

5

หากคุณต้องการทำวิธีอื่นในการใช้ maptool สิ่งนี้น่าจะใช้ได้:

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

กุญแจสำคัญในที่นี้คือคุณต้องผ่านสองสามขั้นตอนเพื่อสร้างคลาสรูปหลายเหลี่ยมเชิงพื้นที่


สวัสดี @Seen ฉันได้ลองวิธีการของคุณ แต่ดูเหมือนจะไม่ทำงาน? ฉันมีข้อผิดพลาด: ข้อผิดพลาดในรูปหลายเหลี่ยม (tkml): coords ต้องเป็นเมทริกซ์สองคอลัมน์> head (tkml) [[1]] [1] -87.88141 30.49800 และฉันมีรายการอยู่แล้ว .. คุณคิดว่ามันแปลง ok หรือไม่ รายการพิกัดไปยังเมทริกซ์? tahnks!
maycca

1

ไม่ทราบว่านี่ยังเป็นปัญหาสำหรับคนอื่นหรือไม่ แต่ฉันทำงานเป็นวงกลมอยู่พักหนึ่ง สิ่งที่ได้ผลในที่สุดสำหรับฉันก็คือด้านล่าง มันใช้XMLแพคเกจเพื่อรับที่xmlValueโหนดขวา ฉันต้องตั้งค่าlayerพารามิเตอร์ของreadOGRชื่อหนึ่งในโฟลเดอร์ภายในไฟล์ kml เมื่อฉันตั้งค่าlayerพารามิเตอร์เป็นไฟล์ kml ฉันจะได้รับข้อผิดพลาดเดียวกับที่ RobinLovelace อธิบายไว้ข้างต้น

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

นอกจากนี้ผมสร้างรายชื่อของไฟล์ KML ดังนั้นมันอาจจะทำให้ได้อย่างง่ายดายในฟังก์ชั่นที่สามารถใส่ในlapply- do.callคู่ สิ่งนี้สามารถดึงข้อมูลจากรายการ kml ที่มีความยาว หรือมีโฟลเดอร์ย่อยมากมายในไฟล์ kml ไฟล์เดียวเนื่องจากดูเหมือนว่าreadOGRไม่สามารถจัดการกับโฟลเดอร์ย่อยหลายไฟล์ในไฟล์ 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

ไม่ทราบว่าควรแก้ไขคำตอบก่อนหน้านี้หรือไม่ บางที แต่นั่นครอบคลุมบางสิ่งที่ไม่ได้อยู่ในคำตอบนี้ฉันจึงตัดสินใจทิ้งมันไว้

อย่างไรก็ตามรหัสด้านล่างทำงานได้ดีสำหรับฉัน มันดูสำหรับทุก xmlNodes ในไฟล์ KML ที่เรียกว่า "โฟลเดอร์" แล้วกำหนดlayerค่าพารามิเตอร์ของการที่readOGR xmlValueทดสอบในไดเรกทอรีการทำงานด้วยไฟล์ kml แยกต่างหากประมาณ 6 ไฟล์ เอาท์พุทเป็นรายการของวัตถุ SpatialDataFrames ที่นำเข้า SpatialDataFrame แต่ละรายการสามารถย่อยได้ง่ายจากรายการ

ยังคงไม่ได้อยู่ไฟล์ kml ที่มีหลายโหนดโฟลเดอร์ แต่สามารถเพิ่มคุณสมบัตินั้นได้อย่างง่ายดายด้วยapplyฟังก์ชันซ้อนกันอื่น

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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.