💻 Interaktive kart#

Open In Colab

Online kart har vært interaktive i lang tid: nesten alle online kart tillater å zoome inn og ut, å panorere i kartet, og å velge kartfunksjoner, eller ellers forespørre informasjon om dem.

Interaktivt innhold i nettsider, som online kart, er typisk implementert ved hjelp av JavaScript/ECMAScript, et skriptspråk opprinnelig rettet mot nettsider, primært, men brukt for mange andre applikasjoner.

I det åpne kildekoderiket finnes det en rekke forskjellige JavaScript biblioteker for interaktiv webkartografi, inkludert Leaflet, som vi vil bruke i denne leksjonen, og OpenLayers.

Ta det rolig, vi vil ikke måtte skrive en eneste linje med JavaScript; dette er et Python kurs, tross alt. Heller, vi vil dra nytte av Folium Python-pakken: den hjelper med å lage interaktive Leaflet-kart fra data lagret i geopandas.GeoDataFrames.

Folium ressurser

Finn mer informasjon om mulighetene til Folium-pakken på dens offisielle nettsider:

Opprette et enkelt interaktivt webkart#

Vi vil starte med å lage et enkelt interaktivt webkart som ikke inneholder noe annet enn et bakgrunnskart. Dette er for at vi skal bli vant til hvordan Folium’s syntaks fungerer, og hvilke trinn vi må ta.

Vi lager et folium.Map-objekt, og spesifiserer rundt hvilken location det skal sentreres og på hvilket utgangs-zoomnivå (~0-20) kartet skal vises. Ved å sette control_scale til True, får vi Folium til å vise en skala også.

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

# Vi vil eksportere HTML-sider i løpet av denne leksjonen,
# la oss også forberede en utdatamappe for dem:
HTML_MAPPE = NOTEBOOK_PATH / "html"
HTML_MAPPE.mkdir(exist_ok=True)
import folium

interactive_map = folium.Map(
    location=(59.665, 10.776),
    zoom_start=10,
    control_scale=True
)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Lagre det resulterende kartet#

For å lagre dette kartet til en HTML-fil som kan åpnes i en hvilken som helst nettleser, bruk folium.Map.save():

interactive_map.save(HTML_MAPPE / "base-map.html")

Endre bakgrunnskartet#

Hvis du vil bruke et annet bakgrunnslag enn standard OpenStreetMap, aksepterer folium.Map parameteret tiles, som kan referere til en av de innebygde kartleverandørene.

Mens vi er i gang, la oss også variere senterlokasjonen og zoomnivået på kartet:

interactive_map = folium.Map(
    location=(59.668, 10.763),
    zoom_start=15,
    tiles="cartodbpositron"
)
interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Eller vi kan peke på en egendefinert tiles URL:

interactive_map = folium.Map(
    location=(59.668, 10.763),
    zoom_start=15,
    tiles="https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}",
    attr="Google maps",
)
interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Legg til en punktmarkør#

For å legge til en enkelt markør til et Folium kart, opprett en folium.Marker. Gi en folium.Icon som parameter icon for å påvirke hvordan markøren er stylet, og sett tooltip for å vise en tekst når musepekeren beveger seg over den.

interactive_map = folium.Map(
    location=(59.668, 10.763),
    zoom_start=15
)

hippocampus = folium.Marker(
    location=(59.668, 10.763),
    tooltip="Hippocampus",
    icon=folium.Icon(color="green", icon="ok-sign")
)
hippocampus.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Legg til et lag med punkter#

Folium støtter også å legge til hele lag, for eksempel, som geopandas.GeoDataFrames. Folium implementerer Leaflet’s geoJSON lag i sin folium.features.GeoJson klasse. Vi kan initialisere en slik klasse (og lag) med en geodataframe, og legge den til et kart. I eksempelet nedenfor bruker vi adresser.gpkg datasettet vi laget tidligere.

import geopandas

adresser = geopandas.read_file(DATA_MAPPE / "oslo_adresser" / "adresser.geojson")
adresser.head()
fid address id adr geometry
0 1 25, Statsråd Mathiesens vei, Linderud, Bjerke,... 100 Statsråd Mathiesens vei 25, 0594 OSLO POINT (10.83648 59.94104)
1 2 15, Slimeveien, Bjørnholt, Søndre Nordstrand, ... 101 Slimeveien 15, 1275 OSLO POINT (10.83432 59.83557)
2 3 Sognsveien 80, Konvallveien, Sogn, Nordre Aker... 102 Sognsveien 80, 0855 OSLO POINT (10.72956 59.95011)
3 4 5, Ullevålsveien, Hammersborg, St. Hanshaugen,... 103 Ullevålsveien 5, 0165 OSLO POINT (10.74356 59.91863)
4 5 30B, Nydalsveien, Nydalen, Nordre Aker, Oslo, ... 104 Nydalsveien 30b, 0484 OSLO POINT (10.76402 59.9503)
interactive_map = folium.Map(
    location=(59.914, 10.744),
    zoom_start=11
)

adresser_lag = folium.features.GeoJson(
    adresser
)
adresser_lag.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Vi kan også legge til et popup-vindu på kartet vårt som viser adressene på interessepunktet ved å klikke:

interactive_map = folium.Map(
    location=(59.914, 10.744),
    zoom_start=11
)

