Estou trabalhando com enormes arquivos .kml (até 10 Gb) e preciso de uma maneira eficiente de lê-los em R. Até agora, tenho convertido-os em shapefiles via QGIS e depois voltado ao R com readShapePoly e readOGR (o último , a propósito, é ~ 1000 mais rápido que o anterior). Idealmente, gostaria de cortar o estágio intermediário do QGIS, pois é complicado e lento.
Como ler arquivos .kml diretamente?
I ver este pode também ser feito com readOGR . Infelizmente, não consigo ver como implementar o exemplo trabalhado (após uma longa preparação do arquivo .kml:) xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities")
. Parece que "cidades" aqui é o nome dos objetos espaciais.
Roger Bivand admite que "Como se descobre esse nome não é óbvio, pois o driver KML no OGR precisa dele para acessar o arquivo. Uma possibilidade é:
system(paste("ogrinfo", paste(td, "cities.kml", sep="/")), intern=TRUE)
"
Mas isso também não funciona para mim. Aqui está um arquivo .kml de teste para experimentá-lo. Com ele no meu diretório de trabalho, readOGR("x.kml", "id")
gera esta mensagem de erro:
Error in ogrInfo(dsn = dsn, layer = layer, encoding = encoding, use_iconv = use_iconv) :
Cannot open layer .
E system(paste("ogrinfo", "x.kml"), intern=TRUE)
gera:
[1] "Had to open data source read-only." "INFO: Open of `x.kml'"
[3] " using driver `KML' successful." "1: x (3D Polygon)"
, que eu simplesmente não entendo.
Iria getKMLcoordinates
{MapTools} ser uma alternativa válida?
Eu também tentei isso:
tkml <- getKMLcoordinates(kmlfile="x.kml", ignoreAltitude=T)
head(tkml[[1]])
tkml <- SpatialPolygons(tkml,
proj4string=CRS("+init=epsg:3857"))
As coordenadas são geradas corretamente, mas minha tentativa de convertê-las novamente em um objeto de polígono falhou com a seguinte mensagem:
Error in SpatialPolygons(tkml, proj4string = CRS("+init=epsg:3857")) :
cannot get a slot ("area") from an object of type "double"
Respostas:
Para ler um KML com o driver OGR, forneça o nome do arquivo e o nome da camada.
O comentário de Roger é que o nome da camada está oculto no arquivo KML e, a menos que você saiba como o KML foi criado, não poderá deduzir o nome da camada no nome do arquivo KML.
Olhando para o seu exemplo de KML, posso ver:
O que está me dizendo que o nome da camada é
x
, nãoid
e assim:funciona bem.
Agora, você pode tentar obter o nome ao analisar o KML como XML usando um analisador R XML, ou você pode talvez tentar lê-lo em R como um arquivo de texto até encontrar a tag nome.
A outra abordagem é executar o programa ogrinfo da linha de comando que cospe os nomes das camadas de um arquivo KML:
aqui mostrando que há uma camada de polígono chamada
x
.fonte
system
em R necessáriapath.expand
em~
paraogrinfo
trabalhar, mesmo que funcionou bem no caminho não expandidas na linha de comando (MacOS;Sys.which('ogrinfo')
ewhich ogrinfo
voltou os mesmos caminhos)Se você deseja fazer a maneira alternativa usando o maptool, isso deve funcionar:
A chave aqui é que você precisa seguir algumas etapas para criar uma classe de polígono espacial.
fonte
Não sei se isso ainda é um problema para mais alguém, mas eu estava correndo em círculos por um tempo com isso. O que finalmente funcionou para mim está abaixo. Ele usa o
XML
pacote para chegar aoxmlValue
nó certo. Eu tive que definir olayer
parâmetro dereadOGR
para o nome de uma das pastas dentro do arquivo kml. Quando eu defino olayer
parâmetro como o do arquivo kml, recebo o mesmo erro que RobinLovelace descrito acima.Abaixo, são mostradas várias linhas de código que mostram apenas como ver os vários níveis de nó do documento kml. Eu acho que isso será um pouco diferente dependendo da fonte do kml. Mas você deve poder usar a mesma lógica para determinar o valor correto do parâmetro.
Além disso, eu criei uma lista de arquivos KML para que pudesse ser facilmente transformado em uma função que poderia ser colocado em um
lapply
-do.call
par. Isso poderia extrair dados de uma longa lista de arquivos kml. Ou muitas subpastas em um único arquivo kml, como parece,readOGR
não podem lidar com várias subpastas em um arquivo kml.fonte
Não sei se eu deveria ter modificado minha resposta anterior. Talvez, mas isso cobre algumas coisas que não estão nesta resposta, então decidi deixá-lo.
De qualquer forma, o código abaixo funciona bem para mim. Ele procura por todos os xmlNodes no arquivo kml que são chamados de "Pasta" e, em seguida, define o
layer
parâmetroreadOGR
para issoxmlValue
. Testado no diretório de trabalho com cerca de 6 arquivos kml separados. Saída é uma lista de objetos SpatialDataFrames importados. Cada SpatialDataFrame pode ser facilmente subconjunto da lista.Ainda não trata os arquivos kml com vários nós de pasta. Mas esse recurso pode ser facilmente adicionado com outra
apply
função aninhada .fonte