KMLファイルをRに読み込みますか?


42

私は巨大な.kmlファイル(最大10 Gb)で作業しており、それらをRに読み込む効率的な方法が必要です。これまでは、QGISを介してシェープファイルに変換し、その後readShapePolyとreadOGR(後者ちなみに、前者よりも1000倍高速です)。面倒で時間がかかるため、QGIS中間段階を切り取りたいと考えています。

.kmlファイルを直接読み込む方法は?

私は、これはまた、readOGRで行うことができます参照します。残念ながら、実際の例を実装する方法はわかりません(.kmlファイルを長時間準備した後xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities"))。ここの「都市」は空間オブジェクトの名前のようです。

Roger Bivandは、「OGRのKMLドライバーはファイルにアクセスするためにこの名前を必要とするため、この名前の発見方法は明らかではありません。1つの可能性は次のとおりです。

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
rgdalの関数ogrListLayersを使用して、kmlのレイヤーを取得できます。
マリオベセラ

回答:


37

OGRドライバーでKMLを読み取るには、ファイル名とレイヤー名を指定します。

Rogerのコメントでは、レイヤー名は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

うまく動作します。

さて、あなたは試してみて、RのXMLパーサーを使用してXMLとしてKMLを解析して名前を取得、またはあなたができることができます多分あなたが名前タグを見つけるまでテキストファイルとしてRでそれを読んでみてください。

もう1つのアプローチは、KMLファイルのレイヤー名を吐き出すコマンドラインogrinfoプログラムを実行することです。

$ 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-すぐに問題を解決しました。このような明確な説明は、スタック交換が大好きになります!「ボーナスポイント」の質問:同じコマンドを使用してデータのサブセット(最初の100万ポリゴンなど)を読み取ることはできますか?それ以外の場合は、外部プログラムで巨大なkmlsを分割します。
RobinLovelace

2
XMLであるKMLは、実際にはランダムアクセス用に設計されていません。実際のソリューションは、空間データを空間データベースに配置し、速度を上げるための空間インデックスを作成することです。PostGISをご覧ください。
Spacedman

OK良い計画-クライアントに、PostGISがそのようなビッグデータの前進方法であり、それが彼がやりたい種類の適切なオプションであると確信しています。私がそれを適切に学ぶ良い言い訳!
RobinLovelace

また、ファイルベースのデータベースであるsqlite空間拡張もあります。これは、サービスをインストールする必要がなく、PostGISよりも少ない構成で済みます。
フランク

奇妙なことに、コマンドラインの未展開のパス(macOS; および同じパスを返します)でsystempath.expand~ogrinfoSys.which('ogrinfo')which ogrinfo
正常に

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、私はあなたのアプローチを試みましたが、うまくいかないようですか?私はエラーがあります:Polygon(tkml)のエラー:座標は2列の行列でなければなりません> head(tkml)[[1]] [1] -87.88141 30.49800 adn it as it as ..マトリックスの座標のリスト?タンクス!
maycca

1

これがまだ他の誰かにとって問題であるかどうかはわかりませんが、私はしばらくの間これをサークルで走っていました。最終的に私のために働いたのは以下です。XMLパッケージを使用しxmlValueて適切なノードに到達します。layerパラメータをreadOGRkmlファイル内のいずれかのフォルダの名前に設定する必要がありました。layerパラメータをkmlファイルのに設定すると、RobinLovelaceが上記で説明したのと同じエラーが表示されます。

以下に示すのは、kmlドキュメントのさまざまなノードレベルを表示する方法のみを示す多くのコード行です。これは、kmlのソースによって多少異なると思います。ただし、同じロジックを使用して正しいパラメーター値を決定できる必要があります。

また、kmlファイルのリストを作成したため、lapply- do.callペアに入れることができる関数に簡単に作成できます。これにより、kmlファイルの長いリストからデータを取り込むことができます。または、単一のkmlファイル内の多くのサブフォルダーは、kmlファイル内のreadOGR複数のサブフォルダーを処理できないようです。

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

以前の回答を変更したかどうかわかりません。おそらく、しかし、それはこの答えにないいくつかのことをカバーしているので、私はそれを残すことにしました。

とにかく、以下のコードは私にとってうまく機能します。kmlファイル内で「Folder」と呼ばれるすべてのxmlNodesを検索し、layerパラメーターreadOGRをそのに設定しますxmlValue。作業ディレクトリで約6個の個別のkmlファイルを使用してテストしました。出力は、インポートされたSpatialDataFramesオブジェクトのリストです。各SpatialDataFrameは、リストから簡単にサブセットにすることができます。

それでも、複数のFolderノードを持つ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.