Sites

BingoDisk
Bookmarks
Complexity Digest
FRIAM
Joyent
NetLogo
RedfishGroup
RedfishTags
RePast
Santa Fe Institute
The Complex

Web Design

A List Apart
CSS and Standards
Eric Costello
Eric Meyer
Jeffrey Zeldman
TextBook
Textpattern
Textpattern Forum
WordPress

Processing: .. with Jython · 2006-10-29

Last article showed how we could use Processing with Eclipse and Java 1.5. Heady with success, I decided to try to convert the near-trivial RandBoxes Processing demo to Jython.

Why?? Well, our group uses Blender quite a bit, and Blender uses Python as its scripting language. More generally, Python is quite popular within our scientific community.

Jython, a Python implementation using the JVM, has been surprisingly successful, having most of what we like about CPython. And its Java integration made it a natural for Processing. This presentation is a good overview.

Java

Here’s the Java 1.4 code we’re starting with, the Processing .java file created when creating the applet above. A few notes:

  1. The two methods setup() and draw() are required by PApplet.
  2. Class Box is an inner class, as is usual for Processing, because:
  3. Several utilities are in PApplet like color(), random() and all drawing methods. Use of inner classes lets you “inherit” these.

public class RandBoxes extends PApplet {
  int numBoxes = 1000;
  ArrayList boxes = new ArrayList();

  public void setup() {
    size(600, 500, JAVA2D);
    while(boxes.size() < numBoxes)
      boxes.add(new Box(random(width), random(height)));
    println("number of boxes = "+boxes.size());
  }
  public void draw() {
    background(128);
    for (int i = 0; i < boxes.size(); i++)
      ((Box) boxes.get(i)).step();
    if (frameCount%10==0)
      println("frameRate="+frameRate+" frameCount="+frameCount);
  }

  class Box {
    int c = color(255, 255, 0);
    float x, y;
    Box(float x, float y) {
      this.x = x;
      this.y = y;
    }
    public void step() {
      x = max(min(x+random(-1, 1), width), 0);
      y = max(min(y+random(-1, 1), height), 0);
      paint();
    }
    public void paint() {
      noStroke();
      fill(c);
      rect(x-2, y-2, 5, 5);
    }
  }
}

Jython

Here’s the Jython I eventually came up with. Note this is not “pythonic” yet, but at least runs. Goals:

  1. Be able to run as an applet if possible
  2. Avoid a “proxy class” subclass of PApplet even though that’s a common stunt to make Jython usage simpler .. i.e. hide any Processing or Jython “warts”! See the Thoughts for an example.
  3. Run easily in the standard Jython environment

To run,
export CLASSPATH=~/local/processing/lib/core.jar:.
then put this in any file other than RandBoxes.py (see notes). I use RandBoxesTest.py :

from javax.swing import JFrame
from processing.core import PApplet
from random import uniform

winWidth=600
winHeight=500
numBoxes = 1000
boxes = []

class RandBoxes (PApplet):
  def __init__(self):
    pass
  def setup(self):
    self.size(winWidth, winHeight, self.JAVA2D)
    while len(boxes)<numBoxes:
      boxes.append(\
        Box(self, uniform(0,winWidth),uniform(0,winHeight)))
    print "number of boxes = %d" % len(boxes)
  # rqd due to PApplet's using frameRate and frameRate(n) etc.
  def getField(self, name):
    return self.class.superclass.getDeclaredField(name).get(self)
  def draw(self):
    self.background(128)
    for b in boxes: b.step()
    if self.frameCount % 10 == 0:
      print "frameRate=%f frameCount=%i" % \
      (self.getField('frameRate'), self.frameCount)

class Box(object):
  def __init__(self, p, x, y):
    self.p = p
    self.x = x
    self.y = y
    self.c = p.color(255,255,0)
  def step(self):
    self.x = max(min(self.x+uniform(-1,1),winWidth),0)
    self.y = max(min(self.y+uniform(-1,1),winHeight),0)
    self.paint()
  def paint(self):
    self.p.noStroke()
    self.p.fill(self.c)
    self.p.rect(self.x-2,self.y-2,5,5)

if __name__ == '__main__':
  frame = JFrame(title="Processing",
    resizable = 0,
    defaultCloseOperation=JFrame.EXIT_ON_CLOSE)
  panel = RandBoxes()
  frame.add(panel)
  panel.init()
  while panel.defaultSize and not panel.finished:
    pass
  frame.pack()
  frame.visible = 1

Notes:

Applet

To build the Applet, I used this jythonc command:

jythonc -J-g:none --core --deep --jar RandBoxes.jar RandBoxesTest.py

The applet tag looks like:

  <applet code="RandBoxesTest$RandBoxes"
         archive="RandBoxes.jar,core.jar"
         width=600 height=500>
  </applet>

The Applet, and similar links, are here:

Thoughts

        import processing.core.*;
        public class PAppletProxy extends PApplet {
          public float getFrameRate() {
            return frameRate;
          }
        }