[wxPython] new mandelbrot version

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[wxPython] new mandelbrot version

Markus Gritsch
Hi!

The calculation time is now further reduced by 30%.  I found, that Mike put
some redundant stuff in the mandelbrot function.  Although Mike used a wxTimer,

the application isn't responsive during calculation, so I didn't include this
approach.

I will continue posting the mandelbrot program to this mailing list, because 1)

The mandelbrot program was born here, 2) Some interested people read this
mailing list (Ionel, Mike, ...) 3) I find it more interesting to do mandelbrot
calculations when the output is shown on the screen 4) There was no response to

Mikes posting on comp.lang.python (maybe because of the high traffic there).

---
Have fun,
Markus


#! /usr/bin/env python
#######################################################################################94x78##

"""
Mandelbrot program, for no particular reason.

        John Farrell: initial version
          Robin Dunn: introduced wxImage.SetData instead of wxBitmapFromData
    Ionel Simionescu: used the Numeric package, and rewrote all of the
                        computation and data displaying code
Alexander Smishlajev: suggestions on optimising loops and drawing
      Markus Gritsch: in-place calculation in the mandelbrot while loop
       Mike Fletcher: Numeric.repeat instead of Numeric.compress
"""

from wxPython.wx import *
import Numeric

WIDTH = 200
HEIGHT = 200

#coords = ((-1.0, -1.5), (0.0, -0.5))
coords = ((-2.0, -1.5), (1.0, 1.5))
WEIGHTS = (16, 1, 32)
MAX_ITERATIONS = 255
zero = complex(0.0, 0.0)

def setup():
    # we use a single array for the real values corresponding to the x
coordinates
    diff = coords[1][0] - coords[0][0]
    xs = 0j + (coords[0][0] + Numeric.arange(WIDTH).astype(Numeric.Float32) *
diff / WIDTH )
    # we use a single array for the imaginary values corresponding to the y
coordinates
    diff = coords[1][1] - coords[0][1]
    ys = 1j * (coords[0][1] + Numeric.arange(HEIGHT).astype(Numeric.Float32) *
diff / HEIGHT )
    # we build <c> in direct correpondence with the pixels in the image
    c = Numeric.add.outer(ys, xs)
    z = Numeric.zeros((HEIGHT, WIDTH)).astype(Numeric.Complex32)
    # use flattened representations for easier handling of array elements
    c = Numeric.ravel(c)
    z = Numeric.ravel(z)
    return (c, z)

def mandelbrot(progressMonitor):
    import time
    t = time.clock()
    (c, z) = setup()
    iterations = 0
    size = WIDTH * HEIGHT
    i_no = Numeric.arange(size)       # non-overflow indices
    data = MAX_ITERATIONS + Numeric.zeros(size)
    # initialize the "todo" arrays;
    # they will contain just the spots where we still need to iterate
    c_ = Numeric.array(c).astype(Numeric.Complex32)
    z_ = Numeric.array(z).astype(Numeric.Complex32)
    while (iterations < MAX_ITERATIONS) and len(i_no):
        # do the calculations in-place
        Numeric.multiply(z_, z_, z_)
        Numeric.add(z_, c_, z_)
        overflow = Numeric.greater_equal(abs(z_), 2.0)
        not_overflow = Numeric.logical_not(overflow)
        # get the indices where overflow occured
        ####overflowIndices = Numeric.compress(overflow, i_no) # slower
        overflowIndices = Numeric.repeat(i_no, overflow) # faster
        # set the pixel indices there
        for idx in overflowIndices:
            data[idx] = iterations
        # compute the new array of non-overflow indices
        i_no = Numeric.repeat(i_no, not_overflow)
        # update the todo arrays
        c_ = Numeric.repeat(c_, not_overflow)
        z_ = Numeric.repeat(z_, not_overflow)
        iterations = iterations + 1
        progressMonitor.progress(iterations, 100.0 * len(i_no) / size)
    print time.clock() - t
    return data

class MandelCanvas(wxWindow):
    def __init__(self, parent, id = -1):
        wx.wxWindow.__init__(self, parent, id)
        self.parent = parent
        self.border = (1,1)
        self.SetSize(wxSize(WIDTH, HEIGHT))
        self.SetBackgroundColour(wx.wxNamedColour("black"))
        self.bitmap = None
        self.colours = Numeric.zeros( (MAX_ITERATIONS + 1, 3) )
        arangeMax = Numeric.arange(0, MAX_ITERATIONS + 1)
        self.colours[:,0] = Numeric.clip(arangeMax * WEIGHTS[0], 0,
MAX_ITERATIONS)
        self.colours[:,1] = Numeric.clip(arangeMax * WEIGHTS[1], 0,
MAX_ITERATIONS)
        self.colours[:,2] = Numeric.clip(arangeMax * WEIGHTS[2], 0,
MAX_ITERATIONS)

    def OnPaint(self, event):
        if not self.bitmap:
            data = mandelbrot(self.parent)
            import time
            t = time.clock()
            data.shape = (HEIGHT, WIDTH)
            # build the pixel values
            pixels = Numeric.take(self.colours, data)
            # create the image data
            self.bitmap = pixels.astype(Numeric.UnsignedInt8).tostring()
            # create the image itself
            image = wxEmptyImage(WIDTH, HEIGHT)
            image.SetData(self.bitmap)
            self.bitmap = image.ConvertToBitmap()
            print time.clock() - t
        dc = wxPaintDC(self)
        dc.BeginDrawing()
        dc.DrawBitmap(self.bitmap, 0, 0, false)
        dc.EndDrawing()

class MyFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title)
        self.CreateStatusBar()
        self.progress(0, 100)
        self.Centre(wxBOTH)
        mdb = MandelCanvas(self)

        self.SetAutoLayout(true)
        self.Layout()
        self.Fit()
        sz = self.GetClientSize()
        self.SetClientSize(wxSize(sz.width-7, sz.height-14))

    def progress(self, done, percent):
        self.SetStatusText("%d/%d, %2.2f" % (done, MAX_ITERATIONS, percent) +
                           "% of pixels left")

class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Mandelbrot")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()



_______________________________________________
wxPython-users maillist  -  [hidden email]
http://starship.python.net/mailman/listinfo/wxpython-users



Reply | Threaded
Open this post in threaded view
|

RE: [wxPython] new mandelbrot version

Mike  Fletcher

Oh, fine, I'll post here :-P ;) , to justify myself I made changes which do
have something to do with the GUI part :) --> this version uses threading
module to do calculation, is slower than the non-threaded version, but does
allow for GUI updates during calculation.  Also adds tiling display (i.e.
you watch the solution "grow" on-screen in little pieces), and eliminates
the global variables.  Still all sorts of rough edges :) .

Cheers,
Mike

-----Original Message-----
From: Markus Gritsch
To: wxPython-users list
Sent: 02/12/99 3:55 AM
Subject: [wxPython] new mandelbrot version

Hi!

The calculation time is now further reduced by 30%.  I found, that Mike
put
some redundant stuff in the mandelbrot function.  Although Mike used a
wxTimer,

the application isn't responsive during calculation, so I didn't include
this
approach.

I will continue posting the mandelbrot program to this mailing list,
because 1)

The mandelbrot program was born here, 2) Some interested people read
this
mailing list (Ionel, Mike, ...) 3) I find it more interesting to do
mandelbrot
calculations when the output is shown on the screen 4) There was no
response to

Mikes posting on comp.lang.python (maybe because of the high traffic
there).

---
Have fun,
Markus
...


mandelbrot3.py (8K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [wxPython] new mandelbrot version

John Farrell-4
In reply to this post by Markus Gritsch
Markus Gritsch wrote:

> The calculation time is now further reduced by 30%.  I found, that Mike put
> some redundant stuff in the mandelbrot function.  Although Mike used a wxTimer,
>
> the application isn't responsive during calculation, so I didn't include this
> approach.
>
> I will continue posting the mandelbrot program to this mailing list, because 1)
>
> The mandelbrot program was born here, 2) Some interested people read this
> mailing list (Ionel, Mike, ...) 3) I find it more interesting to do mandelbrot
> calculations when the output is shown on the screen 4) There was no response to
>
> Mikes posting on comp.lang.python (maybe because of the high traffic there).

Sure is cool to sit here and watch my little program become the subject of
more in-depth analysis than the software on the Mars Polar Lander :-).
Unfortunately it crashes somewhere in the wxpython code with a Windows
illegal memory access error. I am on NT4 SP5. My best guess is that it is
happening at the end of OnPaint, after the return from the Python code.

BTW, is this code really the best way to do to fit the client area?
        self.SetAutoLayout(true)
        self.Layout()
        self.Fit()
        sz = self.GetClientSize()
        self.SetClientSize(wxSize(sz.width-7, sz.height-14))

What do all those lines of code do, and why is it necessary to revert to
hard-coded constants anyway?

John
--
Dr John Farrell - Research Architect - Mincom Limited

This transmission is for the intended addressee only and is confidential
information. If you have received this transmission in error, please delete
it and notify the sender. The contents of this E-mail are the opinion of the
writer only and are not endorsed by Mincom Limited unless expressly stated
otherwise.
----
I don't suffer from stress.  I am a carrier.

_______________________________________________
wxPython-users maillist  -  [hidden email]
http://starship.python.net/mailman/listinfo/wxpython-users



Reply | Threaded
Open this post in threaded view
|

Re: [wxPython] new mandelbrot version

Robin Dunn
> BTW, is this code really the best way to do to fit the client area?
>         self.SetAutoLayout(true)
>         self.Layout()
>         self.Fit()
>         sz = self.GetClientSize()
>         self.SetClientSize(wxSize(sz.width-7, sz.height-14))
>
> What do all those lines of code do, and why is it necessary to revert to
> hard-coded constants anyway?
>


Well, since the frame does not have any layout constraints or sizers, the
first two method calls are useless.  The Fit() will change the Frame's size
to fit it's children with a nice little border around them.  The last two
lines remove the border, but because of the 1-child-resize feature of frames,
(see below) these calls are effectivly useless as well.  (They are more
useful on wxPanel.)

Since this frame has only one child (besides its statusbar) a better approach
would be to remove all these lines, in addition to the explicit size values
for the MandelCanvas, and set the size of the frame explicitly.  Since there
is only one child it automatically resizes it to fit the client area.  (You
can think of it as having a special sizer or layout constraints called
SizeWithParent or something.)

--
Robin Dunn
Software Craftsman
[hidden email]
http://AllDunn.com/robin/
http://AllDunn.com/wxPython/  Check it out!



_______________________________________________
wxPython-users maillist  -  [hidden email]
http://starship.python.net/mailman/listinfo/wxpython-users