Animation and the command prompt

Python doesn’t seem to have a simple method for creating animated gifs, but other programs can be executed from python.  Here is what I’m using. It is simple and works.

1) install ImageMagick.  There are other programs that can be used to bundle images into a gif but this is the first and only one I’ve tried so far.  I installed: ImageMagick-6.7.3-10-Q8-windows-dll.exe

2) create a folder with sequentially numbered images.

3) Run the ImageMagick convert.exe program from a command prompt or from a python program.

This can be done from the command prompt:

C:\>convert C:\...path...\*.png C:\...path...\animation.gif

“Convert.exe” is the ImageMagick program that can bundle an image series (such as *.png above) into an animated gif file (such as animation.gif above).
The convert program can be executed from within a python program like this:

from subprocess import call

call(r'\Program Files\ImageMagick-6.7.3-Q8\convert.exe ' +
     r'\Python26\Lib\site-packages\xy\images\*.png ' +
     r'\Python26\Lib\site-packages\xy\images\im55.gif' )

You can also pass a list. The first item is the program, followed by a list of arguments:

from subprocess import call

command = [r'\Program Files\ImageMagick-6.7.3-Q8\convert.exe',
           r'\Python26\Lib\site-packages\xy\images\*.png',
           r'\Python26\Lib\site-packages\xy\images\im23.gif']
call(command)

Or:

from subprocess import call

call([r'\Program Files\ImageMagick-6.7.3-Q8\convert.exe',
      r'\Python26\Lib\site-packages\xy\images\*.png',
      r'\Python26\Lib\site-packages\xy\images\im23.gif'])

NOTE: Spaces are needed when passing the command as one string but not needed in the list format. Also note that the complete path for the program is needed when using call() which is not required if you run convert.exe directly at the command prompt.

4) Delete the series of images (if not needed).

Sync into the clouds

During the time I left my flashdrive in the computer lab and was not able to pick it up for a week, I decided to look for a good way to backup my files. Long story short: Skydrive – doesn’t sync >> Live Mesh –  syncs but hidden sync status >> Dropbox – much better! I’ve been using it for several days now. It is great. I really like having the little status icon on each file showing its sync status. It also saves old versions of all files which Live Mesh does not do. And if files were changed on different computers before syncing then it appears to create a separate file with an extended name showing the computer of origin.

The only advantage for Live Mesh that I can see so far (apart from having extra cloud space if you run out of Dropbox space) is that you can sync any folder. Dropbox creates a single folder where you throw everything you want synced into.

Right now, I’m using Live Mesh to sync the .spyder2 configuration folder with no problem so far. This might possibly be problematic if the configuration file is made for the particular computer it is on. I wanted to keep my template and workspace configurations the same on all three computers that I use for programming.  I use Dropbox for all my programs and everything else.

Live Mesh – sync any folder you can’t conveniently move to the Dropbox.

  • Program folders with configuration files (possibly may cause problems)
  • Sync any folder you want

Dropbox – sync all files you frequently work with on multiple computers.

  • Sync programming code and frequently used data
  • Quickly confirm sync status with file icon (or badge)
  • Stores old versions of all files for recovery

Interpreting FFT results and plotting

I don’t frequently use FFT, so it still confounds every time I try to interpret the results from FFT, I’ll try to organize my understanding here…

INFORMATION ABOUT THE DATA FILE TO PROCESS

data = array of samples
data_pts = total samples in data file (number of samples/lines in data file)
data_srate = sampling rate (points per second)
data_stime = total time covered in seconds (data_pts / data_srate)

THE numpy.fft() FUNCTION AND THE RESULTS

fft_result = fft(data)
fft_freqs = fftfreq( len(fft_result) )

(fft_result has a real and imag part, but I’m focusing on the real part here)

len(fft_result) == len(data)

but this is mostly meaningless

fft_result[n] corresponds to fft_freqs[n]

PRECISION
The interval difference if fft_freqs equals the inverse of data_stime.
This interval has nothing to do with the number of samples which is what confused me most. I had expected that having 1024 samples per second would return a more precise frequency plotting versus 2 samples per second.
In other words, if the sampled time period is 10 seconds long. No matter if you have 2 or 100 samples per second, the intervals of the frequency ‘bins’ will be 0.1. The number of 0.1-bins depends on the number of samples. In this case, 2 samples per second will produce 20 bins ranging from -1.0 to 0.9; 100 samples will give 1000 bins, from -50.0 to 49.9.

dfreq = 1/data_stime
range = (-dfreq*data_stime*data_srate/2 , dfreq*data_stime*data_srate/2 - dfreq)
      = (-data_srate/2                  , data_srate/2 - dfreq                 )

