2D-s ábrák

Legtöbbször a legjobb ábrák a legegyszerűbb ábrák! Az alábbiakban áttekintünk néhány egyszerű ábrakészítési módot, amelyek segítségével a leggyakrabban előforduló ábrázolási problémáinkat orvosolhatjuk. Fontos megjegyezni, hogy ábrát a matplotlib segítségével több hasonló módon is elő lehet állítani. Az alábbiakban törekedünk a lehető legegyszerűbb módszer bemutatására. Fontos azt is megjegyezni, hogy az alábbi példákban előforduló függvényopciók (kulcsszavas argumentumok) lehetséges értékeinek csak egy szűk halmazára térünk ki. A megfelelő paraméterek lehetséges értékei után vagy a matplotlib mintapéldái vagy a megfelelő függvények, pl. plot,hist,pcolor, contour és contourf docstring-jében érdemes kutatni!

In [1]:
#a már megszokott betöltési parancs
%pylab inline 
Populating the interactive namespace from numpy and matplotlib

Egyszerű függvény és adat ábrázolás

Sok esetben a feladat egy ismert adathalmaz, netán egy analitikus függvény ábrázolása. Ha analitikus fügvénnyel van dolgunk, akkor az ábrázoláshoz először legyártunk kiértékelési pontokat, ezután ezekben a pontokban kiértékeljük az adott függvényt. Az alábbi példában a $\sin(x)$ függvényt fogjuk kiértékelni a $[-\pi,\pi]$ intervallumban 25 pontban.

In [2]:
x=linspace(-pi,pi,25);
y=sin(x);

Az ábrázolás (ahogy azt már korábban is láttuk) a plot paranccsal történik.

In [3]:
plot(x,y)
Out[3]:
[<matplotlib.lines.Line2D at 0x7f35e86fc2b0>]

Vizsgáljunk meg néhány kulcsszavas argumentumot, amely segítségével a plot parancs kimenetelét tudjuk változtatni. A color kulcsszó az ábrázolt adat színeit változtatja meg. Ez az ábra tartalmazza a matplotlib-ben néven nevezett színek nevét. Változtassuk meg a fenti ábrában a görbe színét pirosra!

In [4]:
plot(x,sin(x),color='red')
Out[4]:
[<matplotlib.lines.Line2D at 0x7f35e5f14160>]

A linewidth kulcsszó segítségével a vonalszélességen változtathatunk.

In [5]:
plot(x,sin(x),linewidth=3)
Out[5]:
[<matplotlib.lines.Line2D at 0x7f35e5f09978>]

A linestyle kulcscszó a vonalstílust állítja be. Ez lehet megnevezett kulcsszó (mint az alábbi példában) vagy szimbólum is.

In [6]:
plot(x,sin(x),linestyle='dashed') # szaggatott vonal (angolul: dashed line)
Out[6]:
[<matplotlib.lines.Line2D at 0x7f35e5e7d0f0>]

Ha üres stringet adunk vonalstílusnak, és a marker kulcsszót használjuk, akkor az ábrán csak pontok jelennek meg. Így például ábrázolhatunk olyan adatokat, amik nincsenek szépen sorbarendezve.

In [7]:
plot(x,sin(x),linestyle='',marker='o')
Out[7]:
[<matplotlib.lines.Line2D at 0x7f35e5de7780>]

Ha a linestyle és a marker kulcsszavakat egyszerre alkalmazzuk, akkor a markereket a kért vonalstílussal köti össze a matplotlib.

In [8]:
plot(x,sin(x),linestyle='dashed',marker='s')
Out[8]:
[<matplotlib.lines.Line2D at 0x7f35e5d52dd8>]

Természetesen ahogy már megszoktuk, kulcsszavas argumentumokból egyszerre többet is beadhatunk (vajon mit jelenthetnek azok a kulcsszavak, amiről eddig nem volt szó?):

