[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