Creating Processing Visualizations with Clojure and Incanter

The Processing language, created by Ben Fry and Casey Reas,
“is an open source programming language and environment for people who want to program images, animation, and interactions.”

Incanter now includes the incanter.processing library, a fork of Roland Sadowski‘s clj-processing library, making it possible to create Processing visualizations with Clojure and Incanter. Incanter.processing provides much more flexibility when creating customized data visualizations than incanter.charts — of course, it is also more complex to use.

Several nice examples of the kinds of visualizations that can be created in Processing can be found on Ben Fry’s website and blog, including the cool zipcode, human vs. chimps, baseball salary vs. performance examples.

The processing website has a set of tutorials, including one on getting started, and there are also three great books on Processing worth checking out:

The API documentation for incanter.processing is still a bit underdeveloped, but is perhaps adequate when combined with the excellent API reference on the Processing website.

Incanter.processing was forked from of Roland Sadowski’s clj-processing library in order to provide cleaner integration with Incanter. I have added a few functions, eliminated some, and changed the names of others. There were a few instances where I merged multiple functions (e.g. *-float, *-int) into a single one to more closely mimic the original Processing API; I incorporated a couple functions into Incanter’s existing multi-methods (e.g. save and view); I eliminated a few functions that duplicated existing Incanter functions and caused naming conflicts (e.g. sin, cos, tan, asin, acos, atan, etc); and I changed the function signatures of pretty much every function in clj-processing to require the explicit passing of the ‘sketch’ (PApplet) object, whereas the original library passes it implicitly by requiring that it is bound to a variable called *applet* in each method of the PApplet proxy.

These changes make it easier to use Processing within Incanter, but if you just want to write Processing applications in Clojure without all the dependencies of Incanter, then the original clj-processing library is the best choice.

A Simple Example

The following is sort of a “hello world” example that demonstrates the basics of creating an interactive Processing visualization (a.k.a sketch), including defining the sketch’s setup, draw, and mouseMoved methods and representing state in the sketch using closures and refs. This example is based on this one, found at John Resig‘s Processing-js website.


Click on the image above to see the live Processing-js version of the sketch.

Start by loading the incanter.core and incanter.processing libraries,