In [9]:
jellemzok=dict(color='green', linestyle='dashed', marker='o', markerfacecolor='blue',
               markeredgecolor='red',markeredgewidth=2, markersize=12 )

plot(x, sin(x), **jellemzok)
Out[9]:
[<matplotlib.lines.Line2D at 0x7f35e5d45748>]

Az ábra tengelyeinek tartományát az xlim(), illetve ylim() függvények segítségével tudjuk beállítani, melyeket a plot függvény után hívunk meg:

In [12]:
plot(x,sin(x))
xlim(-pi,pi);

A plot függvény számos más kulcsszavas argumentummal rendelkezik. A docstring-jében mindezek jól le vannak dokumentálva!

In [21]:
?plot

Ha két (vagy több) plot parancsot adunk ki egymás után, akkor az ábrán egyszerre két (vagy több) függvény is megjelenik.

In [15]:
plot(x,sin(x))
plot(x,cos(x))
Out[15]:
[<matplotlib.lines.Line2D at 0x7f35e5a9e240>]

Speciális esete ennek az, amikor az egyik plot csak egyetlen pontot tartalmaz. Ezzel a módszerrel jelölhetünk érdekes pontokat a függvény görbéjén.

In [16]:
plot(x,sin(x))
plot(1,sin(1),'o')
Out[16]:
[<matplotlib.lines.Line2D at 0x7f35e5ba7128>]

Ha több függvényt ábrázolunk, akkor a label kulcsszó és a legend() függvény segítségével tudjuk egyszerűen jelölni, hogy melyik görbe melyik függvényt ábrázolja.

In [17]:
plot(x,sin(x),label='sin(x)',color='red',linestyle='-',linewidth=3)
plot(x,cos(x),label='cos(x)',color='blue',linestyle='--',linewidth=3)
legend()
Out[17]:
<matplotlib.legend.Legend at 0x7f35e5c6c518>

Az xlabel() és az ylabel() függvények segítségével tengelyfeliratokat készíthetünk.

In [25]:
plot(x,sin(x))
xlabel(r'ido',fontsize=20)
ylabel('kiteres',fontsize=20)
Out[25]:
<matplotlib.text.Text at 0x7f35e59995f8>

Az xticks() és yticks() függvények a a tengelybeosztások formázásáért felelősek. Segítségükkel tudjuk a beosztásokat saját igényeink szerint beállítani. Ezen függvények dockstringjeit is érdemes megvizsgálni!

In [28]:
plot(x,sin(x))
xticks([-pi,-pi/2,0,pi/2,pi],[r'$-\pi$',r'$-\pi/2$',r'$0$',r'$\pi/2$',r'$\pi$'],fontsize=20);
yticks(linspace(-1,1,9)); 
#Vajon mi változott a fenti ábrához képest ?

Végül nézzünk meg egy példát, amely a fent tanult trükköket egyszerre alkalmazva egy publikációs minőségű ábrát készít.

In [29]:
plot(x,sin(x),label='sin(x)',color='red',linestyle='-',linewidth=3)
plot(x,cos(x),label='cos(x)',color='blue',linestyle='--',linewidth=3)
xticks([-pi,-pi/2,0,pi/2,pi],[r'$-\pi$',r'$-\pi/2$',r'$0$',r'$\pi/2$',r'$\pi$'],fontsize=20);
yticks(linspace(-1,1,3),fontsize=20);
xlabel('ido',fontsize=20)
ylabel('kiteres',fontsize=20)
legend(loc='upper left',fontsize=20)
xlim(-pi,pi)
grid(True) #Vajon ez a függvény mit csinál ?

Fontos megjegyezni, hogy a vonal- és pontábrázolások kulcsszavas paraméterezését sok másik függvény is megörökölte. Így például 3D-s ábra készítésnél is hasonlóan használhatóak mint itt. Továbbá a tengelyfeliratozás és -beosztás kezelése is hasonlóan általánosan használható, nem csak a plot() paranccsal egyetemben!

