Interaktiiviset kartat#

Edellisessä esimerkissä piirsimme kartan, joka antoi nopeasti hyvän kokonaiskuvan maailman hiilidioksidipäästöistä. Kartalla valtiot oli väritetty siten, että mitä tummempi väri, sitä suuremmat päästöt valtiolla oli. Mitä, jos haluaisimmekin tietää tarkalleen tietyn valtion päästöt?

Tässä harjoituksessa tarkoituksena on tehdä samantyylinen kartta, mutta lisätään siihen interaktiivisia ominaisuuksia. Tehdään sellainen kartta, jossa näytölle ilmestyy alueen tietoja, kun hiirellä liikutaan alueen päälle. Käytetään vaihtelun vuoksi eri esimerkkidataa kuin viime kerralla. Piirretään tällä kertaa Suomen kunnat ja niissä asuvien eläkeläisten osuus väestöstä.

Suomen karttaa varten tarvittavat kuntarajat saadaan ladattua Maanmittauslaitoksen tiedostopalvelusta. Tiedosto löytyy datakansiosta nimellä ”SuomenKuntajako_2020_250k.mid”.

Eläkeläisten osuus kuntien väestöstä on myös avointa dataa ja saatavilla Tilastokeskuksen palvelusta. Tämäkin tiedosto on valmiiksi ladattu ja hieman siistitty paremmin tätä esimerkkiä sopivaksi. Se löytyy datakansiosta nimellä ”elakelaisten_osuus_2018_kuntajako_2020.csv”. Nimi viittaa siihen, että kyseessä on eläkeläisten osuus väestöstä vuodelta 2018, mutta vuoden 2020 kuntajaolla.

Datan lukeminen#

Aloitetaan harjoitus samoin, kuten aiemmin, eli lataamalla datatiedostot ja yhdistämällä ne yhdeksi datasetiksi. Käytämme jälleen pandas ja geopandas -kirjastoja tähän.

import pandas as pd
import geopandas as gpd

# Luetaan kuntarajat sisältävä tiedosto geopandasin read_file()-funktiolla
# encoding='latin1' varmistaa, että ääkköset tulevat oikein
cities = gpd.read_file('../data/SuomenKuntajako_2020_250k.mid', encoding='latin1')

