💻 Henting av data fra OpenStreetMap#

Open In Colab

Hva er OpenStreetMap?#

Logoet til OpenStreetMap (OSM)

Fig. 2 OpenStreetMap er en gratis og åpen karttjeneste, men - først og fremst - er det et globalt samarbeidsprosjekt for å samle inn frie og åpne geodata. Kilde: wiki.openstreetmap.org#

OpenStreetMap (OSM) er en global samarbeidsdatabase (crowd-sourced) og prosjekt som har som mål å lage et fritt redigerbart kart over verden som inneholder informasjon om verden rundt oss. Den inneholder data om gater, bygninger, forskjellige tjenester og arealbruk, for å nevne noe. De innsamlede dataene er også grunnlaget for kartet på openstreetmap.org.

Bidra!

Du kan også registrere deg som bidragsyter hvis du vil legge til i databasen og kartet eller korrigere og forbedre eksisterende data. Les mer i OpenStreetMap Wiki.

OSM har mer enn 8 millioner registrerte brukere som bidrar med rundt 4 millioner endringer daglig. Databasen inneholder data som er beskrevet av mer enn 7 milliarder noder (som utgjør linjer, polygoner og andre objekter).

Mens den mest kjente siden av OpenStreetMap er kartet selv, som vi har brukt som et bakgrunnskart, er prosjektet mye mer enn det. OSMs data kan brukes til mange andre formål som ruting, geokoding, utdanning og forskning. OSM brukes også mye for humanitær respons, for eksempel i kriseområder (for eksempel etter naturkatastrofer) og for å fremme økonomisk utvikling. Les mer om humanitære prosjekter som bruker OSM-data fra Humanitarian OpenStreetMap Team (HOTOSM) nettsted.

Hovedverktøy i denne leksjonen#

OSMnx#

Denne uken skal vi utforske en Python-pakke kalt OSMnx som kan brukes til å hente gate-nettverk fra OpenStreetMap, og konstruere, analysere og visualisere dem. OSMnx kan også hente data om interessepunkter, som restauranter, skoler og forskjellige typer tjenester. Pakken inkluderer også verktøy for å finne ruter på et nettverk lastet ned fra OpenStreetMap, og implementerer algoritmer for å finne korteste forbindelser for gange, sykling eller kjøring.

For å få en oversikt over mulighetene med pakken, se den innledende videoen gitt av hovedutvikleren av pakken, Prof. Geoff Boeing: “Meet the developer: Introduction to OSMnx package by Geoff Boeing”.

Det er også en vitenskapelig artikkel tilgjengelig som beskriver pakken:

Boeing, G. 2017. “OSMnx: New Methods for Acquiring, Constructing, Analyzing, and Visualizing Complex Street Networks.” Computers, Environment and Urban Systems 65, 126-139. doi:10.1016/j.compenvurbsys.2017.05.004

Denne opplæringen gir en praktisk oversikt over OSMnx-funksjonaliteter, og har også inspirert denne notebooken.

NetworkX#

Vi vil også bruke NetworkX til å manipulere og analysere gatenettverksdataene hentet fra OpenStreetMap. NetworkX er en Python-pakke som kan brukes til å opprette, manipulere og studere strukturen, dynamikken og funksjonene til komplekse nettverk.


Last ned og visualiser OpenStreetMap-data med OSMnx#

En nyttig funksjon med OSMnx er enkle å bruke verktøy for å laste ned OpenStreetMap-data via prosjektets OverPass API. I denne delen vil vi lære å laste ned og visualisere gatenettverket og tilleggsdata fra OpenStreetMap som dekker et interesseområde.

Gatenettverk#

osmnx.graph modulen laster ned data for å konstruere en kjørbart vei-nettverksgraf, basert på et brukerdefinert interesseområde. Dette interesseområdet kan spesifiseres, for eksempel ved bruk av et stedsnavn, en begrensningsboks eller et polygon. Her vil vi bruke et stedsnavn for å hente data som dekker Grünerløkka bydel i Oslo.

I stedsnavnsforespørselen bruker OSMnx Nominatim Geocoding API. Dette betyr at stedsnavn må eksistere i OpenStreetMap-databasen (kjør et testsøk på openstreetmap.org eller nominatim.openstreetmap.org).