Mérési adatok ábrázolása hibával - errorbar

Láttuk, hogy a plot függvény segítségével akár mérési adatpontokat is tudunk ábrázolni. Sokszor azonban a mérések során a mérési hiba is rendelkezésünkre áll! Vizsgáljunk meg erre egy példát! Az alábbiakban a történelmi napfoltadatok ábrázolásán keresztül igazi mérési adatokat fogunk ábrázolni. Az adatok a data könyvtárban található SN_m_tot_V2.0.txt file-ban vannak. Ahhoz hogy az adatok a rendelkezésünkre álljanak, először be kell tölteni a file tartalmát. Ezt legegyszerűbben a numpy modul loadtxt függvénye segítségével tehetjük meg. Ez a függvény egyszerűen strukturált adatfileokat olvas be egy array-be.

In [30]:
dat=loadtxt('data/SN_m_tot_V2.0.txt'); # a napfolt adatok betöltése.

A fenti parancs tehát a dat tömbbe beolvasta a file-ban található adatokat. A file 3. oszlopa tartalmazza a megfigyelés idejét években mérve, a 4. oszlop pedig a napfoltok számát. Ábrázoljuk az utolsó 100 pontot az adatfile-ból:

In [31]:
plot(dat[-100:,2],dat[-100:,3],linestyle='',marker='o')
Out[31]:
[<matplotlib.lines.Line2D at 0x7f35e5702710>]

Az 5. oszlop viszont a megfigyelések statisztikus hibáit tartalmazza. Ha a mérési pontokat és a hibát egy ábrán szeretnénk látni, akkor ezt az errorbar() függvény segítségével megtehetjük.

In [32]:
errorbar(dat[-100:,2],dat[-100:,3],dat[-100:,4],linestyle='',marker='o')
Out[32]:
<Container object of 3 artists>

Az errorbar() függvény tehát három bemenő oszlopot vár, amelyekből az első kettő a mérési pontok, illetve a mért értékek, a harmadik pedig a hiba. Ezeken felül, hasonlóan a plot()-hoz kulcsszavakkal vezérelhetjük a megjelenést. Az alábbi példa illusztrál néhány kulcsszót.

In [33]:
jellemzok=dict(linestyle='',marker='o',ecolor='green',capsize=4,capthick=2)
errorbar(dat[-100:,2],dat[-100:,3],dat[-100:,4],**jellemzok)
Out[33]:
<Container object of 3 artists>

További opciókról a docstringben kaphatunk némi felvilágosítást:

In [34]:
?errorbar

Természetesen két különféle ábrázolást is meg lehet egy képen jeleníteni! Az alábbi példában egy plot() és egy errorbar() függvényt kombinálunk.

In [35]:
errorbar(dat[-300:,2],dat[-300:,3],dat[-300:,4],linestyle='',marker='o')
plot(dat[-300:,2],70*cos(2*pi/11*dat[-300:,2]-pi*0.25)+70,color='red',linewidth=3)
Out[35]:
[<matplotlib.lines.Line2D at 0x7f35e5671978>]

Hisztogramok

A hisztogramok a statisztikai elemzések fontos eszközei. A múlt órán már láttunk pár példát hisztogram készítésére a hist parancs segítségével. Ismerkedjünk most meg a hist() hisztogramgyártó-rutin néhány kulcsszavas argumentumával. Először is gyártsunk néhány véletlen számot!

In [36]:
meres1=randn(10000);
meres2=random.normal(2,0.5,10000);

Amint már korábban láttuk, ez a legegyszerűbb módja a hisztogramgyártásnak.

In [37]:
hist(meres1)
Out[37]:
(array([    8.,    81.,   502.,  1475.,  2579.,  2895.,  1774.,   571.,
           98.,    17.]),
 array([-3.91550616, -3.14678063, -2.3780551 , -1.60932956, -0.84060403,
        -0.0718785 ,  0.69684703,  1.46557257,  2.2342981 ,  3.00302363,
         3.77174916]),
 <a list of 10 Patch objects>)