popup = folium.GeoJsonPopup(
    fields=["adr"],
    aliases=["Adresse"],
    localize=True,
    labels=True,
    style="background-color: yellow;",
)

adresser_lag = folium.features.GeoJson(
    adresser,
    popup=popup
)
adresser_lag.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Legg til et polygonlag#

I den følgende delen skal vi gjenbesøke et annet datasett som vi har jobbet med før: Befolkningsrutenettet for Oslo fra SSB.

rutenett = geopandas.read_file(
    DATA_MAPPE
    / "ssb_rutenett"
    / "befolkning_250m_2023_oslo.shp"
)
rutenett.head()
fid ru250m pop_tot geometry
0 1.0 2.263751e+13 14 POLYGON ((264000 6643000, 263750 6643000, 2637...
1 2.0 2.264001e+13 177 POLYGON ((264250 6643000, 264000 6643000, 2640...
2 3.0 2.264251e+13 169 POLYGON ((264500 6643000, 264250 6643000, 2642...
3 4.0 2.264501e+13 261 POLYGON ((264750 6643000, 264500 6643000, 2645...
4 5.0 2.264751e+13 106 POLYGON ((265000 6643000, 264750 6643000, 2647...

Indekskolonne for koroplettkart

Vi vil bruke folium.Choropleth for å vise befolkningsrutenettet. Koroplettkart er mer enn bare polygon-geometrier, som kan vises som et folium.features.GeoJson-lag, akkurat som vi brukte for adressene, ovenfor. Snarere tar klassen seg av kategorisering av data, legger til en legende, og noen flere små oppgaver for å raskt lage temakart.

Klassen forventer et inputdatasett som har en eksplisitt, str-type, indeks kolonne, da den behandler den geografiske inputen og den tematiske inputen som separate datasett som må samles (se også, nedenfor, hvordan vi spesifiserer både geo_data og data).

En god tilnærming for å lage en slik kolonne er å kopiere dataframens indeks til en ny kolonne, for eksempel id.

rutenett["id"] = rutenett.index.astype(str)

Nå kan vi lage koroplettlaget for polygoner, og legge det til et kartobjekt. På grunn av den litt komplekse arkitekturen til Folium, må vi gi en rekke parametere:

  • geo_data og data, geografiske og tematiske inputdatasett, henholdsvis. Kan være den samme geopandas.GeoDataFrameen.

  • columns: en tuple av navnene på relevante kolonner i data: en unik indekskolonne, og kolonnen som inneholder tematiske data

  • key_on: hvilken kolonne i geo_data som skal brukes for å koble data (dette er i utgangspunktet identisk med columns, bortsett fra at det bare er den første verdien)

interactive_map = folium.Map(
    location=(59.914, 10.744),
    zoom_start=11
)

rutenett1 = folium.Choropleth(
    geo_data=rutenett,
    data=rutenett,
    columns=("id", "pop_tot"),
    key_on="feature.id"
)
rutenett1.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

For å gjøre kartet litt finere, la oss fortsatt be om flere kategorier (bins), endre fargeområdet (ved hjelp av fill_color), sett linjetykkelsen til null, og legge til en tittel til legenden:

interactive_map = folium.Map(
    location=(59.914, 10.744),
    zoom_start=11
)

rutenett1 = folium.Choropleth(
    geo_data=rutenett,
    data=rutenett,
    columns=("id", "pop_tot"),
    key_on="feature.id",

    bins=9,
    fill_color="YlOrRd",
    line_weight=0,
    legend_name="Befolkning, 2023",

    highlight=True
)
rutenett1.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Legg til en tooltip til et koroplettkart#

I et slikt interaktivt kart, ville det være fint å vise verdien av hvert rutenett-polygon når du holder musepekeren over det. Folium støtter ikke dette out-of-the-box, men med et enkel triks kan vi utvide funksjonaliteten: Vi legger til et gjennomsiktig polygonlag ved hjelp av en ‘grunnleggende’ folium.features.GeoJson, og konfigurerer den til å vise tooltips.

Vi kan beholde map som vi laget ovenfor, og bare legge til et annet lag på det..

# folium GeoJson lag forventer en stylingfunksjon,
# som mottar hver av kartets funksjon og returnerer
# en individuell stil. Den kan imidlertid også returnere en
# statisk stil:
def style_function(feature):
    return {
        "color": "transparent",
        "fillColor": "transparent"
    }


# Mer komplekse tooltips kan lages ved hjelp av
# `folium.features.GeoJsonTooltip` klassen. Nedenfor bruker vi
# dens mest grunnleggende funksjoner: `fields` spesifiserer hvilke kolonner
# som skal vises, `aliases` hvordan de skal være merket.
tooltip = folium.features.GeoJsonTooltip(
    fields=("pop_tot",),
    aliases=("Befolkning:",)
)


tooltip_layer = folium.features.GeoJson(
    rutenett,
    style_function=style_function,
    tooltip=tooltip
)
tooltip_layer.add_to(interactive_map)

interactive_map
Make this Notebook Trusted to load map: File -> Trust Notebook

Python-pakker for interaktive (web) kart

Folium er bare en av mange pakker som gir en enkel måte å lage interaktive kart ved hjelp av data lagret i (geo-)pandas dataframer. Andre interessante biblioteker inkluderer: