In [1]:
from datetime import datetime
print(f'Päivitetty {datetime.now()}')
Päivitetty 2021-08-15 12:30:40.730287

Matplotlib - osa 1

Yksinkertainen pylväskaavio

Jos teen kaavion suoraan dataframesta (df.plot...), niin käytän pandas-kirjastoon matplotlibin pohjalta rakennettua "viritelmää" kaavion teosta. Lue lisää https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.plot.html

Grafiikkaa varten tuon matplotlib.pyplot-kirjaston plt-nimisenä. Kirjastosta löytyy paljon funktioita grafiikan muotoiluun. Lue lisää https://matplotlib.org/stable/api/pyplot_summary.html

In [2]:
import pandas as pd
import matplotlib.pyplot as plt
In [3]:
df = pd.read_excel('http://taanila.fi/data1.xlsx')
df.head()
Out[3]:
nro sukup ikä perhe koulutus palveluv palkka johto työtov työymp palkkat työteht työterv lomaosa kuntosa hieroja
0 1 1 38 1 1.0 22.0 3587 3 3.0 3 3 3 NaN NaN NaN NaN
1 2 1 29 2 2.0 10.0 2963 1 5.0 2 1 3 NaN NaN NaN NaN
2 3 1 30 1 1.0 7.0 1989 3 4.0 1 1 3 1.0 NaN NaN NaN
3 4 1 36 2 1.0 14.0 2144 3 3.0 3 3 3 1.0 NaN NaN NaN
4 5 1 24 1 2.0 4.0 2183 2 3.0 2 1 2 1.0 NaN NaN NaN
In [4]:
# Lasken eri koulutuksen suorittaneiden lukumäärät
df1 = pd.crosstab(df['koulutus'], 'Lkm')
df1.index = ['Peruskoulu', '2. aste', 'Korkeakoulu', 'Ylempi korkeakoulu']
df1.columns.name = ''
df1
Out[4]:
Lkm
Peruskoulu 27
2. aste 30
Korkeakoulu 22
Ylempi korkeakoulu 2

Vaakapylväskaavio

Teen äsken luomastani dataframesta vaakapylväskaavion plot-toiminnolla. Plot-toiminnolla voin luoda eri kaaviolajeja, esimerkiksi pystypylväskaavion bar tai vaakapylväskaavion barh.

In [5]:
df1.plot.barh()
Out[5]:
<AxesSubplot:>

Kaavion tekstit

Mielestäni yhden arvosarjan kaavioissa selite on tarpeeton, joten piilotan sen legend-parametrilla.

Kaavion otsikoksi (title) annan 'Koulutusjakauma'.

Arvoakselin otsikoksi (xlabel) annan 'Lukumäärä'.

In [6]:
df1.plot.barh(legend = False)

plt.title('Koulutusjakauma')
plt.xlabel('Lukumäärä')
Out[6]:
Text(0.5, 0, 'Lukumäärä')

Hienosäätöä

Lisään x-akselin jakoviivojen mukaisen taustaviivoituksen (grid). Taustaviivoitus menee oletuksena pylväiden päälle, mutta asia korjaantuu parametrilla zorder = 2.

Häivytän y-akselin jakoviivat tick_params-toiminnolla.

Lisään pylväiden pituuksia vastaavat lukumäärät pylväiden viereen. Käytän tähän text-toimintoa, jolla voin lisätä kaavioon tekstejä:

  • Käytän apuna for-silmukkaa, jolla käyn läpi kaavion pylväät (patches-kokoelma) yksi kerrallaan.
  • Kaavioon pääsen käsiksi gca-toiminnolla (get current axes).
  • Vaakasuuntaisen pylvään pituuden saan get_width-toiminnolla.
  • Vaakasuuntaisen pylvään alareunan sijainnin saan get_y-toiminnolla.
  • Pylvään alareunan sijaintiin lisään puolet pylvään paksuudesta (get_height).
  • Pylvään viereen lisättävän lukumäärän muotoilen desimaalittomaksi ja sijoitan label-nimiseen muuttujaan.
  • Lisättävän merkkijonon sijainti määrittyy x:n ja y:n mukaan.
  • Parametri s tarkoittaa lisättävää merkkijonoa, joka tässä tapauksessa sisältää välilyönnin ja pylvään pituutta kuvaavan lukumäärän.
  • va tarkoittaa pystysuuntaista tasausta (vertical alignment).
