Re: [Edu-sig] Re: Teaching graphics with Python (was Introductoryhighschool programming)
Kirby Urner wrote:
Re: www.4dsolutions.net/ocn/python/nks.py
individually. I should try it with rectangles.
Definitely faster with rectangles.
In Tk, getting down to the actual pixel level (pixelsize=1), even with Point (tried in place of Rectangle), I get a fuzzy picture.
Might be some problem with my algorithm I didn't catch.
Actually, Tk doesn't give you pixel level control. In my graphics package, I fake it with small rectangles. So yes, using rectangles would be much better. Another problem with rendering speed is that my graphics package automatically flushes the graphics window after every operation. This makes simple animations easier, but when you are doing lots of small updates, this is very inefficient. My latest version of the package (still in testing) adds an option to turn off the auto-flush. Using this option, you can do a bunch of draws before actually updating the view. I think the result would be a much faster draw, but it's still going to be slower than PIL If you're interested, I could post the latest version of graphics.py.
An advantage of the PIL method is you're building something savable. With graphics.py, I don't see a way to save the canvas to a file.
This is problem with graphics.py. Tk provides a method to dump canvases to postscript, but the last time I checked it only worked under Unix/Linux. I'm not sure if this has been brought into the Windows world as well, I haven't looked recently. --John
(for color coded view, in browser, use: http://www.4dsolutions.net/cgi-bin/py2html.cgi?script=/ocn/python/nks.py
Kirby
If you're interested, I could post the latest version of graphics.py.
Yes, I'm interested.
This is problem with graphics.py. Tk provides a method to dump canvases to postscript, but the last time I checked it only worked under Unix/Linux. I'm not sure if this has been brought into the Windows world as well, I haven't looked recently.
Interesting. I like learning the technical ins and outs. Kirby
John Zelle schrieb:
... My latest version of the package (still in testing) adds an option to turn off the auto-flush. Using this option, you can do a bunch of draws before actually updating the view.
Interestigly the module turtle.py (in the standard distribution of Python) already has a similar feature, namely the function (method) tracer().
I think the result would be a much faster draw, but it's still going to be slower than PIL
If you're interested, I could post the latest version of graphics.py.
Yes, I'm also interested in this latest version.
This is problem with graphics.py. Tk provides a method to dump canvases to postscript, but the last time I checked it only worked under Unix/Linux. I'm not sure if this has been brought into the Windows world as well, I haven't looked recently.
In my experience this still dowsn't work correctly. A ps-file will be produced but it displays only as a tiny blank rectangle. Regards, Gregor
--John
A number of folks expressed interest, so the newest version of graphics.py is now available on my Python page: http://mcsp.wartburg.edu/zelle/python/graphics.py The only difference between this version and the previous is that it allows the auto-flush of graphics updates to be turned off. This line creates a graphics window w/o immediate automatic updates: myWin = GraphWin("Example Graphics Window", 300, 300, False) The "False" in the last parameter turns off auto-updates. This window will be updated when the Tk event loop is idle or when myWin.flush() is called. I tested this out with Kirby's nks.py code, and it makes the drawing essentially instantaneous on my machine. I normally do not release tweaks to the graphics package until it has gone through an entire semester of class-use testing, but I am relatively confident that this small change is working. The documentation has not yet been updated. Please let me know if you find any bugs. By the way, for any who are interested in the history of such things, versions of my graphics package before 2.0 (the previous release) always used lazy updating (the auto-flush False behavior). I added the forced updates to version 2.0 to make the package behave better interactively under windows with Idle 1.0 and newer (using subprocesses). The newest version (2.1) now lets you select which mode you want. --John Gregor Lingl wrote:
John Zelle schrieb:
... My latest version of the package (still in testing) adds an option to turn off the auto-flush. Using this option, you can do a bunch of draws before actually updating the view.
Interestigly the module turtle.py (in the standard distribution of Python) already has a similar feature, namely the function (method) tracer().
I think the result would be a much faster draw, but it's still going to be slower than PIL
If you're interested, I could post the latest version of graphics.py.
Yes, I'm also interested in this latest version.
This is problem with graphics.py. Tk provides a method to dump canvases to postscript, but the last time I checked it only worked under Unix/Linux. I'm not sure if this has been brought into the Windows world as well, I haven't looked recently.
In my experience this still dowsn't work correctly. A ps-file will be produced but it displays only as a tiny blank rectangle.
Regards, Gregor
--John
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Hi John -- Thank you for sharing your latest graphics.py -- indeed it runs a *lot* faster, plus it's nice to have the option of watching screen updates as they happen IF you want to. This is definitely a worthwhile upgrade. ====== Notes: With WinXP, Python 2.3.3, IDLE 1.0.2: * no Tk canvas appears, or, if I add a canvas.flush(), a blank one with an hour glass cursor appears. If I change auto-refresh to True, then I see the canvas being drawn properly. Once it's done, it has the last problem (below) With WinXP, Python 2.3.3, command window: * no problems with Tk canvas With Linux (Mandrake 9.2), Python 2.3.3., IDLE 1.0 * Tk canvas appears, no problem. Both platforms (with or without IDLE): I notice that loading both the PIL and graphics.py modules at the same time causes problems. PIL will fail to show anything if graphics.py is loaded (same with the older version). I think this may have to do with both modules contending for a Tk root, a problem even when running in shell mode. To address the latter problem, I've separated the PIL and graphics.py Canvas classes into separate modules (canvas1.py and canvas2.py), so that only one or the other library gets used. Both platforms, using IDLE: if I choose dimensions greater than the screen, or move the Tk canvas off the edge, portions of the canvas get wiped and don't refresh. ===== Note re nks.py PS: a more demanding test for nks is t1(30,400,200,3). That creates a 3*400 x 3*200 (i.e. 1200x600) canvas. In general, pixelsize (3) multiplies the width (400) and height (200). Plus height should be half the width, given how these particular cellular automata propagate from the center (45 degree slope).
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of John Zelle Sent: Monday, May 10, 2004 8:31 AM To: edu-sig@python.org Subject: Re: [Edu-sig] Re: Teaching graphics withPython (was Introductoryhighschool programming)
A number of folks expressed interest, so the newest version of graphics.py is now available on my Python page: http://mcsp.wartburg.edu/zelle/python/graphics.py
The only difference between this version and the previous is that it allows the auto-flush of graphics updates to be turned off. This line creates a graphics window w/o immediate automatic updates:
myWin = GraphWin("Example Graphics Window", 300, 300, False)
The "False" in the last parameter turns off auto-updates. This window will be updated when the Tk event loop is idle or when myWin.flush() is called. I tested this out with Kirby's nks.py code, and it makes the drawing essentially instantaneous on my machine.
I normally do not release tweaks to the graphics package until it has gone through an entire semester of class-use testing, but I am relatively confident that this small change is working. The documentation has not yet been updated. Please let me know if you find any bugs.
By the way, for any who are interested in the history of such things, versions of my graphics package before 2.0 (the previous release) always used lazy updating (the auto-flush False behavior). I added the forced updates to version 2.0 to make the package behave better interactively under windows with Idle 1.0 and newer (using subprocesses). The newest version (2.1) now lets you select which mode you want.
--John
Kirby Urner wrote:
Hi John --
Thank you for sharing your latest graphics.py -- indeed it runs a *lot* faster, plus it's nice to have the option of watching screen updates as they happen IF you want to. This is definitely a worthwhile upgrade.
======
Notes:
With WinXP, Python 2.3.3, IDLE 1.0.2:
* no Tk canvas appears, or, if I add a canvas.flush(), a blank one with an hour glass cursor appears.
Right. This is a well-known issue. Under IDLE, the graphics program runs as a separate process, and does not share the Tkinter mainloop that runs in IDLE. When IDLE is waiting for input, the subprocess is "frozen." There are a couple of things that you can do to remedy this. One is to simply not get input through the IDLE shell window. For example, instead for pausing to view graphics output with a raw_input (something that requires typing in the shell window), do a win.getMouse() that waits for a mouse click. That will keep the Tk window active. The other "fix" is to run IDLE with the -n option so that the program is not run as a subprocess, but shares IDLE's Tk event loop.
If I change auto-refresh to True, then I see the canvas being drawn properly. Once it's done, it has the last problem (below)
Right, since the updates are done on each draw, the window is fully drawn before the raw_input in the IDLE shell "freezes" it.
With WinXP, Python 2.3.3, command window:
* no problems with Tk canvas
With Linux (Mandrake 9.2), Python 2.3.3., IDLE 1.0
* Tk canvas appears, no problem.
Both platforms (with or without IDLE):
I notice that loading both the PIL and graphics.py modules at the same time causes problems. PIL will fail to show anything if graphics.py is loaded (same with the older version). I think this may have to do with both modules contending for a Tk root, a problem even when running in shell mode.
I was not aware of this problem, I'll have to look into this. Things always get a bit funky with multiple modules attempting to use Tk.
To address the latter problem, I've separated the PIL and graphics.py Canvas classes into separate modules (canvas1.py and canvas2.py), so that only one or the other library gets used.
Good workaround for now.
Both platforms, using IDLE:
if I choose dimensions greater than the screen, or move the Tk canvas off the edge, portions of the canvas get wiped and don't refresh.
This is actually the same problem as above. When IDLE is paused for input, the subprocess freezes, hence you don't get a window repaint. By the way, if you are experimenting interactively and have a variable that contains the GraphWin, you can always force an update by doing win.flush(). That should cause a repaint.
=====
Note re nks.py
PS: a more demanding test for nks is t1(30,400,200,3). That creates a 3*400 x 3*200 (i.e. 1200x600) canvas. In general, pixelsize (3) multiplies the width (400) and height (200). Plus height should be half the width, given how these particular cellular automata propagate from the center (45 degree slope).
-----Original Message----- From: edu-sig-bounces@python.org [mailto:edu-sig-bounces@python.org] On Behalf Of John Zelle Sent: Monday, May 10, 2004 8:31 AM To: edu-sig@python.org Subject: Re: [Edu-sig] Re: Teaching graphics withPython (was Introductoryhighschool programming)
A number of folks expressed interest, so the newest version of graphics.py is now available on my Python page: http://mcsp.wartburg.edu/zelle/python/graphics.py
The only difference between this version and the previous is that it allows the auto-flush of graphics updates to be turned off. This line creates a graphics window w/o immediate automatic updates:
myWin = GraphWin("Example Graphics Window", 300, 300, False)
The "False" in the last parameter turns off auto-updates. This window will be updated when the Tk event loop is idle or when myWin.flush() is called. I tested this out with Kirby's nks.py code, and it makes the drawing essentially instantaneous on my machine.
I normally do not release tweaks to the graphics package until it has gone through an entire semester of class-use testing, but I am relatively confident that this small change is working. The documentation has not yet been updated. Please let me know if you find any bugs.
By the way, for any who are interested in the history of such things, versions of my graphics package before 2.0 (the previous release) always used lazy updating (the auto-flush False behavior). I added the forced updates to version 2.0 to make the package behave better interactively under windows with Idle 1.0 and newer (using subprocesses). The newest version (2.1) now lets you select which mode you want.
--John
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
Thanks, too, John! By changing 2 or 3 lines in Kirbys code I arrived at a tiny animation. (attachment). It's intended to run from the command line. Question: The raw_input() in line 70 seems to be indispensable. It doesn't work without it. Why is this the case? Regards, Gregor
""" Kirby Urners nks.py using Tkinter with tiny animation """ # uncomment one or the other, reload if switching from graphics import GraphWin, Point, Rectangle class Canvas(object): def __init__(self, width, rows, pixelsize): self.pixelsize = pixelsize self.c = GraphWin('NKS',width*pixelsize, rows*pixelsize, False) self.c.setBackground('black') def drawcell(self, thepoint): therow = thepoint[0]*self.pixelsize thecol = thepoint[1]*self.pixelsize therect = Rectangle(Point(therow, thecol), Point(therow + self.pixelsize-1, thecol + self.pixelsize-1)) therect.setFill('yellow') therect.setOutline('yellow') therect.draw(self.c) def showimage(self): self.c.flush() g = raw_input("Hit Enter on this line to close window") self.c.close() def base2(n,pad=8): output = [] while n > 1: digit = n%2 n //= 2 output.append(str(digit)) output.append(str(n)) output.reverse() return (''.join(output)).zfill(pad) def makerule(n): therule = {} output = base2(n) for i in range(8): therule[base2(7-i,3)] = output[i] return therule def sayrule(themap): for i in range(7,-1,-1): thekey = base2(i,3) print "%s --> %s" % (thekey, themap[thekey]) class Pattern(object): def __init__(self, n, width=40, rows=20, pixelsize = 1): self.width = width self.rule = makerule(n) self.therow = ('0' * (width//2) + '1' + '0' * (width - width//2 - 1)) self.rownum = 0 # Canvas imported from either of 2 modules self.canvas = Canvas(width,rows,pixelsize) self.canvas.c.flush() # <=== raw_input("Hit Enter to start automaton!") # <=== def next(self): while True: yield self.therow for i in range(len(self.therow)): if self.therow[i]=='1': self.canvas.drawcell((i,self.rownum)) newrow = ['0'] * len(self.therow) for i in range(1,len(self.therow)-1): thekey = (self.therow[i-1] + self.therow[i] + self.therow[i + 1]) newrow[i] = self.rule[thekey] self.therow = ''.join(newrow) self.rownum += 1 def showimage(self): self.canvas.showimage() def __iter__(self): return self.next() def t1(rule, width, height, pixelsize=1): p = Pattern(rule ,width, height, pixelsize) g = p.next() for i in range(width/2): g.next() p.canvas.c.flush() p.showimage() if __name__ == '__main__': t1(30,200,100,4)
Gregor Lingl wrote:
Thanks, too, John!
By changing 2 or 3 lines in Kirbys code I arrived at a tiny animation. (attachment). It's intended to run from the command line.
Question: The raw_input() in line 70 seems to be indispensable. It doesn't work without it. Why is this the case?
Hmmm, this is a bit confusing to me too. I think the problem is that all of the drawing is complete before Tk even creates the window (under Windows that is; it works fine in Linux). If you change the self.canvas.c.flush() to self.canvas.c.update() then the raw_input is not needed. The difference is that flush() calls Tk's update_idletask() rather than the more definite update. I need to look into the platform differences on these calls. Most of the time, I am developing/testing under Linux, so I used the weaker update, which seems to work fine there.
Regards, Gregor
------------------------------------------------------------------------
"""
Kirby Urners nks.py using Tkinter with tiny animation
"""
# uncomment one or the other, reload if switching
from graphics import GraphWin, Point, Rectangle
class Canvas(object):
def __init__(self, width, rows, pixelsize): self.pixelsize = pixelsize self.c = GraphWin('NKS',width*pixelsize, rows*pixelsize, False) self.c.setBackground('black')
def drawcell(self, thepoint): therow = thepoint[0]*self.pixelsize thecol = thepoint[1]*self.pixelsize
therect = Rectangle(Point(therow, thecol), Point(therow + self.pixelsize-1, thecol + self.pixelsize-1)) therect.setFill('yellow') therect.setOutline('yellow') therect.draw(self.c)
def showimage(self): self.c.flush() g = raw_input("Hit Enter on this line to close window") self.c.close()
def base2(n,pad=8): output = [] while n > 1: digit = n%2 n //= 2 output.append(str(digit)) output.append(str(n)) output.reverse() return (''.join(output)).zfill(pad)
def makerule(n): therule = {} output = base2(n) for i in range(8): therule[base2(7-i,3)] = output[i] return therule
def sayrule(themap): for i in range(7,-1,-1): thekey = base2(i,3) print "%s --> %s" % (thekey, themap[thekey])
class Pattern(object):
def __init__(self, n, width=40, rows=20, pixelsize = 1): self.width = width self.rule = makerule(n) self.therow = ('0' * (width//2) + '1' + '0' * (width - width//2 - 1)) self.rownum = 0 # Canvas imported from either of 2 modules self.canvas = Canvas(width,rows,pixelsize) self.canvas.c.flush() # <=== raw_input("Hit Enter to start automaton!") # <===
def next(self): while True: yield self.therow for i in range(len(self.therow)): if self.therow[i]=='1': self.canvas.drawcell((i,self.rownum))
newrow = ['0'] * len(self.therow) for i in range(1,len(self.therow)-1): thekey = (self.therow[i-1] + self.therow[i] + self.therow[i + 1]) newrow[i] = self.rule[thekey] self.therow = ''.join(newrow) self.rownum += 1
def showimage(self): self.canvas.showimage()
def __iter__(self): return self.next()
def t1(rule, width, height, pixelsize=1): p = Pattern(rule ,width, height, pixelsize) g = p.next() for i in range(width/2): g.next() p.canvas.c.flush() p.showimage()
if __name__ == '__main__': t1(30,200,100,4)
------------------------------------------------------------------------
_______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig
participants (3)
-
Gregor Lingl
-
John Zelle
-
Kirby Urner