💻 Nettverksanalyse i Python#

Open In Colab

Å finne en korteste vei ved hjelp av et bestemt gate-nettverk er et vanlig GIS-problem som har mange praktiske applikasjoner. For eksempel, navigasjon, en av de ‘hverdagslige’ applikasjonene der rute-algoritmer brukes til å finne den optimale ruten mellom to eller flere punkter.

Selvfølgelig har Python-økosystemet produsert pakker som kan brukes til å gjennomføre nettverksanalyser, som for eksempel ruting. NetworkX-pakken gir forskjellige verktøy for å analysere nettverk, og implementerer flere forskjellige rutealgoritmer, som for eksempel Dijkstra’s eller A*-algoritmene. Begge er vanligvis brukt til å finne korteste veier langs transportnettverk.

For å kunne utføre nettverksanalyse, er det selvfølgelig nødvendig å ha et nettverk som brukes til analysene. OSMnx-pakken lar oss hente rutbare nettverk fra OpenStreetMap for forskjellige transportformer (gange, sykling og kjøring). OSMnx-pakken pakker også noen av NetworkX-funksjonene på en praktisk måte for bruk på OpenStreetMap-data.

I følgende avsnitt vil vi bruke OSMnx til å finne den korteste veien mellom to punkter basert på sykkelbare veier. Med bare de minste modifikasjonene, kan vi deretter gjenta analysen for det gangbare gatenettverket.

Få et rutbart nettverk#

For å laste ned OpenStreetMap-data som representerer gatenettverket, kan vi bruke dens graph_from_place()-funksjon. Som parametere forventer den et stedsnavn og, valgfritt, en nettverkstype.

import osmnx

PLACE_NAME = "Grunerløkka, Oslo, Norway"
graph = osmnx.graph_from_place(
    PLACE_NAME,
    network_type="bike"
)
figure, ax = osmnx.plot_graph(graph)
../../_images/1b9970e8972679ed60b28a7d479d94c23a934f3edeeda9c24f8df026ac09f1ce.png

Proft tips!

Noen ganger kan den korteste veien gå litt utenfor det definerte interesseområdet. For å ta hensyn til dette, kan vi hente nettverket for et litt større område enn Grünerløkka bydel, i tilfelle den korteste veien ikke er helt innenfor bydelsgrensene.

# Få området av interesse polygon
place_polygon = osmnx.geocode_to_gdf(PLACE_NAME)

# Re-projiser polygonet til en lokal projisert CRS (slik at CRS-enheten er meter)
place_polygon = place_polygon.to_crs("EPSG:25833")

# Buffer med 200 meter
place_polygon["geometry"] = place_polygon.buffer(200)

# Re-projiser polygonet tilbake til WGS84 (kreves av OSMnx)
place_polygon = place_polygon.to_crs("EPSG:4326")

# Hent nettverksgraf
graph = osmnx.graph_from_polygon(
    place_polygon.at[0, "geometry"],
    network_type="bike"
)

fig, ax = osmnx.plot_graph(graph)
../../_images/6530c0e0f6dd15213f32b9b47b193db18f2e94edf6fcbdced736e45f53042a0d.png

Dataoversikt#

Nå som vi har fått et komplett nettverksdiagram for den reisemåten vi spesifiserte (sykling), kan vi ta en nærmere titt på hvilke attributter som er tildelt noder og kanter i nettverket. Det er sannsynligvis lettest å først konvertere nettverket til en geodata-frame der vi deretter kan bruke verktøyene vi lærte i tidligere leksjoner.

For å konvertere et diagram til en geodata-frame, kan vi bruke osmnx.graph_to_gdfs(). Her kan vi gjøre bruk av funksjonens parametere nodes og edges for å velge om vi vil ha bare noder, bare kanter, eller begge (standard):