In [7]:
df1.plot.barh(legend = False, zorder = 2)

plt.title('Koulutusjakauma')
plt.xlabel('Lukumäärä')

plt.grid(axis = 'x')
plt.tick_params(axis = 'y', length = 0)

for bar in plt.gca().patches:
    x = bar.get_width()
    y = bar.get_y() + bar.get_height() / 2
    label = '{:.0f}'.format(x)
    plt.text(x = x, y = y, s = ' ' + label, va = 'center')

Pystypylväskaavio

Pienin muutoksin voin toteuttaa edellisen pystypylväskaaviona.

  • Huomaa luokka-akselin otsikoiden 45 asteen kääntö (rotation).
  • Huomaa pylvään pituuksia vastaavien lukuarvojen siirto hieman ylöspäin (y = y + 0.3), koska muuten lukuarvot olisivat pylväissä kiinni.
  • ha tarkoittaa vaakasuuntaista tasausta (horizontal alignment).
  • Huomaa, että yläreunaan on lisätty hieman tilaa skaalamalla arvoakseli (ylim(0, 35)).
In [8]:
df1.plot.bar(legend = False, rot = 45, zorder = 2)

plt.title('Koulutusjakauma')
plt.ylabel('Lukumäärä')

plt.grid(axis = 'y')
plt.tick_params(axis = 'x', length = 0)
plt.ylim(0, 35)

for bar in plt.gca().patches:
    x = bar.get_x() + bar.get_width() / 2
    y = bar.get_height()
    label = '{:.0f}'.format(y)
    plt.text(x = x, y = y + 0.3, s = label, va = 'bottom', ha = 'center')

Prosenttien esittäminen

In [9]:
# Luon dataframen, jossa prosentit
df2 = pd.crosstab(df['koulutus'], 'Lkm')
df2['%'] = df2['Lkm'] / df2['Lkm'].sum() * 100
df2.index = ['Peruskoulu', '2. aste', 'Korkeakoulu', 'Ylempi korkeakoulu']
df2.columns.name = ''
df2
Out[9]:
Lkm %
Peruskoulu 27 33.333333
2. aste 30 37.037037
Korkeakoulu 22 27.160494
Ylempi korkeakoulu 2 2.469136
In [10]:
df2['%'].plot.barh(zorder = 2)

plt.title('Koulutusjakauma')

# Pienellä kikkailulla saan n-arvon akselin otsikkoon
plt.xlabel('%, n = ' + str(df2['Lkm'].sum()))

plt.grid(axis = 'x')
plt.tick_params(axis = 'y', length = 0)

for bar in plt.gca().patches:
    x = bar.get_width()
    y = bar.get_y() + bar.get_height() / 2
    label = '{:.0f} %'.format(x)
    plt.text(x = x, y = y, s = ' ' + label, va = 'center')

Kaavion tallennus

Kun tallennan kaavion savefig-toiminnolla, niin tarkkaan ottaen tallennan kuvion (figure), jonka sisällä kaavio on. Kuvioon pääsen käsiksi plt.gcf-toiminnolla (get current figure).

Ilman parametria bbox_inches = 'tight' osia kaavion reunoilta voi jäädä tallentumatta.

Tallennusmuoto määräytyy tiedostonimen tarkentimen (esim. png) perusteella. Mahdolliset tallennusmuodot selviävät komennolla plt.gcf().canvas.get_supported_filetypes()

In [11]:
df2['%'].plot.barh(zorder = 2)

plt.title('Koulutusjakauma')
plt.xlabel('%, n = ' + str(df2['Lkm'].sum()))

plt.grid(axis = 'x')
plt.tick_params(axis = 'y', length = 0)

for bar in plt.gca().patches:
    x = bar.get_width()
    y = bar.get_y() + bar.get_height() / 2
    label = '{:.0f} %'.format(x)
    plt.text(x = x, y = y, s = ' ' + label, va = 'center')

# Tallennus
plt.gcf().savefig('testi1.png', bbox_inches = 'tight')

Lisätietoa

Matplotlib - osa 2 käsittelee useamman arvosarjan pylväskaavioita: https://nbviewer.jupyter.org/github/taanila/kaaviot/blob/master/matplotlib2.ipynb