IN SHORT
That seems more complicated than it needs to be, but it was the thought process that helped me arrive at a better solution. After doing the math and comparisons I find that there is no need to do all these calculations. The sampling rate only needs to be applied to the freq bins, similar to dividing the x-axis array by the rate when plotting the data. Squaring the FFT values helps accentuate the peaks.

    data = []       #array to hold data read from file
    srate=2.        #sample rate
    samples = 0     #counter for the number of lines in file (# of data samples)
    with open(filename, 'r') as rawfile:
        for i, line in enumerate(rawfile):
            data.append(float(line))
        samples = i + 1

    x = arange(samples)/srate

    # PLOT THE ORIGINAL DATA READ FROM FILE
    plt.plot(x, data)
    plt.show()

    # APPLY FFT
    FFT = fft(data)
    freqs = fftfreq(samples) * srate
    print 'bin range=', [freqs.min(), freqs.max()]
    print 'bin interval=', srate/samples

    # PLOT THE POSITIVE HALF OF FREQ VALUES
    plt.plot(freqs[:samples/2], (abs(FFT.real)**2)[:samples/2], 'g*')
    plt.show()

Ax = B is not the same as x = A(inv) B

When given the task to change my explicit ocean model to an implicit version, I had assumed that I would need to invert the ‘A’ matrix to solve Ax=B, and then do some matrix math. I found a few web sites that warn against that because it is possibly a lot more computationally intensive than solving directly. John Cook’s blog explains more about why.

Python’s NumPy has linalg.solve(A, B), which returns the ‘x’ array

x = numpy.linalg.solve(A,B)

It uses a LU decomposition method for solving (not inversion).

Sliding plates implicit

The next assignment was to rewrite the sliding plates using an implicit scheme. Here is a video of the animation produced using Visual Python arrows.

Colored according to speed. The initial velocity of the fluid is zero and the upper plate moves at a constant speed.
The visualization setup using Visual Python looks like this:

#SET UP VISUALIZATION SCENE
scene = display(title='Velocity profile', width=800, height=800, center=(u/2,y_divs/2,0), 
                autoscale=True, fullscreen=False)
base = box(pos=(u/2,-0.5,-2), length=u, height=0.4, width=4)
plate = box(pos=(u/2,y_divs+1.5,-2), length=u, height=0.4, width=4)
quiver = [] #TO HOLD ALL THE VELOCITY VECTOR ARROWS
quiver.append( arrow(pos=(0,0,0), axis=(BOUNDS[0,0],0,0),
                         shaftwidth=0.5, color=color.blue) )
for each in xrange(y_divs):
    quiver.append( arrow(pos=(0,each+1,0), axis=(UM[each,0],0,0),
                         shaftwidth=0.5, color=color.blue) )
quiver.append( arrow(pos=(0,y_divs+1,0), axis=(BOUNDS[-1,0],0,0),
                         shaftwidth=0.5, color=color.red) )
scene.autoscale = False

The main loop with the visualization update looks like this:

    for t in arange(t_divs-1): #START FROM 1, SKIP ZERO
        B = zeros(y_divs)
        B[:] = -1 * UM[:,t]
        B[ 0] -= BOUNDS[ 0,t+1] * alpha
        B[-1] -= BOUNDS[-1,t+1] * alpha
        
        UMnext = linalg.solve( A, B )
        UM[:,t+1] = UMnext[:]
        
        for y in arange(y_divs):
            #UPDATE VECTOR LENGTH BASED ON SPEED
            quiver[y+1].axis = (UM[y,t+1],0,0)
            #CHANGE ARROW COLOR BASED ON SPEED: Blue is slow, Red is fast
            quiver[y+1].color = (UM[y,t+1]/u,0.3,1.-UM[y,t+1]/u)

tidbits from reading

.index() vs. where()

.index() is the builtin function for finding the index of something in a list or tuple. This does not work with NumPy arrays! NP arrays rely on where() to return an array of indices that match the condition.

—————————
for-else statement

‘else’ can be used after a for-loop. But here, the ‘else’ statement only executes if the for-loop completes all iterations. Think of it as using the for-loop to search for something, or expecting a break from the loop. If nothing is resolved or no break occurs then the else statement can be used for notification. The else can be used after a try-except in a similar way; executing only when nothing breaks down, throwing an exception.

—————————
how to prevent a new-line character in a print() statement

Use a comma at the end. You can have consecutive print() statements print to the same line simply by adding a comma at the end of each line.

—————————
Use a dictionary for formatting a long output string

%20s will format a string in the list after a text. But when using this formatting method, the order must match in the supplied list. %(keyword)20s or %(keyword)10f with a supplied dictionary can avoid the ordering issue and having to have the same variable or value in a list multiple times.

—————————
use an asterisk * in front of a functions input argument to accept an infinite number of args.

def MyFunction( *args ): This will accept any number of arguments and create a list to use within the function.

—————————
ternary operation or inline if (iif)

In Java you can use a iif like this ( x == 2 ? y = 4 : y = 0 ).
( condition ? if true do this : if false do this)
I found that Python also has a version of this but ordered differently:
(do this) if (condition) else (do this if false)
Not the same order as java but still pretty straight forward.