KML dosyası R içine okunuyor mu?


42

Çok büyük .kml dosyalarıyla (10 Gb'ye kadar) çalışıyorum ve bunları R'ye okumak için etkili bir yola ihtiyacım var. Şimdiye kadar, onları QGIS üzerinden şekil dosyalarına, sonra da readShapePoly ve readOGR (R) ye geri döndüm. Bu arada, öncekinden ~ 1000 daha hızlıdır). İdeal olarak, QGIS ara aşamasını hantal ve yavaş olduğu için kesmek istiyorum.

Doğrudan .kml dosyaları nasıl okunur?

Bunun readOGR ile de yapılabileceğini görüyorum . Ne yazık ki, çalışılan örneğin nasıl uygulandığını göremiyorum (.kml dosyasının uzunca hazırlanmasından sonra:) xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities"). Görünüşe göre buradaki "şehirler" mekansal nesnelerin adı.

Roger Bivand, "OGR'nin KML sürücüsünün dosyaya erişmesi gerektiğinden, bu adın nasıl anlaşılacağı belli değil." Diyor.

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

"

Ama bu benim için de işe yaramıyor. İşte denemek için bir test .kml dosyası. Benim çalışma dizinde, readOGR("x.kml", "id")bu hata iletisini oluşturur:

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

Ve system(paste("ogrinfo", "x.kml"), intern=TRUE)üretir:

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

ki sadece anlamıyorum.

Misiniz getKMLcoordinates{maptools} geçerli bir alternatif olabilir mi?

Bunu da denedim:

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

Koordinatlar doğru üretildi, ancak onları bir çokgen nesnesine geri dönüştürme girişimim şu mesajla başarısız oldu:

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

1
Rgdal fonksiyonunu ogrListLayers kullanarak katları kml içinde alabilirsiniz.
Mario Becerra

Yanıtlar:


37

OGR sürücüsüyle bir KML okumak için, ona dosya adını ve katman adını verin.

Roger'ın yorumu, katman adının KML dosyasına gizlenmiş olduğu ve KML'nin nasıl oluşturulduğunu bilmiyorsanız, katman adını KML dosya adından çıkaramazsınız.

Örnek KML’nize baktığımda şunları görebilirim:

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

Bu da bana katman adının xdeğil id, öyle olduğunu söylüyor :

> 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

güzel çalışıyor.

Şimdi, denemek ve bir R XML ayrıştırıcı kullanarak XML olarak KML ayrıştırma yoluyla isim vermezsen sen can belki sen ad etiketini bulana kadar bir metin dosyası olarak R okumaya deneyin.

Diğer yaklaşım ise, bir KML dosyasının katman adlarını yayan komut satırı ogrinfo programını çalıştırmaktır:

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

burada gösterilen bir çokgen katmanı var x.


Cevabınız için teşekkürler Spaced - sorunu hemen çözdü. Bu beni böyle açık bir şekilde açıklıyor, bu da borsayı değiştirmeyi seviyorum Bir 'bonus puan' sorusu: aynı komutu, verilerin bir alt kümesinde okumak için kullanabilir miyim (örneğin, ilk 1 milyon poligon)? Aksi halde, büyük kml'leri harici bir programla bölmek isteyecektir.
RobinLovelace,

2
XML olan KML, rastgele erişim için tasarlanmamıştır. Asıl çözüm, uzamsal verilerinizi uzamsal bir veritabanına koymak ve hız için bazı uzamsal dizinlere sahip olmaktır. PostGIS'e göz atın.
Spacedman

Tamam iyi plan - Müşteriye, PostGIS'in bu kadar büyük veriler için ileriye dönük bir yol olduğunu ve yapmak istediği şeyler için doğru seçenek olduğuna ikna oldum. Düzgün öğrenmek için iyi bir bahane!
RobinLovelace,

Ayrıca bir servisi yüklemenizi gerektirmeyen ve PostGIS'ten daha az yapılandırma gerektiren dosya tabanlı bir veritabanı olan sqlite için uzamsal bir uzantı vardır.
Frank,

garip systemR ihtiyaç path.expandüzerine ~için ogrinfo(; MacOS o komut satırında genişlememe yolda cezası çalıştığı halde, işe Sys.which('ogrinfo')ve which ogrinfoaynı yolları döndü)
MichaelChirico

5

Maptool kullanarak alternatif bir yol yapmak istiyorsanız, bu çalışması gerekir:

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

Burada anahtar mekansal çokgen sınıfını yapmak için birkaç adım atmanız gerekir.


hi @Seen, yaklaşımınızı denedim ama işe yaramadı gibi görünüyor? Bir hatam var: Poligonda hata (tkml): kodlayıcılar iki sütunlu bir matris> baş (tkml) [[1]] [1] -87.88141 30.49800 adında olmalı. matrislere koordinat listesi? tahnks!
maycca

1

Bunun hala bir başkası için bir sorun olup olmadığını bilmiyorum, ama bununla bir süre daireler çiziyordum. Sonunda benim için çalışan şey aşağıda. Sağ düğüme XMLulaşmak için paketi kullanır xmlValue. layerParametresini readOGRkml dosyasındaki klasörlerden birinin adına ayarlamak zorunda kaldım . Ben ayarladığınızda layerkml dosyasının parametreyi, ben RobinLovelace yukarıda anlatılan aynı hatayı tanınacak.

Aşağıda, yalnızca kml belgesinin çeşitli düğüm düzeylerinin nasıl görüneceğini gösteren birçok kod satırı gösterilmiştir. Bu km'nin kaynağına bağlı olarak biraz farklı olacağını düşünüyorum. Ancak, doğru parametre değerini belirlemek için aynı mantığı kullanabilmelisiniz.

Kolayca bir koymak olabilir bir fonksiyonu içine yapılmış olabilir böylece Ayrıca, ben kml dosyaların listesini oluşturdu lapply- do.callçifti. Bu daha sonra uzun bir kml dosya listesinden veri alabilir. Veya, tek bir kml dosyasındaki readOGRbirçok alt klasör, bir kml dosyasındaki birden fazla alt klasörle ilgilenemez gibi görünmektedir .

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

Önceki cevabımı değiştirmeli miydim bilmiyorum. Belki, ama bu cevapta olmayan bazı şeyleri kapsar, ben de bırakmaya karar verdim.

Neyse, aşağıdaki kod benim için iyi çalışıyor. Bu "Klasör" denir kml dosyasında xmlNodes tüm arar ve sonra ayarlar layerparametresini readOGRbuna xmlValue. Çalışma dizininde yaklaşık 6 ayrı kml dosyasıyla test edilmiştir. Çıktı, içe aktarılan SpatialDataFrames nesnelerinin bir listesidir. Her SpatialDataFrame kolayca listeden alt küme olabilir.

Yine de birden fazla Folder düğümü olan kml dosyalarını ele almıyor. Ancak bu özellik başka bir yuvalanmış applyfonksiyonla kolayca eklenebilir .

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