[python] Vykreslování grafů

Karel Šrot karel.do.pekla.zajel na seznam.cz
Pátek Květen 25 08:55:27 CEST 2007


Zdravim,

pocitat funkcni hodnoty a pak je spojit (lomenou) carou je naprosto 
bezny zpusob. Treba Maple (progrma pro symbolicke vypocty) pocita 
defaultne jen sto referencnich bodu. Pokud je v nejakem bode hodnota 
nedefinovana (deleni nulou), Maple ji ignoruje (tedy bodu je pak min a 
cara lomenejsi). Pomoci parametru lze specifikovat, zda se maji hledat 
body nespojitosti. V tom pripade se pomoci "sofistikovanych" algoritmu 
tyto body hledaji. Vcelku jednoduchou metodu Jan Jakubuv, ikdyz trochu 
nepresne. To, ze je funkce nespojita jeste neznamena, ze ma limitu v 
tomto bode rovnu nekonecnu.

Ja osobne bych tu moznost hledani bodu nespojitosti pouzil, tedy pokud 
by uzivatel nic nezaskrtl, tak by se nehledaly a kresleni by bylo 
rychlejsi.
V opacnem pripade bych se smiril s pomalosti a pouzil bych pro hledani 
bodu nespojitosti toto:
Nejdrive si rozdelim cely interval na nekolik mensich, treba pomoci 200 
(ci vice) referencnich bodu. Budu mit treba seznam [[0,1], [1,2], [2,3],...]

Neni-li funkce v nejakem bode X definovana, je to bod nespojitosti. Do 
seznamu ulozim hodnoty dva intervaly, pricemz pravy krajni bod prvniho 
je X-E, a levy krajni bod druheho X+E, kde E je dostatecne mala hodnota, 
ktera na grafu odpovida treba mene nez jednomu pixelu v grafu (to aby to 
nebylo poznat).

Prochazim jednotlive intervaly a urcim tangens lomene cary, tedy 
(f(a)-f(b))/(b-a). Pokud by byl tangens v absolutni hodnote vetsi nez 
nejaka krajova zvolena hodnota (pro zacatek treba 5), bude interval 
podezrely. Ulozim interval do seznamu podezrelych intervalu. Az mam 
hotovo, prochazim kazdy podezrely interval.
Rozdelim jej tedy napul a misto nej puvodniho mam ted dva intervaly. 
Pocitam totez pro oba a ten, ktery je stale podezrely (hodnota tangens 
bude v abs. hodnote jeste vetsi, nez byla predtim), budu zkoumat dal. 
Ten, co uz podezrely neni, tak dam ze seznamu podezrelych pryc. Kdyz by 
nahodou v polovine intervalu nebyla funkce spojita, pouziji to rozdeleni 
na dva intervaly s tim S-E, S+E a ani jeden z intervalu neberu za 
podezrely, protoze bod nespojitosti je mezi (tedy dam tyto intervaly 
mezi nepodezrele a koncim). Podezrele intervaly muzu okrajovat znova a 
znova, dokud hodnota tangens neprekroci nejakou danou mez. Pak 
prohlasim, ze na intervalu je funkce nespojita a tento interval kreslit 
nebudu. Protoze je strasne malej, tak to ani nebude vadit.

Az mi to bude stacit, tak pospojuji vsechny nepodezrele intervaly. Takze 
seznam intervalu setridim, aby lezely za sebou. Pak je projdu odleva a 
kdyz dva sousedni maji spolecny krajni bod, tak je nahradim jednim 
velkym. Takze uplne nakonec budu mit seznam intervalu, kde je funkce 
spojita. V mezerach mezi temito intervaly jsou body nespojitosti, ale 
tyto mezery jsou male. Takze nakonec vykreslim gram funkce na kazdem z 
techto intervalu.

Avsak kresneni nespojitych funkci je vzdy problem. Kdyz je funkce hodne 
divoka (jde rychle do nekonecna), tak se muze stat, ze vam pretece 
rozsah datoveho typu. Ale co se da delat.

Snad to bylo trochu jasne, zkus si to kdyztak projit s tuzkou, papirem a 
grafem. Mnou uvedeny algoritmus bude potrebovat optimalizovat, protoze 
se tam zbytecne moc manipuluje se seznamy a tak. Lze ho navrhnout lip, 
ale ja zvolil tuto formu kvuli srozumitelnosti. Az ho pochopis, tak 
jiste prijdes na to, ze se obejdes bez nadbytecneho vytvareni seznamu 
itervalu.

No snad ti to pomuze, preci jen me to stalo trictvrte hodiny zivota. :-)

Karel


> 2) Nevím jak vy byste vypočítávali body pro vykreslení grafu, ale já na 
> to mám takovoutu metodu:
>  
> cislo=spodni_hranice
> while cislo < horni_hranice:
>        x=cislo
>        y=eval(funkce.replace('x',cislo))
>        body.append([x,y])
>        cislo=cislo+preciznost
>  
> Ale výpočet se mi zdá poměrně dlouhý a tak se ptám jesetli vás nenapadá 
> něco efektivnějšího. Dále jakou hodnotu by měla mít proměnná preciznost 
> (nebo jestli by měl mít uživatel možnost ji nastavit).
> 3) Nyní program dostává body jako souřadnice x,y a vykresluje jednotlivé 
> pixely. Pochopitelně je to způsob relativně nepřehledný, protože pak 
> může být na plátně jenom několik nic neříkajicích teček a proto by je 
> chtělo nějak spojit. Napadlo mě spojit každé dva vedlejší body čárou ale 
> pak mi došlo že to je nemožné, například kvůli grafu 1/cos(x).  Nevíte 
> jaký způsob používají jiné programy?
>  
>  
> Děkuji za případné odpovědi.
>  
> Jakub Vojáček.


Další informace o konferenci Python