wij zijn bezig met het maken van een python tool die de ruwheidsfactor van het terrein bepaalt. Deze zal vervolgens weer worden gebruikt om de stuwdruk van de wind op een gebouw te bepalen.
Voor het bepalen van de ruwheidsfactor zouden we graag de data van 3DBAG binnenhalen in cityjson format. Dat doen we via api.3dbag.nl.
Omdat we een groot gebied nodig hebben (5km straal), moet er dus erg veel data opgehaald worden. Individuele requests na elkaar duurt erg lang, dus zouden we dat graag asynchroon doen.
Het lukt me alleen niet om meer dan 20 succesvolle requests op rij te sturen. De requests daarna komen terug met ofwel een 504 of 502 status code. Als ik het script vervolgens nog een keer run komt er geen enkele request succesvol terug.
Ik vermoed daarom dat er een rate limiter op de api zit, die mij niet toestaat zoveel requests te sturen.
Mijn vraag aan jullie is of er een andere manier is om toch op een snelle manier deze wat grotere hoeveelheid data binnen te halen? Misschien geeft de api me mogelijkheden die ik over het hoofd zie. Ik hoop dat jullie me verder kunnen helpen!
groeten, Marijn
Hierbij het script dat ik gebruik om te testen:
import time
import asyncio
import aiohttp
BBOX = "87679,434204,97679,444204"
LIMIT = 100
AMOUNT = 100
def make_urls(bbox: str, limit: int, amount: int):
urls = []
for i in range(amount):
urls.append(f"https://api.3dbag.nl/collections/pand/items?bbox={bbox}&offset={i*limit+1}&limit={limit}")
return urls
async def fetch(session: aiohttp.ClientSession, url: str):
print(f"Starting request: {url}")
async with session.get(url) as response:
print(f"Completed request: {url}")
return response
async def perform_async(urls: list[str]):
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
responses = await asyncio.gather(*tasks)
print(f"Now collected {len(responses)} responses")
return responses
def main():
t = time.perf_counter()
urls = make_urls(BBOX, LIMIT, AMOUNT)
print(f"Starting async requests to {len(urls)} urls...")
responses = asyncio.run(perform_async(urls))
print(f"Time taken for async: {time.perf_counter()-t:.2f} seconds")
succesful_responses = [response for response in responses if response.status == 200]
unsuccesful_responses = [response for response in responses if response.status != 200]
print(f"Amount of succesful responses: {len(succesful_responses)}")
print(f"Amount of unsuccesful responses: {len(unsuccesful_responses)}")
status_codes = [response.status for response in responses]
print(f"Status code 200: {status_codes.count(200)}")
print(f"Status code 502: {status_codes.count(502)}")
print(f"Status code 504: {status_codes.count(504)}")
if unsuccesful_responses:
print("Example of unsuccesful response:")
unsuccesful_responses[0].raise_for_status()
main()
Heb je hier de lod 2.2 van de 3dBAG voor nodig? Ik kan me voorstellen dat een dsm geotiff of een simpele extrusie geometrie ook al voldoende is. Deze zijn eenvoudiger en sneller binnen te halen.
De ruwheidsfactor van het terrein is een functie van de oppervlakte van het grondvlak van een gebouw en bijbehorende gemiddelde hoogte. De data attributes die uit de 3DBAG api komen lenen zich goed voor deze berekening.
Een digital surface model is volgensmij in ons geval niet geschikt, omdat hierin voor zover ik weet geen onderscheid is tussen bebouwd gebied en onbebouwd gebied?
Hi Raymond, het liefst gebruik ik een api service hiervoor. Deze python tool zal worden gebruikt vanuit een web app dus zal zelf ook op een api draaien.
Is er naar jullie weten een manier om de requests op api.3dbag.nl te versnellen? Kan ik bijvoorbeeld filteren op lod of op data attributes?
dag Marijn, ik ben heel toevallig met exact hetzelfde bezig, het lukt me vooralsnog prima met binnenhalen van een aantal Tiles van het gebied van interesse. maar via de API request loop ik ook inderdaad tegen hetzelfde aan dat er max 100 panden aangevraagd kunnen worden per request.