9 Teikning með Matplotlib¶
9.1 Inngangur¶
Matplotlib er teiknipakki fyrir Python sem er byggður á tölvugrafík í Matlab-kerfinu. Með Matplotlib er hægt að teikna (eða birta, sýna) myndir (images), hæðarlínur (countours), punktarit (scatter plot), línurit og gröf (line plots) og þrívíðar upplýstar myndir. Pakkinn er þannig að framendinn (frontend) eða skilgreining teikningarinnar er aðskilinn frá bakendanum (backend) sem birtir hana. Þannig er hægt að skrifa forrit sem býr til teikningu, og svo er hægt að sýna teikninguna inni í Jupyter-bók, sem sjálfstæðan glugga á skjá, á vef, í pdf-skjali, í Latex-skjali, á prentara o.s.frv. án þess að breyta teikniforritinu sjálfu. Auk þess er hægt að fá alls kyns viðbætur við Matlplotlib, t.d. fyrir kortagerð, þrívíða teikningu, samskipti við Pandas og samskipti við Excel, svo fáeinar séu nefndar. Af þessum viðbótum er er líklega helstan að telja pakkann Seaborn, sem tengist Pandas nánum böndum. Markmið höfunda Seaborn er að teikna sem „nútímalegust“ tölfræðileg gröf á sem sjálfvirkastan máta.
Eftirfarandi mynd sýnir dæmi um myndir teiknaðar með Matplotlib.
Athugasemd: Skipun eða fall
Hér verður talað um teikniskipanir þegar strangt tiltekið ætti kannski frekar að tala um teikniföll: scatter-fallið, plot-fallið o.s.frv. Einn kostur við að segja frekar skipun er að það veldur síður ruglingi þegar verið er að teikna föll.
9.2 Einfaldar myndir¶
9.2.1 Undirbúningur teikningar¶
Venjulegasta notkun Matplotlib er að nota undirpakkann pyplot og í Matplotlib notendahandbókinni er mælt með að flytja hann inn sem plt, svo það er fyrir vikið alsiða. Teiknaðar myndir birtast sjálfkrafa inni í bókinni, neðan við forritsreitinn. Hér er kafli sem hægt er að setja fremst í vinnubók sem teiknar, þar sem bætt hefur verið við skipunum sem láta rúðunet teiknast undir öðrum teiknuðum hlutum, breyta sjálfgefinni stærð myndar, og koma í veg fyrir að fyrirsagnir og ásamerkingar yfirskrifi hver aðra.
# Frumstilling teikningar
import matplotlib.pyplot as plt
plt.rc('axes', axisbelow=True)
plt.rc('figure', figsize=(8,4)) # (6,4) er sjálfgefið
plt.rc('figure.constrained_layout', use=True) # forðast skörun myndhluta
9.2.2 Punktarit og línurit¶
Ein mikilvægasta notkunin á Matplotlib er að teikna myndir af talnalistum, sem geta hvort sem er verið venjulegir Python listar eða NumPy vigrar eins og við kynnumst í 10. kafla.
Hér er forrit sem teiknar punktana \((x,y)\) þar sem \(y = \sqrt x\)
fyrir \(x = 0, 1, 2, 3, 4, 5\) og tengir þá með beinum línustrikum.
Skipunin plt.figure
býr til nýja mynd og tilgreinir breidd hennar og hæð,
scatter-skipunin teiknar punktana sjálfa með flatarmál u.þ.b. 40 ferpunkta
(punktur ≈ 1/3 mm) og plot-skipunin teiknar strikin á milli þeirra. Að lokum
teiknar grid rúðunet. Í skipuninni
er hægt að tilgreina lit punkta, sbr.
fyrra sýnidæmið í kafla 9.3.2 og þeir geta
líka verið hver með sínum lit sbr. dæmið um besta plan í kafla
13.5.
from math import sqrt
x = list(range(6))
y = [sqrt(xi) for xi in x]
plt.figure(figsize=(7,3))
plt.scatter(x,y,s=50)
plt.plot(x,y)
plt.grid(True)
Athugasemd: Einingar í figsize
Stærð myndarinnar er gefin í tommum og (6,4) er sjálfgefið. Myndin er sköluð niður í ca. 2/3 þegar hún birtist á venjulegum fartölvuskjá, en er (a.m.k. nokkurnvegin) ósköluð ef bókin er prentuð sem pdf.
Æfing:
Afritið skipanirnar að ofan inn í vinnubók og keyrið. Prófið að breyta:
fjölda punkta
stærð myndarinnar
stærð punktanna (aftasti stikinn í
scatter
)sleppa rúðunetinu
9.2.3 Súlurit¶
Hér er búið til súlurit (histogram) af normaldreifðum slembigögnum. Stikinn
bins
gefur fjölda súlna og range
gefur svæðið á x-ás sem súluritið nær
yfir. Góð regla er að láta súlurnar mætast í rúnnuðum (round) tölum t.d.
heilum eða hálfum (hér mætast þær í hálfum tölum). Kallið gauss(mu,sigma)
skilar slemitölu úr normaldreifingu með meðaltal mu og staðalfrávik sigma
(Gauss-dreifing er annað nafn á normaldreifingu)
import matplotlib.pyplot as plt
from random import gauss
x = [gauss(0,1) for i in range(500)]
plt.hist(x, bins=12, range=(-3,3))
plt.xlabel('x')
plt.ylabel('fjöldi gilda á hverju bili (af 500)')
plt.show()
Skipunin hist
reiknar sjálf hæð hverrar súlu en það er líka hægt að láta
hæð súlnanna koma úr lista eða vigri með því að nota skipunina bar
. Um það
er sýnt dæmi í næsta kafla.
Æfing:
Prófið skipanirnar að ofan. Prófið að fækka og fjölga punktum. Prófið líka að nota 6 súlur (það þarf að breyta bæði bins og range).
Athugasemd: Kyrrstæðar og lifandi myndir
Myndirnar í þessum 9. kafla eru kyrrstæðar (static) en Matplotlib getur líka búið til bæði hreyfimyndir (animated) og lifandi (interactive) myndir með stýrihlutum (widgets), t.d. hnöppum og sleðum, hvort sem er í úttaksglugga í vinnubók eða í sérstökum sjálfstæðum myndaglugga (amk. með JupyterLab). Þá má láta myndina hreyfast eins og í teiknimynd eða breytast með músastýringu. Lítið dæmi um lifandi mynd með stýrisleða er í kafla 16.2.4 og dæmi um hreyfimynd er í kafla 16.3.2.
Skipunin plt.show()
er valkvæð þegar teiknað er beint í vinnubók, en hana
þarf ef sérstakur gluggi er opnaður. Notkun hennar hefur þann viðbótarkost að
losna við aukaupplýsingar sem sumar teikniskipanir skrifa ef þær eru aftast í
vinnubók.
9.3 Teikningar af gögnum í skrám¶
9.3.1 Innlestur talnagagna í dálkum¶
Algengt er að maður vilji teikna upplýsingar sem eru geymdar í skrám, og oft eru
það dálkar í skránni sem þarf að teikna. Í sýnidæminu í kafla 8.2.4 var sýnt hvernig hægt er að lesa dálka í slíkri skrá inn í lista af strengjum. Ef dálkarnir geyma tölur þarf beita float
-fallinu á innihaldið. Til að lesa inn skrá xy.txt
með tveimur talnadálkum má nota:
x = []
y = []
with open("xy.txt") as f:
for lína in f:
(xs, xy) = lína.split()
x.append(float(xs))
y.append(float(xy))
plt.plot(x,y)
Ef skráin er á vefnum þarf í fyrsta lagi að nota urlopen
í stað open
og svo þarf líka að nota decode()
á línuna, eins og gert var í kafla 8.2.4. Annar möguleiki er svo að nota NumPy sem er á dagskrá í 10. kafla.
9.3.2 Dæmi um teikningu talnagagna¶
Hér eru tvö sýnidæmi um teikningu gagna sem eru fengin úr gagnaskrám. Það fyrra teiknar punktarit (scatter plot) og það síðara súlurit.
Sýnidæmi: Eðlisþyngd og bræðslumark
Í kafla 8.3.4 var skoðuð skrá með bræðslumarki og eðlisþyngd fjögurra málma (sbr. líka verkefni 17. Hér er forrit sem teiknar punktarit af skránni.
from urllib.request import urlopen
import matplotlib.pyplot as plt
with urlopen("https://cs.hi.is/python/malmar.txt") as f:
next(f) # sleppa fyrirsögnum
nafn = []
eðlisþ = []
bræðslum = []
for lína in f:
(n,e,b) = lína.decode().split()
nafn.append(n)
eðlisþ.append(float(e))
bræðslum.append(float(b))
plt.scatter(eðlisþ, bræðslum, s=40, color='Crimson')
plt.grid(True)
plt.xlim(0,20)
plt.ylim(800,1800)
for (x,y,n) in zip(eðlisþ, bræðslum, nafn):
plt.text(x, y, n + " ", fontsize=16, color='DarkBlue',
ha="right", va="center")
plt.xlabel('Eðlisþyngd g/ml')
plt.ylabel('Bræðslumark °C')
plt.show()
Hér fylgir myndin sem birtist, og tækifærið hefur verið notað til að sýna
hvernig hægt er að skrifa texta inn á mynd með plt.text
(sjá töflu
9.2)
Sýnidæmi: Kosningasúlurit
Hér er dæmi sem teiknar súlurit af kosningaúrslitunum 2021. Þessi úrslit eru aftur á dagskrá í verkefnum verkefni 16) og 24; í því síðara er fínna súlurit búið til.
from urllib.request import urlopen
import matplotlib.pyplot as plt
with urlopen("https://cs.hi.is/python/kosningar-2021.txt") as f:
next(f)
listi = []
atkvæði = []
for lína in f:
(l, a, þs) = lína.decode().split()
listi.append(l)
atkvæði.append(float(a))
x = range(len(listi))
plt.figure(dpi=90)
plt.bar(x, atkvæði, color="tomato")
plt.xticks(x, listi);
plt.ylabel('Atkvæði')
plt.title('Úrslit alþingiskosninga 2021')
plt.show()
Hér er verður x listinn [0,1,2…10] (það voru 11 framboðslistar). Hér er listi yfir liti. Forritið teiknar svo þessa mynd:
Æfing: Súlurit af einkunnum
Notið hist
til að teikna súlurit af einkunnunum í skránni https://cs.hi.is/python/einkunn.txt.
9.4 Töflur yfir Matplotlib-skipanir¶
Hér eru töflur yfir helstu teikniskipanirnar, stýristika og stýriskipanir. Aftast í seinni dálki taflanna er víða í svigum tilvísun í kafla sem útskýrir notkun viðkomandi skipunar eða stika. Eins og framar í þessum fyrirlestrarnótum eru töflurnar fyrst og fremst hugsaður til uppflettingar og ekki til að læra utanað.
Fyrst er tafla yfir aðal teikniskipanirnar og svo sérstök tafla bara um hvernig hægt er að setja texta inn á myndir með text-skipuninni.
|
|
|
Teiknar punkta í tilgreindum x- og y-hnitum (9.2.2) |
|
|
|
Teiknar súlurit yfir tíðni – hæð súlna fæst með talningu (9.2.3 og 9.5.3) |
|
Teiknar súlurit með gefinni súluhæð (9.3.2) |
|
Vistar teikningu í png-skrá ( |
|
Skrifar texta inn á mynd (sjá töflu ref:%s<text-fallið>) (9.3.1) |
|
Birtir mynd (þarf ekki ef teiknað er í glugga í vinnubók (9.2.3) |
|
skrifar texta aftan við punkt (x,y) |
|
– með n punkta letri (9.3.1) |
|
– neðan við punkt (vertical alignment) (9.3.1) |
|
– ofan við punkt (eða center/baseline) |
|
– aftan við punkt (horizontal algn) |
|
– með punkt í miðjum texta (eða right) |
Teikniskipanirnar bjóða svo upp á fjölda stýristika (control parameters) til að stjórna lit teikninga, breidd súlna, leturstærð, merkingum ása o.s.frv. Auk stýristikanna eru svo notaðar ýmsar hjálpar- eða stýriskipanir til breyta mörkum ása, bæta við skýringartextum, rúðuneti o.fl. Næstu töflur gefar yfirlit yfir helstu stýristika og stýriskipanir.
|
Litur línurits (grafs) eða súlurits. Má skammstafa r, g, b, y, w, k |
|
gagnsæi, 0 alveg gagnsætt, 1 alveg ógagnsætt (sjálfgefið) |
|
Breidd línu í línuriti eða súluramma í súluriti. Eining punktar |
|
Línutegund, getur t.d. verið |
|
Merki fyrir punkta í plot. Algengur marker er |
|
Stærð markers í |
|
Litur á rönd súlna eða merkja. Ein tegund súlurita notar |
|
|
|
|
|
ytri mörk súlurits (gott að velja bins í samræmi við range) (k. 9.2.3 og 9.5.3) |
|
„relative width“ (sjálfgefið 1.0) (9.5.3) |
|
Merki fyrir punkta, sjá marker í töflu 9.3 |
|
stærð punkta, flatarmál í ferpunktum (punktur ≈ 1/3 mm). Má vera vigur og |
|
litur (allir punktar í sama lit), sjá color í töflunni að ofan (9.3.2) |
|
vigur af litum (hver punktur í sínum lit). Má vera vigur af
tölum og þá litast |
|
gagnsæi, sjá töfluna að ofan |
|
litur á rönd punkta |
Athugasemd: Um punktastærð
Sjálfgefin punktastærð er 36 = 6^2, sem gefur sömu stærð og o
-merki í
plot-skipun með markersize 6 (sem er sjálfgefna stærðin í plot). Ath. að það
er ekki stutt að skrifa size
í stað s
Athugasemd: Um litaskala :class: athugid
Þessar fyrirlestrarnótur skauta framhjá umfjöllun um litaskala, en um þá er fjallað allítarlega í Viðauka A4 í *Valin efni í
- stærðfræði og reiknifræði*. Um litaskala er líka fjallað í 4. kafla í
|
stillir neðri og efri mörk x-áss (kafli 9.5) |
|
Stillir neðri og efri mörk y-áss (9.5) |
|
Stillir neðri og efri mörk "litaáss" innan litaskala sem er |
|
setur fyrirsögn á teikningu (9.3.2) |
|
|
|
|
|
setur merkingar á tilgreindar staðsetningar á x-ás |
|
setur merkingar á tilgreindar staðsetningar á y-ás |
|
setur bæði staðsetningar og merkingar (eins fyrir y-ás) |
|
lætur merkingar á x-ás verða A, B og C (eins fyrir y-ás) |
|
stillir strikin við ásamerkingarnar (l og w mælt |
|
teiknar rúðunet (nota má |
|
fjarlægir ramma utanum teikningu (9.6.2) |
|
bætir við lóðréttri línu (sjálfgefið er x = 0) (9.6.2 og 9.6.4) |
|
bætir við láréttri línu (sjálfgefið er y = 0) (9.6.2 og 9.6.4) |
|
bætir við kassa með skýringum á línum/skatter-punktum |
Loks er hér hlekkur á yfirlit yfir allar Matplotlib-skipanir.
9.5 Þrjú dæmi um teikningar¶
Til frekari glöggvunar eru hér þrjú viðbótardæmi og nokkrar æfingar.
9.5.1 Dæmi um plot¶
from math import sqrt x = range(5) y = [sqrt(t) for t in x] plt.figure(figsize=(4, 1.8), dpi=90) # dpi=72 sjálfgefið plt.plot(x, y, lw=3, ls=':', c='r', marker='o', ms=8) plt.xlabel('x') plt.ylabel('y = √x')Æfing: Stikar í plot
Prófið þessar skipanir. Prófið að breyta:
dpi (dots-per-inch; myndin stækkar)
ls (line style, prófið
'-'
)lw (line width)
c (color prófið t.d.
'b'
)marker (prófið
'+'
og'x'
)ms (marker size)
9.5.2 Dæmi um legend¶
from math import pi, sin from random import random t = [k*2*pi/20 for k in range(21)] s = [sin(x) for x in t] y = [random() for k in range(21)] plt.figure(figsize=(5,2)) plt.plot(t, s, label='sin(x)') plt.plot(t, y, label='slembitölur') plt.grid(True) plt.legend();Æfing: Legend
Prófið þessar skipanir. Prófið svo að bæta við cos(x) með tilheyrandi label. Prófið líka að fjölga punktunum (það þarf að breyta bæði 20 og 21 í stærri tölur).
9.5.3 Dæmi um hist¶
from random import gauss x = [gauss(0,1) for i in range(500)] plt.figure(figsize = (6,3)) plt.hist(x, bins=12, range=(-3,3), rwidth=0.8, color='c', ec='k'); plt.xlabel('x-gildi'); plt.ylabel('fjöldi'); plt.grid(True, axis='y')Æfing: Súlurit
Prófið skipanirnar og einhverjar breytingar á þeim. Stikunum er lýst í töflu 9.3
9.6 Teikning af gröfum falla¶
Við byrjum þennan kafla á æfingu, sem snýst bæði um efni undanfarandi kafla og þessa. Lesendur eru hvattir til að spreyta sig á henni áður en þeir lesa áfram því hér á eftir koma svör við ýmsum atriðum í henni.
Til að teikna graf er byrjað á að núllstilla með því að keyra:
import matplotlib.pyplot as plt
plt.rc('axes', axisbelow=True)
def linspace(a,b):
return [a + (b-a)*i/200 for i in range(201)]
Með linspace(a,b)
fæst listi með 200 jafnt dreifðum þétt liggjandi
\(x\)-gildum á bilinu frá a til b, og svo reiknum við fallsgildin \(y =
f(x)\) í öllum þessum \(x\)-um og nálgum graf fallsins með því að teikna
línustrik sem tengja alla punktana.
9.6.1 Einfalt graf¶
Við getum teiknað graf sínus-fallsins á bilinu \([0, 4\pi]\) með:
- Forrit:
from math import pi, sin, cos, exp x = linspace(0, 4*pi) y = [sin(xi) for xi in x] plt.plot(x, y);- Úttak:
9.6.2 Fínna graf¶
Hægt er að bæta ýmsu við forritsbúinn í kafla 9.6.1. Byrjum á að afrita hann og endurbætum hann svo:
teygjum á grafinu (breikkum myndina) með skipuninni
plt.figure(figsize=(12,4))
(á undan plot).Svo má bæta við rúðuneti með
plt.grid
Það er hægt að teikna x- og y-ása með
plt.axhline
ogplt.axvline
. Notið með stikac='k'
til að fá svarta ása.Við getum látið x-ásinn ná t.d. frá -0.2 til \(4\pi\) með
plt.xlim([-0.2, 4*pi])
.Það má fjarlægja rammann með
plt.box(False)
Síðasta tötsið fæst með
plt.tick_params(length=0)
- Forrit (sjá úttak í svari við lið 3):
plt.figure(figsize=(15,4)) plt.grid(True) plt.axvline(c='k') plt.axhline(c='k') plt.box(False) x = linspace(0, 4*pi) y = [sin(xi) for xi in x] plt.plot(x, y) plt.xlim([-0.2, 4*pi]) plt.tick_params(length=0);
9.6.4 Graf vísisfallsins exp(x)¶
Teiknum nú nýja mynd með \(y = e^x\) á bilinu \([-5, 2]\).
- Forrit:
(a,b) = (-5,2) x = linspace(a,b) plt.figure(figsize=(9,6)); plt.grid(True) plt.axvline(c='k'); plt.axhline(c='k') plt.box(False) plt.plot(x, [exp(t) for t in x]) plt.xlim([a,b]) plt.tick_params(length=0)- Úttak:
Æfing: Fallateikning.
Æfið ykkur í að teikna föll með því að nota hugmyndir í þessum kafla. Teiknið t.d. gröf eftirfarandi falla og prófið ykkur áfram í hverju tilviki til að finna hæfilegt bil á x-ás svo helstu eiginleikar fallanna komi fram. Þið getið byrjað á að afrita forritið hér næst á undan.
\(x\sin x\)
\(e^{-2x+1}\)