Mandelbrotmenge mit Tkinter

Code-Stücke können hier veröffentlicht werden.
Antworten
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

Naja, dazu gibt's nicht viel zu sagen, ausser: ja, mir is heute fad :wink:

Code: Alles auswählen

from Tkinter import *

SIZE = 200
LEFT = -2
RIGHT = 0.5
TOP = 1.25
BOTTOM = -1.25
ITERATIONS = 20

root = Tk()
can = Canvas(width=250,height=200)
can.pack()

for y in range(SIZE):
	for x in range(SIZE):
		z = complex(0,0)
		c = complex(LEFT+x*(RIGHT-LEFT)/SIZE, TOP+y*(BOTTOM-TOP)/SIZE)
		norm = abs(z)**2
		for count in range(ITERATIONS):
			if norm <= 4.0:
				z = complex(z.real*z.real - z.imag*z.imag + c.real, z.imag*z.real*2+c.imag)
				norm = abs(z)**2
		if norm <= 0.05:
			can.create_text(x,y,fill='black',text='.')
		elif norm <= 0.10:
			can.create_text(x,y,fill='green',text='.')
		elif norm <= 0.15:
			can.create_text(x,y,fill='blue',text='.')
		elif norm <= 0.20:
			can.create_text(x,y,fill='red',text='.')
		elif norm <= 0.25:
			can.create_text(x,y,fill='yellow',text='.')
		elif norm <= 0.30:
			can.create_text(x,y,fill='grey',text='.')
		root.update()

root.mainloop()
Gruß, mawe
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das ist ja super cool!!!!

Aber ich sehe, das du eigentlich Text-Punkte setzt... Gibt es nicht auch wirkliche Grafische Sachen in TK???

Hab es mal zum Benschmarken mit psyco benutzt: http://python.sandtner.org/viewtopic.php?p=14103
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi jens!

Klar gibt's auch "graphische Sachen" in Tkinter. Allerdings fand ich die Methode mit den Textpunkten für diese Anwendung am einfachsten, weil ich nur jeweils einen x und y Wert angeben muß. Mit create_oval oder create_rectangle wären es immer 2 (und dafür bin ich einfach zu faul :wink:).

Gruß, mawe
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das habe ich mir schonb fast gedacht... Also nicht das mit deiner Faulheit :)
ramin
User
Beiträge: 8
Registriert: Sonntag 15. Mai 2005, 15:07

Also irgendwie schaut das Ergebnis komisch aus !

habe mir den Code angesehen:

1) Du arbeitest mit dem Complex Datentyp, warum rechnest Du dann z=z*z+c 'händisch' ?

2) Dir Farbe ergibt sich nicht durch den Abstand vom Ursprung (norm), sondern durch die Anzahl an Iterationen, bis der Punkt den Kreis mit Radius 2 (norm<4.0) verläßt, oder eben nicht. Hier also abhängig von count ist.

Jetzt schaut das Ergebnis beseer aus, oder ?

Grüße,
Ramin

Code: Alles auswählen

from Tkinter import * 

SIZE = 200 
LEFT = -2 
RIGHT = 0.5 
TOP = 1.25 
BOTTOM = -1.25 
ITERATIONS = 20 

root = Tk() 
can = Canvas(width=250,height=200) 
can.pack() 

for y in range(SIZE): 
    for x in range(SIZE): 
        z = complex(0,0) 
        c = complex(LEFT+x*(RIGHT-LEFT)/SIZE, TOP+y*(BOTTOM-TOP)/SIZE) 
        norm = abs(z)**2 
        for count in range(ITERATIONS): 
            if norm <= 4.0: 
                #z = complex(z.real*z.real - z.imag*z.imag + c.real, z.imag*z.real*2+c.imag) 
                z=z*z+c
                #norm = abs(z)**2 
                norm=abs(z*z)
            else:
                break
        if count<=5:
            can.create_text(x,y,fill='grey',text='.') 
        elif count<=10:
            can.create_text(x,y,fill='green',text='.') 
        elif count<=15:
            can.create_text(x,y,fill='blue',text='.') 
        else:
            can.create_text(x,y,fill='black',text='.') 
