Natural movement using polar coordinates in shoebot

Here’s a little shoebot bot to experiment with natural movement.

This uses polar coordinates to decide the direction and velocity of an arrow on the screen.

Polar coordinates mean we can give an object a sense of ‘forward’, ‘back’, ‘left’ and ‘right’

The code below works on the current version of shoebot

https://github.com/shoebot/shoebot.git

With planar.py to handle the directions and velocity

https://pypi.python.org/pypi/planar

Continue reading

Adding files to the django auto refresh

Django runserver and the app django-autotest are both good as they’ll restart when modifcations are made to files in the app they will restart, however not *all* files will trigger a restart.

Wanting to get some other files noticed, I added some in the __init__.py of my app, so it looked like this:

try:
    from django.conf import settings

    if settings.DEBUG:
        import forms, util, tests
except:
    pass

This seemed to be working fine until I swapped to postgres and tried to do syncdb .. and reset, uh oh !

Postgres said (names changed to protect the innocent):

2012-05-10 09:47:57 BST STATEMENT:
                    SELECT c.relname
                    FROM pg_catalog.pg_class c
                    LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
                    WHERE c.relkind IN ('r', 'v', '')
                        AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
                        AND pg_catalog.pg_table_is_visible(c.oid)
2012-05-10 09:47:57 BST LOG:  could not receive data from client: Connection reset by peer
2012-05-10 09:47:57 BST LOG:  unexpected EOF on client connection
2012-05-10 09:49:14 BST ERROR:  relation "sandwich_maker_filling" does not exist at character 72
2012-05-10 09:49:14 BST STATEMENT:  SELECT "sandwich_maker_filling"."id", "sandwich_maker_filling"."name" FROM "sandwich_maker_filling"
2012-05-10 09:49:14 BST ERROR:  current transaction is aborted, commands ignored until end of transaction block

And django wasn’t too happy either:

