Az ábrakészítéshez természetesen az eddig használt matplotlib modul mellett számos másik függvénycsomag is létezik. A lent röviden bemutatott plotly modul előnye, hogy az alapbeállításokat használva is elegáns és interaktív ábrákat tudunk készíteni.
A plotly szintaxisa az eddigiektől azonban némiképp eltér, ennek a rövid bemutatására törekszünk néhány példán keresztül.
A plotly alapvetően egy webes felület, melyen egy ingyenes regisztráció és bejelentkezés után mindenkinek lehetősége nyílik adatok feltöltésére, azok feldolgozására interaktív ábrák formájában, majd a legyártott ábrák megosztására. Ez a módszer jelentősen megkönnyítheti egy csoporton belül a kollaborációt, hiszen a csoporttagok nemcsak az ábrákhoz férnek hozzá, hanem magukhoz az adatokhoz és az ábrákat legyártó kódrészletekhez is. Így ha valaki csak a vonalak színét szeretné egy ábrán megváltoztatni, nem kell e-mailben megkérnie az ábra eredeti gyártóját, hogy ezt tegye meg, hanem a kód átírásával saját maga is megoldhatja.
Néha azonban a vizsgált adatok természetüknél fogva nem tölthetők fel egy publikus tárhelyre, a privát tárhely használatához pedig Pro accountra van szükség, ami értelemszerűen nem ingyenes. Gyakran előfordul olyan probléma is, hogy a feldolgozni kívánt adatfájlok annyira nagyok, hogy feltöltésük (illetve bármilyen mozgatásuk) nem praktikus. Ilyen és ehhez hasonló esetekben szükség lenne egy "lokális" ábrakészítő opcióra, mellyel nem az adatok mennek a plotlyhoz, hanem a plotly jön az adatokhoz. Ennek a megoldására készült a Plotly Offline verziója, mellyel az ábrák és adatok nem egy központi szerveren tárolódnak, hanem a lokális gépen, illetve notebookban. A lenti példákban ezt az offline verziót használjuk. A plotly online dokumentációjában részletes leírást találhatunk találunk a csomag által kínált ábra készítő rutinokról.
(A plotly ábrák generálása emellett nemcsak a mostanra megszokott Python nyelven lehetséges, hanem akár R-ben vagy JavaScriptben is. Ezekről az alábbiakban nem ejtünk szót.)
# a szokásos pylab import
%pylab inline
# plotly specifikus importok és inicializálás
from plotly import *
from plotly.offline import *
init_notebook_mode()
Mint ahogy a matplotlib modulnál is láttuk, minden ábra generálásához elsőként az adatok betöltésére vagy legyártására van szükség. Nézzük a szokásos példánkat: ábrázoljuk a $sin(x)$ függvényt $0$ és $2π$ között.
x_pontok = linspace(0,2*np.pi,10)
y_pontok = sin(x_pontok)
A plotly kicsit másképp viselkedik, mint amit a matplotlib
-nél láttunk. Itt egy ábrát alapvetően különféle objektumokkal és egymásba ágyazott dict
-ekkel definiálhatunk. Az ábra minden egyes jellemzőjéhez (pl. színek, rács, az adatok, stb.) tartozik egy kulcs-érték páros.
Ezeket a jellemzőket a plotly két kategóriába sorolja, a trace
-ekbe és a layout
-ba. A trace
-ek olyan objektumok, melyek egy adatsort írnak le az ábrán, például egy Scatter vagy egy Heatmap objektum. Egy ábrán természetesen több trace
is lehet, ha például kétféle adatsort is ábrázolni szeretnénk. A trace
-ek emellett ábrákon belül is kombinálhatók, egyetlen ábrán megjeleníthetünk elszórt mérési pontokat és oszlopdiagramot is. A layout
jellemzők pedig az ábra egészére vonatkozó formázási utasítások, például az ábra címe, a háttér színe, a tengelyfeliratok, illetve további annotációk (szövegek).
Az ábrakészítésben a plotly dokumentációja sok segítséget ad.
1. Trace
-ek legyártása
Egy ábra definiálásakor tehát elsőként az adatokból le kell gyártanunk a megfelelő trace
-eket. A konkrét példában egy olyan ábrát szeretnénk, ahol a fenti y_pontok
array az x_pontok
array függvényében van ábrázolva, és a pontok folytonos vonallal vannak összekötve. Ezt az alábbi utasítással tehetjük meg:
trace_sin_gorbe = graph_objs.Scatter(x=x_pontok, y=y_pontok, mode='lines')
trace_sin_gorbe
Itt tehát legyártottunk egy "gráf objektumot", mely most éppen Scatter
típusú. A kiíratásból láthatjuk, hogy bár ezt, mint egy objektumot definiáltuk, valójában egy olyan dict
, melyben a 'type'
kulcshoz a 'scatter'
érték tartozik. Tehát tulajdonképpen az alábbi módszer is működne a fenti trace
definiálására, az objektumként való megadás csak a kényelmünket szolgálja.
trace_sin_gorbe = {'mode': 'lines',
'type' : 'scatter',
'x': x_pontok,
'y': y_pontok}
Arra viszont figyeljünk, hogy ha a dict
-ként való megadást választjuk, akkor a kulcs-érték párokat kettősponttal válasszuk el, a gráf objektumként való megadás esetén pedig egyenlőségjellel.
A mode
kulcshoz írt 'lines'
azt jelenti, hogy az adatpontokat vonallal szeretnénk az ábrán összekötni. Ha csak be szeretnénk szórni a pontokat az ábrára, akkor ide írjuk a 'markers'
kifejezést.
Végül tegyük be az adatok_sin_gorbe
listába a legyártott trace
objektumokat. Mivel ebben a példában csak egyetlen trace
-re volt szükség, így ez elhagyható lenne, de több trace
esetén az összeset célszerű egy listába összefűzni:
adatok_sin_gorbe = [trace_sin_gorbe]
2. A layout
definiálása
Adjunk az ábránknak címet, a tengelyekre pedig rakjunk tengelyfeliratot. Ezt a Layout
objektum specifikálásával tehetjük meg az alábbiak szerint:
layout_sin_gorbe = graph_objs.Layout(title='Ez az ábra címe',
xaxis=graph_objs.XAxis(title='x'),
yaxis=graph_objs.YAxis(title='sin(x)'))
layout_sin_gorbe
A Layout
objektum xaxis
változója egy XAxis
objektum, melyben már a title
változó értéke közvetlenül megadható. Hasonlóan járunk az yaxis
változó esetén is. Látjuk azonban, hogy csakúgy mint a trace
esetén, ezek az objektumok itt is helyettesíthetők egymásba ágyazott dict
-ekkel:
layout_sin_gorbe = {'title': 'Ez az ábra címe',
'xaxis': {'title': 'x'},
'yaxis': {'title': 'sin(x)'}}
3. A Figure
objektum legyártása
Miután az összes szükséges objektum elkészült (az adatokhoz a megfelelő trace
-ek, az ábra formázásához pedig a Layout
), ezeket összefűzve definiálhatjuk a Figure
objektumot:
figure_sin_gorbe = graph_objs.Figure(data=adatok_sin_gorbe, layout=layout_sin_gorbe)
figure_sin_gorbe
A fentiekhez hasonlóan ez is "csak" egy egymásba ágyazott dict
objektum lesz, melyet a hagyományos úton is definiálhattunk volna.
4. Az ábra kirajzoltatása
Az így elkészített Figure
objektum már ábrázolható:
iplot(figure_sin_gorbe)
Összefoglalva:
A fentiek talán bonyolultnak tűnnek, de valójában néhány sorban el tudjuk készíteni a fenti ábrát. Láthattuk, hogy a gráfobjektumok definiálása mindig a graph_objs
almodul használatával történik. Érdemes tehát az egész almodul összes függvényét importálni, így többé nem kell kiírnunk a graph_objs.
részletet.
A fenti ábra persze nagyon "szögletes" egy valódi sin-görbének, de ezen könnyen segíthetünk: növeljük meg a mintavételezési pontok számát és ábrázoljuk újra, most azonban a cos-görbével együtt. Ekkor már két trace
objektumot kell gyártanunk.
from plotly.graph_objs import *
x_pontok_uj = linspace(0,2*np.pi,50)
y_pontok_sin = sin(x_pontok_uj)
y_pontok_cos = cos(x_pontok_uj)
trace_sin_gorbe = Scatter(x=x_pontok_uj, y=y_pontok_sin, mode='lines')
trace_cos_gorbe = Scatter(x=x_pontok_uj, y=y_pontok_cos, mode='lines')
adatok = [trace_sin_gorbe, trace_cos_gorbe]
layout_sin_gorbe = Layout(title='Ez az új ábra címe',
xaxis=XAxis(title='x'),
yaxis=YAxis(title='sin(x), cos(x)'))
figure_uj = Figure(data=adatok, layout=layout_sin_gorbe)
iplot(figure_uj)
Milyen szép sima görbéket kaptunk! Ellenőrizzük, hogy ez valóban így van-e! Próbáljunk az ábra jobb felső sarkában lévő gombokkal ráközelíteni egy-egy csúcsra. Látható, hogy ilyen skálán még ezek a görbék is szögletesek.
A plotly nagy előnye az ilyen jellegű interaktív nézegetési lehetőség. Ha egy ábrán nagyon sok mérési pont van, akkor csak kellően ráközelítve tudjuk őket megkülönböztetni egymástól. A jobb oldalon a trace 0
és trace 1
feliratok melletti vonalakra kattintva az aktuális görbe az ábráról ideiglenesen eltűntethető, majd ismételt kattintással újra megjeleníthető.
Ha a fenti ábrát nem vonalakkal szeretnénk elkészíteni, hanem mondjuk a cos függvényt oszlopdiagrammal, csak a trace
típusán kell változtatnunk:
trace_sin_gorbe = Scatter(x=x_pontok_uj, y=y_pontok_sin, mode='lines')
trace_cos_gorbe = Bar(x=x_pontok_uj, y=y_pontok_cos)
adatok = [trace_sin_gorbe, trace_cos_gorbe]
layout_sin_gorbe = Layout(title='Ez az oszlopos ábra címe',
xaxis=XAxis(title='x'),
yaxis=YAxis(title='sin(x), cos(x)'))
figure_oszlop = Figure(data=adatok, layout=layout_sin_gorbe)
iplot(figure_oszlop)
A matplotlib
-es példák során megvizsgáltuk, hogy 3D-s görbéket, illetve felületeket hogyan lehet ábrázolni. Lássunk most pár példát arra, hogy a plotly
segítségével hogyan tudunk a matplotlib
-nél jóval reszponzívabb térbeli ábrákat készíteni.
Első példaként készítsünk itt is egy spirált:
t=linspace(0,2*pi,100) # mintavételezési pontok és 3D koordináták elkészítése
xp=cos(3*t) # a spirál paraméteres egyenlete alapján
yp=sin(3*t)
zp=t
Most nem az eddig használt Scatter
objektumra van szükség, hanem ennek a 3D-s változatára, a Scatter3d
-re.
trace = Scatter3d(x=xp, y=yp, z=zp, mode='lines') # Adatok csoportosítása trace-be
adatok = [trace]
layout3d=Layout(title='Spirál')
fig_3D = Figure(data=adatok,layout=layout3d) # ábra objektum létrehozása
iplot(fig_3D) # ábra megjelenítése
A következő háromdimenziós ábrához az ábrázolni kívánt pontok koordinátáit a plotly_3D.txt
szövegfájlban találjuk. Az adatok innen származnak, hasonló ábrák készítéséhez hasznos adatfájlok itt találhatók.
Az adatfájlban az első oszlop az x, a második az y, a harmadik pedig a z koordináta. Elsőként olvassuk be az adatokat. Ehhez a loadtxt függvényt használjuk, mely a numpy modulban található.
data_file = loadtxt('data/plotly_3D.txt')
x_tengely = data_file[:,0]
y_tengely = data_file[:,1]
z_tengely = data_file[:,2]
Hasonlóan a spirál elkészítéséhez itt is definiáljuk a trace, layout és ábra objektumokat. Vajon milyen hatásai vannak a különböző opcióknak amiket a Scatter3d
-nek és a Layout
-nak megadunk ?
# trace objektum létrehozása
trace_3D = Scatter3d(x=x_tengely, y=y_tengely, z=z_tengely, mode='markers', marker = dict(size=2))
adatok_3D = [trace_3D]
#layout objektum létrehoozása
layout_3D = Layout(width=900,height=500,scene=dict(aspectmode='manual', aspectratio = dict(x=0.2, y=1, z=2/3)))
#ábra létrehozása és megjelenítése
fig_3D = Figure(data=adatok_3D, layout=layout_3D)
iplot(fig_3D)
Az utolsó példában azt vizsgáljuk meg, hogy a plotly segítségével hogyan ábrázolhatunk térbeli felületeket. Ehhez gyártsunk le először is egy egyszerű adatsort, ami egy kétdimenziós Gauss-görbét $z=e^{-x^2-y^2}$ mintavételez:
x,y=meshgrid(linspace(-5,5,50),linspace(-5,5,50)) # mintavételezés az x,y síkban
z=exp(-x**2-y**2) # z koordináták az x és y függvényében
A használt függvények és objektum létrehozó rutinok, melyeket az ábrák gyártásához használtunk, számos jól kigondolt alapértelmezett paraméterrel rendelkeznek, ezért ha csak gyorsan akarunk egy adatsort ábrázolni akkor az alábbi minimális egysoros konstrukció alkalmazható:
iplot(Figure(data=[Surface(x=x,y=y,z=z)]))