(use '(incanter core processing))

Now define some refs that will represent the state of the sketch object,

(let [radius (ref 50.0)
      X (ref nil)
      Y (ref nil)
      nX (ref nil)
      nY (ref nil)
      delay 16

The variable radius will provide the value of the circle’s radius; X and Y will indicate the location of the circle; and nX and nY will indicate the location of the mouse. We use refs for these values because their values are mutable and need to be available across multiple functions in the sketch object.

Now define a sketch object, which is just a proxied processing.core.PApplet, and its required setup method,

sktch (sketch
        (setup []
          (doto this
            (size 200 200)
            (stroke-weight 10)
            (framerate 15)
            smooth)
          (dosync
            (ref-set X (/ (width this) 2))
            (ref-set Y (/ (width this) 2))
            (ref-set nX @X)
            (ref-set nY @Y)))

The first part of the setup method sets the size of the sketch, the stroke weight to be used when drawing, the framerate of the animation, and indicates that anti-aliasing should be used. The next part of the method uses a dosync block and ref-set to set initial values for the refs. Note the @ syntax to dereference (access the values of) the refs X and Y.

Processing sketches that use animation require the definition of a draw method, which in this case will be invoked 15 times per second as specified by the framerate.

  (draw []
   (dosync
     (ref-set radius (+ @radius 
                        (sin (/ (frame-count this) 4))))
     (ref-set X (+ @X (/ (- @nX @X) delay)))
     (ref-set Y (+ @Y (/ (- @nY @Y) delay))))
   (doto this
     (background 125) ;; gray
     (fill 0 121 184)
     (stroke 255)
     (ellipse @X @Y @radius @radius)))

The first part of the draw method uses dosync and ref-set to set new values for the radius, X, and Y refs for each frame of the animation. The sin function is used to grow and shrink the radius over time. The location of the circle, as indicated by X and Y, is determined by the mouse location (nX and nY) with a delay factor.

The next part of the draw method draws the background (i.e. gray background) and the circle with the ellipse function.

Finally, we need to define the mouseMoved method in order to track the mouse location, using the mouse-x and mouse-y functions, and set the values of the nX and nY refs. All event functions in incanter.processing, including mouseMoved, require an event argument; this is due to limitations of Clojure’s proxy macro, and isn’t required when using the Processing’s Java API directly.

(mouseMoved [mouse-event]
  (dosync
    (ref-set nX (mouse-x mouse-event)) 
    (ref-set nY (mouse-y mouse-event)))))]

Now that the sketch is fully defined, use the view function to display it,

(view sktch :size [200 200]))

The complete code for this example can be found here.

In future posts I will walk through other examples of Processing visualizations, some of which can be found in the Incanter distribution under incanter/examples/processing.

17 responses to “Creating Processing Visualizations with Clojure and Incanter

  1. Very cool. Nice write up!

  2. Great ! Thanks for adding Processing into Incanter.

  3. Nice post. I always wanted to take a look at processing. With a clojure bridge, i have no excuse now.
    Thanks.

  4. Anyone else getting the following error when they try this sample?

    >bin/clj examples/simple_interaction.clj
    Exception in thread “main” java.lang.IllegalArgumentException: No method in multimethod ‘view’ for dispatch value: class user.proxy$processing.core.PApplet$0 (simple_interaction.clj:0)

    • Hi James,

      Thanks for catching that bug. I introduced it when I removed the Processing library dependency from incanter.core recently. I’ve pushed a fix to Github, let me know if you have any further problems.

      David

      • updated, rebuilt and it works great!

        thanks for your great work.

      • although I just tried the us map data example and while it does run there is an error reported…

        bin/clj examples/processing/us_map_data.clj
        Exception in thread “Animation Thread” java.lang.IllegalArgumentException: No method in multimethod ‘save’ for dispatch value: class user.proxy$processing.core.PApplet$0

      • D’oh! I forgot that the ‘save’ multi-method used the same dispatch logic. Fix uploaded, give it a try.

        Thanks for the debugging help :)

        David

      • All good!

        Glad I could help.

  5. Hi again,

    I wonder if you or any of your readers could help me with getting any of the 3d modes to work.

    When defining the setup if I pass “P3D” as the third argument to size I get an error…

    “Exception in thread “Animation Thread” java.lang.RuntimeException: You need to use “Import Library” to add P3D to your sketch.
    at processing.core.PApplet.makeGraphics(PApplet.java:1193)”

    Usually in processing P3D is available without importing.
    I also tried OPENGL following the instructions in clj-processing about adding to the classpath etc but no joy.

    If anyone can provide a simple example that would be great.

    thanks,

    James

    • I haven’t worked with P3D or OpenGL within Processing yet, but I think the problem you’re experiencing is because you are passing “P3D” to the size function. Try passing the ‘constant’ P3D (which has the value “processing.core.PGraphics3D”). Let me know if this fixes your problem.

      Good luck,
      David

      • David, you were of course correct :)

        I had actually tried that before after seeing it in your processing.clj file but I must have done something else wrong at the time as I thought that it wasn’t working.

        So I put together a simple example from your simple_interaction.clj and the RGB cube example on the Processing site…


        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ; Simple 3d Clojure code example for Incanter and Processing
        ; Adapted by James Swift (james at 3dengineer com)
        ; from the simple_interation.clj example that comes with incanter
        ; and the RGB cube example here http://processing.org/learning/3d/rgbcube.html
        (ns example
        (:use [incanter core processing]))
        ;; set up variable references to use in the sketch object
        (let [X (ref nil)
        Y (ref nil)
        nX (ref nil)
        nY (ref nil)
        delay 16
        ;; define a sketch object (i.e. PApplet)
        sktch (sketch
        ;; define the setup function
        (setup []
        (doto this
        (no-stroke)
        (size 790 590 P3D)
        (color-mode RGB 1))
        (dosync
        (ref-set X (/ (width this) 2))
        (ref-set Y (/ (width this) 2))
        (ref-set nX @X)
        (ref-set nY @Y)))
        ;; define the draw function
        (draw []
        (doto this
        (background (color 0xFFFFFF))
        (push-matrix)
        (translate (/ (width this) 2) (/ (height this) 2) -30)
        (rotate-x (- @nX))
        (rotate-y (- @nY))
        (scale 90)
        (begin-shape QUADS)
        (fill 0 1 1) (vertex -1 1 1)
        (fill 1 1 1) (vertex 1 1 1)
        (fill 1 0 1) (vertex 1 -1 1)
        (fill 0 0 1) (vertex -1 -1 1)
        (fill 1 1 1) (vertex 1 1 1)
        (fill 1 1 0) (vertex 1 1 -1)
        (fill 1 0 0) (vertex 1 -1 -1)
        (fill 1 0 1) (vertex 1 -1 1)
        (fill 1 1 0) (vertex 1 1 -1)
        (fill 0 1 0) (vertex -1 1 -1)
        (fill 0 0 0) (vertex -1 -1 -1)
        (fill 1 0 0) (vertex 1 -1 -1)
        (fill 0 1 0) (vertex -1 1 -1)
        (fill 0 1 1) (vertex -1 1 1)
        (fill 0 0 1) (vertex -1 -1 1)
        (fill 0 0 0) (vertex -1 -1 -1)
        (fill 0 1 0) (vertex -1 1 -1)
        (fill 1 1 0) (vertex 1 1 -1)
        (fill 1 1 1) (vertex 1 1 1)
        (fill 0 1 1) (vertex -1 1 1)
        (fill 0 0 0) (vertex -1 -1 -1)
        (fill 1 0 0) (vertex 1 -1 -1)
        (fill 1 0 1) (vertex 1 -1 1)
        (fill 0 0 1) (vertex -1 -1 1)
        (end-shape)
        (pop-matrix)
        ))
        ;; define mouseMoved function (mouseMoved and mouseDraw
        ;; require a 'mouse-event' argument unlike the standard Processing
        ;; methods)
        (mouseMoved [mouse-event]
        (dosync
        ;; mouse-x and mouse-y take the mouse-event as an argument
        (ref-set nX (* (/ (mouse-y mouse-event) (width this)) TWO_PI))
        (ref-set nY (* (/ (mouse-x mouse-event) (height this)) TWO_PI)))))]
        ;; use the view function to display the sketch
        (view sktch :size [800 600]))

        Might help people like me who are new to all this.

        thanks again,

        James

      • James,

        Your example works great, and it’s a nice simple example of interactive 3D. I’d like to include it in the examples/ directory of the Incanter distribution, if it’s alright with you.

        David

      • Of course!
        Every little helps :)

        If I do any more that might be interesting I’ll post them up here and you can feel free to add them.

      • Thanks, and I’d love to have additional Processing examples to include! Keep it up :)

        David

Leave a comment