Ha növelni akarjuk a hisztogram felbontását, akkor azt a bins argumentummal tehetjük meg. Ha a bins egy számot kap a bemenetre, akkor annyi automatikusan legenerált beosztás szerint gyártódik le a hisztogramm.

In [38]:
hist(meres1,bins=100);

A beosztások széleit önkényesen is megadhatjuk!

In [39]:
hist(meres1,bins=[-2,0,1,2,3]);

Ha oszlopok helyett egy folytonos vonallal szeretnénk elkészíteni a hisztogramot, akkor a histtype kulcsszó segít!

In [40]:
hist(meres1,histtype='step');

Természetesen ahogy a plot parancsnál, úgy a hist parancsnál is lehet egyszerre több hisztogramot egy képen ábrázolni.

In [41]:
hist(meres1,bins=100,linewidth=0);
hist(meres2,bins=100,linewidth=0);

Ha nagyon eltakarná a két eloszlás egymást, akkor az alpha kulcsszó segítségével némileg áttetszővé tehetjük őket!

In [42]:
hist(meres1,bins=100,linewidth=0,alpha=0.5);
hist(meres2,bins=100,linewidth=0,alpha=0.5);

Kétváltozós függvények ábrázolásai, kontúrábrák, hőtérképek

Kétváltozós függvények megjelenítése az egyváltozósokéhoz hasonlóan, adatgyűjtéssel vagy mintavételezéssel kezdődik. A már ismert linspace() függvényt kombinálva a meshgrid() függvénnyel a múlt órán megismert módon mintavételezünk egy kétváltozós paraméterteret:

In [43]:
x2,y2 = meshgrid(linspace(-4,4,50),linspace(-3,3,50)) #mintavételezési pontok legyártása
z2 = sin(x2) ** 10 + cos(10 + y2 * x2) * cos(x2)          #függvény kiértékelés

A fenti kódsor tehát legyártott három tömböt. Az első kettő tartalmazza a (2 indexes array formájában) a mintavételezési pontok $x$ és $y$ koordinátáját. A z2 változó pedig a kiértékelt függvényt. Most már csak ábrázolni kell! Ezt legegyszerűbben - ahogy már láttuk - a pcolor() függvény teszi meg:

In [44]:
pcolor(x2,y2,z2)
Out[44]:
<matplotlib.collections.PolyCollection at 0x7f35e5195860>

Hogy egy adott szín mit jelent, azt a colorbar() függvény segítségével tudhatjuk meg.

In [45]:
pcolor(x2,y2,z2)
colorbar()
Out[45]:
<matplotlib.colorbar.Colorbar at 0x7f35e5850f98>

Sok színsála létezik. Mindegyiknek megvan a maga előnye és hátránya. A matplotlib színskálák oldalán néhány megnevezett színsála közzül a cmap kulcsszó segítségével tudunk válogatni.

In [46]:
pcolor(x2,y2,z2,cmap='viridis')
colorbar()
Out[46]:
<matplotlib.colorbar.Colorbar at 0x7f35e5498c50>

Kétváltozós függvényeket szokás kontúrok segítségével is ábrázolni. Egy kontúrvonal azokat a pontokat tartalmazza, ahol az adott kétváltozós függvény ugyanazt az értéket veszi fel. A contour() függvény segítségével tudunk kontúrábrákat generálni:

In [47]:
contour(x2,y2,z2)
Out[47]:
<matplotlib.contour.QuadContourSet at 0x7f35e5481550>

Ha csak megadott kontúrértékekre vagyunk kíváncsiak, akkor azt a levels kulcsszó használatával tehetjük meg.