Vi vil lese et OSM-gatenettverk ved hjelp av OSMnxs graph_from_place()-funksjon:

import osmnx

PLACE_NAME = "Grunerløkka, Oslo, Norway"
graph = osmnx.graph_from_place(PLACE_NAME)

Sjekk datatypen til grafen:

type(graph)
networkx.classes.multidigraph.MultiDiGraph

Det vi har her er et networkx.MultiDiGraph objekt.

OSMnxs grafer har ikke en innebygd metode for å plotte dem, men pakken kommer med en funksjon for å gjøre det:

figure, ax = osmnx.plot_graph(graph)
../../_images/568ab42aeac91e13d976a180de7e67413a35f7a719b6ae3c1440de9a9d2ed150.png

Akkurat som dens GeoPandas- og Pandas-ekvivalenter, bruker osmnx.plot_graph() matplotlib. Funksjonen returnerer en (figure, axes)-tuple, som kan brukes til å modifisere figuren ved hjelp av alle matplotlib-funksjonene vi allerede har blitt kjent med.

Vi kan se at grafen vår inneholder noder (punktene) og kanter (linjene) som kobler disse nodene til hverandre.

Konverter en graf til GeoDataFrames#

Gatenettverket vi nettopp lastet ned er en graf, mer spesifikt en networkx.MultiDiGraph. Hovedformålet er å representere de topologiske forholdene mellom noder og koblingene (kanter) mellom dem. Noen ganger er det mer praktisk å ha de underliggende geodataene i geopandas.GeoDataFrames. OSMnx kommer med en praktisk funksjon som konverterer en graf til to geodataframes, en for noder, og en for kanter: osmnx.graph_to_gdfs().

