A HTML dokumentumokból való szövegkinyerés közel sem triviális feladat -- úgy tűnhet, hogy elég kidobálni minden HTML taget és kész is vagyunk. Sajnos, már a tagek törlése is gyakran problémás, mert egy ártatlan HTML mélyén aljas Javascript-ek, kommentek, etc, etc.. lapulhatnak.
A másik probléma, hogy nem minden szöveg "szöveg" abban az értelemben, hogy érdemes vele foglalkozni: egy átlagos page jókora része kölünféle linkekből , feliratokból és egyéb haszontalan elemekből áll; és akkor még itt van a kommentek kérdése is.
Sztenderd és széles körben alkalmazott szemantikus tagelésnek pedig továbbra is híján vagyunk...
Jó hasznát vehetjük azonban a HTML dokumentumok fa-természetének, illetve a józan paraszti észnek -- pl. kiindulhatunk abból, hogy sok oldalon a cikkek szövegét P tagek közé ékelik.
És szerencsére itt van nekink a BeautifulSoup nevű remek python modul: HTML-t iterálható és kereshető objektumokká alakít. Ennyi az egész:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Ettől a kis változtatástól a kulcsszó-kiemelő sokkal tisztább bemeneti szövegekkel tud dolgozni, és sokkal jobb eredményt is produkál:
Egy másik érdekes megfigyelés, hogy az első 6 kulcsszó alapján a Google már elég jó eséllyel rátalál a kérdéses dokumentumra (és valójában lejjebb is lehet menni, tessék kipróbálni!). Így tehát bizonyítottnak tekinthetjük, hogy a Google is használ TF-IDF elemeket az algoritmusában:)
Korábban már írtam a kulcsszó kiemelésről a TF-IDF modell segítségével, most pedig végre volt egy kis időm, és megírtam rendesen minimálisan működőképesre.
Az igazi öröm számomra eközben a Google App Engine-nel való megismerkedés volt: a google ugyanis megengedi, hogy a felhőben futtassuk a kis alkalmazásainkat, ad hozzá egy elég gyorsan kiismerhető framework-ot, és nem utolsó sorban 1GB tárhelyet az adataink tárolására. INGYEN! (aztán ha több kell, lehet venni még)
A kulcsszó-kiemelő egy blog (vagy bámi más) RSS feedjének címét kéri, valamint még két paramétert: hány oldalt szeretnénk kielemeztetni a géppel és hány karakternél vágjuk le az oldal alját (ezt azonnal megérted, ha rákattintasz).
A dolog persze messze nem tökéletes, pl. szótövezés nincs beépítve, és nagyon kevés dokumentumhoz képest elemzi a kód az adott dokumentum kifejezését (egészen pontosan csak az adott feedhez képest). Igazából az a meglepő, hogy így is viszonylag értelmes dolgokat dob ki!
Tessék ezért minnél több feed címét beírni, mert az alkalmazás szorgalmasan elmenti a statisztikákat, ami a későbbiekben nagy segítség lesz nekem!;)
Az Udacity nevű online-egyetemen futó algoritmika kurzuson éppen a közösségi hálózatokról van szó, illetve a téma kapcsán a gráfokról -- isteni, csak ajánlani tudom!
A
kurzuson bevezették a csomósodási együttható (clustering coefficient)
fogalmát is, amely azt mutatja meg, hogy egy gráf adott csúcsa mennyire
foglal el központi helyet a hálózatban. A kiszámításához két dolgot kell
tudni:
egy blogra hány oldalról mutat link (legyen LINK)
a fenti oldalak között hány link van (legyen INTERLINK)
Az együttható kiszámítása a következő képlettel történik:
2*INTERLINK / (LINK*(LINK-1))
Minnél sűrűbb a hivatkozó oldalak közti linkhálózat, ez az érték annál nagyobb lesz.
A
csomósodási együttható segítségével meg tudjuk mondani, mely blogok
körül csomósodnak a linkek -- ezek az oldalak vélhetően hasonló
témakörben publikálnak, hiszen különben nem linkelnének egymásra. Ezzel
ellentétben, egy nagyon népszerű, sok befelé mutató linkkel rendelkező
blognál ez az érték valószínűleg kisebb, hisz a hivatkozók egymásra
ritkábban hivatkoznak.
A gyakorlatban több problémával is
meg kell küzdeni: először is, az adatok rossz minősége itt már komoly
probléma -- az index egymást körbehivatkozó foci-blogjai nagyon csúnyán
eltorzítják az ábrát. Ezen kívül, komolyan el kell gondolkodni azon is,
hogy mit számolunk: a befelé vagy a kifelé mutató linkeket, esetleg mind
a kettőt? Végül, egy kicsi hálózatnak jellemzően nagyobb lesz a
csomósodási együtthatója, ezért valamilyen határt is fel kell állítani
-- az itt látható ábrákon 5 hivatkozásnál kevesebbel rendelkező blogok
nem válhattak 'központokká'.
1. ábra
Az
1. ábrán kiválóan látható, hogy a boros blogok szépen kirajzolódó
hálózatokba szerveződnek (a hálózat központja mindig színes hátterű, és
az adott hálózat élei is ilyen színűek)
Itt
az látható, hogy a hálózatok átfedik egymást -- egy csúcs több
hálózatnak is tagja lehet, hiszen bármely szomszédból lehet "központ",
ha elég magas a csomósodási együtthatója.
Itt az index focis blogjai egymásra települt hálózatokat
alkotnak, ezért a sok párhuzamos él. Értelmezhetetlen, de legalább
szép:)
Szép a gráf, de áttekinthetetlen. Mennyivel szebb egy scatter plot (hogy van magyarul?), amelyen minden pont egy linket képvisel; az X koordináta az mondja meg, honnan, az Y pedig, hogy hová mutat (ez ugyanaz, mintha felírnánk a gráfot mátrix-alakban).
A tengelyek mentén a blogokra mutató linkek összessége (kékkel, az Y mentén), illetve a blogokon található hivatkozások száma (pirossal, X mentén) látható. A legnépszerűbb oldalakat fel is írtam az ábrára (kékkel), mint ahogy a legtöbb oldalra mutató blogok nevét is (pirossal). Ebből látszik, hogy a népszerű oldalak nem feltétlenül hivatkoznak sokat (itt persze közrejátszik az adatok minősége is, ugyanis teljes szöveget veszünk, olvasói kommentekkel is, amelyekben sok link lehet).
Érdekes kérdés, vajon ezek az adatok alapján csoportokba lehet-e rendezni a blogokat, és vajon ezek a csoportok kirajzolnak-e valamilyen értelmes mintát? (a gráfot nézegetve látható valamiféle mintázat, pl. a politikai blogok egymáshoz közel vannak). Ehhez valamilyen clustering-algoritmust kell alkalmazni, de mielőtt ezzel megpróbálkoznék, még át kell olvasnom egy-két dolgot;)
Kis híján kigyulladt a számítógépem, de végül mégiscsak sikerült rávenni a Graphviz-t, hogy számolja le a magyar blogoszféra első 500 oldalát. Az előző posztban a graphviz dot parancsával számoltam (ez szép, görbe, csúcsokat gondosan megkerülő éleket rajzol) -- ennek azonban sajnos ára van (lassú). Az fdp parancs egyszerű vonalakkal operál.
Érdekes, hogy így sokkal szebben látszik a linkek sűrűsége. Pl. az ábra jobb alsó felén az index saját foci-EB blogjai vannak, amelyek minden oldala linkel egymásra, de "kintről" már sokkal kevesebb kapcsolódási pont van. Feljebb, balra, az igazi sűrűben továbbra is a politikai-közéleti blogok uralkodnak.
Egyébként már a 150 oldalas mintán is látszik az 500 oldalas mintán kirajzolódó struktúra: ugyanazok az oldalak a legnépszerűbbek, és hasonlóképpen is rendeződnek egymás mellé.
Kicsit azért ciki, hogy ha beírom a
google képkeresőbe a "magyar blogoszféra" kifejezést,
Tóta W. Árpád valamint Orbán Viktor képe jelenik meg. Úgyhogy
kéne csinálni valami informatívabbat.
Az webet jól lehet ábrázolni
gráfként, hiszen minden oldal egy csomó másikra mutat -- minden
oldal csúcs, minden link él. Azt is tudjuk a google óta, hogy
minnél több oldal mutat egy oldalra, az annál fontosabb.
A rajzolás piszkos munkáját meg
lehet spórolni a graphviz programcsomaggal -- amely egy
szkriptelhető, gráf-rajzoló rendszer. A lényeg elovasható pl.
itt.
Gyorsan írtam egy buta pókot, ami
elindul a blog.hu-n, és az ott talált linkeken továbbmászik (hogy
csak blogokat találjon, csak a blog.hu-s linkekre figyelünk).
Összeszámoljuk, honnan hová mutatnak a linkek. Ez után generálunk
egy .dot kimenetet, ami hihetetlenük egyszerű:
digraph blogosphere {
//ezek a csúcsok, vagyis az egyes
blogok
blog1 [label="első blog"]
blog2 [label="második blog"]
//satöbbi
// itt jönnek az élek
blog1 -> blog2
blog1 -> blog3
satobbi -> blabla
}
Érdekes kérdés, hogy mennyi idő
után tiltja le a blog.hu szervere a pókot -- 500 kérést gyorsan
egymás után még kibír, de valószínűleg mindennek van határa...
A fentiek után a .dot file-t
megetetjük a graphviz-zel és kész is vagyunk -- minden másról a
program gondoskodik. Jó, mi?
dot -Tpng teszt500.dot >
teszt500.png
Mivel a graphviz próbálja minnél
ésszerűbben elrendezni az éleket, az egymásra gyakran mutató,
vagyis tartalmilag közel álló blogok közel kerülnek egymáshoz.
Pl. a modoros, dezsőmail és a gyűlölt ellenségeink (ezek vicces
blogok, ha valaki nem ismernő) egymáshoz közel, az ábra felső
részében helyezkednek el, jobbra lent találhatók a politikus
blogok, balra középen pedig a meztelen csajos oldalak helyezkednek
el. De vannak itt furcsaságok is: ide került a tévé-sorozatos és
a cuki állatos blog is. Hogy mi vannak!
Egyébként, itt egy 150 oldalnál
megálló pók útja látható -- 500 oldal egyszerre nem fér fel a
lapra (elfogy a memória), de bizonyosan van valami okos megoldás
erre is.
Az első rész az adatok beszerzéséről, használható formába öntéséről, a szemét eltávolításáról és az értelmes összefüggések felkutatásáról szól.
Tegyük fel, hogy szeretnénk kideríteni, hogy egy weboldalon körülbelül miről írnak, aztán ezt gyorsan áttekinthető formában megtekinteni -- egy jól felépített oldal esetében a lap címlapja magáért beszél, esetleg még kulcsszavakat is mellékeltek -- de mi van, ha mégsem? Az index.hu pl. viszonylag értelmes címekkel látja el a cikkeit, de nem biztos, hogy ez elmondható egy pletykalapról vagy egy személyes blogról is.
Jó ötlet lehet minden oldalnál megjeleníteni a legjellemzőbb kulcsszavakat -- a fenti képen ennek egy kezdetleges változata látható. De hogyan szereztük meg ezeket?
Az adatokbeszerzésének az első lépése itt az oldalak letöltése lesz -- már itt is számos problémáva ütközhetünk. Ha szerencsénk van, találhatunk RSS feedeket, ha nincs, akkor különféle trükkökkel kell kinyerni a releváns linkeket a HTML lapokból. Ezután a tisztítás következik, ami esetünkben a HTML tagek kidobását, esetleg a reklámok, kommentek, stb. eltávolítását jelenti. A magyar nyelv esetében külön probléma a karakterkódolás is.
A következő lépés a finomabb szűrés -- írásjelek, rövidítések, számok, stb... Hatalmas -- nyelvspecifikus -- probléma, hogy a magyar ragozó nyelv, így egy jellemző kulcsszó külünböző alakjait nem biztos, hogy sikerül felismerni.
Eddig eljutva látszólag használható adataink vannak: egy csomó cikk, tiszta szöveges formában. A kulcsszavak megtalálása látszólag pofonegyszerű: megszámolunk minden szót (pl. az python NLTK eszközeivel), és a leggyakoribbakat kijelöljük kulcsszónak (ez a bag of words technika). Sajnálatos módon azonban minden nyelvben a leggyakoribbak a segédszavak (a, az, van, meg...), így ezzel semmire nem megyünk. Ha ezeket a szavakat ignoráljuk, már valamennyire juthatunk, de még így sem az igazi -- kifinomultabb modellre van szükség.
A Számítógépes Nyelvészet blogon már szóba került a TF-IDF formula, mint a keyword kinyerés elterjedt eszköze (leírás itt és itt). Az eljárás lényege, hogy egy dokumentum jellemző kulcsszavait nem csak a dokumentumhoz képest, hanem más (lehetőleg hasonló) dokumentumokhoz képest is vizsgáljuk: ha az index.hu újságírói szívesen használnak bizonyos kifejezéseket, akkor ezt figyelembe kell vennünk a kulcsszavak keresése közben, és az ilyen "általában gyakori" kifejezéseket "le kell pontoznunk".
Egészen pontosan így működik a formula:
kulcsszó fontossága: TF x IDF
TF: (term frequency): egy kulcsszó előfordulása az adott dokumentumban IDF: (invers document freqency) egy kulcszó előfordulása a teljes dokumentum-szettban -- majd ennek az értéknek az "inverze", pl. reciproka, logaritmusa, stb.
Így a fontos kulcsszavak azok lesznek, amelyek gyakoriak az adott dokumentumban ÉS ritkák a teljes szettben.
A fenti két linkeken ezt a modellt vektor térben mutatják be. Ez elsősorban akkor jön jól, ha NAGYON SOK adatunk van, mivel így könnyeb lesz számolni (mármint a gépnek;)
Érdekes kérdés, hogy mennyire KEVÉS adatnál kezd el működni a modell. Hiszen, az egyik viszonyítási pontunk a teljes dokumentum-szett, így ha az túl kicsi, akkor nem biztos, hogy a jól méri fel a modell a kulcsszavak valódi fontosságát. A fenti próba azt mutatja, hogy meglepően kevés szöveg is elég -- az index címlapon egyszerre körülbelül 40 cikk szerepel -- ezeken végigfuttatva a modellt már értelmes eredményeket produkál.
Van tehát egy használhatónak tűnő adatszettünk és egy modellünk. A következő lépés az adatok tetszetős megjelenítése és a felhasználóval való interakció lesz.
A processing.org-on igazán remek oktató anyagok találhatók (szerintem ezek egy része átfedésben lehet a külön megvásárolható könyvek tartalmával, bár ki tudja...). A vektorokról szóló anyag inspirálta a következő alkotást.
Húzd a lap felé az egeret, majd kattintgass, vagy nyomkodd az ENTER-t!
Az oktató anyag nagyon jól elmagyaráz mindent a vektorokkal és a mozgás modellezésével kapcsolatban. A lényeg tulajdonképpen az, hogy a processing rendelkezik egy beépített PVector osztállyal -- ez az adattípus két- és háromdimenziós vektorok tárolására lett kitalálva, a metódusai pedig az ehhez tartozó matematikai műveletek (összeadás, kivonás, skalárszorzat, vektorszorzat, normalizálás, etc.) elvégzésének a nyűgét veszik le a vállunkról.
A fent látható sketch-ben tulajdonképpen nem történik más, mint hogy a repülő labdákat mindig abba az irányba gyorsítjuk, amelyik irányba az egérkurzor esik tőlük. Szóval, mindig az egér felé akarnak repülni. Az érdekesség ott van a dologban, hogy mivel egészen addig, amíg el nem érik a kurzort, gyorsítjuk őket, mindig túlrepülnek -- hogy aztán megfordulhassanak és ismét gyorsulhassanak, csak immár a másik irányba. És így tovább, a végtelenségig.
A processing nem csak két dimenzióban enged firkálni a rajzfelületre, de három dimenziós világokat is elég egyszerű létrehozni. Következzenek az első tapasztalataim.
Húzd az egeret a rózsaszín felület fölé!
A kód, utána pedig a kommentár:
void setup() { size(640, 360, P3D); background(0); frameRate(10); } void draw() { background(#FF66CC); lights(); for (int i=0; i <= 32; i++) { for (int c=0; c < 20; c++) { int plusz=0; int forgat=0; float tav=dist(i,c,int(mouseX/20),int((height-mouseY)/20)); if (tav < 10) { //plusz=int((11-tav)*4); forgat=int((11-tav)*3); } fill(255); lemez(i*23,360-plusz,-c*23,forgat); } } } void lemez (int x,int y,int z, int forgat) { pushMatrix(); translate(x,y,z); rotateX(radians(random(forgat))); rotateY(radians(random(forgat))); rotateZ(radians(random(forgat))); scale(10); beginShape(QUADS); vertex(-1, 0, -1); vertex(- 1, 0, 1); vertex( 1, 0, 1); vertex(1, 0, - 1); endShape(); popMatrix(); }
A rajzlapot a harmadik dimenzió felé megnyitni a size parancs harmadik paraméterével tudjuk. Az alapvető rajzoló funkciók ugyanúgy működnek, vagyis minden képkockánál törölhetünk (vagy éppen nem), vonalat húzhatunk, stb.
size(640, 360, P3D);
A három dimenziós testek építése egy kicsivel trükkösebb, mint a két dimenziós rajzolás. A kódban ez mind a lemez() függvényben történik. Először minden testet fel kell építenünk egy pufferben, amit a
pushMatrix();
paranccsal hozunk létre, majd a
popMatrix();
rajzoljuk ki a tartalmát a "vászonra".
Közvetlenül a puffer létrehozása után kell megmondanunk azt is, hogy hová akarjuk elhelyezni a testet, illetve mennyit szeretnénk forgatni rajta (radiánban kéri!). A kódban ez így néz ki:
translate(x,y,z);
rotateX(radians(random(forgat)));
rotateY(radians(random(forgat)));
rotateZ(radians(random(forgat)));
Ezek után nem meglepő, hogy az olyan primitív testek, mint a box() vagy a sphere() csak egy paramétert kérnek: a méretüket. Ha magunk szeretnénk építkezni, megtehetjük:
beginShape(QUADS);
vertex(-1, 0, -1);
vertex(- 1, 0, 1);
vertex( 1, 0, 1);
vertex(1, 0, - 1);
endShape();
Ilyen felületekből akármennyit létrehozhatunk. Fontos megjegyezni, hogy ez egy relatív koordináta-rendszer, vagyis ahhoz, hol fog megjelenni a képernyőn, nincsen semmi köze (ezt a translate csinálja). Annál fontosabb a (0,0,0) pont: e körül tudjuk forgatni a testet.
Ennyivel gyakorlatilag már képesek vagyunk egyszerű három dimenziós világokat készíteni.
További példákért és információért ide érdemes ellátogatni, illetve továbbra is figyelemmel kísérni a Kép és Kód blogot:)
Nagyon megörültem, hogy a teljes BKV menetrend-adatbázis elérhető, és szabadon lehet vele játszadozni -- a GTFS formátum ugyanis ezt erősen megkönnyíti. Az adatok egyszerű plain text-ben, egészen pontosan CSV-ben, vagyis veszőkkel elválasztva érkeznek. Ezt az Excel és társai minden további nélkül tudják olvasni.
Mivel az adatbázis nagyon sok mindent tartalmaz, szükséges egy kis előszűrés -- egyrészt, hogy egyszerűbb legyen az élet, másrészt, mert a processing bizony elég lassú. A nagy adatbázis alatt kb. 200 megabájt szöveges adatot kell érteni, vagyis egy táblázatkezelővel még éppen, egy egyszerű python szkripttel pedig pikk-pakk megbírkózhatunk vele.
Én legalábbis ezt csináltam: csupán az útvonalakat szerettem volna ábrázolni egy minimálisan interaktív térképen. Ehhez teljesen felesleges foglalkozni a járatok indulási idejével, vagy éppen azzal, hogy melyik jármű mikor melyik megállóban áll. Nekem csak annyit kell tudni, hogy melyik járat mely megallókat érinti. Csakhogy, a GTFS külön táblákban tárolja a járatokat, a megállókat és a járatok által érintett pontokat, Ezért szükség volt az adatok előkészítésére, ami python-nal és táblázatkezelővel történt. Természetesen a legelegánsabb megoldás az összes adatot bedobni egy adatbázisba, és táblákon átívelő lekérdezéseket csinálni, de verébre felesleges ágyúval lőni.
Tehát, lássuk a működő programot (mozgatás: az egér húzgálásával, zoom: +/-):
A forrás az alábbi linken érhető el. A kódot viszonylag sűrűn kommentáltam. Talán érdemes kiemelni, hogy processing-ben nagyon kényelmes a saját adat-típusok (objektumok) létrehozása (ilyenben tárolom a megállókat és az útvonalakat). A másik megjegyzés, hogy ebben a programban a folyamatosan újrainduló draw() funkció csak a hosszúsági és szélességi koordináták kiírásáért felel; a térképet a program elején, illetve csak akkor rajzoljuk ki, ha pl. elmozdítottuk (ugyanis elég sokat kell számolni hozzá). A mozgatásra és a zoomolásra a mousePressed() és a keyPressed() funkciók figyelnek (ezek a nyelvbe beépített funkciók).
A Statisztikai Hivatalnál elérhető a Helységnévtár, amiben megtalálható az összes magyar település földrajzi koordinátája (és még számos egyéb). Remekül el lehet szórakozni például az irányítószámok eloszlásának ábrázolásával:
De ami ennél sokkal felvilanyozóbb: a BKV fél éve publikálta a teljes menetrend-adatbázisát. És nem is akárhogy, hanem a Google Maps által bevezetett GTFS formátumban -- így gyakorlatilag bárki megírhatja a saját menetrend-tervező applikációját. Nekem persze nincsenek ilyen ambícióim, de azért jó tudni, hogy Budapetről is van egy csomó egyszerűen feldolgozható földrajzi adat (nem is olyan rég került fel a netre a Budapest egy napja videó -- szintén ezekből táplálkozik).
Ez Budapest összes viszonylata -- a hiba egyelőre ott van, hogy csaka végpontokat kötjük össze, vagyis pl. a körúti villamosból csak egy vonás marad. A HÉV és a metróvonalak azonban már itt is felismerhetők.
A Számítógépes Nyelvészeten korábban már szóba került a processing programozási környezet,
amelyet azért terveztek, hogy egyszerűen és hatékonyan lehessen
vizuális alkalmazásokat készíteni: egy java-ra épülő
(pontosabban, a java alá épülő) nyelvről van szó, amely a
számos grafikus megjelenítéssel kacsolatos feladatot megkönnyít
a beépített funciók segítségével.
Mint már akkor Zoli elmondta, nem egy
játékról van szó, hanem egy igen hatékony eszközről; ugyanezt
Ben Fry (a nyelv egyik atyja), Visualizing Data c. könyvében úgy
fogalmazza meg, hogy kész eszközök helyett a processing
építőkockákat ad -- egyedi problémákhoz ugyanis szinte
lehetetlen előre legyártott szabványos megoldásokat kitalálni.
A processing építőkockái
valójában nem mások, mint a beépített funkciók -- valójában
mindent a Java programnyelv végez, így nem is meglepő, hogy a
szintaxis megegyező; és az sem, hogy bármikor "kinyúlhatunk"
a processing nyelvből a Java funkcióihoz.
Mit szeretnénk tehát? A processing
két dologban jó: a vizualizációban és az interaktivitásban;
tehát -- hogy újra feltaláljuk a spanyolviaszt -- készítünk egy
primitív tag-felhőt. A megoldás annyiban nem lesz szabványos,
hogy kezdetben minden tag-et azonos méretben fogunk megjeleníteni;
csak utóbb, a az egér mozgatásával dönti el a felhasználó,
hogy mennyire szeretné "kiugrasztani" a gyakran előforduló
elemeket. Tehát, lesz egy "áttekintő nézetünk" és egy
"közelítő nézetünk".
Áttekintő nézet -- minden szó egyforma méretű
A gyakori szavakat kiemeltük
OK. A legegyszerűbb processing program
két funkcióból áll: a setup() és a draw(). A
setup() induláskor fut le egyszer, mint neve is mutatja, itt
érdemes elhelyezni minden kezdetben szükséges lépést. Pl., mi
itt állítjuk be a rajzfelület méretét (800x600), itt töltjük
be a betűtípust és itt olvassuk be az adat.txt-ből a
szavakat, amelyeket majd később ki szeretnénk írni a képernyőre.
Ezután a draw() funkció fut
le. Ez, mint neve is mutatja, alapvetően a megjelenítésért felel,
de természetesen bármi mást is elhelyezhetünk itt. Kiemelt
szerepe abban áll, hogy folyamatosan ismétlődik, vagyis miután a
program mindent kirajzolt, azonnal újra kezdi. Hogy mire jó ez? Ha
úgy képzeljük el a dolgok, mint az egymást követő filmkockákat,
egyből értelmet nyer a dolog: ha a két kocka közt nincs eltérés,
akkor nem veszünk észre semmit. Azonban ha van, akkor mozgásba
lendül a kép. Pl., ha egy kirajzolt pont koordinátáit minden
egyes funkció-híváskor megnöveljük egyel (x++;), akkor egy mozgó
pont lesz az eredmény. A processing környezet tehát azt a
könnyedséget adja, hogy nem kell magunknak megírnunk a "filmkockák
kirajzolásáért" felelős részt, elég csak a képekkel
foglalkoznunk.
Ezen a ponton érdemes megjegyezni,
hogy a processing komolyan veszi a globális és lokális változók
kérdését. Pl. a draw() funkción belül deklarált változók
minden egyes újrahíváskor elvesznek, így ha pl. a mozgó képpont
x koordinátáját az x változóban tárolnánk, azt
mindenképpen globálisan (vagyis a funkción kívül) kell először
deklarálnunk. A programunkban pl. ilyen az adat[], meret_szamlalo
vagy a lastMX.
Az interaktivitás beépítését a
processing azzal támogatja, hogy nagyon egyszerűvé teszi teszi a
különböző események figyelését. Pl. minden alkalommal, amikor
kattintunk, a mousePressed() funkció kerül meghívásra,
majd visszatér a program oda, ahol abbahagyta a futást. Ugyanez a
történik a mouseMoved() funkció esetén is. Az egérkurzor
koordinátáit a mouseX ill. a mouseY változókból
tudhatjuk meg.
Lássuk tehát, mi történik az
interaktív szövegfelhőnk kódjában. Először deklarálunk néhány
globális változót (mivel azt szeretnénk, hogy minden funkció
elérje ezeket). Ezután elindul a setup(), ami betölti az
adat.txt tartalmát (itt a szavak és a hozzájuk
tartozó értékek találhatók).
Végül elindul a draw(), amely
folyamatosan ismétlődik a program leálltáig. Először
kirajzoljuk az "irányító felületet" -- ez az a része a
képernyőnek, amelyen ha megmozdítjuk az egeret, akkor változik a
szavak mérete. Majd kiszámoljuk (egy gyökvonással), hogy hány
sorba és hány oszlopba rendezzük az adatainkat. Ezután elindítunk
egy ciklust, amely szép sorban kiírja megfelelő helyekre az adat[]
tömbben tárolt szavakat. Ha a szó maximális mérete nagyobb, mint
az aktuálisan beállított szövegméret, akkor az utóbbit
használjuk. Ha az aktuális szövegméret nagyobb, akkor a szó
maximális méretét használjuk.
Az utolsó két funkció az egér
mozgatását és az egérkattintást figyeli. Ha megmozdítjuk az
egeret ÉS a kurzor a "kezelőfelület" felett áll, akkor
növeljük vagy csökkentjük a szöveg méretét (attól függően,
hogy jobbra vagy balra húztuk az egeret). Ha kattintunk, akkor egy
új szöveg-elrendezést kérünk -- ezt egyszerűen úgy érjük el,
hogy megkeverjük az adat[] tömböt.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1. A virtuális gép és a grafikus
felület sajnos lelassítja a program futását. Nagyon. Ezért az
egymásba ágyazott ciklusokkal, nagy tömbökkel és minden
hasonlóval csak nagyon óvatosan szabad bánni. Szerencsére a
bonyolultabb grafikus műveletekhez vannak beépített funkciók.
2. A Java típusai sokkal finnyásabbak,
mint mondjuk a python-éi. A float nem változik automatikusan
integerré, a string-et nem lehet csak úgy pikk-pakk karakterekké
szedni, stb... A tömbök sem túl rugalmasak: deklaráláskor el
kell döntenünk, milyen hosszúak legyenek, tehát nem tudjuk őket
a végtelenségig bővíteni. Többdimenziós tömbök léteznek, de
egy tömbnek csak egy eleme már nem lehet egy újabb tömb.
Dictionary/hash típus nincsen.
4. A programok könnyen konvertálhatók
java appletté, illetve az processing.js javascript könyvtár
segítségével közvetlenül böngészőből is futtathatók.