In [48]:
contour(x2,y2,z2,levels=[-0.5,0,0.5])
Out[48]:
<matplotlib.contour.QuadContourSet at 0x7f35e4e79278>

A clabel() függvény segítségével a kontúr vonalakat a megfelelő értékek szerint tudjuk feliratozni.

In [49]:
cs=contour(x2,y2,z2,levels=[-0.5,0,0.5])
clabel(cs)
Out[49]:
<a list of 28 text.Text objects>

A contourf() függvény a pcolor() és a contour() függvények jó tulajdonságait ötvözi. Segítségével kitöltött színes ábrákat tudunk generálni, amelyek jobban illeszkednek a megjelenítendő függvény alakjához.

In [50]:
contourf(x2,y2,z2)
Out[50]:
<matplotlib.contour.QuadContourSet at 0x7f35e4f6b710>

A levels kulcsszó segítségével feljebb vehetjük a felbontást.

In [51]:
contourf(x2,y2,z2,levels=linspace(-1.5,1.5,100))
colorbar()
Out[51]:
<matplotlib.colorbar.Colorbar at 0x7f35e51efda0>

Előfordulhat, hogy a mintavételezés valamilyen oknál fogva nem volt egyenletes. Ekkor az adatpontok háromszögelésének segítségével lehet ábrázolni a kérdéses függvényt. Az alábbiakban erre látunk példát.

Gyártsunk le először is véletlenszerűen síkbeli pontokat!

In [52]:
tx,ty = [8*rand(50*50)-4,6*rand(50*50)-3]                 #mintavételezési pontok legyártása

Értékeljük ki ezekben a véletlen mintavételezési pontokban az ábrázolni kívánt függvényt!

In [55]:
tz = sin(tx) ** 10 + cos(10 + ty * tx) * cos(tx)          #függvény kiértékelés

Ha az adatpontok rendezetlenek, akkor a tripcolor(), tricontour() és tricontourf() függvényeket használhatjuk a pcolor(), contour(), illetve a contourf() függvényekkel teljesen analóg módon!

In [56]:
tripcolor(tx,ty,tz)
Out[56]:
<matplotlib.collections.PolyCollection at 0x7f35e462cda0>
In [57]:
tricontourf(tx,ty,tz,linspace(-1.5,1.5,100))
Out[57]:
<matplotlib.tri.tricontour.TriContourSet at 0x7f35e443a0b8>

Vektorterek ábrázolási lehetőségei, nyílseregek és áramvonalak

A fizikában gyakran van dolgunk erőterekkel. Gondoljunk csak az elektrodinamikára vagy a meteorológiára. Vizsgáljuk meg az eddig ábrázolt kétváltozós függvény gradiensét. A síkbeli gradiensvektor az alábbiak szerint adódik:

In [58]:
u=-y2*sin(x2*y2 + 10)*cos(x2) + 10*sin(x2)**9*cos(x2) - sin(x2)*cos(x2*y2 + 10)
v=-x2*sin(x2*y2 + 10)*cos(x2)

A quiver() függvény segítségével a sík minden pontjához, amelyet az x2 és y2 tömbök definiálnak, egy az u és v tömbök által definiált vektort tudunk rendelni. Azaz a tér (x2[i],y2[i]) pontjába egy (u[i],v[i]) vektor kerül!

In [59]:
quiver(x2,y2,u,v)
Out[59]:
<matplotlib.quiver.Quiver at 0x7f35e4309e80>

Rajzoljuk csak minden harmadik vektort ki, piros színnel és kicsit vastagabban.

In [60]:
quiver(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3],
    color='red',width=0.005)
Out[60]:
<matplotlib.quiver.Quiver at 0x7f35e42b9c88>

Mint ahogy azt fent is említettük, további részletekért érdemes a dokumentációt böngészni!

In [61]:
?quiver

A quiver() alternatívája az áramvonal-ábrázolás, avagy a streamplot():