# Katsotaan, mitä tiedosto sisältää
cities.head()
gml_id natcode namefin nameswe landarea freshwarea seawarea totalarea geometry
0 1601100430 691 Reisjärvi Reisjärvi 474.60 28.74 0.00 503.34 MULTIPOLYGON (((418701.443 7055306.898, 418485...
1 1601100624 853 Turku Åbo 245.66 3.47 57.22 306.35 POLYGON ((249073.975 6725828.546, 248775.530 6...
2 1601100110 318 Kökar Kökar 63.57 0.43 2101.02 2165.02 POLYGON ((172798.744 6674623.732, 173415.386 6...
3 1601100668 859 Tyrnävä Tyrnävä 491.82 3.04 0.00 494.86 POLYGON ((440372.786 7197460.702, 440107.431 7...
4 1601100521 747 Siikainen Siikainen 463.29 28.02 0.00 491.31 POLYGON ((236801.933 6882124.138, 236897.467 6...
# Luetaan kuntien eläkeläistiedot sisältävä tiedosto pandasin read_csv()-funktiolla
pensioners = pd.read_csv('../data/elakelaisten_osuus_2018_kuntajako_2020.csv')

# Katsotaan, mitä tiedosto sisältää
pensioners.head()
alue elakelaisten_osuus
0 Akaa 27.3
1 Alajärvi 33.0
2 Alavieska 28.7
3 Alavus 32.7
4 Asikkala 37.2
# Yhdistetään tiedot kaupunkien nimien perusteella
data = cities.merge(pensioners, left_on='namefin', right_on='alue')

# Katsotaan tulos
data.head()
gml_id natcode namefin nameswe landarea freshwarea seawarea totalarea geometry alue elakelaisten_osuus
0 1601100430 691 Reisjärvi Reisjärvi 474.60 28.74 0.00 503.34 MULTIPOLYGON (((418701.443 7055306.898, 418485... Reisjärvi 32.0
1 1601100624 853 Turku Åbo 245.66 3.47 57.22 306.35 POLYGON ((249073.975 6725828.546, 248775.530 6... Turku 24.2
2 1601100110 318 Kökar Kökar 63.57 0.43 2101.02 2165.02 POLYGON ((172798.744 6674623.732, 173415.386 6... Kökar 36.4
3 1601100668 859 Tyrnävä Tyrnävä 491.82 3.04 0.00 494.86 POLYGON ((440372.786 7197460.702, 440107.431 7... Tyrnävä 16.2
4 1601100521 747 Siikainen Siikainen 463.29 28.02 0.00 491.31 POLYGON ((236801.933 6882124.138, 236897.467 6... Siikainen 41.9

Kartan piirtäminen Bokeh-kirjaston avulla#

Hienoa, datan lukeminen onnistui! Piirretään seuraavaksi tiedot näytölle Bokeh-kirjaston avulla. Kuvan piirtämiseksi tarvitsemme seuraavia funktioita tai luokkia:

  • figure(): Alustetaan kuva. Voidaan antaa esim. kuvan otsikko tässä vaiheessa ”title”-parametrilla.

  • GeoJSONDataSource: Muutetaan datamme GeoJSONDataSource-muotoiseksi, jotta sen piirtäminen bokeh:lla onnistuu helposti.

  • LinearColorMapper: Lisätään värit karttaan.

  • Greens: Käytetään vihreää värikarttaa.

  • output_notebook(): Tämän funktion avulla ḱuva piirtyy koodisolun alapuolelle (jos show-funktiota on myös käytetty). Muussa tapauksessa kuva avautuisi uuteen välilehteen.

  • show(): Tällä käskyllä näytetään kuva.

# Tuodaan tarvittavat funktiot. Huom. ne pitää tuoda oikeista kirjastoista.
from bokeh.plotting import figure
from bokeh.models import GeoJSONDataSource, LinearColorMapper
from bokeh.palettes import Greens
from bokeh.io import output_notebook, show

# Alustetaan kuva ja asetetaan otsikko. Tallennetaan kuva muuttujaan "fig".
fig = figure(title="Eläkeläisten osuus väestöstä vuonna 2018 vuoden 2020 kuntajaolla (%). ")

# Muutetaan datamme ensin json-tyyppiseksi ja sen jälkeen GeoJSONDataSource:ksi
data_json = data.to_json()
geosource = GeoJSONDataSource(geojson = data_json)

# Valitaan 6 eri väriä Greens-värikartasta. Lopussa oleva [::-1] kääntää värikartan toisinpäin, toisin sanoen tummemmat
# ilmaisevat silloin suurempaa lukuarvoa.
palette = Greens[6][::-1]

# Valitaan värien minimiarvoksi datamme pienin arvo ja maksimiarvoksi datamme suurin arvo.
color_mapper = LinearColorMapper(palette = palette,
                                 low = data['elakelaisten_osuus'].min(),
                                 high = data['elakelaisten_osuus'].max())

# Piirretään kuntarajat kartalle. GeoJSONDataSourcessa datamme 'geometry'-sarake on muuttunut 'xs'- ja 'ys'-sarakkeiksi.
# Piirretään siis ne käyttäen lähteenä määrittämäämme "geosource"-muuttujaa.
# Lisätään vielä värit kartalle määrittelemällä "fill_color", jolle pitää kertoa sekä datasarakkeen nimi sekä
# käyttämämme värikartta.
fig.patches('xs','ys',
            source = geosource,
            fill_color={'field':'elakelaisten_osuus','transform': color_mapper})

# Asetetaan tulos näkymään solun alapuolella.
output_notebook()

# Näytetään kartta
show(fig)
Loading BokehJS ...

Noniin, nyt saimme piirrettyä kartan käyttämällä bokeh-kirjastoa! Huomataan, että Itä-Suomessa on paljon tummanvihreitä alueita, joissa eläkeläisten osuus väestöstä on suuri verrattuna esimerkiksi pääkaupunkiseutuun. (Huom. rannikolla olevien kuntien rajat näyttävät oudoilta, koska myös merialueet on huomioitu kartassa)

Kartassa on valmiiksi hyödyllisiä työkaluja, joiden avulla voimme zoomata ja liikutella karttaa tai halutessamme vaikkapa tallentaa sen. Tässä on jo hieman interaktiivisuutta, mutta tavoitteenamme oli tehdä sellainen kartta, jossa näytölle ilmestyy alueen tietoja, kun hiirellä liikutaan alueen päälle. Tätä varten tarvitsemme vielä HoverTool-työkalun bokeh-kirjastosta.

from bokeh.models import HoverTool

# Tehdään uusi HoverTool-olio ja tallennetaan se muuttujaan "hover".
hover = HoverTool()

# Lisätään hover-oliolle "tooltips"-tietoja, eli nämä tiedot näkyvät, kun hiiri liikutetaan alueen päälle.
# @-merkin jälkeen tuleva sana kertoo, mistä datan sarakkeesta tiedot haetaan.
hover.tooltips = [('Kaupunki', '@alue'),('Eläkeläisten osuus (%)','@elakelaisten_osuus')]

# Lisätään hover kuvan työkaluihin
fig.add_tools(hover)

# Näytetään kuva.
output_notebook()
show(fig)
Loading BokehJS ...

Loistavaa! Voimme nyt poimia kartastamme kuntia hiirellä ja nähdä, mikä on eläkeläisten osuus väestöstä kyseisissä kunnissa! Eikä siihen mennyt montaakaan koodiriviä.

Kokeile itse hakea jokin muu kuntakohtainen data, piirtää se kartalle ja lisätä vielä interaktiivinen ”hover”-työkalu. Voit myös yrittää etsiä jotain muuta, kuten valtiokohtaista dataa tai jotakin muuta, kunhan löydät sopivan tiedoston, joka sisältää alueiden rajat.