1 votos

Cómo solucionar el error DataIncomplete al acceder al resultado de la consulta overpy

Recientemente he preguntado esta pregunta y tengo esta respuesta que fue muy útil para identificar los lagos que utilizan overpass-turbo.eu . Efectivamente, si ejecuto la consulta, obtengo el resultado deseado. Un ejemplo, en el que he hecho clic en una fuente, es el siguiente (Oslo estaba en el centro del mapa cuando ejecuté la consulta).

enter image description here

Quiero ejecutar la misma consulta usando Python. Defino un cuadro delimitador:

bbox = {'latLower':59.9,'lonLower':10.7,'latHigher':60.0,'lonHigher': 10.8}

Este recuadro cubre una zona de Oslo. A continuación, construya el texto de la consulta:

querytext=\
f'''
/*
From: https://gis.stackexchange.com/a/412100/191643

This has been generated by the overpass-turbo wizard.
The original search was:
“(natural=water and type=multipolygon) or natural=water”
*/
[out:json][timeout:25];
// gather results
(
  // query part for: “natural=water and type=multipolygon”
  node["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  way["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  relation["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  // query part for: “natural=water”
  node["natural"="water"]{overpy_bbox};
  way["natural"="water"]{overpy_bbox};
  relation["natural"="water"]{overpy_bbox};
);
// print results
out body;
'''

A continuación, la propia consulta mediante overpy :

import overpy
api = overpy.Overpass()
result = api.query(querytext)

Accedo a todos los ways por:

result.get_ways()

que devuelve una lista, un pantallazo parcial de la misma:

enter image description here

He resaltado la línea que contiene el mismo ID que tenía arriba en el overpass-turbo.eu interfaz. Accediendo al primer nodo, por ejemplo:

result.get_ways()[0]

La salida:

<overpy.Way id=4258487 nodes=[25526443, 4731901953, 4731901954, 4731901952, 25526546, 6794539693, 25526545, 6794539694, 4731901950, 6794539695, 25526439, 6794539696, 4731901951, 25526544, 4731901957, 7576044285, 7576027484, 25526543, 4731901958, 25526542, 23597818, 7576027483, 5273979151, 4731901959, 23597804, 4751403582, 25526444, 4751403583, 4731901960, 25526445, 4751403584, 4731901961, 4751403585, 25526446, 4751403586, 25526448, 4731901962, 4751403587, 25526452, 347545612, 347545599, 25526454, 23597806, 25526474, 8690362851, 25526558, 4751403592, 25526557, 25526554, 25526553, 25526552, 25526551, 25526498, 25526481, 4731901943, 25526475, 25526456, 23597809, 4731901944, 4731901945, 23597811, 4731901948, 4731901949, 4731901947, 4731901946, 23597814, 4731901963, 6839492557, 6839492556, 23597816, 6839492559, 25526549, 6839492558, 25526550, 7576044287, 25526548, 7576044286, 4731901956, 25526547, 4731901955, 25526443]>

Luego quiero acceder a los nodos propiamente dichos:

result.get_ways()[0].nodes

Pero esto me da un error:

---------------------------------------------------------------------------
DataIncomplete                            Traceback (most recent call last)
<ipython-input-141-59cf0ff05ef6> in <module>()
----> 1 result.get_ways()[0].nodes

1 frames
/usr/local/lib/python3.7/dist-packages/overpy/__init__.py in nodes(self)
    894         List of nodes associated with the way.
    895         """
--> 896         return self.get_nodes()
    897 
    898     def get_nodes(self, resolve_missing=False):

/usr/local/lib/python3.7/dist-packages/overpy/__init__.py in get_nodes(self, resolve_missing)
    921 
    922             if not resolve_missing:
--> 923                 raise exception.DataIncomplete("Resolve missing nodes is disabled")
    924 
    925             # We tried to resolve the data but some nodes are still missing

DataIncomplete: ('Data incomplete try to improve the query to resolve the missing data', 'Resolve missing nodes is disabled')

Así que no puedo obtener datos de la consulta de esta manera.

¿Cómo puedo acceder a los datos que aparecen en el overpass-turbo.eu (por ejemplo, la ubicación de los nodos), utilizando Python?

Idealmente, me gustaría tener polígonos / multipolígonos formados para los nodos que forman parte de un camino.

0voto

Bob Brown Puntos 21

La clave era utilizar get_nodes(resolve_missing=True) .

El código completo se encuentra a continuación.

Instala el overpy:

%%shell
pip install overpy
pip install geopandas

Importaciones:

import overpy
from overpy.exception import OverpassTooManyRequests, OverpassGatewayTimeout
import time
from tqdm import tqdm
import folium
from shapely.geometry.polygon import Polygon
import numpy as np
import geopandas as gpd

Definir un cuadro delimitador:

bbox = {'latLower':59.9,'lonLower':10.75,'latHigher':59.91,'lonHigher': 10.775}

Crea una cadena a partir de ella, para utilizarla dentro de la consulta Overpass:

overpy_bbox=\
f"({bbox['latLower']},{bbox['lonLower']},{bbox['latHigher']},{bbox['lonHigher']})"

Crear el texto de la consulta Overpass, basándose en esta respuesta :

querytext=\
f'''
/*
From: https://gis.stackexchange.com/a/412100/191643

This has been generated by the overpass-turbo wizard.
The original search was:
“(natural=water and type=multipolygon) or natural=water”
*/
[out:json][timeout:25];
// gather results
(
  // query part for: “natural=water and type=multipolygon”
  node["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  way["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  relation["natural"="water"]["type"="multipolygon"]{overpy_bbox};
  // query part for: “natural=water”
  node["natural"="water"]{overpy_bbox};
  way["natural"="water"]{overpy_bbox};
  relation["natural"="water"]{overpy_bbox};
);
// print results
out body;
'''

Consulta:

api = overpy.Overpass()
result = api.query(querytext)

Procesar la consulta:

waydict={}
for way in tqdm(result.get_ways()):
    while True:
        try:
            nodes = way.get_nodes(resolve_missing=True)
            nodelist=[]
            for node in nodes:
                nodelist.append([float(node.lon), float(node.lat)])
            waydict[way.id]=nodelist
        except OverpassTooManyRequests:
            time.sleep(1)
            print('Retrying...')
            continue
        except OverpassGatewayTimeout:
            time.sleep(10)
            print('OverpassGatewayTimeout, retrying...')
            continue
        break

Procesar un poco el resultado:

for id, way in waydict.items():
    polygon_obj = Polygon(np.array(way))

polygondict={}
for id, way in waydict.items():
    polygondict[id]= Polygon(np.array(way))

Crear un cuadro delimitador Polygon :

bbox_polygon_obj = Polygon(np.array([
                        [bbox['lonLower'],bbox['latLower']],
                        [bbox['lonLower'],bbox['latHigher']],
                        [bbox['lonHigher'],bbox['latHigher']],
                        [bbox['lonHigher'],bbox['latLower']]
                        ]))

Colocar los resultados en el mapa de Folium:

m = folium.Map(location=[0.5*(bbox['latLower']+bbox['latHigher']),
                         0.5*(bbox['lonLower']+bbox['lonHigher'])], zoom_start=15, tiles='CartoDB positron')

for id, polygon in polygondict.items():
    geo_j = folium.GeoJson(data=gpd.GeoSeries(polygon).to_json(),style_function=lambda x: {'fillColor': 'red'})
    geo_j.add_to(m)

geo_j_bbox = folium.GeoJson(data=gpd.GeoSeries(bbox_polygon_obj).to_json(),style_function=lambda x: {'fillColor': 'red'})
geo_j_bbox.add_to(m)

m

Una captura de pantalla del resultado:

enter image description here

Es decir, hemos accedido a los datos de los polígonos utilizando Python y los hemos mostrado en un mapa (con el cuadro delimitador también): objetivo conseguido.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X