In [62]:
streamplot(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3])
Out[62]:
<matplotlib.streamplot.StreamplotSet at 0x7f35def00470>

További részletek a dokumentációban:

In [63]:
?streamplot

A streamplot()-ot és a quiver()-t használhatjuk közösen a pcolor() és a kontúrkészítő rutinokkal!

In [64]:
pcolor(x2,y2,z2)
colorbar()
quiver(x2[::2,::2],y2[::2,::2],u[::2,::2],v[::2,::2],color='white',width=0.005)
Out[64]:
<matplotlib.quiver.Quiver at 0x7f35dee04dd8>
In [65]:
contourf(x2,y2,z2,levels=linspace(-1.5,1.5,100))
colorbar()
streamplot(x2[::3, ::3], y2[::3, ::3], u[::3, ::3], v[::3, ::3],color='white')
Out[65]:
<matplotlib.streamplot.StreamplotSet at 0x7f35debd6a90>

Ábrafeliratozás, nyilazás, ábratömbök

Egy ábra véglegesítése során sokszor előfordulhat, hogy valamilyen magyarázó szövegre van szükség, esetleg az ábra egy részét valamiért ki szeretnénk emelni. Ezt a text() és az annotate() függvények segítségével tehetjük meg. A text() függvény 3 alapvető bemenő paraméterrel rendelkezik. Az első kettő egy koordináta, a harmadik pedig egy string. Nézzünk egy példát!

In [66]:
plot(x,y);
text(1,0,'Ez egy felirat')
text(-3,0,'Ez egy másik felirat',fontsize=13,color='red')
Out[66]:
<matplotlib.text.Text at 0x7f35de94cf98>

Ha egy részt ki szeretnénk emelni, akkor arra a legalkalmasabb megoldás az annotate(). Ezen függvény segítségével egy "rámutató" nyilat és egy magyarázó szöveget helyezhetünk el az ábrán. Az első bemenő paraméter egy string, ami a magyarázat, ezen kívül kulcsszavakkal vezéreljük a függvény további viselkedését. Az xy kulcsszó a kiemelni kívánt pont helye. Az xytext a magyarázat helye, az arrowprops pedig egy olyan dict-et tartalmaz, amely a nyíl tulajdonságait határozza meg.

In [67]:
plot(x,y)
annotate('lokális minimum', xy=(-pi/2, -1), xytext=(-pi, 0.5),arrowprops=dict(color='red',width=3),fontsize=20)
Out[67]:
<matplotlib.text.Annotation at 0x7f35de915278>
In [68]:
?annotate

Végül lássunk néhány példát ábratömbökre! A subplot() függvény segítségével tudunk ábratömböt vagy ábrarácsot generálni. Ha egy kódcellába több subplot() parancsot írunk, akkor minden subplot() parancs alatti ábrázolórutin külön alábrára kerül. A subplot(n,m,i) kód jelentése a következő: ami ezután jön, azt rajzold egy n*m-es ábratömb i-edik alábrájába. Vigyázzunk rá, hogy itt i nem haladhatja meg n*m-et!

Lássunk néhány példát:

In [69]:
figsize(12,4) #ábraméret nagyítása vízszintesen
subplot(1,2,1)
plot(x,y)
subplot(1,2,2)
pcolor(x2,y2,z2)
Out[69]:
<matplotlib.collections.PolyCollection at 0x7f35de847e10>
In [70]:
figsize(6,8) #ábraméret nagyítása függőlegesen
subplot(2,1,1)
plot(x,y)
subplot(2,1,2)
pcolor(x2,y2,z2)
Out[70]:
<matplotlib.collections.PolyCollection at 0x7f35de703748>

Ábra mentése

A legenerált ábrákat a savefig() paranccsal tudjuk kimenteni képfile-okba.

In [71]:
figsize(6,4) # megszokott ábraméret visszaállítása
plot(x,y)
savefig('az_en_abram.png')