Nagy mennyiségű adatok feldolgozásánál elengedhetetlen dolog a számítógépek memóriáján (RAM) kívül a külső tárolókon (merevlemezek, egyéb adathordozók) tárolt file-ok használata is. Az alábbiakban a python
alapértelmezett filekezelő függvényeivel ismerkedünk meg először, majd a numpy
csomag filekezelő rutinjaival barátkozunk meg, végül néhány tudományos kutatásokban használt formátumot (hdf5 és fits) kezelő függvényt mutatunk be.
A notebookot - mint mindig - most is kezdjük a már megszokott sorral:
%pylab inline
Ebben a fejezetben a python
egyéb moduloktól független, alapvető fileműveleteket biztosító függvényeivel fogunk megismerkedni. Ezen függvények egy file tartalmát többnyire karakterláncok formájában kezelik, ezért konkrét formátumú adatok beolvasása, illetve kiírása némi bonyodalommal jár, melyeket legtöbbször valamilyen specifikusan az adott feladatra megírt függvény tesz lehetővé. Az alábbi részben a történelmi napfoltszám-megfigyelések adatainak az elemzésén keresztül ismerkedünk meg ezekkel a függvényekkel.
Egész file beolvasása egyetlen karakterláncba az alábbiak szerint történik.
Előszöris az open()
függvény segítségével megnyitjuk a beolvasni kívánt file-t. Az open()
függvény egy előkészítő függvény, amely arra készíti fel a rendszert, hogy az adott merevelemezen (vagy más adattárolón) fellelhető file-lal dolgozni tudjunk. Legegyszerűbb esetben ez a file nevének a megadásával történik.
file1 = open('data/SN_m_tot_V2.0.txt')
file1
A fenti kódsor hatására a file1
változón keresztül férhetünk hozzá a file tartalmához. A file teljes tartalmát például a következő utasítással tölthetjük be egy karakterlánc formájában az egeszfile
változóba:
egeszfile=file1.read()
Figyelem, ne keverjük össze a file1
és az egeszfile
változókat! Amint azt fent is említettük, az egeszfile
egy karakterlánc, a file1
pedig a file-ból való olvasást, illetve a file-ba való írást segítő segédobjektum, amelyet szokás esetenként (adat)folyam-nak vagy angolul streamnek is nevezni.
Ha már minden olvasás és írás befejeződött, akkor a close()
utasítással zárhatjuk be a folyamot, azaz ez a parancs szakítja meg a kommunikációt az adattárolóval.
print(file1.closed)
file1.close()
print(file1.closed)
Mivel fent betöltöttük a file tartalmát az egeszfile
stringbe, ezért ennek segítségével bele is pillanthatunk, vizsgáljuk meg például az első 100 karaktert a file-ból:
egeszfile[:100]
Ha megnézzük magát a file-t, akkor látható hogy tényleg ezek a dolgok vannak benne. Figyeljük meg hogy a sor vége helyett a \n
karakter szerepel!
A read()
függvény előre specifikált számú karakter olvasását is lehetővé teszi. Nyissuk meg ismét az előző file-t ismét:
file1 = open('data/SN_m_tot_V2.0.txt')
Olvassunk be 10 karaktert a fileból az alábbi módon:
karakterek1=file1.read(10)
A karakterek1
változó ezután a file első 10 karakterét tartalmazza (vessük össze ezt az egeszfile[:100]
parancs kimenetével):
karakterek1
Ha ismét meghívjuk a file1
változó read()
függvényét, akkor az a következő 10 karaktert olvassa be:
karakterek2=file1.read(10)
karakterek2
Látjuk tehát hogy a read()
utasítás hatására könyörtelenül haladunk végig a file karakterein: úgy tűnhet, ha már egyszer valamit beolvastunk, akkor azt többé már nem tudjuk! Szerencsére ez nem így van, mivel a tell()
és a seek()
függvények segítségével kérdezhetjük le, illetve állíthatjuk be egy megnyitott filefolyam aktuális pozicióját.
A tell()
függvényt alkalmazva a file1
változóra megkaphatjuk az aktuális folyampoziciót. Ami a jelen esetben 20, hiszen az előző két read parancs 10 karaktert olvasott be!
file1.tell()
A seek()
parancs segítségével a file egy tetszőleges helyére ugorhatunk. A seek(n)
függvény alkalmazásával a file n
-edik karakterére ugrunk. Ha ezután alkalmazzuk a read()
függvényt, akkor a file tartalmát ettől a pozíciótól olvassuk.
file1.seek(5)
Az alábbi parancs tehát a 5. karaktertől olvas be újabb 10 darab karaktert.
karakterek3=file1.read(10)
karakterek3
Zárjuk ismét be a file-t!
file1.close()
Hogy véletlenül se felejtsük el bezárni a file-t pythonban van egy kényelmes/hasznos konstrukció a with
. Ez meghívja az adott objektum __enter__()
es __exit__()
tagfüggvényeit. A with
block után a változó megmarad, de a file már zárva van.
A with
előnyei:
with open('data/SN_m_tot_V2.0.txt') as f:
print(f.closed) # Itt még nyitva kell hogy legyen a file
print(f.closed) # Itt a with már bezárja nekünk
Nagyon sok esetben az adatfile-okban hordozott információ táblázatszerűen van rendezve. Az file minden sora hasonló tagolással csoportosítja a számunkra értékes adatokat. Egy megnyitott file minden sorát - mint soronkénti karakterláncok listáját - a readlines függvény segítségével gyárthatjuk le.
with open('data/SN_m_tot_V2.0.txt') as f:
sorok = f.readlines()
A sorok lista minden eleme most tehát egy egy sor a file-ból, vizsgáljuk meg például az első 10 sort:
sorok[0:10]
Amint látjuk, az első hat sor a '#' karakterrel kezdődik, és minden ilyen sor azt mondja meg hogy a tényleges adatok megfelelő oszlopa mit tartalmaz. A hetedik sortól lefelé viszont szóközökkel elválasztott számok vannak, ez maga a hőn áhitott adat, de sajnos még mindig karakterláncok formájában!
Az első értékes adatsor a file 7.-sora:
sorok[6]
Egy karakterláncot a split()
parancs segítségével adott karakterek mentén fel tudunk vágni egy listába. A split()
parancs alapértelmezésben szóközök szerint vágja fel a megjelölt karakterláncot, így az első értékes adatsor oszlopokra szabása az alábbiak szerint történik:
sorok[6].split()
Az eredmény tehát egy lista mely tartalmazza az értékes adatokat, ugyan még mindig karakterláncok formájában!
Az egyes elemeket lebegőpontos számmá a már ismert float()
függvénnyel konvertálhatjuk. Tehát az első adatsor negyedik oszlopából a következő módon készíthetünk hús-vér számot:
float(sorok[6].split()[3])
Ha már egy elemet számmá tudunk konvertálni, akkor egy for
ciklus segítségével számokat tartalmazó listákba tudjuk rendezni az adatokat a már megszokott módon:
num_napfolt=[]
meresi_ido=[]
for sor in sorok[6:]:
num_napfolt.append( float(sor.split()[3]) )
meresi_ido.append( float(sor.split()[2]) )
Ábrázoljuk végül a napfoltok számát az évek függvényében:
plot(meresi_ido,num_napfolt)
xlabel('T[ev]')
ylabel('Napfoltszam')
Jól látszik, hogy az elmúlt 250 év során a napfoltok száma periodikusan változik.
Nagy fájlok olvasása esetén nem érdemes, és néha nem is lehetséges, hogy egyszerre beolvassuk az egész fájlt a memóriába. Erre is van egy kényelmes megoldás a pythonban.
A nyitott fájlon egyszerűen végigiterálhatunk egy for ciklusban.
with open('data/SN_m_tot_V2.0.txt') as f:
num_napfolt,meresi_ido=[],[]
for sor in f: # így iterálhatunk végig egy adatfolyamon vagy fileon
if sor[0]!='#':
num_napfolt.append( float(sor.split()[3]) )
meresi_ido.append( float(sor.split()[2]) )
plot(meresi_ido,num_napfolt) # Ez az ábra ugyan az mint az előző
xlabel('T[ev]')
ylabel('Napfoltszam')
Az adatok beolvasása mellett sokszor lehet szükség a feldolgozott információ újbóli kiírására. Erre a python
az adatfolyam típusú változókra alkalmazott write()
függvényt kínálja. Vizsgáljuk meg, egy egyszerű példán, hogyan is működik a fileírás!
Nyissunk meg egy file-t, amelybe írni szeretnénk, ezt az open()
függvény mode
kulcsszavas paraméterén keresztül tudjuk jelezni a mode='w'
beállítással. Itt a w
az írási módot jelenti.
A file2
folyamba a write()
függvény segítségével tudunk karakterláncokat írni:
with open('data/out_mentes1.dat',mode='w') as f:
print(f)
with open('data/out_mentes1.dat',mode='w') as f:
print(f.write('#Ez az elso kiirt fileom!\n'))
Ha már meglévő file-hoz szeretnénk további karaktereket fűzni, akkor az open()
függvény mode
paraméterének mode='a'
beállításával jelezzük ezt. Az 'a'
karakter itt az append angol szó rövidítése, mely ismerős lehet már számunkra egy, a listákra vonatkozó függvény nevéből.
with open('data/out_mentes1.dat',mode='a') as f:
print(f)
Írjuk ki a mérési idő (meresi_ido
) és a napfoltok számát tartalmazó (num_napfolt
) adatokat a már fent létrehozott data/out_mentes1.dat
file-ba.
Ezt egy for
ciklus segítségével fogjuk megtenni:
with open('data/out_mentes1.dat',mode='a') as f:
for i in range(len(meresi_ido)):
f.write(str(meresi_ido[i])+' '+str(num_napfolt[i])+'\n')
A write()
függvény hasába írt karakterlánc a meresi_ido
és num_napfolt
tömbök megfelelő sorában lévő elemet tartalmazza szóközzel elválasztva, illetve a sor végét egy sortörés '\n'
-el jelezve.
A beolvasáshoz hasonlóan a kiíratásnál is van lehetőség egész sorok kiírására. Ezt, talán nem túl meglepő módon a writelines()
függvény valósítja meg. Ez a függvény karakterláncok listáját írja ki egy file-ba egy megnyitott filefolyamon keresztül.
Ha a lista minden karakterlánca '\n'
karakterre végződik, akkor a kiíratás során a file-ban minden listaelem egy-egy külön sorba kerül:
sorok=['Ez az elso sor\n','Ez a masodik sor\n']
with open('data/out_mentes1.dat',mode='a') as f:
f.writelines(sorok)
Mi történik, ha lemarad a '\n'
?
sorok=['Ez az harmadik','Ez hova kerult?\n']
with open('data/out_mentes2.dat',mode='a') as f:
f.writelines(sorok)
Vizsgáljuk meg magát a file-t!
Ha sorokat akarunk írni, és nem akarunk bajlódni a sorvége karakterek írásával, akkor egyszerűen a print()
függvényt is használhajtuk a fájlba írásra.
sorok=['Ez az harmadik','Ez hova kerult?']
with open('data/out_mentes3.dat',mode='w') as f:
for s in sorok:
print(s,file=f)
karakter | jelentés |
---|---|
\n | sortörés |
\r | kocsi vissza |
\t | vízszintes kihagyás (TAB) |
\v | függőleges kihagyás (TAB) |
\xhh.. | hexadecimális karakter hh.. értékkel |
A print függvény segítségével az alábbi példán demonstráljuk a '\r'
, '\t'
, és a már ismert '\n'
hatását:
print("EZEK ITT NAGYBETUKezek itt kisbetuk")
print("EZEK ITT NAGYBETUK\rezek itt kisbetuk")
print("EZEK ITT NAGYBETUK\tezek itt kisbetuk")
print("EZEK ITT NAGYBETUK\nezek itt kisbetuk")
Ezek a karakterek file-ba való írás közben is hasonlóan viselkednek!
Amint korábbiakban is láthattuk, a numpy
csomag array
típusú változói számos előnyös tulajdonsággal rendelkeznek a sima list
típusú változókhoz képest. A numpy
csomag biztosít néhány hasznos filekezelő rutint, melyek az array
tipusú változók file-ba kiírására, illetve file-okból történő beolvasására használhatóak. Az alábbiakban két érdekes példán keresztül fogjuk megvizsgálni ezeket a függvényeket.
Elemezzük Felix Baumgartner ugrásának adatait. Az ugrás megtett út-idő adatait a data/h_vs_t
file-ban találjuk. (Vizsgáljuk meg magát a file-t is! ) A file két oszlopnyi számot tartalmaz. Az első oszlop az idő s-ban, a második oszlop az adott időben mért magasság m-ben. Ilyen jellegű egyszerű struktúrájú file-ok beolvasására és az adatok array-ba való töltésére a numpy
csomag loadtxt
függvényét használhatjuk:
baum_data=loadtxt('data/h_vs_t.txt')
A baum_data
tömb első oszlopát a t
változóba, a második oszlopát pedig a h
változóba tároljuk:
t=baum_data[:,0] # idő
h=baum_data[:,1] # magasság
Ábrázoljuk az adatokat! A tengelyfeliratok természetesen nem maradhatnak el!
plot(t,h)
xlabel('Ido [s]')
ylabel('Magassag [m]')
Az ugrással kapcsolatban egy igen fontos kérdés volt, hogy vajon sikerült-e szabadesésben átlépni a hangsebességet? Vizsgáljuk meg, hogy ezen adatok alapján vajon átlépte-e Felix Baumgartner a hanghatárt! Először is szükség van a sebesség időfüggésére. Ezt a magasság$--$idő függvény numerikus deriváltjával fogjuk most meghatározni. Ha egy $y(x)$ függvényt mintavételezésével véges darab $x_i,y_i$ párt kapunk, akkor az $y(x)$ függvény numerikus deriváltját a következő differencia hányadossal közelíthetjük:
$$\left . \frac{\mathrm{d}y}{\mathrm{d}x}\right|_{x_i} =\frac{y_{i+1}-y_i}{x_{i+1}-x_i} $$
Definiáljunk most egy függvényt, mely két ugyanolyan hosszúságú tömb x
és y
adataiból legenerálja a két tömb numerikus derviáltját. Figyeljük meg, hogy az utolsó és az első adatpontban a fenti képlettől egy kicsit eltérő módon járunk el.
# numerikus derivált függvény
def nderiv(y,x):
"Első szomszéd differenciál"
n = len(y) # adatpontok száma
d = zeros(n) # változó inicializálás. A zeros() függvény tetszőleges alakú és 0-kat tartalmazó arrayt gyárt
# mivel a legegyszerűbb numerikus differenciálás nem szimmetrikus a végpontokat
# kicsit másképp kezeljük mint a tömb belsejében lévő pontokat
for i in range(1,n-1):
d[i] = (y[i+1]-y[i])/(x[i+1]-x[i]) #egy általános pont deriváltja
d[0] = (y[1]-y[0])/(x[1]-x[0]) #az első pont deriváltja
d[n-1] = (y[n-1]-y[n-2])/(x[n-1]-x[n-2]) # az utolsó pont deriváltja
return d
Az nderiv függvény segítségével a sebesség meghatározható.
v=nderiv(h,t) # Figyelem az első változó a h a második a t!!!
Vizsgáljuk meg a sebesség-idő függvényt!
plot(t,v)
xlabel('Ido [s]')
ylabel('Sebesseg [m/s]')
Mivel általában a hang terjedési sebessége függ a magasságtól, ezért annak érdekében, hogy megtudjuk, hogy sikerült-e áttörni a hanghatárt, célszerű a sebességet a magasság függvényében ábrázolni:
plot(h,abs(v))
xlabel('Magasság [m]')
ylabel('Sebesség [m/s]')
A wikipédián található adatok alapján a hangsebesség 25km magasságban valamivel 300 m/s alatt van. Ezen a magasságon Felix sebessége 350 m/s körül mozgott, tehát a rekord - a mérési adatok alapján - sikerült!
A numpy savetxt függvényével írjuk ki az elkészített v-t adatokat.
savetxt('data/out_tv.txt',[t,v])
Vizsgáljuk meg az elkészített filet!
Nagy tömbök kiíratása szöveges fájlokba nagyon lassú lehet. Ha nem merül fel, hogy ember is olvasni fogja a fájlt, amit lementünk, és nagyon fontos a gyors kiírás-beolvasás, érdemes lehet a numpy bináris save-load függvényeit használni.
Csináljunk egy jó nagy tömböt.
#nagyobbacska tomb
a=random.random((2048,2048))
Írjuk ki szövegesen, és mérjük le mennyi időbe telik.
%time savetxt('data/out_tmp.txt',a)
Írjuk ki binárisan. Ezt egyszerűen a numpy
modul save
függvényével tehetjük meg mely változók bináris formátumba történő kiiratását teszi lehetővé.
%time save('data/out_tmp.npy',a)
Olvassuk be szövegesen.
%time a1=loadtxt('data/out_tmp.txt')
Olvassuk be binárisan.
%time a2=load('data/out_tmp.npy')
Hasonlítsuk össze a két tömböt.
all(a1==a2)
Hasonlítsuk össze a fájlok méretét is!
! du -h data/out_tmp.txt
! du -h data/out_tmp.npy
Jól látszik tehát hogy akár több mint egy nagyságrendel gyorsabban történik a merevlemezre írás bináris formátumban illetve, hogy a bináris fileok mérete is kisebb mint a sima szöveges fileok mérete.
Előfordulhat, hogy nem egy egyszerű táblázatot, vagy más fájlban könnyen reprezentálható dolgot akarunk lementeni. Ebben az esetben sem kell bonyolult kiírató, beolvasó függvényeket gyártani, hanem segítségünkre van a python beépített pickle csomagja, ami bármilyen python objektumot byte-okká tud alakítani és így le is tudja menteni egy fájlba.
Tegyük fel hogy le akarok menteni egy nagyon komplex számot, amin már nagyon sokat dolgoztam, de még egy picit kéne később.
class Complex:
"""
Az en komplex szam osztalyom, mert a pythone bena.
Igaz meg ezen is lehetne dologzni ...
"""
def __init__(self,re,im):
self.re,self.im=re,im
def __add__(self,other):
return Complex(self.re+other.re,self.im+other.im)
def __mul__(self,other):
re=self.re*other.re - self.im*other.im
im=self.re*other.im + self.im*other.re
return Complex(re,im)
def __abs__(self):
return (self.re**2 + self.im**2)**0.5
def __str__(self):
return str(self.re)+' + '+str(self.im)+'i'
__repr__=__str__
z=Complex(3,4)
'teszt:',z,abs(z),z+z,z*z
import pickle #nem tul meglepő módon így töltjük be a pickle modult
Nyitunk egy fájlt és abba tudunk írni. A pickle
csomagban a file-ba való írást a dump
függvénnyel tudjuk elvégezni.
with open("data/out_complex.pkl","wb") as f:
pickle.dump(z,f)
Töltsük be. Ezt a pickle
-modul load
függvényével tesszük meg:
with open("data/out_complex.pkl","rb") as f:
uj_z = pickle.load(f)
uj_z
Pythonban nagyon könnyen lehet képekkel is dolgozni. Most csak a legkézenfekvőbb matplotlib programokat nézzük meg, de rengeteg másik, komolyabb képmanipuláló csomag létezik pl.: opencv,scikit-image,pillow.
Betölteni képet legegyszerűbben a matplotlib.image.imread függvényel tudunk.
im=imread('data/Photo_51_x-ray_diffraction_image.jpg')
A betöltött kép már jól ismert numpy array lesz.
type(im)
A képet meg is nézhetem itt, más színekkel, skálával.
imshow(im[:,:,2],cmap='Blues') # a kek csatorna kekkel
colorbar() #skala
Képek manipulálásakor figyeljünk arra, hogy tipikusan uint8 típusú számokból állnak. Ezen válltozók értékei típus 8bit-en reprezentált egész számok, tehát a [0-255] intervallumból vett egész számok.
im.dtype
Ha 255-höz hozzáadok egyet, akkor az nem 256!
im[0][0][0]
im[0][0][0]+=1
im[0][0][0]
Miután meghatároztuk a DNS térszerkezetét a fenti kék ábrából elmenthetjük a képet! A használt kiterjesztés implicit módon meghatározza a kép fomrátumát.
imsave('data/out_mentett_kep.jpg',im) # így mentünk jpg-be
imsave('data/out_mentett_kep.png',im) # így mentünk png-be
imsave('data/out_mentett_kep.tiff',im) # így mentünk tiff-be
A Hierarchical Data Format vagy röviden hdf, egy széles körben elterjedt formátum nagymennyiségű tudományos adatok tárolására, és megosztására. Két fontos verziója használatos, melyek nem igazán kompatibilisek. Itt a HDF5-ös fájlok megnyitásáról lesz szó, mely jelentősen egyszerűbb adatcsoportosítást használ az elődjénél (4-es verzió).
A HDF5 fájlok esetében az értékes adatokat csoportokba, és alcsoportokba lehet rendezni, melyek között lehetőség van hivatkozásokat tenni. Úgy lehet elképzelni, mint egy kisebb fajta könyvtárszerkezetet, melyben szerteszét vannak az adatok.
A HDF5 fájlok belső szerkezete két fő egységből építhető fel, mint ahogy az ábrán is látszik. Leíró részek azaz metadatok illetve maguk az adatok. Az adatokat többdimenziós adattáblákban tároljuk.
Maga a HDF5 fájl belső csoportosítása hasonlóan hívható meg, mint egy hagyományos könyvtárstruktúra. Itt is definiálva van a "root" csoport, aminek alcsoportjai vannak, melyeknek (mint a könyvtárainknak) neveket adjhatunk. Egy adott adattömb elérési útvonala: /"csoportnév"/adatok
A pythonban a hdf5 fájlokat a h5py csomag tudja legegyszerűbben beolvasni, így itt ennek a működését mutatjuk be.
import h5py
A h5py.File
függvénnyel tudjuk a hdf5 állományokat megnyitni. Ebben a lépésben el kell dönteni, hogy olvasni, vagy írni szeretnénk a fájlt (lehet mindkettő is). Olvasni például, hasonlóan a korábbiakhoz, a második argumentumban megadott "r" opcióval lehet.
f = h5py.File("data/data.h5", "r")
Az adat-könyvtár elemeinek a neveit például a dict
-eknél megszokott keys
metódus segítségével tudjuk lekérdezni.
list(f.keys()) # ha nem rendezzük listába akkor nem írja ki szépen!
a hierarchiában egy szintel lejjebb pedig ezek a kulcsok találhatóak:
list(f["data"].keys())
Most nézzünk bele "data/data" csoportba, amiben a tényleges adatok szerepelnek:
f["data/data"] # Ez már egy adattáblát rejt.
f["/data/data"][:] # így már array-t kapunk!
A HDF5 fájlok nagyon hatékonyan tudják a bonyolult adatszerkezeteket tárloni. A hatékony adattárolást nagyban segíti, hogy az adattömbök különböző relációkat és összefüggéseket is eltárolhatnak. Ennek persze az az ára, hogy az ilyen fájlok felhasználó általi olvasása nehezebb, mint az egyszerű szövegfájlok esetén, a konkrét adatok eléréséhez ismerni kell ezen fájlok felépítését.
A következők megmutatjuk hogyan kell ábrázolni a HDF5 fájlok adatait.
f = h5py.File("data/h5ex_t_enum.h5", "r")
A values()
metódust alkalmazva látható, hogy ebben a mintafájlban csak 1 adatcsoport van, melynek a neve DS1. Sőt azt is megmutatja a rendszer, hogy 4x7-es mátrixot kell kiolvasni.
list(f.values())
Ahogy már megtanultuk a python imshow
parancsa képes a mátrixban tárolt adatok képi megjelenítésére (f["DS1"], egy mátrix).
imshow(f["DS1"])
Bővebb információt a HDF5 fájlok feldolgozásáról:
A fits a modern csillagászat legelterjetteb képformátuma. A fits képeknek nemcsak az a célja, hogy eltárolja a képi információt, hanem egyéb, a további feldolgozás szempontjából nélkülözhetetlen adatot is megőrizzen, mint amilyen az eszköz beállításai, a pontos idő stb.
A fits állományoknak alapvetően 2 fő része van. Az egyik a fejléc, ami a kép elemezéséhez szolgáló információkat tárolja, míg a másik a ténylegesen megfigyelt adatsor. Általában 2 dimenziós tömbök tárolódnak adatokként (amit a távcsőre szerelt CCD kamerák látnak), de van lehetőség több (maximum 999) dimenziós adattárolásra is.
Ebből a két fő részegységből szegmensek építhetőek, és összefűzhetőek 1 fits állományba. Ezeket a szegmenseket hívjuk, HDU-nak (Header/Data Units). Egy fits állomány több HDU-ból is állhat. Például 1 kép tárolhatja a különböző szűrőkkel készített felvételeket.
Szokás az első hdu-t az elsődleges (Primary), majd a többi hdu-t a kiterjesztett (Extend) jelzővel illetni. Ez azt is jelenti, hogy alapértelmezésben mindig a legelső fejléc és adattábla van használatban.
A fits képekben 3 féle adattábla lehetséges:
A fits fájlok feldolgozásához szükség van az astropy csomagra. Ebből a gigász modulból is az astropy.io kezeli a fits képeket. Illetve az astropy.wcs csomag lehetővé teszi a különböző koordinátarendszerek közötti átszámítást, így a képünket nem feltétlenül kell pixel-pixel módon ábrázolni.
#from astropy.io import fits
import astropy.io.fits as fits
#from astropy import wcs as wcs
import astropy.wcs as wcs
A mellékelt adatok közt található a data/HorseHead.fits
. Ha megnézitek hagyományos szövegmegjelenítővel, mint amilyen a bash-ban a cat
azt látjátok, hogy ez egy többnyire olvashatlan bináris állomány:
! cat data/HorseHead.fits | head -n 2 | tail -1
Az astropy csomag fits.open
parancsával lehet betölteni az állományt:
hdu=fits.open('data/HorseHead.fits')
Ennek a betöltött adatsornak több tulajdonsága is van. Az egyik ilyen, hogy megnézhetjük a benne levő HDU-kat. Ez esetben 2 szegmense is van a képnek.
hdu.info()
Ha kiválasztunk egy szegmenst, akkor lehetőség van megnézni a fejléc tartalmát a header
opcióval. Jól látszik, hogy mennyi minden bele van írva a fejlécbe.
len(hdu[0].header)
hdu[0].header[:10] # Ez csak az első 10 sor a header-ből
Magát a képi információt a data
opcióval lehet kiolvasni a szegmensből. Ez egy már ismerős numpy array.
image=hdu[0].data
image.shape
image
A csillagészatban használ fits állományok nagy előnye, hogy a képi információ mellet a fejléc olyan fontos információkat is tartalmaz, mint kép készítésének körülményei, illetve a kép pontos égi koordináták szerinti helyzetéről is vannak adatok. Ezeket a koordináta adatokat a wcs.WCS
paranccsal listázhatjuk ki.
kord=wcs.WCS(hdu[0].header)
kord
A koordinátainformációk birtokában lehetőségünk van olyan ábrát készíteni, aminek tengelyei az égi koordinátatengellyel egyeznek meg, így leolvasható a kép adott részének égi pozíciója.
Először készítsük el azt a "box"-ot, amibe a képet bele fogjuk helyezni, ez analóg módon történik a 3D-s ábrák rajzolásával:
subplot(111,projection=kord) # így mondjuk meg a matplotlib-nek hogy a égi koordinátákat használja
Végül töltsük fel a box-ot a képi információval.
subplot(111,projection=kord)
plt.imshow(image, cmap="magma", origin='lower')
plt.xlabel('RA')
plt.ylabel('Dec')