Traceback (most recent call last):
  File "manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
    utility.execute()
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/core/management/commands/syncdb.py", line 60, in handle_noargs
    tables = connection.introspection.table_names()
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/db/backends/__init__.py", line 896, in table_names
    return self.get_table_list(cursor)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/introspection.py", line 33, in get_table_list
    AND pg_catalog.pg_table_is_visible(c.oid)""")
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/db/backends/util.py", line 40, in execute
    return self.cursor.execute(sql, params)
  File "/home/stu/.virtualenvs/the_app/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 52, in execute
    return self.cursor.execute(query, args)
django.db.utils.DatabaseError: current transaction is aborted, commands ignored until end of transaction block

In the end the solution was simple, just check for the args where we need the refresh to happen automatically:

## Automatically reload when forms or tests changed
try:
    from django.conf import settings

    if settings.DEBUG:
        import sys
        if sys.argv == ['manage.py', 'autotest'] or sys.argv == ['manage.py', 'runserver']:
                # Need to check params as otherwise this can break syncdb, reset and
                # Friends !!
                import forms, util, tests
except:
    pass

Hopefully this will be helpful to somebody with a similar error or that wants autotest or runserver to see more files.
 

This article was particularly helpful in debugging this:  debugging django syncdb

Cairo with python Ctypes

Uploaded some experiments with python and ctypes to here:

https://gitorious.org/pycairo-ctypes/pycairo-ctypes

 

This is a really rough proof of concept that the pycairo API can be implemented with ctypes + metclasses.

 

 

So far only ImageSurface is supported on the SVG backend, along with Contexts.   The nice thing about this is that you can use a pycairo like API on pypy, where things should be faster (in theory).

 

There’s a test that can be run to show the outputs the same for pycairo and cairo ctypes.

Using PyCha with Django

A quick post on using Python Charts to generate nice SVG charts for your django website (I’ve had the code hanging around for ages – so should just post it). The code is based on the examples there, here I integrate it into Django.

To install you’ll need to do

pip install pycha

Heres the code for a simple view to output a chart directly to SVG:

# views.py

from StringIO import StringIO
from django.http import HttpResponse

import cairo

def colors(request):
    in_req = 1

    svg_buffer = StringIO()

    width, height = (500, 400)
    surface = cairo.SVGSurface(svg_buffer, width, height)

    dataSet = (
     ('dataSet 1', ((0, 1), (1, 3), (2, 2.5))),
     ('dataSet 2', ((0, 2), (1, 4), (2, 3))),
     ('dataSet 3', ((0, 5), (1, 1), (2, 0.5))),
    )

    options = {
       'legend': {'hide': True},
       'background': {'color': '#f0f0f0'},
    }

    #import pycha.bar
    #chart = pycha.bar.VerticalBarChart(surface, options)

    import pycha.line
    chart = pycha.line.LineChart(surface, options)
    chart.addDataset(dataSet)
    chart.render()

    del chart
    del surface

    response = ''
    response = HttpResponse(mimetype='image/svg+xml')
    svg_buffer.seek(0)
    response.write( svg_buffer.read() )
    return response

The basic idea is that – instead of the chart outputting to an svg file, the output goes to a buffer, this is triggered by calling the destructors of the chart and it’s cairo surface.  Once the data is in the buffer, it is rewound and played back to the Http Response.

 

Inline SVG

As is, this won’t work as inline svg, because outputting the XML preamble in the middle of the page will cause problems.  Below is an example that let’s you decide if you need the preamble (full SVG output), or not (SVG fragment for inclusion in a page or another SVG):

# Create your views here.

from StringIO import StringIO
from django.http import HttpResponse
from django.shortcuts import render_to_response

import cairo

XML_PREAMBLE = '<?xml version="1.0" encoding="UTF-8"?>'

def colors_chart(inline = False):
    """
    Generate colours chart

    Set inline to True to disable the XML preamble
    """
    in_req = 1

    svg_buffer = StringIO()

    width, height = (500, 400)
    surface = cairo.SVGSurface(svg_buffer, width, height)

    dataSet = (
     ('dataSet 1', ((0, 1), (1, 3), (2, 2.5))),
     ('dataSet 2', ((0, 2), (1, 4), (2, 3))),
     ('dataSet 3', ((0, 5), (1, 1), (2, 0.5))),
    )

    options = {
       'legend': {'hide': True},
       'background': {'color': '#f0f0f0'},
    }

    import pycha.bar
    chart = pycha.bar.VerticalBarChart(surface, options)

    #import pycha.line
    #chart = pycha.line.LineChart(surface, options)
    chart.addDataset(dataSet)
    chart.render()

    del chart
    del surface

    response = ''

    if inline:
        svg_buffer.seek(len(XML_PREAMBLE))
    else:
        svg_buffer.seek(0)
    return svg_buffer.read()

def colors_svg(request):
    """ render a pure SVG chart """
    response = HttpResponse(mimetype='image/svg+xml')
    response.write(colors_chart(inline = False))
    return response

def index(request):
    """ render a chart into the template """
    chart_svg = colors_chart(inline = True)

    return render_to_response(
        'shapes_index.html',
        { "chart" : chart_svg },
        mimetype='application/xhtml+xml')

An example project with the above code is available here:
pycha_django

 

[EDIT 25/2/2011] Fixed PyCha URL

[EDIT: 2010/10/05]

Oops, I’ve been using TCC/LE by JPSoft as my shell… the following doesn’t work in the normal command prompt

[/EDIT]

I just had a look at SET and it lets you set user/system variables:

Display, create, modify, or delete environment variables.

SET [/A /D /E /P /R file... /S /U /V /X] [name[=][value ]]
        file:  One or more files containing variable definitions
        /A(rithmetic)           /S(ystem variables)
        /D(efault variables)    /U(ser variables)
        /E(nv vars)             /V(olatile variables)
        /R(ead from file)       /X override VariableExclude
        /P(ause)

So to set save a variables MYAPP_HOME as the current directory, just do

SET /U MYAPP_HOME=%CD

Wish I’d have looked that up a few years ago, it’ll save a few seconds next time I need to setup some dev sdk :)

Simple python spectrograph with shoebot

Seeing”Realtime FFT Graph of Audio WAV File or Microphone Input with Python…”  on python.reddit.com reminded me of one I’d built in python with shoebot.

While it works OK, I feel like I’m missing a higher level audio library (especially having seen Minim, for C++ and Java).

To run it in shoebot:

sbot -w audiobot.bot

audiobot.bot

# Major library imports
import atexit
import pyaudio
from numpy import zeros, short, fromstring, array
from numpy.fft import fft

NUM_SAMPLES = 512
SAMPLING_RATE = 11025

def setup():
    size(350, 260)
    speed(SAMPLING_RATE / NUM_SAMPLES)

_stream = None

def read_fft():
    global _stream
    pa = None

    def cleanup_audio():
        if _stream:
            _stream.stop_stream()
            _stream.close()
        pa.terminate()

    if _stream is None:
        pa = pyaudio.PyAudio()
        _stream = pa.open(format=pyaudio.paInt16, channels=1,
                           rate=SAMPLING_RATE,
                           input=True, frames_per_buffer=NUM_SAMPLES)
        atexit.register(cleanup_audio)

    audio_data  = fromstring(_stream.read(NUM_SAMPLES), dtype=short)
    normalized_data = audio_data / 32768.0

    return fft(normalized_data)[1:1+NUM_SAMPLES/2]

def flatten_fft(scale = 1.0):
    """
    Produces a nicer graph, I'm not sure if this is correct
    """
    for i, v in enumerate(read_fft()):
        yield scale * (i * v) / NUM_SAMPLES

def triple(audio):
    '''return bass/mid/treble'''
    c = audio.copy()
    c.resize(3, 255 / 3)
    return c

def draw():
    '''Draw 3 different colour graphs'''
    global NUM_SAMPLES
    audio = array(list(flatten_fft(scale = 80)))
    freqs = len(audio)
    bass, mid, treble = triple(audio)

    colours = (0.5, 1.0, 0.5), (1, 1, 0), (1, 0.2, 0.5)

    fill(0, 0, 1)
    rect(0, 0, WIDTH, 400)
    translate(50, 200)

    for spectrum, col in zip((bass, mid, treble), colours):
        fill(col)
        for i, s in enumerate(spectrum):
            rect(i, 0, 1, -abs(s))
        else:
            translate(i, 0)

    audio = array(list(flatten_fft(scale = 80)))

Cairo: Surface for recording commands and playback

An update on my latest cairo adventures…

When cairo 1.10 comes out we’ll get a RecordingSurface so you can record commands and play them back to another surface, but how to do something similar now ?

Skip to the end if you just want the code, explanation of how I got there ahead:

My first advice was to try using PDFSurface, and set the file object to None.

# Record a red rectangle onto a surface.
#
# Create another surface and draw a background on it
# Draw the first surface onto this surface
#
from cairo import PDFSurface, ImageSurface, FORMAT_ARGB32, Context

recording = PDFSurface(None, 200, 200)
target = ImageSurface(FORMAT_ARGB32, 200, 200)

# Record a red rectangle
cr = Context(recording)
cr.set_source_rgb(1.0, 0.0, 1.0)
cr.rectangle(20, 20, 10, 10)

cr.fill_preserve()
cr.set_source_rgb(0.0, 0.0, 1.0)
cr.stroke()

target_context = Context(target)

# Draw background
target_context.set_source_rgb(1.0, 1.0, 0)
target_context.paint()

# Replay recording to target
target_context.set_source_surface(recording)
target_context.paint()

target.write_to_png('output.png')

That seems to work, except when I tried in Windows, when it complained that the file object was wrong.

OK, we can work round that:

def RecordingSurface(w, h):
    if os.name == 'nt':
        fobj = 'nul'
    else:
        fobj = None
    return PDFSurface(fobj, w, h)

This seems to be working, but my animation seemed slow… time for some benchmarking; I rendered 1000 frames and got a rough wall clock time:
1m48.

Hmm… perhaps SVGSurface will be quicker:
1m28

This is much better, 20 seconds difference just by changing what kind of surface is returned!

Animation not smooth though

The animation still seemed jerky it occured to me that when the surfaces are disposed they will attempt to out their content to the file object !

Luckily, get_similar_surface() comes to the rescue; it returns a surface not associated with a file object. Using this the original surface can be kept around forever, and never output.

Wallclock time:
50 seconds!

And here it is:

_svg_surface = None
def RecordingSurface(*size):
    '''
    We don't have RecordingSurfaces until cairo 1.10, so this kludge is used

    SVGSurfaces are created, but to stop them ever attempting to output, they
    are kept in a dict.

    When a surface is needed, create_similar is called to get a Surface from
    the SVGSurface of the same size
    '''
    global _svg_surface
    if os.name == 'nt':
        fobj = 'nul'
    else:
        fobj = None
    if _svg_surface is None:
        _svg_surface = SVGSurface(fobj, 0, 0)
    return _svg_surface.create_similar(cairo.CONTENT_COLOR_ALPHA, *size)

This is really useful, you can record commands and play them back to other surfaces.

A simple cairo draw queue using closures

Often it’s useful to be able to store up drawing commands so you can use them later somewhere else (or even just pass them to another thread).

This is a simple drawing model, implemented in cairo, hopefully somebody will find it useful.

Queue

class DrawQueue:
    '''
    A list of draw commands, stored as callables that, are
    passed a set of parameters to draw on from the canvas
    implementation.
    '''
    def __init__(self, render_callables = None):
        self.render_callables = render_callables or deque()

    def append(self, render_callable):
        '''
        Add a render callable to the queue
        '''
        self.render_callables.append(render_callable)

    def render(self, cairo_ctx):
        '''
        Call all the render callables with cairo_ctx
        '''
        for render_callable in self.render_callables:
            render_callable(cairo_ctx)

The queue just accepts callables (any old function), and calls them when you call render, passing them a cairo context you pass in.

To get useful functions you can call closure functions like these:

def paint_closure():
    def paint(ctx):
        ctx.paint()
    return paint

def fill_closure():
    def fill(ctx):
        ctx.fill()
    return fill

def set_source_rgb_closure(r, g, b):
    def set_source_rgb(ctx):
        ctx.set_source_rgb(r, g, b)
    return set_source_rgb

def moveto_closure(x, y):
    def moveto(ctx):
        ctx.move_to(x, y)
    return moveto

def rectangle_closure(x, y, w, h):
    def rectangle(ctx):
        ctx.rectangle(x, y, w, h)
    return rectangle

Adding commands to the queue is simple:

dq = DrawQueue()
dq.append(set_source_rgb_closure(1, 1, 1))
dq.append(paint_closure())
dq.append(moveto_closure(10, 0))
dq.append(rectangle_closure(0, 0, 20, 20))
dq.append(set_source_rgb_closure(0, 0, 0))
dq.append(fill_closure())

This is the same drawing model I’m using in my branch of shoebot, I’m hoping to expand it to be multithreaded; while a foreground thread adds commands a background thread is executing them.

Here it is all put together in a simple example to draw a black rectangle

from collections import deque
import cairo

class DrawQueue:
    '''
    A list of draw commands, stored as callables that, are
    passed a set of parameters to draw on from the canvas
    implementation.
    '''
    def __init__(self, render_callables = None):
        self.render_callables = render_callables or deque()

    def append(self, render_callable):
        '''
        Add a render callable to the queue
        '''
        self.render_callables.append(render_callable)

    def render(self, cairo_ctx):
        '''
        Call all the render callables with cairo_ctx
        '''
        for render_callable in self.render_callables:
            render_callable(cairo_ctx)

#### drawing closures
def paint_closure():
    def paint(ctx):
        ctx.paint()
    return paint

def fill_closure():
    def fill(ctx):
        ctx.fill()
    return fill

def set_source_rgb_closure(r, g, b):
    def set_source_rgb(ctx):
        ctx.set_source_rgb(r, g, b)
    return set_source_rgb

def moveto_closure(x, y):
    def moveto(ctx):
        ctx.move_to(x, y)
    return moveto

def rectangle_closure(x, y, w, h):
    def rectangle(ctx):
        ctx.rectangle(x, y, w, h)
    return rectangle

#### /drawing closures

dq = DrawQueue()

# Add some commands to the drawing queue
dq.append(set_source_rgb_closure(1, 1, 1))
dq.append(paint_closure())
dq.append(moveto_closure(10, 0))
dq.append(rectangle_closure(0, 0, 20, 20))
dq.append(set_source_rgb_closure(0, 0, 0))
dq.append(fill_closure())

# Create a surface and context
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 200, 200)
ctx = cairo.Context(surface)

# run defered rendering
dq.render(ctx)

surface.write_to_png('output.png')

Processing with Jython and Nodebox/Shoebot libraries

Update: 26/April/2010

Problems I was having with incomplete images have been fixed in the current version of the web library, available in shoebots mecurial repository.

Using Processing from Jython is a promising idea, so I took the base from this post on backspaces.net where they explained how to use Jython and built on it a little.

This is great as Shoebot/Nodebox have great libraries for data manipulation, while processing is more focused on graphics.

The result is the attached Netbeans project which demonstrates using the nodebox web library and  drawing with processing.

Slowcessing

The glue code is in slowcessing.py

Theres a special version of PApplet (PJApplet), and ‘pj_frame’ which can put this in a JFrame.

The other method is ‘shoebot_imports’ adds the shoebot imports to the library path

In case anybody doesn’t want to download the whole project, heres the code:

imagestrip.py

from slowcessing import PJApplet, pj_frame, shoebot_imports
from processing.opengl import *

shoebot_imports()
import web
import thread

class ImageQueue(list):
    """
    Download images in the background and add them to a list
    """
    def __init__(self, search, size):
        list.__init__(self)
        self._search = search
        self._image_size = size
        thread.start_new_thread(self._get_images, ())

    def _image_downloaded(self, path):
        p = PJApplet()
        self.append(p.loadImage(path))

    def _get_images(self):
        for image in self._search:
            image.download(self._image_size, asynchronous=False)
            self._image_downloaded(image.path)

class WebTest (PJApplet):
  def setup(self):
    self.size(400, 400, self.P3D)
    self.images = ImageQueue(web.morguefile.search("sweets", max=1), size='small')

  def draw(self):
    self.background(0);
    y = (self.height * 0.2) - self.mouseY * (len(self.images) * 0.58)
    for image in self.images:
        self.image(image, 20, y)
        y += image.height

if __name__ == '__main__':
    pj_frame(WebTest)

slowcessing.py

from javax.swing import JFrame

from processing.core import PApplet

class PJApplet(PApplet):
  # rqd due to PApplet's using frameRate and frameRate(n) etc.
  def getField(self, name):
      return PApplet.getDeclaredField(name).get(self)

def pj_frame(pj_applet, **kwargs):
    from time import sleep

    frame = JFrame(kwargs.get('title', 'Slowcessing'))
    frame.defaultCloseOperation = kwargs.get('defaultCloseOperation', JFrame.EXIT_ON_CLOSE)
    frame.resizable = kwargs.get('resizable', False)

    panel = pj_applet()
    frame.add(panel)
    panel.init()

    while panel.defaultSize and not panel.finished:
        sleep(0.5)

    frame.pack()
    frame.visible = 1

    return frame

def shoebot_imports():
    """
    Allow import of the shoebot libraries
    """
    ##APP = 'shoebot'
    import sys
    DIR = sys.prefix + '/share/shoebot/locale'
    ##locale.setlocale(locale.LC_ALL, '')
    ##gettext.bindtextdomain(APP, DIR)
    ###gettext.bindtextdomain(APP)
    ##gettext.textdomain(APP)
    ##_ = gettext.gettext

    LIB_DIR = sys.prefix + '/share/shoebot/lib'
    sys.path.append(LIB_DIR)

Problems

There are some things I couldn’t work :

The callback to say that images have been downloaded happens before the whole file is available, for this reason there are grey parts on the images on the first run.

Nodebox web…

While I did manage to fix things to get this working in Jython and get Morguefile working, I had a lot of trouble understanding what was going on here.

Cheers to Tom De Smedt for fixing these the areas of nodebox-web that I couldn’t :)

Processing…

Some parts of PApplet to do with image loading seem to be static, which may also explain problems I was getting with reentrancy.

Download

If you want to have a go, you’ll need to:

Install Netbeans 6.8

Install Jython (2.5 or higher) by installing the Netbeans python module

Add python to the path (if using Netbeans it’s copy is where Netbeans is installed).

Get nodebox-web by downloading shoebot and install it with:

jython setup.py install

In Netbeans, add all the jars in the processing\lib folder to the Jython classpath, and opengl\library\opengl.jar

Download the PythonOnProcessing (tested on Netbeans 6.8)

Using Cairo to generate SVG in Django

Cairo is a 2D vector graphics api used by Firefox, Gtk and other desktop projects.

I’m going to show here that it can also be used to generate web content, using Django.

I’m going to port two examples from the Michael Urmans Cairo Tutorial for PyGTK Programmers.

To understand the cairo and it’s drawing model I’d recommend his his Cairo Tutorial for Python Programmers.

Note: In this example I’ll be generating SVGs…  as I.E. (as of 2010) does not support them, you might want to generate PNG or PDF – if you need to do this with cairo, look for one of the many cairo tutorials on the web.

The example django project can be downloaded at the end of the article.

Continue reading