#         if norm <= 0.07: 
#             can.create_text(x,y,fill='black',text='.') 
#         elif norm <= 0.10: 
#             can.create_text(x,y,fill='green',text='.') 
#         elif norm <= 0.15: 
#             can.create_text(x,y,fill='blue',text='.') 
#         elif norm <= 0.20: 
#             can.create_text(x,y,fill='red',text='.') 
#         elif norm <= 0.25: 
#             can.create_text(x,y,fill='yellow',text='.') 
#         elif norm <= 0.30: 
#             can.create_text(x,y,fill='grey',text='.') 
        root.update() 

root.mainloop() 
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wie ist es damit:

Code: Alles auswählen

from Tkinter import *

import time

import psyco
psyco.full()
print "import Psyco"

StartTime = time.time()

SIZE = 100
LEFT = -2
RIGHT = 0.5
TOP = 1.25
BOTTOM = -1.25
ITERATIONS = 20

root = Tk()
can = Canvas(width=SIZE,height=SIZE)
can.pack()

for y in range(SIZE):
    for x in range(SIZE):
        z = complex(0,0)
        c = complex(LEFT+x*(RIGHT-LEFT)/SIZE, TOP+y*(BOTTOM-TOP)/SIZE)
        norm = abs(z)**2
        for count in range(ITERATIONS):
            if norm <= 4.0:
                #z = complex(z.real*z.real - z.imag*z.imag + c.real, z.imag*z.real*2+c.imag)
                z=z*z+c
                #norm = abs(z)**2
                norm=abs(z*z)
            else:
                break
        if count<=4:
            can.create_text(x,y,fill='grey',text='.')
        elif count<=8:
            can.create_text(x,y,fill='green',text='.')
        elif count<=10:
            can.create_text(x,y,fill='blue',text='.')
        elif count<=12:
            can.create_text(x,y,fill='red',text='.')
        elif count<=15:
            can.create_text(x,y,fill='yellow',text='.')
        else:
            can.create_text(x,y,fill='black',text='.')

        root.update()

EndTime = time.time()

print "Dauer:",EndTime-StartTime

root.mainloop()

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Hallo,
@jens:
es wäre besser, einen grauen Punkt auf grauem Hintergrund nicht zu zeichen!
Schreib hier einfach "pass" und das Programm läuft viel schnell.
Vergleich bei SIZE=200:
a) Zeichnen des Grauen Punkts: Dauer: 224.440915108
b) Kein Zeichnen des Grauen Punktes (pass): Dauer: 53.4089848995
Sollte man sich also überlegen!
Gruß
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Die Rechenzeit lässt sich nochmal drastisch verkürzen, wenn man gleich wxpython und das GDI verwendet.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

@heraklit: ist die angabe in sekunden? bei mir mit laptop dauerts 9sekunden

mit und ohne psyco gibt sich nicht viel.

durch das nicht printen der grauen punkte wird 66% schneller gut sollte sich linear zur anzahl verhalten, von punkten die einsparrt.
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

heraklit hat geschrieben:Die Rechenzeit lässt sich nochmal drastisch verkürzen, wenn man gleich wxpython und das GDI verwendet.
Zeig mal!

Die Rechenzeit lässt sich übrigens DRASTISCHST :) verbessern, wenn man das root.update() nur für jede Zeile, oder überhaupt ganz am Ende ausführt (also eine oder zwei Tabs nach aussen rücken) ;)
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Wie du willst. Ich habe jetzt den SIZE parameter auf 900 gewählt, also schon recht groß und brauche knapp eine halbe Minute. Das Programm verwendet jetzt wxpython, wie schon erwähnt.


Schön, nicht wahr? :wink:
Zuletzt geändert von heraklit am Samstag 23. Februar 2008, 18:45, insgesamt 5-mal geändert.
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Vielleicht kann ich den Code nächstes Semester für ein Seminar verbauen. Am liebsten würde ich noch einen Screenshot hier posten, aber leider habe ich keinen Webspace o.ä.
Mein Programm braucht ca. 25 sek.Falls man das root.update() verschiebt komm ich immer noch auf rund 40 sek.In beiden Fällen wird SIZE=900 gesetzt und psyco verwendet.
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

heraklit hat geschrieben:Schön nicht war
Dein Code oder das Bild?

