Instantly share code, notes, and snippets.
Created
November 11, 2020 10:30
-
Save LtGlahn/9f5a5658c538d6c25a467e69c76cb1c1 to your computer and use it in GitHub Desktop.
Stedsnavn i SSR versus navn på tunneller i NVDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Script som sammenligner navn på tunneller i NVDB med stedsnavn i SSR | |
Logikken er som følger: | |
- Søk i SSR skjer innafor boundingbox laget fra 500 meter buffer rundt tunnelløpene | |
(de forekomstene av objekttype 67 Tunnelløp som er datterobjekter av denne forekomsten av 581 Tunnel) | |
- Hvis nødvendig, søker vi flere ganger i SSR: | |
1. Først på eksakt match på NVDB navnet | |
2. Deretter wildcard-søk etter *tunnel* (innafor boundingbox) | |
3. Deretter fjerner vi tallord fra NVDB navnet (1, I, IV og så videre) | |
4. Deretter fjerner vi frasen "tunnel" (og feilstavinger av "tunnel", "tunellen" osv) fra 3) | |
5. Hvis ikke dette går så gir vi opp... | |
Resultatene lagres som geopackage og excel-regneark. | |
""" | |
import requests | |
import xmltodict | |
import pdb | |
import collections | |
import geopandas as gpd | |
from shapely import wkt | |
from shapely.geometry import LineString | |
from shapely.ops import unary_union | |
from pyproj import Transformer | |
import STARTHER # Kun nødvendig om du bruker https://github.com/LtGlahn/workinprogress, en omvei til nvdbapi-V3 | |
import nvdbapiv3 # https://github.com/LtGlahn/nvdbapi-V3 | |
def finnssrtunnel( nvdbnavn, geom, omkrets=500, rekursjon=False): | |
""" | |
Finner tunnelnavn i SSR innafor bbox rundt geom | |
Prøver primitiv "fuzzy search" om vi ikke får eksakt treff | |
se SSR api https://www.kartverket.no/en/api-and-data/stedsnavndata/brukarrettleiing-stadnamn-api | |
ARGUMENTS: | |
nvdbnavn: String, navn på tunnel i NVDB | |
geom: shapely geometrisk objekt. | |
KEYWORDS: | |
omkrets: Størrelse på boundingbox vi søker innafor | |
rekursjon: Boolean, hvis True og søket returnerer null treff så prøver vi ut ymse wildcard-pertubasjoner | |
RETURNS: | |
Tuple med følgende elementer: | |
ssrNavn: Liste med en oppføring per SSR-treff | |
ssrKvalitet: Angir om det er eksakt eller fuzzy treff | |
antallSsrTreff: Antall søketreff | |
ssrId: Liste med SSR ID for alle søketreffene | |
ssrSkrivemaateStatus: Liste med en oppføring per skrivestatus på treffene fra SSR | |
sokefrase: Søkefrasen som ga treff | |
ssrKommune: Liste med en oppføring per kommune som treffene befinner seg i | |
ssrNavnetype: Liste med en oppføring per SSR navnetype blant treffene | |
""" | |
(ostLL,nordLL,ostUR,nordUR) = geom.buffer(omkrets).bounds | |
ssrUrl = 'https://ws.geonorge.no/SKWS3Index/ssr/sok' | |
params= { 'navn' : nvdbnavn, 'ostLL' : ostLL, 'nordLL' : nordLL, 'ostUR': ostUR, 'nordUR' : nordUR, 'eksakteForst' : 'true' } | |
r = requests.get( ssrUrl, params=params) | |
ssrNavn = [] | |
ssrKvalitet = 'INGEN' | |
antallSsrTreff = 0 | |
ssrId = [] | |
ssrSkrivemaateStatus = [] | |
ssrKommune = [] | |
ssrNavnetype = [] | |
sokefrase = nvdbnavn | |
ssrNavnetype = [] | |
if r.ok and '<?xml' in r.text[0:5] and not '<totaltAntallTreff>0</totaltAntallTreff>' in r.text: | |
r.encoding = 'utf-8' | |
myDict = xmltodict.parse( r.text ) | |
ssrKvalitet = 'EKSAKT' | |
antallSsrTreff = int( myDict['sokRes']['totaltAntallTreff'] ) | |
if isinstance( myDict['sokRes']['stedsnavn'], collections.OrderedDict ): | |
ssrNavn.append( myDict['sokRes']['stedsnavn']['stedsnavn'] ) | |
ssrId.append( myDict['sokRes']['stedsnavn']['ssrId'] ) | |
ssrSkrivemaateStatus.append( myDict['sokRes']['stedsnavn']['skrivemaatestatus'] ) | |
ssrKommune.append( myDict['sokRes']['stedsnavn']['kommunenavn'] ) | |
ssrNavnetype.append( myDict['sokRes']['stedsnavn']['navnetype'] ) | |
elif isinstance( myDict['sokRes']['stedsnavn'], list): | |
ssrNavn.extend( [ x['stedsnavn'] for x in myDict['sokRes']['stedsnavn'] ] ) | |
ssrId.extend( [ x['ssrId'] for x in myDict['sokRes']['stedsnavn'] ] ) | |
ssrSkrivemaateStatus.extend( [ x['skrivemaatestatus'] for x in myDict['sokRes']['stedsnavn'] ] ) | |
ssrKommune.extend( [ x['kommunenavn'] for x in myDict['sokRes']['stedsnavn'] ] ) | |
ssrNavnetype.extend( [ x['navnetype'] for x in myDict['sokRes']['stedsnavn'] ] ) | |
else: | |
print( 'Null treff??? This should not happen... ') | |
elif rekursjon: | |
# Får vi treff når vi søker på *tunnel* innafor bbox? | |
if antallSsrTreff == 0: | |
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \ | |
finnssrtunnel( '*tunnel*', geom, omkrets=omkrets, rekursjon=False) | |
ssrKvalitet = 'Søkeord *tunnel*' | |
# Har vi telleord? | |
nysokefrase = fjerntelling( nvdbnavn ) | |
if antallSsrTreff == 0 and nysokefrase != nvdbnavn: | |
print( 'Fjernet telling fra tunnelnavn', nvdbnavn, '=>', nysokefrase) | |
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \ | |
finnssrtunnel( nysokefrase, geom, omkrets=omkrets, rekursjon=False) | |
ssrKvalitet = 'Fjernet tallord' | |
# Fjerner ordet "tunnel" fra søketermen, prøver igjen... | |
if antallSsrTreff == 0: | |
sokefrase2 = nysokefrase.lower() | |
sokefrase2 = sokefrase2.replace( 'tunnelen' , '') | |
sokefrase2 = sokefrase2.replace( 'tunelen' , '') | |
sokefrase2 = sokefrase2.replace( 'tunellen' , '') | |
sokefrase2 = sokefrase2.replace( 'tunell' , '') | |
sokefrase2 = sokefrase2.replace( 'tunnellen' , '') | |
sokefrase2 = sokefrase2.replace( 'tunnel' , '') | |
sokefrase2 = sokefrase2.replace( 'tunel' , '') | |
sokefrase2 = sokefrase2.strip() | |
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \ | |
finnssrtunnel( sokefrase2, geom, omkrets=omkrets, rekursjon=False) | |
ssrKvalitet = 'Fjernet tallord og "tunnel"' | |
if antallSsrTreff == 0: | |
ssrKvalitet = 'INGEN' | |
print( 'Ingen søketreff', nvdbnavn, 'eller', sokefrase2 ) | |
ssrSkrivemaateStatus = list( set( ssrSkrivemaateStatus ) ) | |
ssrNavn = list( set( ssrNavn ) ) | |
ssrKommune = list( set( ssrKommune )) | |
ssrNavnetype = list( set( ssrNavnetype )) | |
return( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) | |
def fjerntelling( tunnellnavn): | |
""" | |
Fjerner telling av typen Diggbartunnellen 1, Diggbartunnelen 2 og så videre | |
ARGUMENTS: | |
tunnelnavn - string | |
KEYWORDS: | |
None | |
RETURNS: | |
tunnelnavn | |
""" | |
navnebiter = tunnellnavn.split( ) | |
godebiter = [] | |
for bit in navnebiter: | |
try: | |
x = int( bit ) | |
except ValueError: | |
if bit.upper() not in [ 'I', 'II', 'III', 'IV', 'V', 'VI' ]: | |
godebiter.append(bit) | |
else: | |
godebiter.append(bit) | |
nyttnavn = ' '.join( godebiter ) | |
return nyttnavn | |
if __name__ == "__main__": | |
trans = Transformer.from_crs('EPSG:5973', 'EPSG:5972') | |
data = [] | |
# For debugging | |
# miliste = [ 92204012, 237272463, 237272458, 275871985, 92204576, 92204147, 272037773, 440826971, 228222589, 83669781, 83645662 ] | |
# for objid in miliste: | |
# r = nvdbapiv3.finnid( objid, kunfagdata=True ) | |
tunsok = nvdbapiv3.nvdbFagdata(581) | |
tun = tunsok.nesteNvdbFagObjekt() | |
while tun: | |
# Geometrihåndtering | |
geom = wkt.loads( tun.geometri['wkt'] ) | |
(x, y) = trans.transform( geom.x, geom.y) | |
vref = tun.lokasjon['vegsystemreferanser'][0]['kortform'] | |
mydict = { 'NVDB-id' : tun.id, | |
'vegkategori' : vref[0], | |
'vegsystemreferanse' : vref, | |
'Tunnelforvalterområde' : tun.egenskapverdi( 12087), | |
'Tunnel kommune' : tun.lokasjon['kommuner'][0], | |
'Navn i NVDB' : tun.egenskapverdi( 5225 ), | |
'Tunnelnummer' : tun.egenskapverdi( 9306 ), | |
'Brutus Id' : tun.egenskapverdi( 9329 ), | |
'Åpningsår' : tun.egenskapverdi( 'Åpningsår'), | |
'Offisiell lengde' : tun.egenskapverdi( 8945), | |
'Antall parallelle hovedløp' : tun.egenskapverdi( 3947 ), | |
'UTM32 Øst' : x, | |
'UTM32 Nord' : y | |
} | |
# Inspiserer datterobjekter av typen tunnelløp | |
tunfam = tun.relasjon( 67 ) | |
kommuner = set( ) | |
tlopgeom = LineString( ) | |
if tunfam and 'vegobjekter' in tunfam.keys(): | |
for datterId in tunfam['vegobjekter']: | |
datter = nvdbapiv3.finnid( datterId, kunfagdata=True ) | |
if datter and 'geometri' in datter.keys(): | |
kommuner = kommuner.union( set( [ str(x) for x in datter['lokasjon']['kommuner'] ] ) ) | |
tlopgeom = unary_union([ tlopgeom, wkt.loads( datter['geometri']['wkt'] ) ]) | |
elif datter: | |
print( tun.id, tun.egenskapverdi(5225), 'har datter uten geometri:', datter['id']) | |
else: | |
print( tun.id, tun.egenskapverdi(5225), 'har ugyldig tunnelløp-datterobjekt:', datterId ) | |
mydict['Kommuner tunnelløp'] = ','.join( list( kommuner ) ) | |
if len( list( kommuner )) == 0: | |
print( 'Fant ingen gyldige døtre for tunnel', tun.id, tun.egenskapverdi( 5225 )) | |
tlopgeom = geom | |
# Søker etter stedsnavn | |
if mydict['Navn i NVDB']: | |
( ssrNavn, ssrKvalitet, antallSsrTreff, ssrId, ssrSkrivemaateStatus, sokefrase, ssrKommune, ssrNavnetype ) = \ | |
finnssrtunnel( mydict['Navn i NVDB'], tlopgeom, omkrets=500, rekursjon=True ) | |
mydict['Navn i SSR'] = ','.join( ssrNavn ) | |
# mydict['Kvalitet navnesøk'] = ssrKvalitet | |
mydict['Antall SSR-treff'] = antallSsrTreff | |
mydict['ssrId'] = ','.join( ssrId ) | |
mydict['SSR Skrivemåtestatus'] = ','.join( ssrSkrivemaateStatus ) | |
mydict['Søkefrase'] = sokefrase | |
mydict['SSR kommuner'] = ','.join( ssrKommune ) | |
mydict['SSR navnetype'] = ','.join( ssrNavnetype ) | |
mydict['geometry'] = geom | |
data.append( mydict ) | |
tun = tunsok.nesteNvdbFagObjekt() | |
myGdf = gpd.GeoDataFrame( data ) | |
myGdf.to_file( 'tunnelnavn.gpkg', driver='GPKG' ) | |
myGdf.to_excel( 'tunnelnavn.xlsx', index=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment