Sunday, March 30, 2008

Uniform deviates on the surface of a sphere

Here is a simple example of how to generate points randomly on the surface of the sphere that are uniformly distributed. The reason I'm posting it here is that it shows how convenient mayavi's mlab is for this sort of thing.

Anyone who has studied pseudo random numbers should know that the following will not generate points uniformly on the sphere. Here is a demonstration of the fact:

$ ipython -wthread
In [1]: from numpy import *
In [2]: from enthought.mayavi import mlab
In [3]: p = random.random(10000)*2*pi
In [4]: t = random.random(10000)*pi
In [5]: x, y, z = sin(t)*cos(p), sin(t)*sin(p), cos(t)
In [6]: g = mlab.points3d(x, y, z, z, mode='point')
In [7]: g.actor.property.point_size = 2

The point size is made larger so you can see the points more clearly. Here is the picture it produces:


Notice the clustering at the poles. OTOH, the following works nicely,

In [3]: p = random.random(10000)*2*pi
In [10]: mlab.clf()
In [12]: t = arccos(random.random(10000)*2.0 - 1.0)
In [13]: x, y, z = sin(t)*cos(p), sin(t)*sin(p), cos(t)
In [14]: g1 = mlab.points3d(x, y, z, z, mode='point')
In [15]: g1.actor.property.point_size = 2


This is the picture this one produces:



As you can see the transformation has worked and generates what appears to be a uniform distribution on the surface of a sphere. Visual testing isn't good enough uniformness but that isn't the point here.

Using virtualenv under Linux

Mayavi and TVTK are part of ETS (Enthought Tool Suite). The stable version of ETS is 2.7.1. ETS-2.7.1 ships with Traits2 and Envisage2. However, the latest traits version is 3 and Envisage3 is the current development Envisage version. These are part of ETS-3.0. Thus far mayavi was being developed in the branches. Earlier, in order to test mayavi with both ETS-2.7.1 and ETS-3.0, I used to manage a bunch of directories with symbolic links to switch between the ETS versions. It has been a while since I did that and yesterday I wanted to try out virtualenv to see if it would solve my problem easily. I'm using a Gutsy i386 system. In short, virtualenv worked like a charm. This is what I did.

I first needed to clean up my older setup. In the past I used a .pydistutils.cfg file that was in my home directory to tell easy_install to use my custom directories (which were in my PYTHONPATH). I removed this. Then I downloaded the virtualenv tarball from pypi and did the usual python setup.py install dance.

$ cd virtualenv-1.0
$ sudo python setup.py install --prefix=/usr/local

Then I did the following:

$ mkdir -p ~/usr/virtualenv
$ cd ~/usr/virtualenv
$ virtualenv ets_stabe # for ETS-2.7.1
$ ln -s ets_stable/bin/activate .
# edit .bash_profile and add "source ~/usr/virtualenv/activate" (or whatever for your particular shell) to it.

Now, either login afresh or source ~/usr/virtualenv/activate to use the newly created virtual environment.

Now you are all set. I then installed ETSProjectTools and installed ets==2.7.1 and everything else I needed in the stable environment (using either python setup.py [option] or via easy_install). You just need to make sure you use the corresponding virtual environments python and easy_install.

To switch to the truk I created another virtualenv like so:

cd ~/usr/virtualenv
virtualenv ets_trunk


Then I installed the trunk related packages here. To switch between virtual environments I have a small shell script that looks like this:

#!/bin/sh
# switch_ets.sh
cd ~/usr/virtualenv
rm activate
ln -s $1/bin/activate .

So to switch I simply run:
$ switch_ets.sh ets_trunk

and I'm all set to go when I start a new shell.

Mayavi sprint in July 2008

This is to announce a Mayavi sprint between 2nd July to 9th July, 2008.
The sprint will be held at the Enthought Office, Austin Texas.
Here are the details:

Dates: 2nd July 2008 to 9th July 2008
Location: Enthought Office at Austin, TX

Please do join us. Both Gaƫl and myself will be at the sprint on all
days and there will be developers from Enthought joining us as well.
Enthought is graciously hosting the sprint.

The agenda for the sprint is yet to be decided.

This was announced earlier on the enthought-dev and mayavi-users lists.

Saturday, March 29, 2008

Debugging Python scripts

Elementary debugging

I've noticed that many students who submit assignments in Python for a course I teach don't know how to use a debugger. Here are some simple notes on debugging Python scripts to get people started. Lets say you have the following trivial code:

# -- junk.py ---
print "hello"
foo
a = 1
print a+1

Importing this from IPython produces this::
In [1]: import junk
hello
---------------------------------------------------------------------------
Traceback (most recent call last)

/tmp/ in ()

/tmp/junk.py in ()
1 print "hello"
----> 2 foo
3 a = 1
4 print a+1
5

exceptions.NameError: name 'foo' is not defined
If you have a non-trivial program you can debug this right away using IPython's %debug magic.

In [2]: %debug
> /tmp/junk.py(2)()
1 print "hello"
----> 2 foo
3 a = 1

ipdb>

This drops you into ipdb which is an enhanced, pdb. At this point you can print variables and step through your code, go up the stack of execution etc. For more details on ipdb read the pdb documentation.

If you use the %pdb magic then IPython automatically drops you into the debugger whenever it sees an error. This is often very convenient.


Debugging a VTK-Python script

This is obviously a little more complicated (because VTK is implemented in C++ and you want to step through C++ code to figure out what is wrong) and there are a few ways of doing this. In the following I assume that you are doing this on a *nix/Linux/Mac machine. Suppose you run a Python script that segfaults and need to figure out where it crashed you can do the following (assuming you have gdb installed of course):

$ gdb python
(gdb) run your_script.py
[gdb messages]
Segmentation fault (or whatever)
(gdb) backtrace

The backtrace should typically give you more information about the crash.

Several weeks ago I needed to debug a VTK related problem where a window was not being resized if the off screen rendering mode was set. Debugging this can again be achieved by running the script using Python started from gdb and then setting a breakpoint in gdb. However, I thought I'd illustrate a very handy gdb feature of debugging running applications. In my particular case, I had a simple Python script that was demonstrating a VTK bug. At the appropriate location wher, I added a simple raw_input('DBG:') to give me a point where execution would be paused. I then ran the script like so:

$ python offscreen.py

On another shell I did the following:

$ ps uax | grep python

Using the PID of the process (30708) I did the following:

$ gdb
(gdb) attach 30708
[tons of output]
Loaded symbols for /usr/lib/libwx_gtk2u_gl-2.8.so.0
Reading symbols from /usr/lib/libGLU.so.1...done.
Loaded symbols for /usr/lib/libGLU.so.1
0xffffe410 in __kernel_vsyscall ()
(gdb)

On the gdb prompt I specify a break point where I want to stop execution::

(gdb) br vtkXOpenGLRenderWindow.cxx:1185
Breakpoint 1 at 0xb52846a0: file /skratch/prabhu/vtk/cvs/VTK/Rendering/vtkXOpenGLRenderWindow.cxx, line 1185.
(gdb) c
Continuing.
[Switching to Thread -1210595664 (LWP 30708)]

Breakpoint 1, vtkXOpenGLRenderWindow::SetSize (this=0x99bfb78, width=800,
height=800)
at /skratch/prabhu/vtk/cvs/VTK/Rendering/vtkXOpenGLRenderWindow.cxx:1185
1185 if ((this->Size[0] != width)||(this->Size[1] != height))
Current language: auto; currently c++
(gdb)

At this point I can step through the code and try and figure out what is going on. This is extremely convenient and handy.