Naja. Dein Programm braucht bei mir 26.irgendwas und die Tkinter-Version 31.eipaarzerquetschte (beides ohne Psyco). Also unter "drastisch verkürzen" versteh ich was anderes ;)
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Hallo,
bei mir braucht die TKinter Version 40 sek. nachdem man root.update() entsprechend eingerückt hat. Falls man es nicht macht, dauert die Ausführung um ein Vielfaches länger (bei SIZE=900). Meine WX-Version braucht rund 25 sek. In beiden Fällen wurde psyco verwendet.
Geht man von deinen gemessenen Zeiten aus, erhält man immerhin einen Unterschied von 5 sek, was bei den rund 30 Sekunden prozentual doch viel ist.
Dein Code oder das Bild?
Beides! Aber vor allem das Bild :-)
Als nächstes könnte man die Anzahl der Iterationen raufsetzen, um eine detailliertere Darstellung zu erhalten. Dann könnte man das Programm so erweitern, dass der Benutzer einen bestimmten Bereich markieren kann, der dann im selben Fenster (vergrößert) dargestellt wird. Ich habe nicht vor deine TKinter-Version als langsam abzustempeln o.ä. Im Gegenteil: Durch deinen Code wird der Algorithmus klar dargestellt.
Es sollte nur ein Vorschlag sein, wie dein Programm mit anderen GUI-Toolkits realisiert werden kann, auch weil man mit WX-Python (und das lässt sich wohl nicht abstreiten) mehr Möglichkeiten hat, als mit TKinter. Dies ist v.a. im Hinblick auf Programmerweiterungen (wie obiges Beispiel) nützlich.
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Mein voriger Beitrag hat vielleicht den Eindruck erweckt, dass ich die Tkinter-Version verteidigen will ... nicht wirklich. Ich will auch deinen Code nicht schlechtreden, ganz im Gegnteil, ich arbeite selbst gerne mit wx. Dass wx mehr Möglichkeiten als Tkinter bietet stimmt sicher, wenns um Grafiken geht, bin ich aber trotzdem immer wieder von Tk begeistert.
Hat mich ein wenig enttäuscht, dass der Performancegewinn eher mager ausgefallen ist (IMO). Mir hat mal jemand eine Version mit Pygame geschickt (kann sie grad nicht finden, ich such aber noch). Die war, wenn ich mich recht erinnere, furchtbar schnell.

PS: Psyco bringt hier überhaupt nix :)
heraklit
User
Beiträge: 31
Registriert: Donnerstag 8. März 2007, 16:50

Nochmals Hallo,
ich hab jetzt SIZE auf 650 verringert. Mit psyco komme ich auf 13.3 sek, ohne auf 17.9 sek. Also scheint psyco doch etwas zu bringen, zumindest bei wx. Hmm, du hast pygame erwähnt. Find ich zwar eigenartig mit pygame sowas zu erstellen, aber gut. Mit pygame hab ich auch noch nichts gemacht. Vielleicht fällt jemand im Forum noch eine Möglichkeit ein, wie man meinen wx-code optimieren könnte, damit er schneller läuft.
Gruß
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Klassiker:
1. Berechne nichts doppelt, z.b. auch dein z*z wird 2 mal berechnet
2. Verzichte auf die eingebauten Komplexen Zahlen von Python. Selbst rechnen ist schneller da du einige Berechnungen die dort "automatisch" passieren gar nicht brauchst. Damit kannst du z.b. auch gleich auf abs(z*z) verzichten da du gleich direkt mit dem Bailout**2 vergleichen kannst. Damit hättest du 2muls, 2adds und ein sqrt eingespart, pro Bildpunkt. Weitere Kleinigkeiten werden dir selbst auffallen sobald du die Komplexen Zahlen selbst implementierst.
4. Zeichnen mit einer Library die direktere Zugriffe auf Bildpunkte zulässt, z.b. Pygame

guck mal auf mein Blog, da hab ich mehr darüber geschrieben.

lgherby
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Auch wenn es schon sehr lange her ist... Ich bin heute auf die Ursprungssourcen gestoßen und hab es ein wenig verbessert:

Wenn man root.update() nicht jedesmal Aufruft, wird es wesentlich schneller, sieht dann so aus:
https://gist.github.com/1391335/

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten