Estoy trabajando con grandes archivos .kml (hasta 10 Gb) y necesito una forma eficiente de leerlos en R. Hasta ahora, los he convertido en archivos de forma a través de QGIS y luego de vuelta a R con readShapePoly y readOGR (este último , por cierto, es ~ 1000 más rápido que el anterior). Idealmente, me gustaría cortar la etapa intermedia de QGIS, ya que es engorrosa y lenta.
¿Cómo leer archivos .kml directamente?
Yo veo esto también se puede hacer con readOGR . Desafortunadamente, no puedo ver cómo implementar el ejemplo trabajado (después de una larga preparación del archivo .kml:) xx <- readOGR(paste(td, "cities.kml", sep="/"), "cities")
. Parece que "ciudades" aquí es el nombre de los objetos espaciales.
Roger Bivand admite que "cómo se descubre este nombre no es obvio, ya que el controlador KML en OGR lo necesita para acceder al archivo. Una posibilidad es:
system(paste("ogrinfo", paste(td, "cities.kml", sep="/")), intern=TRUE)
"
Pero esto tampoco funciona para mí. Aquí hay un archivo de prueba .kml para probarlo. Con él en mi directorio de trabajo, readOGR("x.kml", "id")
genera este mensaje de error:
Error in ogrInfo(dsn = dsn, layer = layer, encoding = encoding, use_iconv = use_iconv) :
Cannot open layer .
Y system(paste("ogrinfo", "x.kml"), intern=TRUE)
genera:
[1] "Had to open data source read-only." "INFO: Open of `x.kml'"
[3] " using driver `KML' successful." "1: x (3D Polygon)"
, que simplemente no entiendo.
¿Sería getKMLcoordinates
{maptools} una alternativa válida?
También he intentado esto:
tkml <- getKMLcoordinates(kmlfile="x.kml", ignoreAltitude=T)
head(tkml[[1]])
tkml <- SpatialPolygons(tkml,
proj4string=CRS("+init=epsg:3857"))
Las coordenadas se generan correctamente, pero mi intento de convertirlas nuevamente en un objeto poligonal falló con el siguiente mensaje:
Error in SpatialPolygons(tkml, proj4string = CRS("+init=epsg:3857")) :
cannot get a slot ("area") from an object of type "double"
Respuestas:
Para leer un KML con el controlador OGR, debe asignarle el nombre del archivo y el nombre de la capa.
El comentario de Roger es que el nombre de la capa está oculto en el archivo KML y, a menos que sepa cómo se creó el KML, no puede inferir el nombre de la capa a partir del nombre del archivo KML.
Mirando su ejemplo KML, puedo ver:
Lo que me dice que el nombre de la capa es
x
, noid
, y así:funciona bien
Ahora, se puede tratar de obtener el nombre mediante el análisis del KML como XML usando un analizador R XML, o puede quizá tratar de leerlo en I como un archivo de texto hasta que encuentre la etiqueta con su nombre.
El otro enfoque es ejecutar el programa ogrinfo de línea de comandos que escupe los nombres de capa de un archivo KML:
aquí mostrando que hay una capa de polígono llamada
x
.fuente
system
en I necesariapath.expand
en~
paraogrinfo
al trabajo, a pesar de que funcionó bien en el camino sin expandir en la línea de comandos (macOS;Sys.which('ogrinfo')
ywhich ogrinfo
devuelto los mismos caminos)Si desea hacer la forma alternativa usando maptool, esto debería funcionar:
La clave aquí es que debe seguir un par de pasos para crear una clase de polígono espacial.
fuente
No sé si esto sigue siendo un problema para alguien más, pero estuve corriendo en círculos por un tiempo con esto. Lo que finalmente funcionó para mí está abajo. Utiliza el
XML
paquete para llegar alxmlValue
nodo correcto. Tuve que establecer ellayer
parámetro dereadOGR
al nombre de una de las carpetas dentro del archivo kml. Cuando configuro ellayer
parámetro en el archivo kml, obtengo el mismo error que RobinLovelace describió anteriormente.A continuación se muestran muchas líneas de código que solo muestran cómo ver los distintos niveles de nodo del documento kml. Creo que esto será ligeramente diferente dependiendo de la fuente del kml. Pero debería poder usar la misma lógica para determinar el valor de parámetro correcto.
Además, he creado una lista de archivos KML por lo que se podría hacer fácilmente en una función que se podría poner en un
lapply
-do.call
par. Esto podría extraer datos de una larga lista de archivos kml. O bien, muchas subcarpetas dentro de un solo archivo kml, ya que parecereadOGR
que no pueden manejar múltiples subcarpetas en un archivo kml.fuente
No sé si debería haber modificado mi respuesta anterior. Quizás, pero eso cubre algunas cosas que no están en esta respuesta, así que decidí dejarlo.
De todos modos, el siguiente código funciona bien para mí. Busca todos los xmlNodes en el archivo kml que se llaman "Carpeta" y luego establece el
layer
parámetro dereadOGR
esoxmlValue
. Probado en el directorio de trabajo con alrededor de 6 archivos kml separados. La salida es una lista de objetos SpatialDataFrames importados. Cada SpatialDataFrame puede ser fácilmente subconjunto de la lista.Todavía no aborda los archivos kml con múltiples nodos de carpeta. Pero esa característica podría agregarse fácilmente con otra
apply
función anidada .fuente