nodes, edges = osmnx.graph_to_gdfs(graph)
nodes.head()
y x street_count highway ref geometry
osmid
79448 59.921549 10.750836 3 NaN NaN POINT (10.75084 59.92155)
79465 59.928495 10.761100 4 traffic_signals NaN POINT (10.7611 59.9285)
79475 59.928343 10.759132 4 traffic_signals NaN POINT (10.75913 59.92834)
79476 59.928694 10.764892 4 traffic_signals NaN POINT (10.76489 59.92869)
79490 59.929560 10.768588 5 traffic_signals NaN POINT (10.76859 59.92956)
edges.head()
osmid oneway lanes name highway reversed length geometry maxspeed width ref junction bridge service access tunnel
u v key
79448 3165357950 0 129061337 False 2 Maridalsveien secondary False 109.067 LINESTRING (10.75084 59.92155, 10.75079 59.921... NaN NaN NaN NaN NaN NaN NaN NaN
79465 3441703718 0 4211442 False 2 Toftes gate secondary True 8.531 LINESTRING (10.7611 59.9285, 10.7611 59.92842) NaN NaN NaN NaN NaN NaN NaN NaN
3441703770 0 349267814 False 2 Toftes gate secondary False 8.408 LINESTRING (10.7611 59.9285, 10.7611 59.92857) 40 NaN NaN NaN NaN NaN NaN NaN
1469875895 0 882463938 False 3 Sannergata tertiary True 10.489 LINESTRING (10.7611 59.9285, 10.76107 59.92849... 40 NaN NaN NaN NaN NaN NaN NaN
1469875898 0 882463954 False 3 Sannergata tertiary False 6.402 LINESTRING (10.7611 59.9285, 10.76113 59.9285,... 40 NaN NaN NaN NaN NaN NaN NaN

Fint! Nå, som vi kan se, har vi grafen vår som GeoDataFrames og vi kan plotte dem ved hjelp av de samme funksjonene og verktøyene som vi har brukt før.

Stedspolygon#

La oss også plotte polygonet som representerer vårt interesseområde (Grünerløkka, Oslo). Vi kan hente polygon-geometrien ved hjelp av osmnx.geocode_to_gdf() funksjonen.

# Hent stedsgrensen relatert til stedsnavnet som en geodataframe
area = osmnx.geocode_to_gdf(PLACE_NAME)

Som navnet på funksjonen allerede forteller oss, returnerer den et GeoDataFrame-objekt basert på det spesifiserte stedsnavnsøket. La oss fortsatt verifisere datatypen:

# Sjekk datatypen
type(area)
geopandas.geodataframe.GeoDataFrame

La oss også ta en titt på dataene:

# Sjekk dataverdier
area
geometry bbox_north bbox_south bbox_east bbox_west place_id osm_type osm_id lat lon class type place_rank importance addresstype name display_name
0 POLYGON ((10.74799 59.91964, 10.74992 59.91939... 59.937559 59.913477 10.80766 10.747989 150874432 relation 1279942 59.925471 10.777421 boundary administrative 18 0.431265 suburb Grünerløkka Grünerløkka, Oslo, Norway
# Plot området:
area.plot()
<Axes: >
../../_images/01921c92de31e936809fb5d9753644cca20625b4add487034187660275dc4f2f.png

Bygningsavtrykk#

I tillegg til nettverksdata, kan OSMnx også laste ned alle andre data som finnes i OpenStreetMap-databasen. Dette inkluderer for eksempel bygningsavtrykk og forskjellige interessepunkter (POI-er). For å laste ned vilkårlige geometrier, filtrert av OSM-tags og et stedsnavn, bruk osmnx.features_from_place(). Taggen for å hente alle bygninger er building = yes.

buildings = osmnx.features_from_place(
    PLACE_NAME,
    {"building": True},
)
len(buildings) 
3682
buildings.head() 
amenity capacity fee name operator parking wheelchair geometry bicycle foot ... ref advertising mapillary name:signed substation man_made craft ways type location
element_type osmid
way 9334580 NaN NaN NaN NaN NaN NaN NaN POLYGON ((10.78349 59.93551, 10.78414 59.93566... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011865 NaN NaN yes Zoologisk museum UiO NaN limited POLYGON ((10.77116 59.92019, 10.77091 59.92019... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011866 NaN NaN yes Geologisk museum UiO NaN limited POLYGON ((10.7725 59.92019, 10.77214 59.92019,... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011867 NaN NaN NaN Lids hus UiO NaN limited POLYGON ((10.77252 59.91824, 10.77227 59.91822... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011868 NaN NaN NaN NaN NaN NaN NaN POLYGON ((10.77092 59.91871, 10.77091 59.91868... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

5 rows × 98 columns

Som du kan se, er det flere kolonner i buildings. Hver kolonne inneholder informasjon om en spesifikk tag som OpenStreetMap-bidragsytere har lagt til. Hver tag består av en nøkkel (kolonnenavnet) og verdier (for eksempel building=yes eller building=school). Les mer om tags og tagging praksis i OpenStreetMap wiki.

buildings.columns 
Index(['amenity', 'capacity', 'fee', 'name', 'operator', 'parking',
       'wheelchair', 'geometry', 'bicycle', 'foot', 'access', 'layer',
       'opening_hours', 'website', 'operator:type', 'image', 'tourism',
       'nodes', 'building', 'ref:bygningsnr', 'building:levels', 'heritage',
       'name:en', 'name:no', 'wikidata', 'wikimedia_commons', 'wikipedia',
       'description', 'old_name', 'old_name:en', 'check_date',
       'check_date:opening_hours', 'name:de', 'alt_name', 'architect',
       'deanery', 'denomination', 'diocese', 'height', 'image:0', 'note',
       'parish', 'phone', 'start_date', 'ele', 'roof:levels', 'religion',
       'toilets', 'roof:shape', 'office', 'leisure', 'owner', 'ref:anlegg',
       'sport', 'building:use', 'building:flats',
       'building:levels:underground', 'building:material', 'source', 'url',
       'level', 'email', 'internet_access', 'internet_access:fee',
       'contact:facebook', 'contact:instagram', 'outdoor_seating', 'bridge',
       'cuisine', 'historic', 'payment:credit_cards', 'payment:debit_cards',
       'shop', 'roof:orientation', 'diet:vegetarian', 'drive_through',
       'contact:email', 'note:en', 'ref:isil', 'source:opening_hours',
       'payment:contactless', 'indoor_seating', 'shelter_type', 'brand',
       'brand:wikidata', 'brand:wikipedia', 'theatre:genre', 'power', 'ref',
       'advertising', 'mapillary', 'name:signed', 'substation', 'man_made',
       'craft', 'ways', 'type', 'location'],
      dtype='object')

Interessepunkter#

Interessepunkt (POI) er et generisk konsept som beskriver punktlokasjoner som representerer steder av interesse. Siden osmnx.features_from_place() kan laste ned alle geometridata som finnes i OpenStreetMap-databasen, kan det også brukes til å laste ned alle typer POI-data.

I OpenStreetMap beskrives mange POI-er ved hjelp av amenity taggen. Vi kan for eksempel, hente alle restaurantlokasjoner ved å spørre om amenity=restaurant.

restaurants = osmnx.features_from_place(
    PLACE_NAME,
    {
        "amenity": "restaurant"
    }
)
len(restaurants) 
/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/osmnx/features.py:294: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.
  polygon = gdf_place["geometry"].unary_union
105

Som vi kan se, er det ganske mange restauranter i området.

La oss utforske hvilke attributter vi har i vår GeoDataFrame for restauranter:

# Tilgjengelige kolonner
restaurants.columns.values 
array(['amenity', 'check_date', 'cuisine', 'name', 'opening_hours',
       'outdoor_seating', 'smoking', 'website', 'wheelchair', 'geometry',
       'brand', 'diet:vegan', 'diet:vegetarian', 'email', 'phone',
       'takeaway', 'bar', 'internet_access', 'toilets:wheelchair',
       'opening_hours:signed', 'branch', 'contact:instagram', 'alt_name',
       'source', 'fax', 'start_date', 'indoor_seating', 'facebook',
       'twitter', 'check_date:opening_hours', 'internet_access:fee',
       'contact:website', 'delivery', 'brand:wikidata', 'brand:wikipedia',
       'level', 'reservation', 'capacity', 'drive_through', 'diet:meat',
       'diet:halal', 'diet:non-vegetarian', 'website:menu', 'name:en',
       'opening_hours:kitchen', 'delivery:partner', 'payment:coins',
       'payment:diners_club', 'payment:jcb', 'payment:mastercard',
       'payment:notes', 'payment:unionpay', 'payment:vipps',
       'payment:visa', 'brewery', 'diet:gluten_free',
       'payment:contactless', 'toilets', 'addr:housenumber',
       'addr:postcode', 'addr:street'], dtype=object)

Som du kan se, er det ganske mye (potensiell) informasjon relatert til fasilitetene. La oss velge ut kolonnene og undersøke dataene videre. Kan vi hente ut alle restauranters navn, adresse og åpningstider?

# Velg noen nyttige kolonner og skriv ut
interesting_columns = [
    "name",
    "opening_hours"
]

# Skriv ut kun valgte kolonner
restaurants[interesting_columns].head(10) 
name opening_hours
element_type osmid
node 26380802 Abelone Kjøkken & Bar Mo-Sa 10:00-01:00, Su 12:00-24:00
263710832 Villa Paradiso Grünerløkka Mo-We 08:00-21:00; Th-Fr 08:00-22:00; Sa 10:00...
292143398 Theka Mo-Fr 15:00-22:00; Sa-Su 12:00-22:00
292143401 Mucho Mas Tu-Fr 16:00-21:00; Sa 14:00-22:00; Su 14:00-21:00
292145479 Delicatessen NaN
310780987 Markveien Mat & Vinhus Tu-Sa 16:00-24:00
383735732 Le Benjamin NaN
816424311 Colonel Mustard Mo-Th, Su 11:00-01:00; Fr, Sa 11:00-03:00
838574104 Eldhuset NaN
838853684 Foccaceria Paradiso NaN

Tip

hvis noe av informasjonen trenger en oppdatering, gå til openstreetmap.org og rediger kildeinformasjonen!

Parker og grøntområder#

La oss prøve å hente alle offentlige parker på Grünerløkka. I OpenStreetMap, skal parker være tagget som leisure = park. Mindre grøntområder er noen ganger også tagget landuse = grass. Vi kan kombinere flere tags i en dataforespørsel.

parks = osmnx.features_from_place(
    PLACE_NAME,
    {
        "leisure": "park",
        "landuse": "grass",
    },
)
/opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/osmnx/features.py:294: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.
  polygon = gdf_place["geometry"].unary_union
parks.head()
geometry source nodes leisure name wikidata wikimedia_commons wikipedia name:ko image surface website landuse alt_name architect layer opening_hours ways type
element_type osmid
way 3235895 POLYGON ((10.76135 59.92438, 10.76137 59.92353... NaN [1387802128, 1387802112, 1387802111, 138780208... park Sofienbergparken Q12001727 Category:Sofienbergparken en:Sofienberg Park NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3236548 POLYGON ((10.75745 59.92331, 10.7575 59.92246,... NaN [1386653284, 1386653277, 1386598814, 138659881... park Olaf Ryes plass Q4993079 Category:Olaf Ryes plass, Oslo en:Olaf Ryes plass NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3236549 POLYGON ((10.75932 59.92572, 10.75931 59.92573... NaN [9196599875, 9196599873, 9196599850, 919659984... park Birkelunden Q4916412 NaN NaN 비르케룬덴 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
3610607 POLYGON ((10.75002 59.92791, 10.75002 59.92795... NaN [1424670751, 5221368582, 1282127386, 119390035... park NaN Q4587519 NaN no:Alexander Kiellands plass (Oslo) NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
4648330 POLYGON ((10.75736 59.93085, 10.7574 59.93093,... NaN [5169533336, 5169533335, 5169533334, 516953333... park NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
parks.plot(color="green") 
<Axes: >
../../_images/e4d78c0a25e8bc520cedc9104a7fc73f44cbe0612648197240855b964a67cb37.png

Plotting av dataene#

La oss lage et kart ut av gatene, bygningene, restaurantene og områdepolygonet.

import matplotlib
figure, ax = matplotlib.pyplot.subplots(figsize=(12,8))

# Plot avtrykket
area.plot(ax=ax, facecolor="black")

# Plot parkene
parks.plot(ax=ax, facecolor="green")

# Plot gate 'kanter'
edges.plot(ax=ax, linewidth=1, edgecolor="dimgray")

# Plot bygningene
buildings.plot(ax=ax, facecolor="silver", alpha=0.7)

# Plot restaurantene
restaurants.plot(ax=ax, color="yellow", alpha=0.7, markersize=10)
<Axes: >
../../_images/b74f760b48317ebbecbce49b102556be12c1805eba5970ac5172d63e7de54d6d.png

Kult! Nå har vi et kart der vi har plottet restaurantene, bygningene, gatene og grensene for det valgte området ‘Grünerløkka’ i Oslo. Og alt dette krever bare noen få linjer med kode. Ganske flott!

Sjekk din forståelse

Hent OpenStreetMap-data fra et annet område! Last ned disse elementene ved hjelp av OSMnx-funksjoner fra ditt interesseområde:

  • Utstrekning av området ved hjelp av geocode_to_gdf()

  • Gate-nettverk ved hjelp av graph_from_place(), og konverter til geo-data frame ved hjelp av graph_to_gdfs()

  • Bygningsavtrykk (og andre geometrier) ved hjelp av geometries_from_place() og passende tags.

Merk, jo større område du velger, jo lenger tid tar det å hente data fra API!

# Spesifiser navnet som brukes for å søke etter dataene. Sjekk at steds-
# navnet er gyldig fra https://nominatim.openstreetmap.org/ui/search.html
MY_PLACE = ""
# Hent gate-nettverk
# Hent bygningsavtrykk
# Plot dataene

Videre lesing#

For å analysere OpenStreetMap-data over store områder, er det ofte mer effektivt og meningsfullt å laste ned dataene på en gang, i stedet for separate spørringer til API. Slike datadumper fra OpenStreetMap er tilgjengelige i forskjellige filformater, OSM Protocolbuffer Binary Format (PBF) er en av dem. Datautdrag som dekker hele land og kontinenter er tilgjengelige, for eksempel, på download.geofabrik.de.

Pyrosm er en Python-pakke for lesing av OpenStreetMap-data fra PBF-filer til geopandas.GeoDataFrames. Pyrosm gjør det enkelt å hente vei-nettverk, bygninger, interessepunkter (POI), arealbruk, naturlige elementer, administrative grenser og mye mer - likt OSMnx, men tilpasset analyser av store områder. Mens OSMnx leser dataene fra Overpass API, leser pyrosm dataene fra en lokal PBF-fil.

Les mer om henting og bruk av pbf-filer som kilde for å analysere OpenStreetMap-data i Python fra pyrosm dokumentasjonen.