# Hent bare kanter fra grafen
edges = osmnx.graph_to_gdfs(graph, nodes=False, edges=True)
edges.head()
osmid oneway name highway maxspeed reversed length geometry lanes ref width tunnel junction bridge service access
u v key
79316 25335244 0 3236576 True Møllergata unclassified 30 False 108.269 LINESTRING (10.75135 59.91923, 10.75131 59.919... NaN NaN NaN NaN NaN NaN NaN NaN
6945985051 0 39825586 False Rosteds gate residential 30 True 81.266 LINESTRING (10.75135 59.91923, 10.75113 59.919... 2 NaN NaN NaN NaN NaN NaN NaN
1424670590 0 311012187 False Hausmanns gate secondary 30 True 31.268 LINESTRING (10.75135 59.91923, 10.75153 59.919... 2 NaN NaN NaN NaN NaN NaN NaN
8714388689 0 1044541319 True NaN cycleway NaN False 20.933 LINESTRING (10.75135 59.91923, 10.75152 59.919... NaN NaN NaN NaN NaN NaN NaN NaN
79317 25389708 0 4854886 False Wilses gate living_street 8 True 73.470 LINESTRING (10.75036 59.91792, 10.75029 59.917... NaN NaN NaN NaN NaN NaN NaN NaN

Den resulterende geodata-framen består av en lang liste med kolonner. De fleste av dem relaterer til OpenStreetMap-tags, og navnene deres er ganske selvforklarende. Kolonnene u og v beskriver topologisk forhold innen nettverket: de betegner start- og slutt-noden for hver kant.

Table 1 Kolonner i edges#

Kolonne

Beskrivelse

Datatype

bridge

Broelement

boolean

geometry

Geometri av elementet

Shapely.geometry

highway

Tag for veier (veitype)

str / list

lanes

Antall kjørefelt

int (or nan)

length

Lengden på elementet (meter)

float

maxspeed

Maksimal lovlige hastighetsbegrensning

int /list

name

Navn på (gata) elementet

str (or nan)

oneway

Enveisvei

boolean

osmid

Unike id-er for elementet

list

u

Startnoden for kanten

int

v

Sluttnoden for kanten

int

Hvilke typer gater består nettverket vårt av?

edges["highway"].value_counts()
highway
service                                 1683
residential                             1343
cycleway                                 745
secondary                                352
path                                     300
tertiary                                 283
unclassified                             221
primary                                  166
living_street                             65
pedestrian                                47
trunk                                     30
[path, service]                           30
[cycleway, residential]                   26
trunk_link                                21
[service, residential]                    20
[unclassified, service]                    4
[cycleway, service]                        4
[path, residential]                        4
[unclassified, residential]                3
[unclassified, cycleway]                   2
[pedestrian, service]                      2
[pedestrian, living_street, service]       2
[path, cycleway, service]                  2
[cycleway, living_street]                  2
[living_street, cycleway]                  2
[pedestrian, service, residential]         2
[pedestrian, cycleway]                     2
[trunk_link, trunk]                        1
Name: count, dtype: int64

Transformere til projisert referansesystem#

Nettverksdataens kartografiske referansesystem (CRS) er WGS84 (EPSG:4326), et geografisk referansesystem. Det betyr at avstander er registrert og uttrykt i grader. Dette er ikke praktisk for nettverksanalyser, som for eksempel å finne en korteste vei.

Igjen, OSMnx’s graf-objekter tilbyr ikke en metode for å transformere deres geodata, men OSMnx kommer med en separat funksjon: osmnx.project_graph() tar en inngangsgraf og en CRS som parametere, og returnerer en ny, transformert, graf. Hvis crs utelates, er transformasjonen standard til den mest egnede UTM-sonen lokalt.

# Transformere grafen til UTM
graph = osmnx.project_graph(graph) 

# Hent re-projiserte noder og kanter
nodes, edges = osmnx.graph_to_gdfs(graph)

nodes.crs
<Projected CRS: EPSG:32632>
Name: WGS 84 / UTM zone 32N
Axis Info [cartesian]:
- E[east]: Easting (metre)
- N[north]: Northing (metre)
Area of Use:
- name: Between 6°E and 12°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Austria. Cameroon. Denmark. Equatorial Guinea. France. Gabon. Germany. Italy. Libya. Liechtenstein. Monaco. Netherlands. Niger. Nigeria. Norway. Sao Tome and Principe. Svalbard. Sweden. Switzerland. Tunisia. Vatican City State.
- bounds: (6.0, 0.0, 12.0, 84.0)
Coordinate Operation:
- name: UTM zone 32N
- method: Transverse Mercator
Datum: World Geodetic System 1984 ensemble
- Ellipsoid: WGS 84
- Prime Meridian: Greenwich

Analysering av nettverksegenskaper#

Nå som vi har forberedt et rutbart nettverksdiagram, kan vi gå over til de mer analytiske funksjonene til OSMnx, og hente informasjon om nettverket. For å beregne grunnleggende nettverksegenskaper, bruk osmnx.basic_stats():

# Beregn nettverksstatistikk
osmnx.basic_stats(graph)
{'n': 2407,
 'm': 5364,
 'k_avg': 4.457000415454923,
 'edge_length_total': 303132.26999999996,
 'edge_length_avg': 56.512354586129746,
 'streets_per_node_avg': 2.5592023265475694,
 'streets_per_node_counts': {0: 0, 1: 658, 2: 21, 3: 1459, 4: 262, 5: 7},
 'streets_per_node_proportions': {0: 0.0,
  1: 0.2733693394266722,
  2: 0.008724553385957623,
  3: 0.6061487328624844,
  4: 0.10884918986289988,
  5: 0.0029081844619858743},
 'intersection_count': 1749,
 'street_length_total': 169802.93599999987,
 'street_segment_count': 3014,
 'street_length_avg': 56.33806768414063,
 'circuity_avg': 1.0651316280918361,
 'self_loop_proportion': 0.0026542800265428003}

Dette gir oss ennå ikke alle interessante egenskaper ved nettverket vårt, som OSMnx ikke automatisk tar hensyn til området som er dekket av nettverket. Vi kan gjøre det manuelt, ved, først, å avgrense nettverkets convex hull (fra en ‘unary’ union av alle funksjonene), og deretter, andre, beregne området av dette skallet.

convex_hull = edges.unary_union.convex_hull
convex_hull
/tmp/ipykernel_2307/2186647520.py:1: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.
  convex_hull = edges.unary_union.convex_hull
../../_images/756b05761f1ae990f86fe48bc8b611825f5853a590058827ffabc1125232430f.svg
stats = osmnx.basic_stats(graph, area=convex_hull.area)
stats
{'n': 2407,
 'm': 5364,
 'k_avg': 4.457000415454923,
 'edge_length_total': 303132.26999999996,
 'edge_length_avg': 56.512354586129746,
 'streets_per_node_avg': 2.5592023265475694,
 'streets_per_node_counts': {0: 0, 1: 658, 2: 21, 3: 1459, 4: 262, 5: 7},
 'streets_per_node_proportions': {0: 0.0,
  1: 0.2733693394266722,
  2: 0.008724553385957623,
  3: 0.6061487328624844,
  4: 0.10884918986289988,
  5: 0.0029081844619858743},
 'intersection_count': 1749,
 'street_length_total': 169802.93599999987,
 'street_segment_count': 3014,
 'street_length_avg': 56.33806768414063,
 'circuity_avg': 1.0651316280918361,
 'self_loop_proportion': 0.0026542800265428003,
 'node_density_km': 321.86957012617927,
 'intersection_density_km': 233.8802983592387,
 'edge_density_km': 40535.543596291194,
 'street_density_km': 22706.438727246816}

Som vi kan se, har vi nå mye informasjon om gatenettverket vårt som kan brukes til å forstå strukturen. Vi kan for eksempel se at gjennomsnittlig nodetetthet i nettverket vårt er 321.9 noder/km og at den totale kantlengden på nettverket vårt er mer enn 303 kilometer.


Korteste vei-analyse#

La oss nå beregne den korteste veien mellom to punkter ved hjelp av osmnx.shortest_path().

Opprinnelses- og destinasjonspunkter#

Først må vi spesifisere opprinnelses- og destinasjonspunkter for ruten vår. Hvis du er kjent med Grünerløkka-området, kan du spesifisere et egendefinert stedsnavn som en kildeposisjon. Eller, du kan følge med og velge disse punktene som opprinnelse og destinasjon i analysen:

Vi kunne finne ut koordinatene for disse stedene manuelt, og lage shapely.geometry.Points basert på koordinatene. Men hvis vi ville ha mer enn bare to punkter, ville det raskt bli et ork. I stedet kan vi bruke OSMnx til å geokode lokasjonene.

Husk å transformere opprinnelses- og destinasjonspunktene til samme referanse system som nettverksdataene.

origin = (
    osmnx.geocode_to_gdf("Trondheimsveien 110 C, Oslo, Norway", which_result=1)  # hent geolokasjon
    .to_crs(edges.crs)  # transformer til UTM
    .at[0, "geometry"]  # velg geometri av første rad
)

destination = (
    osmnx.geocode_to_gdf("Grünerhagen")
    .to_crs(edges.crs)
    .at[0, "geometry"]
    .centroid
)

Vi har nå shapely.geometry.Points som representerer opprinnelses- og destinasjon plasseringene for nettverksanalysen vår. I en neste trinn, må vi finne disse punktene på det rutbare nettverket før den endelige rutingen.

Nærmeste node#

For å rute på nettverket, må vi først finne et startpunkt og sluttpunkt som er en del av nettverket. Bruk osmnx.distance.nearest_nodes() for å returnere den nærmeste nodens ID:

origin_node_id = osmnx.nearest_nodes(graph, origin.x, origin.y)
origin_node_id
832779407
destination_node_id = osmnx.nearest_nodes(graph, destination.x, destination.y)
destination_node_id
16193897

Ruting#

Nå er vi klare for ruting og for å finne den korteste veien mellom opprinnelses- og målplasseringene. Vi vil bruke osmnx.shortest_path().

Funksjonen tar tre obligatoriske parametere: en graf, en opprinnelsesnod-id, og en destinasjonsnod-id, og to valgfrie parametere: weight kan settes til å vurdere en annen kostnadsimpedans enn lengden på ruten, og cpus kontrollerer parallell beregning av mange ruter.

# Finn den korteste veien mellom opprinnelse og destinasjon
route = osmnx.shortest_path(graph, origin_node_id, destination_node_id)
route
[832779407,
 2481252143,
 841832182,
 12534265,
 79607,
 330463916,
 79605,
 106138,
 5580791789,
 10973871838,
 4618464230,
 12534258,
 4618464227,
 1387802061,
 1426810245,
 106168,
 106141,
 106169,
 106171,
 837970612,
 10178369286,
 16193897]

Som et resultat får vi en liste over alle nodene som er langs den korteste veien.

Vi kunne hente plasseringene til disse nodene fra nodes GeoDataFramen og lage en LineString-presentasjon av punktene, men heldigvis, OSMnx kan gjøre det for oss og vi kan plotte korteste vei ved hjelp av plot_graph_route()-funksjonen:

# Plot den korteste veien
fig, ax = osmnx.plot_graph_route(graph, route)
../../_images/5ac535a8920ed4b52f5dd0c4b59068ae55b1fee51ff61c4ac587473967820766.png

Flott! Nå har vi den korteste veien mellom opprinnelses- og målplasseringene våre. Å kunne analysere korteste veier mellom steder kan være verdifull informasjon for mange applikasjoner. Her analyserte vi bare de korteste veiene basert på avstand, men ganske ofte er det mer nyttig å finne de optimale rutene mellom steder basert på reisetiden. Her, for eksempel kunne vi beregne tiden det tar å krysse hvert veisegment ved å dele lengden på veisegmentet med fartsgrensen og beregne de optimale rutene ved å ta hensyn til fartsgrensene også som kan endre resultatet spesielt på lengre turer enn her.

Lagre korteste veier til disk#

Ganske ofte må du lagre ruten til en fil for videre analyse og visualiseringsformål, eller i det minste ha den som et GeoDataFrame-objekt i Python. La oss derfor fortsette litt til og se hvordan vi kan lage ruten til en linjestreng og lagre den korteste veigeometrien og relaterte attributter i en geopackage-fil.

Først må vi få nodene som tilhører den korteste veien:

# Få nodene langs den korteste veien
route_nodes = nodes.loc[route]
route_nodes
y x highway street_count lon lat ref geometry
osmid
832779407 6.644504e+06 599257.916763 NaN 3 10.775706 59.926021 NaN POINT (599257.917 6644503.528)
2481252143 6.644431e+06 599258.760391 NaN 4 10.775686 59.925368 NaN POINT (599258.76 6644430.804)
841832182 6.644408e+06 599241.069524 NaN 3 10.775359 59.925170 NaN POINT (599241.07 6644408.291)
12534265 6.644354e+06 599198.726208 NaN 3 10.774576 59.924697 NaN POINT (599198.726 6644354.409)
79607 6.644248e+06 599114.681136 NaN 3 10.773023 59.923766 NaN POINT (599114.681 6644248.447)
330463916 6.644186e+06 599065.091608 NaN 3 10.772106 59.923213 NaN POINT (599065.092 6644185.549)
79605 6.644070e+06 598990.718616 traffic_signals 4 10.770721 59.922193 NaN POINT (598990.719 6644069.855)
106138 6.643971e+06 598936.431294 NaN 4 10.769704 59.921318 NaN POINT (598936.431 6643970.977)
5580791789 6.643978e+06 598905.840513 NaN 3 10.769160 59.921385 NaN POINT (598905.841 6643977.636)
10973871838 6.643998e+06 598808.771092 NaN 3 10.767434 59.921596 NaN POINT (598808.771 6643998.474)
4618464230 6.644015e+06 598727.331337 NaN 3 10.765987 59.921766 NaN POINT (598727.331 6644015.331)
12534258 6.644040e+06 598608.730564 NaN 3 10.763878 59.922015 NaN POINT (598608.731 6644039.89)
4618464227 6.644047e+06 598574.797489 NaN 3 10.763275 59.922086 NaN POINT (598574.797 6644046.918)
1387802061 6.644070e+06 598458.146066 traffic_signals 4 10.761200 59.922323 NaN POINT (598458.146 6644070.197)
1426810245 6.643977e+06 598459.143340 NaN 3 10.761173 59.921483 NaN POINT (598459.143 6643976.587)
106168 6.643929e+06 598460.276750 traffic_signals 3 10.761171 59.921059 NaN POINT (598460.277 6643929.364)
106141 6.643929e+06 598355.529450 NaN 4 10.759298 59.921076 NaN POINT (598355.529 6643928.517)
106169 6.643927e+06 598248.893522 NaN 4 10.757391 59.921090 NaN POINT (598248.894 6643927.178)
106171 6.643926e+06 598156.956908 NaN 3 10.755747 59.921100 NaN POINT (598156.957 6643925.874)
837970612 6.643926e+06 598115.499469 NaN 3 10.755006 59.921111 NaN POINT (598115.499 6643925.978)
10178369286 6.643944e+06 598123.855354 NaN 4 10.755164 59.921270 NaN POINT (598123.855 6643943.949)
16193897 6.643977e+06 598146.833170 NaN 3 10.755590 59.921562 NaN POINT (598146.833 6643977.092)

Som vi kan se, har vi nå alle nodene som var en del av den korteste veien som en GeoDataFrame.

Nå kan vi lage en LineString ut av punktgeometriene til nodene:

import shapely.geometry

# Lag en geometri for den korteste veien
route_line = shapely.geometry.LineString(
    list(route_nodes.geometry.values)
)
route_line
../../_images/ebfc96910c809b7319a2e76d26303e973796a2a33f653c4d07d913af5adf77dd.svg

Nå har vi ruten som en LineString-geometri.

La oss lage en GeoDataFrame ut av den med litt nyttig informasjon om ruten vår, for eksempel en liste over osm-idene som er en del av ruten og lengden på ruten.

import geopandas

route_geom = geopandas.GeoDataFrame(
    {
        "geometry": [route_line],
        "osm_nodes": [route],
    },
    crs=edges.crs
)

# Beregn rute-lengden
route_geom["length_m"] = route_geom.length

route_geom.head()
geometry osm_nodes length_m
0 LINESTRING (599257.917 6644503.528, 599258.76 ... [832779407, 2481252143, 841832182, 12534265, 7... 1669.84227

Nå har vi en GeoDataFrame som vi kan lagre til disk. La oss fortsatt bekrefte at alt er ok ved å plotte ruten vår på toppen av gatenettverket og noen bygninger, og plot også opprinnelses- og målpunktene på toppen av kartet vårt.

Last ned bygninger:

bygninger = osmnx.features_from_place(
    PLACE_NAME,
    {
        "building" : True
    }
).to_crs(edges.crs)

La oss nå plotte ruten og gatenettverkselementene for å bekrefte at alt er som det skal:

import contextily
import matplotlib.pyplot

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

# Plot kanter og noder
edges.plot(ax=ax, linewidth=0.75, color='gray')
nodes.plot(ax=ax, markersize=2, color='gray')

# Legg til bygninger
ax = bygninger.plot(ax=ax, facecolor='lightgray', alpha=0.7)

# Legg til ruten
ax = route_geom.plot(ax=ax, linewidth=2, linestyle='--', color='red')

# Legg til bakgrunnskart
contextily.add_basemap(ax, crs=bygninger.crs, source=contextily.providers.CartoDB.Positron)
../../_images/75eeb7e50b00cbfd5407deb1156871377ed858e4005dddf23e7a08fe50c98314.png

Flott, alt ser ut til å være i orden! Som du kan se, har vi nå full kontroll over alle elementene i kartet vårt, og vi kan bruke alle estetiske egenskaper som matplotlib gir for å endre hvordan kartet vårt vil se ut. Nå er vi nesten klare til å lagre dataene våre på disk.

Forbered data for lagring til fil#

Dataene inneholder visse datatyper (som list) som bør konverteres til tegnstrenger før du lagrer dataene til fil (et alternativ ville være å droppe ugyldige kolonner).

edges.head()
osmid oneway name highway maxspeed reversed length geometry lanes tunnel junction ref width bridge service access
u v key
79316 25335244 0 3236576 True Møllergata unclassified 30 False 108.269 LINESTRING (597916.667 6643710.788, 597914.829... NaN NaN NaN NaN NaN NaN NaN NaN
6945985051 0 39825586 False Rosteds gate residential 30 True 81.266 LINESTRING (597916.667 6643710.788, 597904.519... 2 NaN NaN NaN NaN NaN NaN NaN
1424670590 0 311012187 False Hausmanns gate secondary 30 True 31.268 LINESTRING (597916.667 6643710.788, 597926.961... 2 NaN NaN NaN NaN NaN NaN NaN
8714388689 0 1044541319 True NaN cycleway NaN False 20.933 LINESTRING (597916.667 6643710.788, 597926.099... NaN NaN NaN NaN NaN NaN NaN NaN
25335244 79317 0 3236576 True Møllergata unclassified 30 False 47.137 LINESTRING (597882.414 6643608.012, 597877.956... NaN NaN NaN NaN NaN NaN NaN NaN
# Kolonner med ugyldige verdier
problematiske_kolonner = [
    "osmid",
    "lanes",
    "name",
    "highway",
    "width",
    "maxspeed",
    "reversed",
    "junction",
    "bridge",
    "tunnel",
    "access",
    "service",
]

#  konverter valgte kolonner til strengformat
edges[problematiske_kolonner] = edges[problematiske_kolonner].to_string()
route_geom["osm_nodes"] = route_geom["osm_nodes"].astype(str)
print(edges.dtypes)
osmid         object
oneway          bool
name          object
highway       object
maxspeed      object
reversed      object
length       float64
geometry    geometry
lanes         object
tunnel        object
junction      object
ref           object
width         object
bridge        object
service       object
access        object
dtype: object

Nå kan vi se at de fleste attributtene er av typen object som ganske ofte (som vår her) refererer til en datatypetype.

Lagre dataene:#

import pathlib
NOTEBOOK_PATH = pathlib.Path().resolve()
DATA_MAPPE = NOTEBOOK_PATH / "data"

Avhengig av hvor stort interesseområde vi har definert, så kan denne filen bli veldig stor, derfor lagrer vi bare ruten i denne omgang:

# Lagre ett lag etter et annet
output_gpkg = DATA_MAPPE / "osm_data"/ "OSM_Grunerlokka.gpkg"
#edges = edges[["osmid","name","highway","maxspeed","length","geometry","width"]]
#edges.to_file(output_gpkg, layer="streets")
route_geom.to_file(output_gpkg, layer="route")
#nodes.to_file(output_gpkg, layer="nodes")
#bygninger[['geometry', 'name', 'addr:street']].to_file(output_gpkg, layer="buildings")
display(bygninger.describe())
display(bygninger)
amenity capacity fee name operator parking wheelchair geometry bicycle foot ... ref advertising mapillary name:signed substation man_made craft ways type location
count 33 5 6 80 13 1 15 3682 1 1 ... 1 1 1 1 1 4 1 16 16 3
unique 15 4 2 78 7 1 3 3682 1 1 ... 1 1 1 1 1 2 1 16 1 1
top place_of_worship 500 yes Chokoladefabrikken Kirkelig fellesråd i Oslo multi-storey limited POLYGON ((599664.3266955729 6645572.2019701665... yes yes ... 1735 board 293938462404822 no minor_distribution silo yes [133363272, 112236630] multipolygon indoor
freq 10 2 3 2 5 1 6 1 1 1 ... 1 1 1 1 1 3 1 1 16 3

4 rows × 98 columns

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 ((599664.327 6645572.202, 599700.091 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011865 NaN NaN yes Zoologisk museum UiO NaN limited POLYGON ((599021.107 6643847.082, 599007.188 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011866 NaN NaN yes Geologisk museum UiO NaN limited POLYGON ((599096.358 6643849.709, 599075.963 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011867 NaN NaN NaN Lids hus UiO NaN limited POLYGON ((599103.169 6643631.899, 599088.901 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
27011868 NaN NaN NaN NaN NaN NaN NaN POLYGON ((599012.323 6643681.946, 599011.947 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
relation 13803840 NaN NaN NaN NaN NaN NaN NaN POLYGON ((597928.252 6644296.877, 597927.103 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN [1031362635, 112898983] multipolygon NaN
13803841 NaN NaN NaN NaN NaN NaN NaN POLYGON ((598151.179 6643166.871, 598163.554 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN [112236619, 1031362641] multipolygon NaN
15885246 NaN NaN NaN NaN NaN NaN NaN POLYGON ((600151.857 6643897.11, 600142.549 66... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN [486231544, 1174948320, 1174948319] multipolygon NaN
15896730 NaN NaN NaN NaN NaN NaN NaN POLYGON ((600162.955 6645115.376, 600163.099 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN [1024970009, 1175254280] multipolygon NaN
15896731 NaN NaN NaN NaN NaN NaN NaN POLYGON ((600118.937 6645122.072, 600155.178 6... NaN NaN ... NaN NaN NaN NaN NaN NaN NaN [1175254283, 64605831, 1175254281] multipolygon NaN

3682 rows × 98 columns

Flott, nå har vi lagret alle dataene som ble brukt til å produsere kartene i en geopakke.

Videre lesing#

Her lærte vi hvordan man løser en enkel ruteoppgave mellom opprinnelses- og målpunkt. Hva om vi har hundrevis eller tusenvis av opprinnelser? Dette er tilfelle hvis du vil utforske reiseavstandene til en spesifikk plassering over hele byen, for eksempel når du analyserer tilgjengeligheten av jobber og tjenester (som i reisetidsmatrisedataene som ble brukt i tidligere seksjoner).

Sjekk ut pyrosm-dokumentasjonen om arbeid med grafer for mer avanserte eksempler på nettverksanalyse i python. For eksempel er pandana et raskt og effektivt python-bibliotek for å lage aggregerte nettverksanalyser på kort tid over store nettverk, og pyrosm kan brukes til å forberede inngangsdataene for en slik analyse.